I'm writing a library that exposes the following function
function call(instance, func, arguments) {
return {
call: {
instance: instance,
func: func,
arguments: arguments
}
}
}
Is the name arguments ok to use? It's really the best name for it, but I don't want to clash with the builtin variable. It works in Node. Will this work in all browsers and JavaScript environments?
Edit:
Note that the above function does work as expected in Node. What I'm wondering is whether this will work everywhere.
I'd rather not rename it unless there's a technical reason to. I'd really like this external-facing function and the docs to reflect this parameter name, because the returned object is going to be serialized as JSON and used across languages.
It is okay to use the name arguments in "sloppy mode", but not recommended.
It is forbidden in strict mode, which all new code should use if the author cares about code quality.
function a(arguments) {
console.log(arguments);
}
a(1);
// Prints "1"
(function () {
'use strict';
function a(arguments) {
console.log(arguments);
}
a(1);
}());
// Uncaught SyntaxError: Unexpected eval or arguments in strict mode
This is akin to naming a variable "Object". Maybe in some obscure context it makes sense to use that name, but by doing so you lose access to the global Object object and useful methods on it like Object.keys. Similarly, by making this poor naming decision, you can no longer manipulate the arguments object, which is varargs in JS.
In the interest of improving the maintainability of your code, it is best to avoid creating ticking time bombs like this one. There is a good reason why it is not allowed in strict mode: It is likely to cause misery for anyone who wants to use arguments as it is typically used.
It looks like that is taken. arguments is a quick, array-like way to get all the arguments of a function. See this explaining it.
Maybe you could use parameters instead?
EDIT: To see how this variable works, I wrote this:
function sayHelloTo(objectToSayHiTo){
alert("Hello "+arguments[0]+"!");
}
sayHelloTo("world");
EDIT #2:
Apparently, it will not be affected:
function sendGreetings(name, arguments){
alert("I'm "+name+"!");
for(var count=0;count<arguments.length;count++){
alert("Hello "+arguments[count]+"!");
}
}
sendGreetings("kittycat3141", ["world", "StackExchange", "Joe"]);
However, I haven't tried all browsers yet.
EDIT #3
I have tried 5 major browsers (IE, Chrome, Safari, Firefox, and Opera) and the code above works properly. However, as iCobot said in the comments, it is best not to use builtin names because it can save you confusion and frustration later, for you and anyone reading the code.
Related
First of all, I want to clarify, I know that with is deprecated, and using it is generally a bad practice.
However, my question is about a special case: using a special Proxy object as the parameter of with.
Background
I'm working on a project, where I have to limit access of a piece of code to the global scope.
One approach might be to use a loop with eval, that creates constant variables with the value of undefined for each property of the global object, but that seems even worse than using with, and cannot limit access to variables created with let and const.
The idea
The idea is to use a Proxy as the argument of with, whose...
has trap always returns true, therefore it doesn't allow any lookups or assignments to go beyond the with statement
get trap operates normally, except that it throws ReferenceErrors when trying to access a non-existing variable (i.e. property)
set trap operates normally (or maybe contains some custom logic)
target object has no [[Prototype]] (i.e. it was created with Object.create(null))
target object has an ##unscopables property, with the value of an empty object, to allow scoping of every property
So, something like this code:
const scope = Object.create(null)
Object.assign(scope, {
undefined,
console,
String,
Number,
Boolean,
Array,
Object,
/* etc. */
[Symbol.unscopables]: Object.create(null)
})
const scopeProxy = new Proxy(scope, {
get: (obj, prop) => {
if (prop in obj)
return obj[prop]
else
throw new ReferenceError(`${prop} is not defined`)
},
set: Reflect.set,
has: () => true
})
with(scopeProxy) {
//Sandboxed code
foo = Number('42')
console.log(foo) //42
try{
console.log(scopeProxy) //Inaccessible
}catch(e){
console.error(e) //ReferenceError: scopeProxy is not defined
}
}
Avoiding contras
There are several contras listed on the MDN's page about the with statement, but this usage of it gets rid of each.
1. Performance
The problem:
Looking up identifiers that aren't a member of with statement's parameter object is less performant.
Avoidance:
No lookups can go beyond the parameter object.
2. Ambiguity
The problem:
It is hard to decide, which identifier gets looked up of those with the same name.
Avoidance:
All lookups and assignments retrieve or modify the property of the parameter object.
3. Forward compatibility
The problem:
The properties of the parameter object or its prototype might change in the future.
Avoidance:
The parameter object is initially empty and has no prototype, therefore no properties can change.
Question
The above code works perfectly, and the contras listed on MDN don't seem to apply to this case.
So, my question is:
Is it still a bad practice to use the with statement, and if so, what are the downsides of using it in this specific case?
Note: I know that this approach in itself is not secure and can be bypassed. However, this question is limited only to whether it's considered bad for some reason to use the abovementioned Proxy-with combination. In this question, I'm not concerned about security (that's a related, but different question).
Sounds like the good old lexical vs dynamic scope topic. In general lexical scope is more safe but in some situations dynamic scope makes sense, because it simplifies some solutions very much. I would say your example is one of the cases, where it may be useful.
So I was coding today and I found odd that
arguments.concat(someNumber);
gave me an error for undefined function. At first I thought that arguments might be some kind of native object for performance reasons, but in the end I found out it is in fact a plain javascript object and not an array or internal native object. I was left wondering if there is any special reason for that.
The arguments object is special ("exotic" in Harmony parlance) because it maintains the live connection between its own numeric properties and scope variables:
function x(a) {
arguments[0] = 42;
document.write(a);
}
x(10)
To support this functionality, arguments needs to override a lot of stuff from the default object. That's why it's a separate type.
I've seen this syntax for creating an anonymous constructor function in JavaScript:
var Application = Application || {};
!function(window, Application) {
Application.property = {/*...*/}
Application.method = function(){/*...*/}
}(window, Application);
I want to understand what the following parts here:
What is the advantage of using first line (i.e. var o = o || {};) vs just stating var o = (function(){})();?
Why ! is used in front of function?
Why would I pass window or Application as parameters when they are global object?
Is this the most convenient way for anonymous constructor function and how is this better than:
4a)
var Application = {
property: {},
method: function(){}
}
or 4b)
var Application = (function() {
var method = function(){/*...*/}
return {method:method};
}());
The first line is to ensure that Application always exists, and is generally used in cases where it's expected that Application already should exist, and the function just augments the existing object. If it doesn't exist, this makes sure that we don't get an error for accessing properties of undefined. Your examples are only equivalent in the case where Application does not yet exist. In all other cases, your code will obliterate the existing Application, which is almost certainly not the intent.
The comment from Vatev explains what the ! does. It's another syntax for making the function in question become a self executing anonymous function. (Incidentally, it also takes the return value of the function - which is currently undefined, and flips its truthyness, so it evaluates as true. Since the result isn't stored in any variable, though, that's clearly not the purpose.)
Finally, why pass window and Application into the function and use it there? This is a safety feature, in case other code changes window or Application later on. It guarantees that within the anonymous function, window and Application are exactly what you expect it to be. In the shorthand example you gave, this may appear to not matter - after all, why protect these variables if you're using them immediately and not storing them? In many cases, you return something from this function, and then window and Application would be stored in the closure, so you'd retain the variables. It makes it safe from people who later on decide to say Application = {...}.
I don't know all of the answers but I'll try to answer what I can.
Using var Application = Application || {}; simply means that you are dealing with scope. If the "Application" variable has already be defined, it will just mean that it inherits and is now available in the current scope. If not, the "||" part (means OR) means that it will be created as an empty object. You are dealing with creating an object and then acting on it, not just having the result given back raw. That's why you shouldn't use "o = (function() {...});". "o" would then be the result of the function and not the object.
The use of "!function" causes it to be treated as an expression, but this can be tricky because you may have to think in opposites. E.g. !null means you are checking that it isn't null, not that you are checking for it to be null.
Passing in the window and Application objects deal with scoping, again. It is explicitly passing them into the function, then returning them at the end. Think of this as putting clothes in the washing machine. You put them in, stuff can happen, then you get them back out. It's a really crude idea and isn't the best example, but it's how I thought of it a while back. You put clothes in, call then rinse function, then soap function, then rinse again, then spin to drain water.
Hopefully someone else can answer that, I'm not sure what the differences are.
Since two answers so far neglected these two details: A pattern used by libraries like jQuery is using the following two parameters:
(function (window, undefined) {
window.myPlugin = ...;
})(window);
There are two things going on here:
undefined is specified as a parameter, but not passed in. This way, undefined is guaranteed to have th expected value within the inner scope. This is only necessary for older browsers which allowed overwriting undefined (though it has always been considered bad practice to do so – it's just what libraries like jQuery do to avoid other code interfering with their code).
Aliasing a global object like window within the scope allows the code to be minified more (also works for undefined). Obviously, the more references you have to the aliased object(s), the more you will save:
.
(function(w,u){w.myPlugin=...;w.somethingElse=...;if(whatever===u){return;}})(window);
compared to
(function(){window.myPlugin=...;window.somethingElse=...;if(whatever===undefined){return;}})();
You won't save much with window since typically you don't wanna clutter the global object up anyway. But aliasing undefined can save you quite some space.
It's been a while since ECMAScript 5 came out and is being supported quite well in most modern browsers (IE9, CH 19+, FF 4+) and with it so is the "Immutable undefined". Though I keep seeing "undefined" being passed like so:
(function ( ..., undefined ) {
})(...);
From what I can tell Crockford's JSLint tool doesn't really like it:
Expected an identifier and instead saw 'undefined' (a reserved word).
Even though it's not being passed (there's no argument on the function call) and it's really an identifier. I understand that his tool isn't a bible we should follow to the death and on the other hand JSHint doesn't seem to care about it.
Is this still considered a best practice today and how does it affect code performance/security? Considering browser support >= IE9.
Is this still considered a best practice today and how does it affect code performance/security? Considering browser support >= IE9.
Much like undefined, Infinity is a non-writable property of the global object rather than a literal like null, so it can be used as a parameter name without raising an error. Lets consider a function like this
function example(Infinity) {
return Infinity;
}
In example, Infinity is no longer a non-writable property and instead acts like any other parameter to a function, initialised as undefined if nothing is passed or otherwise taking the value of the argument. This means in this function you can't just assume Infinity will mean Infinity, because it doesn't, but you could assume it will mean undefined.
So let's go back to the question of undefined. It will be initialised as undefined so the meaning will stay the same, however, it has now lost it's immutability within the function and therefore any typos assinging a values to undefined will have this error carried forward. Additionally, if a parameter is passed to the function the value will be different from the start.
Therefore to conclude, it does have an effect on security, as an undefined like this is no longer as "safe" because it has lost it's immutable status and can be changed.
It may be interesting to note that undefined is not actually a reserved word. If you require an undefined for compatibility, rather than adding it as a parameter name, I would suggest using a simple var undefined; at the top of the function or in the global namespace where you will find var undefined; undefined = 1; undefined; // undefined where it is immutable.
If you wanted to comply with jsLint, you could use another variable that is not a reserved word instead of undefined. The following complies with jsLint:
(function (window, document, undef) {
'use strict';
}(window, document));
You would, however, need to remember to use your newly defined variable (in this case undef instead of undefined). The strict mode above was added to comply with jsLint. This is mostly used so that you know for certain that the variable you are testing to be undefined is actually undefined.
Note, that if you're running this example in the text area provided on the jsLint website, you may need to define window and document. I was receiving two errors until I did so.
var window = window; //global window object
var document = document; //global window object
However, I'm of the opinion that:
(function (..., undefined) {
'use strict';
}(...));
is perfectly fine and more importantly, highly recommended.
There are cases where reserved words can be changed from their normal states. Such as setting undefined to true. Paul Irish discusses this briefly in his video: http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/
Why was the arguments.callee.caller property deprecated in JavaScript?
It was added and then deprecated in JavaScript, but it was omitted altogether by ECMAScript. Some browser (Mozilla, IE) have always supported it and don't have any plans on the map to remove support. Others (Safari, Opera) have adopted support for it, but support on older browsers is unreliable.
Is there a good reason to put this valuable functionality in limbo?
(Or alternately, is there a better way to grab a handle on the calling function?)
Early versions of JavaScript did not allow named function expressions, and because of that we could not make a recursive function expression:
// This snippet will work:
function factorial(n) {
return (!(n>1))? 1 : factorial(n-1)*n;
}
[1,2,3,4,5].map(factorial);
// But this snippet will not:
[1,2,3,4,5].map(function(n) {
return (!(n>1))? 1 : /* what goes here? */ (n-1)*n;
});
To get around this, arguments.callee was added so we could do:
[1,2,3,4,5].map(function(n) {
return (!(n>1))? 1 : arguments.callee(n-1)*n;
});
However this was actually a really bad solution as this (in conjunction with other arguments, callee, and caller issues) make inlining and tail recursion impossible in the general case (you can achieve it in select cases through tracing etc, but even the best code is sub optimal due to checks that would not otherwise be necessary). The other major issue is that the recursive call will get a different this value, for example:
var global = this;
var sillyFunction = function (recursed) {
if (!recursed)
return arguments.callee(true);
if (this !== global)
alert("This is: " + this);
else
alert("This is the global");
}
sillyFunction();
Anyhow, EcmaScript 3 resolved these issues by allowing named function expressions, e.g.:
[1,2,3,4,5].map(function factorial(n) {
return (!(n>1))? 1 : factorial(n-1)*n;
});
This has numerous benefits:
The function can be called like any other from inside your code.
It does not pollute the namespace.
The value of this does not change.
It's more performant (accessing the arguments object is expensive).
Whoops,
Just realised that in addition to everything else the question was about arguments.callee.caller, or more specifically Function.caller.
At any point in time you can find the deepest caller of any function on the stack, and as I said above, looking at the call stack has one single major effect: It makes a large number of optimizations impossible, or much much more difficult.
Eg. if we can't guarantee that a function f will not call an unknown function, then it is not possible to inline f. Basically it means that any call site that may have been trivially inlinable accumulates a large number of guards, take:
function f(a, b, c, d, e) { return a ? b * c : d * e; }
If the js interpreter cannot guarantee that all the provided arguments are numbers at the point that the call is made, it needs to either insert checks for all the arguments before the inlined code, or it cannot inline the function.
Now in this particular case a smart interpreter should be able to rearrange the checks to be more optimal and not check any values that would not be used. However in many cases that's just not possible and therefore it becomes impossible to inline.
arguments.callee.caller is not deprecated, though it does make use of the Function.caller property. (arguments.callee will just give you a reference to the current function)
Function.caller, though non-standard according to ECMA3, is implemented across all current major browsers.
arguments.caller is deprecated in favour of Function.caller, and isn't implemented in some current major browsers (e.g. Firefox 3).
So the situation is less than ideal, but if you want to access the calling function in Javascript across all major browsers, you can use the Function.caller property, either accessed directly on a named function reference, or from within an anonymous function via the arguments.callee property.
It is better to use named functions than arguments.callee:
function foo () {
... foo() ...
}
is better than
function () {
... arguments.callee() ...
}
The named function will have access to its caller through the caller property:
function foo () {
alert(foo.caller);
}
which is better than
function foo () {
alert(arguments.callee.caller);
}
The deprecation is due to current ECMAScript design principles.
Just an extension. The value of "this" changes during recursion. In the following (modified) example, factorial gets the {foo:true} object.
[1,2,3,4,5].map(function factorial(n) {
console.log(this);
return (!(n>1))? 1 : factorial(n-1)*n;
}, {foo:true} );
factorial called first time gets the object, but this is not true for recursive calls.