YUI JS minifier mess up code - yui

I'm using BundleTransformer.Yui.Minifiers.YuiJsMinifier in asp.net MVC 4 project, but I think it's YUI compressor bug...
...
var varName='...';
alert(varName); //alert('...')
$.ajax({
url: url,
success: function (t, s) {
alert(varName); //alert(t);
}
When BundleTrasformer minify & obfuscate this code using YUI compressor variable varName becomes t, and function parameter t stays t, so varName get's overwritten with t...
checkout commented alert...
My question is should I change compressor, or maybe rename all one, and two letter variables into longer ones? Am I doing something wrong?
if I just change one line of code, all is OK, so I'm pretty sure it's YUI compressor bug
...
var varName='...';
alert(varName);
$.ajax({
url: url,
success: function (data, s) {
alert(varName);
}
PS
I know it's not good practice to have one letter variable names, but it's still YUI compressor bug...
PPS:
I'm using eval inside succes function. (Know that's not good practice also, but still, YUI compressor shouldn't break up the code :/)

The varName variable is global, and therefore it's name is not processed.
You need to make it local. To do this, wrap the code in a IIFE (Immediately Invoked Function Expression):
(function(){
...
var varName='...';
alert(varName);
$.ajax({
url: url,
success: function (data, s) {
alert(varName);
}
})();

Related

Check if a function exists inside another function in nodejs

Propose the following situation:
function functionExists(functionName) {
if (typeof window[functionName] == 'function') console.log("It's a function");
}
What would be an equivalent function in nodejs for functionExists where there is no global window variable?
CONCRETE SITUATION:
My concrete situation uses webpack instead of nodejs, but basically the problem is the same. I could use window here, but it would be too complicated to implement everything cleanly, and it isn't advised by webpack to mitigate things out to the window global variable.
Basically, I have a PHP backend, which generates a html <form> adding some options to it via a data attribute. When the page is loaded, my javascript initializes this <form> and gives it a bunch of functionalities (like validation for example). Another thing javascript does with this form, is that it parses the data attribute of it, and instead of the normal page reload submit, it changes the form so it is being submited over an ajax request to the server.
When this submit happens, it is set up, that the button and the whole form gets disabled, until my Ajax script sends back a response. How this is done, is that I have a Project_Form class, which when it is initialized, attaches itself to the jQuery submit event, stops the basic submit event, and runs an inner function which sends an ajax request to an api method. The ajax request is set up, that when a response is received, the same instantiated class will receive this response, so I can continue working with it.
When the form receives the response, it must do something with it. In the most basic situation, it must show a success message to the user, but there are some more complex situation, where for example, it has to make a page redirect (for example a login form). Right now, it is set up, that as a default, it will show a message, but when I define this form in PHP, I have the option to "hijack" this default behaviour, and instead of it, send the ajax response to a custom function, which will resolve the situation specifically.
When I am rendering the form in PHP, I already know where the form should send a success response (to which javascript function), but I can only provide this information to javascript, via a string. So my Project_Form class, should fetch this string, and should try to fetch a function from it which it will use. This is where my problem is coming from.
Unless you specifically KNOW that this is a global function (which is almost never the case in nodejs), functions by default in nodejs are scoped to the module and there is NO way to look them up by string name like you did with the window object in the browser, just like there is no way to look up local variables by name inside a function in Javascript.
In general, don't pass functions by string name. Or, if you have to, then you need to create a lookup table that you can check the function name against.
I'd suggest you explain the real problem you're trying to solve here because passing the function by string name is not how you would generally want to do things.
There is a bit of a hack using eval() that can see if a string represents a function name that is in scope:
// Warning, you must know that the argument f (if it is a string) does not
// contain harmful Javascript code because it will be used with eval()
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
Note: This tests to see if the function is in the scope of the isFunction() function. If you want to test if it's in your current scope, then you need to do the:
eval(`typeof ${f} === "function"`)
inline in your current scope so it runs in the scope you want to do the lookup from.
To ever consider using this, you will HAVE to know that the source of your string is safe and cannot contain harmful code. But, as I said earlier, it's better to design your program differently so you aren't referring to functions by their string name.
And, here's a runnable snippet that shows it in action (also works in a node.js module):
function test() {
console.log("in test");
}
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
console.log(isFunction("test")); // true
console.log(isFunction(test)); // true
console.log(isFunction("notAFunction")); // false
More added after question edit
If you only have the function name as a string and the function that it points to is not a property of some known object, then the only way I know of to turn that string into a function reference is with eval().
You could directly execute it with eval() such as eval(functionName + "()") or you could get a reference to the function with eval("let fn = " + functionName) and then use the newly defined fn variable to call the function.
If you control the various functions that could be referenced (because they're your Javascript), then you can make all those functions be a property of a known object in your Javsacript:
const functionDispatcher = {
function1,
function2,
function3,
function4
}
Then, instead of using eval(), you can reference them off the functionDispatcher object like you would have referenced before with window (except this isn't a global) as in:
functionDispatcher[someFunctionName]();
This would be a preferred option over using eval() since there is less risk of insertion of random code via an unsafe string.
In node.js you can achieve this like:
function functionExists(functionName) {
if(functionName && typeof functionName === "function")
console.log("It is a function");
}
Hope this works for you.

Another Node.js newb who doesn't get it

EDITED: adjusted my narrative, and attempted to add output to code as examples show but it doesn't work. What am I doing wrong?
Hi experts or enthusiast superior to myself,
The question is "how to properly get the output from a asynchronous function in node.js as a return". The examples all talk of this mysterious callback function but in the context of my code I don't see how it applies or gets implemented.
Yes, the question has been asked many times, if I had to ask it again it is because the explanations provided didn't get this newb to a understanding. Yes, I spent near 24 hours or so trying to follow the examples, documentation, and other posts, but I didn't find one that explained it clear enough that I could apply to my code.
The concept of asynchronous makes sense, the code runs but the, in this case, https call hasn't. The code doesn't wait for the https call. You have to somehow grab the result after it has completed. While I haven't found the practicality of it, I am sure I will as I continue to learn why node.js is special in this way. Assuming my understanding is mostly right, my question is still the same. Concept is one thing, application and syntax are another.
This seems to be a common question and something nearly everyone new has trouble with.
Thus far none of the examples or explanations seem to clarify where or how with what I am working with. I understand there are additional modules that handle these differently but I believe I wont understand the 'why/how' as it applies unless I figure this out properly.
As I am brand new to node.js feel free to expand on any aspect of my code as I am eager to learn.
If anyone is finding this, this code will get data from the official Clash Royal API for which you require to register your IP and get a token from https://developer.clashroyale.com.
app.js
require('dotenv').config();
var func = require('./functions.js');
console.log(func.uChests(process.env.MyPlayer)); //this should output the value
functions.js
require('dotenv').config();
//console.log('Loaded Functions')
module.exports.uChests = func_uChests
//Clearly wrong application
//function func_uChests (playerID) {
function func_uChests (playerID,output) {
//console.log('uChests')
var http = require("https");
var options = {
"method": "GET",
"hostname": "api.clashroyale.com",
"port": null,
"path": "/v1/players/%23"+ playerID + "/upcomingchests",
"headers": {
"content-length": "0",
"authorization": "Bearer " + process.env.Token,
"accept": "application/json"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
/* example output
{"items":[{"index":0,"name":"Magical Chest"},{"index":1,"name":"Silver Chest"},{"index":2,"name":"Silver Chest"},{"index":3,"name":"Golden Chest"},{"index":4,"name":"Silver Chest"},{"index":5,"name":"Silver Chest"},{"index":6,"name":"Silver Chest"},{"index":7,"name":"Golden Chest"},{"index":8,"name":"Silver Chest"},{"index":22,"name":"Legendary Chest"},{"index":40,"name":"Giant Chest"},{"index":76,"name":"Super Magical Chest"},{"index":77,"name":"Epic Chest"}]}
{"items":[{"index":0,"name":"Magical Chest"},{"index":1,"name":"Silver Chest"},{"index":2,"name":"Silver Chest"},{"index":3,"name":"Golden Chest"},{"index":4,"name":"Silver Chest"},{"index":5,"name":"Silver Chest"},{"index":6,"name":"Silver Chest"},{"index":7,"name":"Golden Chest"},{"index":8,"name":"Silver Chest"},{"index":22,"name":"Legendary Chest"},{"index":40,"name":"Giant Chest"},{"index":76,"name":"Super Magical Chest"},{"index":77,"name":"Epic Chest"}]}
*/
});
});
req.end();
}
//Clearly wrong application
function uChests(input, output) {
func_uChests(input, output);
console.log(output);
};
i think you should understand better na async nature of node , the only way you can return values to the caller statement is using a function parameter or Async/Await with Promises API,take a look below.
´
// return from a function parameter
myAsyncFunction(function(value){
console.log(value)
})
// or using the Promise API
let value = await myAsyncFunction()´

Ideal way of using for loop in node

I've written a very tiny script in node.js to check out how links can be passed to a function using loop.
I could see that I can do the same in two ways but can't figure out which way I should stick to, meaning which one is ideal and why?
One way: for (link in links) {}
var request = require('request');
var links = ['https://stackoverflow.com/questions/ask', 'https://github.com/request/request'];
for (link in links) {
(function(url) {
request(url, function() {
console.log(url);
});
})(links[link]);
}
The other way: for (const link of links) {}
var request = require('request');
var links = ['https://stackoverflow.com/questions/ask', 'https://github.com/request/request'];
for (const link of links) {
(function(url) {
request(url, function() {
console.log(url);
});
})(link);
}
There is no ideal way or at least an universal ideal way of doing this, So i will point out the difference between these two.
In first for loop you are iterating the array as an object (in javascript array is an object which can traverse with indexes). But will create a global variable called link after the execution. So an unwanted variable and memory location is created.
Try console.log(link) after the execution.
The second for loop is introduced with ECMA Script 6 and won't create a global variable and is recommended. Because of the readability and the more control over your data, and link can be defined as const if you want. So it won't be modified inside the loop.
For node.js I guess second one may be perfect for most scenarios. But in javascript, the first one may be higher in performance wise, if you are compiling it from ES6 to ES5 and it is the case for most scenarios.

Moving Function With Arguments To RequireJS

I'm not only relatively new to JavaScript but also to RequireJS (coming from string C# background). Currently on my web page I have a number of JavaScript functions. Each one takes two arguments. Imagine that they look like this:
functionA(x1, y1) { ... }
functionB(x2, y2) { ... }
functionC(x3, y3) { ... }
Currently, these functions exist in a tag on my HTML page and I simply call each as needed.
My functions have dependencies on KnockoutJS, jQuery, and some other JS libraries. I currently have Script tags that synchronously load those external .js dependencies. But I want to use RequireJS so that they're loaded asynchronously, as needed. To do this, I plan to move all three functions above into an external .js file (a type of AMD "module") called MyFunctions.js. That file will have a define() call (to RequireJS's define function) that will look something like this:
define(["knockout", "jquery", ...], function("ko","jquery", ...) {???} );
My question is how to "wrap" my functionA, functionB, and functionC functions where the ??? is above so that I can use those functions on my page as needed. For example, in the onclick event handler for a button on my HTML page, I would want to call functionA and pass two it two arguments; same for functionB and functionC.
I don't fully understand how to expose those functions when they're wrapped in a define that itself is located in an external .js file. I know that define assures that my listed libraries are loaded asynchronously before the callback function is called, but after that's done I don't understand how the web page's script tags would use my functions. Would I need to use require to ensure they're available, such as:
require(["myfunctions"],function({not sure what to put here})]
I think I understand the basics of RequireJS but I don't understand how to wrap my functions so that they're in external .js files, don't pollute the global namespace, and yet can still be called from the main page so that arguments can be passed to them. I imagine they're are many ways to do this but in reviewing the RequireJS docs and some videos out there, I can't say I understand how...
Thank you for any help.
Just let your MyFunctions.js file return an object to which you have added the methods you want to expose, like so:
define([], function(){
function myPrivateFunction(){
console.log('in private function');
}
function myPublicFunction(){
console.log('in public function');
}
function myOtherPublicFunction(){
console.log('in the other public function');
}
return {
functionA: myPublicFunction,
functionB: myOtherPublicFunction
};
});
The name you give the parameter to your function which requires the MyFunctions does not matter at all. The name strings and the order of the strings in the dependency array does matter, as does the order of the parameters to the function, but the names of the parameters does not. E.g.
require('myFunctions', 'knockout', 'jquery', function(myFunctions, ko, $){
//here we can use the myFunctions, ko and $ variables.
//To call the public function, use the name which the function was
//exposed as; functionA
myFunctions.functionA();
});
The above sample code works exactly the same as the following:
require('myFunctions', 'knockout', 'jquery', function(my, k, j){
//In this example, your functions will be on the value of the 'my' variable,
//knockout will be the value of the 'k' variable and jQuery will be the
//value of the 'j' variable.
//To call the public function, use the name which the function was
//exposed as; functionA
my.functionA();
});

How do I call a basic YUI3 function from within a normal JavaScript function?

I'd like to call a simple YUI3 function from within a JavaScript function.
Here is some code that does what I want in a very verbose way:
function changeContent (message) {
YUI().use("node", function(Y) {
Y.all('#content-div').setContent(message);
});
}
Is there a better way to do this?
NOTE: I don't want to attach this function to any event, I just want a global changeContent() function available.
If you want the API to exist outside of the YUI().use(...function (Y) { /* sandbox */ }), you can capture the returned instance from YUI().
(function () { // to prevent extra global, we wrap in a function
var Y = YUI().use('node');
function changeContent(message) {
Y.one('#content-div').setContent(message);
}
...
})();
Be aware that there is a race condition here if you use the seed file (yui-min.js) and dynamic loader to pull in the other modules. changeContent could be called before the Node API is loaded and added to Y. You can avoid this by using a combo script up front. You can get the combo script url from the YUI 3 Configurator. There is a performance penalty for loading the modules in a blocking manner up front. You may or may not notice this in your application.
You can do like this:
(function(){
YUI().use("node", function(Y) {
APP = {
changeContent: function(message){
Y.all('.content-div').setContent(message);
}
};
});
})();
Then, you can call changeContent by calling APP.changeContent(message); from anywhere you want. Hope this helps. :D

Resources