Recently I started learning JavaScript through Nicholas C. Zakas' book Professional JavaScript For Web Developers and I came across some questions that I could not solve by myself.
As the title says, that's all about named arguments and arguments object in JavaScript functions.
E.g. we have this piece of code:
function doAdd(num1 , num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
doAdd(10 , 20);
The book says that values in the arguments object are automatically reflected by the corresponding named arguments, so num2 enters the function with a value of 20 and then it gets overwritten via arguments[1] and finally gets a value of 10.All good all clear up to this point. Then it says that
this effect goes only one way: changing the named argument does not result in a change to the corresponding value in arguments.
And that's where the problems start.
I tried to modify this code a bit to understand what the author says but I failed.
E.g.
function doAdd(num1 , num2) {
arguments[1] = 10;
num2 = 40;
alert(arguments[0] + arguments[1]);
}
doAdd(10 , 20);
This time num2 enters function with a value of 20 again, it changes to 10 via arguments[1] and then it changes once more to 40 via the named argument num2 this time. Alert pops up 50, since a change to a named argument does not result in a change to the corresponding value in arguments. Why does alert not pop up 20?
This is because the book assumes you're using strict mode.
If you run the code in strict mode, you'll get the behavior you'd expect given what's written in the book.
function doAdd(num1 , num2) {
"use strict";
arguments[1] = 10;
num2 = 40;
alert(arguments[0] + arguments[1]);
}
doAdd(10 , 20); // this alerts 20, alerts 50 in nonstrict mode
A little known fact is that the entire point of strict mode is to avoid this sort of dynamic scoping (which is why arguments is fixated, with isn't allowed and eval behaves differently). Aside from clarity gains, this allows for massive speed improvements.
Also see this:
For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values.
This is what NCZ means in context, quoting the book itself:
Strict mode makes several changes to how the arguments object can be used. First, assignment,
as in the previous example, no longer works. The value of num2 remains undefined even though
arguments[1] has been assigned to 10. Second, trying to overwrite the value of arguments is a
syntax error. (The code will not execute.) - Page 82, Language Basics, Professional JavaScript, Nicholas C. Zakas
Quoting from ECMA 5.1 Specifications for Arguments Object,
NOTE 1 For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa.
It didn't alert 20 because, as per the ECMA 5.1 specifications, in a non-strict mode function, mutating arguments object with the numeric key, will also change actual formal parameter corresponding to the numeric key.
In your case, when you change arguments[1], you are also changing the second parameter. The same way, when you change num2, you are also changing arguments[1].
Related
I'm currently studying javascript by following the "you dont know js" series.
In section "this & object prototype", the author came up with an way to soft bind this.
However, I am extremely confused by the code. So I was wondering if someone could kindly explain it to me, steps by steps, what the code really does?
//step 1: if "softBind" property does not exist on `Function.prototye`
if (!Function.prototype.softBind) {
//step 2: create a property named "softBind" on "Function.prototype" and assign to "softBind" the following function
Function.prototype.softBind = function(obj) {
//step 3: what is the point of assigning "this" to the variable "fn"?
//what does "this" represent at this point in time?
var fn = this,
//step 4: I understand that "arguments" is an array-like object, i.e. "arguments" is not a true array.
//But you can convert "arguments" to an true array by using "[].slice.call(arguments)".
//The thing I dont understand here is, why the 1?
//I understand it tells "slice" method to start slicing at index 1, but why 1?
//And what is the purpose of "curried" variable?
curried = [].slice.call( arguments, 1 ),
bound = function bound() {
//step 5: I understand what "apply" function does
return fn.apply(
//step 6: I dont really understand how "!this" works.
(!this ||
//step 7: utterly confused...
(typeof window !== "undefined" &&
this === window) ||
(typeof global !== "undefined" &&
this === global)
//step 8: if the above statements evaluates to "true", then use "obj",
//otherwise, use "this"
) ? obj : this,
//step 9: can't I write "curried.concat(arguments)" instead?
//why the convoluted syntax?
curried.concat.apply( curried, arguments )
);
};
//step 10: Why assign the "fn.prototype" as the prototype to "bound.prototype"?
bound.prototype = Object.create( fn.prototype );
return bound;
};
}
I'm very sorry for the long question, but I thought instead of dividing the question into several posts, it is more convenient if they are put into one place.
step 3: what is the point of assigning "this" to the variable "fn"?
The value of this holds a pointer to the currently executing function object. Only function objects can be held, so only things actually created through new() or equivalent notation. This can be useful for passing a reference to an outer object to an inner object created within said outer object.
Here's a minimal example:
function fn1() {
var x = this; // x = fn1.
this.u = 5;
function fn2() {
this.u = 10;
console.log(this.u); // Prints the member of fn2.
console.log(x.u); // Prints the member of fn1.
};
var W = new fn2();
}
var V = new fn1();
The output should be:
10
5
First, an object of type fn1 is created called V. It has a member variable u holding the value 5. Then, we create an object of type fn2 called W within fn1. It also has a member variable u, but here it holds the value 10. If we wanted to print the value of V.u within W, then we need a pointer to V. Calling this.u within W would output its u value (10), which is not what we want. So we define a variable x within the scope of the class fn1, holding the this pointer for us. Now it's possible to access the members of fn1 within fn2.
Step 4
The first argument is the object being bound to. You don't want to pass that to the function being bound, that would break its functionality, for it does not expect an extra argument prepended to its normal list of arguments. So, the first argument has to be removed.
step 6: I dont really understand how "!this" works.
!this is simply a way of checking whether this is defined. If it is not, then the value will be true. Otherwise, since this
would be an object (which evaluate to true when cast to a boolean), then it is false.
step 7: utterly confused...
Here, the original author checks if this is equal to either window, or global. Note; In modern browsers, checking for just window is enough, but IE exists (as do non-browser javascript environments). So, the full statement evaluates to this thing:
If I am not called from within an object, or if I'm called from the object window or global, then return the object softbind was created with. Otherwise, return the object I was called from
Note that this is exactly what the author of the original article wants. When a library function is called with this special binding, then we can be sure that whatever the library does; it can't access the global context through the use of the this variable. But, it can access any other object, allowing you to interface with the library.
step 9: can't I write "curried.concat(arguments)" instead?
Curried holds all arguments the original softbind function was called with, except for the first argument. arguments , at this point, is not equal to arguments in the earlier call. Here, it refers to the arguments the bound function is called with, not those it was bound with. This line integrates the two sets of arguments, allowing you to provide default arguments. The trick used here is to concatenate the arguments, e.g. Suppose your function has default arguments [1,2,3,4] and you supply [5,6]:
[1,2,3,4].concat([5,6]) produces [1,2,3,4,5,6].
Why not simply concatenate, and use the prototype? Arrays are passed by reference in javascript, so this will keep curried the same, while concatenating arguments to the call. Equivalently, you could write this:
curried2 = curried.concat(arguments);
return fn.apply(
(.....)
curried2);
Admittedly, the terseness does not help the understandability of this example. Simply re-naming arguments to calledArguments and curried (an advanced math term not relevant to the explanation) to be defaultArguments and using a simple for loop over each argument would be far easier to understand, if a little more verbose. I guess the author wanted to be fancy.
step 10: Why assign the "fn.prototype" as the prototype to "bound.prototype"?
Go up a bit on the article to the part where the author talks about the default bind function and how it works: basically, the end result of replacing the prototype back with the default prototype during the function call means that when your softbind enabled function is called with the new operator this will be set to itself, rather than the default bound object. prototype will not work when simply calling the bound function.
It also enables inheritance, meaning that creating things for a softbind enabled function using its prototype will not have that prototype be overruled by that of softbind when it is bound. (That would make softbind incompatible with prototypes). Instead, both prototypes are used.
Also see this reddit post.
A word of warning
We're extending the language with new features here. Features that aren't exactly necessary, and are largely concerned with semantics. If you're just interested in learning the language, this really goes way too far, you don't exactly need special binding semantics. Worse, it can be confusing if this does not behave in a way you expect it to.
A simpler alternative
Enable strict mode. Now this will default to undefined whenever it points to the global object. Prevents the problem this convoluted code is trying to solve (by usually resulting in errors from functions trying to access member variables or functions of undefined), while at the same time being far easier to use, and at the same time it will complain about a lot of syntax that is valid regular javascript, but a bug in any normal use-case. Also see the MDN article about it. It will catch a lot of potential errors for you instead of silently doing nonsensical things.
Another alternative
bind tries to resolve 'losing' the object when you pass a member function of it to another function, such as setTimeout. Another way of doing it is by using an anonymous function. Instead of using (soft) binding, assuming obj is an object holding a function fn being passed a parameter param;
setTimeout(obj.fn(param), 500);
You can use:
setTimeout(function(param){obj.fn(param);}, 500);
Which avoids the problem through a layer of indirection by passing an anonymous function. Also see this question.
I am a newbie to js although years of experience with Java
I suppose when I declare a function,it is essentially a special type of object,and got some builtin fields that are accessible directly such as "arguments" and "length"
I notice I can access something like "arguments" inside the scope of a function
i.e.
function add(a,b) {
return arguments[0]+arguments[1]
}
Also I can access something like "length" outside the scope
//2
alert(add.length)
the above snippet should be the right way to use
however
function sum(a,b) {
// error
return length
}
// null
alert(sum.arguments)
I suppose arguments and length are not of the same basic, is it right idea?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After some research,I got the root cause of the confusion.
The issue revolves around property VS variable in JavaScript
Property belong to Object while Variable belong to Context.
The two ideas can be interchangeable sometimes:
The global context happen to be window
<script>
//property
window.foo="a"
//variable
var bar="b"
//a
alert(foo)
//b
alert(bar)
</script>
In most scenario,say,function context,they are completely different ideas,partly because you can never access the function object in your code.Thus,contrary to a global setting ,assign a property is impossible! What is possible is just declare a variable in scope
In my question
"arguments" is a variable
while "length" is a property
I failed to distinguish the two
For more information,please refer to
this post
Functions are objects in JavaScript. Proper, real objects.
length
The length property of a function is the number of declared arguments it has (this is also called the "arity" of the function). The arity (length) of add is two because you declared two formal arguments for it: a and b.
arguments
The arguments pseudo-array is not part of the function object. It's an object created when the function is called, and only in scope within that function call's context. It contains all of the arguments that the function was actually called with, which can be different from the number of arguments it declares. Each separate call to the function gets its own separate arguments object.
In JavaScript's "loose mode" (the only mode it had before 2009's ECMAScript 5th edition specification), there's a live connection between the arguments pseudo-array and the declared arguments:
// In loose mode only
function foo(a) {
console.log("a = " + a);
console.log("arguments[0] = " + arguments[0]);
a = 42;
console.log("a = " + a);
console.log("arguments[0] = " + arguments[0]);
}
foo(67);
In loose mode, that outputs:
a = 67
arguments[0] = 67
a = 42
arguments[0] = 42
In "strict" mode (which is the preferred mode to use), that link doesn't exist (we'd see arguments[0] = 67 at the end), which is useful for JavaScript engines for optimization purposes.
Yes, length and arguments are different concepts.
Contrary to Java, where fields (attributes) of your object, methods, and local variables are all accessible in the same scope (just via an identifier), JavaScript does distinguish heavily between scope variables (with closures, lexically referenced) and object properties (possibly inherited) - not only in concept, but also in syntax. Properties are always1 accessed via . or [] notation.
The .length of Function instances is such a property. You will always have to write add.length or sum.length (or …["length"]). If you just use length inside of the function, it doesn't automatically refer to the property - it's a variable reference, in this case to an undeclared one.
The arguments object in contrast works like a variable. It cannot be accessed as a property of the function2. Admittedly, it's a bit special, because you cannot see the declaration of the variable - it is created implicitly in every function scope. It works a bit as if there was a const arguments = {0: a, 1: b}; statement in the first line of the function.
1: Not exactly true, there's a with statement that explicitly lifts object properties into a scope. It's despised due to its ambiguity and deprecated in strict mode though.
2: There also is a deprecated .arguments property on functions, accessing it on strict mode functions throws. If not accessed during the invocation, it's null.
I'm new to JavaScript (though experienced in C++), and today, I wrote something like this:
function foo(bar) {
bar = "something else";
}
var x = "blah";
foo(x);
alert(x); // Alerts with "blah", but I was expecting it to alert with "something else"
This confused me a lot, as I've been watching some JavaScript videos by Douglas Crockford, and remember him saying something like "JavaScript is always pass by reference".
The way I can explain this situation is that JavaScript passes references to objects, but those references are copied. This would mean in the foo function, I am assigning a new reference to bar, which then goes out of scope, leaving to reference that x has left untouched. Essentially we start with:
x ---->"blah"
Then when foo is called, bar references the same data:
x ---->"blah"
bar -----^
So when "something else" is assigned to bar, this happens:
x ---->"blah"
bar ---->"something else"
Is that an accurate model of what is actually happening in JavaScript, or am I missing something else?
As an extra question, is there any way to say, change the data referenced by this variable? Is this a situation that comes up often, or can it be easily avoided?
Edit:
Douglas Crockford in the video I watched says "objects are always passed by reference they're not passed by value", which is correct, but arguments to functions are passed by value, it's just the reference is passed by value.
Your interpretation is spot on.
First, you have a variable called x which is a reference to a string object. Let's say that memory is 0x100. x points to 0x100, which contains the bytes blah:
var x = "blah"; // x is 0x100 which references a string in memory
Next, you pass 0x100 into the function foo:
function foo(bar) {
bar = "something else";
}
As everything in JavaScript is passed by value, even references, JavaScript makes a copy of this reference in memory, which is now called bar within that function:
foo(x); // Copies the value of x (a reference) to bar
At this point, we have two separate variables. x and bar. Both happen to have the same value, 0x100. Thus, if you were to change a property of the object either of those is referencing, it would affect both x and bar.
However, what you're doing is assigning bar to point to something else:
bar = "something else"; // Now references some other string we just created
Now, bar gets re-assigned to reference a new string we've just allocated memory for. bar no longer has a value of 0x100, it now has a value of some other address (say 0x500). x of course still has a value of 0x100 since bar was merely a copy of x, and not a reference to x.
For this reason, when you:
alert(x);
You'll still get the original value, as that is what x is pointing to.
Second question:
is there any way to say, change the data referenced by this variable?
Is this a situation that comes up often, or can it be easily avoided?
Yes, just wrap it in another object. For example:
var x = {Value: "blah"};
foo(x);
Now, we have a reference to an object with a property called Value, which contains a reference to a string in memory somewhere.
In foo, we can do:
bar.Value = "something else";
Which will affect the Value property of x, since both bar and x referenced the same object, and you never changed the value of either of them.
In other words, you cannot re-assign the reference you're passing into a function, since you're simply re-assigning a copy. You can, however, change a property of an object being referenced, since other copies of that reference all point to the data you're changing.
Your interpretation is correct.
You can change the values of keys in an object, which lets you do something similar to pass-by-reference:
function foo(bar) {
bar.msg = "something else";
}
var x = { msg: "blah" };
foo(x);
alert(x.msg);
Douglas Crockford in the video I watched says "objects are always
passed by reference they're not passed by value", which is correct,
but arguments to functions are passed by value, it's just the
reference is passed by value.
It's not correct. What that describes is precisely called pass-by-value. JavaScript, like Java, only has pass-by-value. There is no pass-by-reference.
You understanding is correct. Every value in JavaScript is either a primitive, or a reference (pointer to an object). An object itself can never be a value directly. When you pass or assign a reference (pointer to an object), the new copy of the pointer sees the same object as the original pointer. But they are still two different pointer variables.
I know you've answered your own question with your edit...
Douglas Crockford in the video I watched says "objects are always passed by reference they're not passed by value", which is correct, but arguments to functions are passed by value, it's just the reference is passed by value.
but because that edit made me suddenly grok how this worked... which I will admit I was struggling with here is a code sample and pen that I think really demonstrates it.
x = {};
y = x; //point y reference to same object x is pointed to
console.log(x === y) //true both pointed at same object
function funky(o) //pass by value a reference to object
{
o = null; //change reference to point to null away from object
}
funky(x);
console.log(x)//not null still an object
var myObj = {
value: "Hello"
};
function change(localObj) {//pass reference to object
localObj.value = "Bye";//change property through the reference
localObj = null;//point the reference to null away from object
}
console.log(x === y) //still same reference;
change(myObj);
console.log(myObj.value) // Prompts "Bye"
console.log(myObj) //not null - its an object;
x = myObj; //point x to different object
console.log(x === y) //false pointed at different object;
console.log(x);
console.log(y);
https://codepen.io/waynetheisinger/pres/YewMeN
"JavaScript is always pass by reference" is, well, a [white] lie and a confusion of terms. While there is some "gray area", I go by these definitions of evaluation strategies.
Here are my arguments and reasoning. If you hold a different view, make sure that you can at least support it.
Call By Reference
Call By Reference means (to many people) that assigning to a parameter affects bindings in the caller.
In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value. This typically means that the function can modify (i.e. assign to) the variable used as argument—something that will be seen by its caller.
This is not the case in JavaScript, as the original post has noted in the observed behavior. Re-assigning a parameter (which can be thought of as a local variable with a dynamically supplied value) has no affect on any supplied arguments.
Sometimes, "Call By Reference" is [confusingly] used to mean "Call By Sharing" or "Call By Value [of the Reference]" as discussed next; true Call By Reference is found in languages like C++ and VB, but not JavaScript.
Call By [Object] Sharing
JavaScript's calling conventions can be discussed entirely in terms of Call By [Object] Sharing semantics.
All JavaScript objects are values; and all primitive values (which are a subset of all values) are immutable.
The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller, so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics.
An example of these Shared mutations is provided in ultrayoshi's answer and can be explained simply: when an expression (such as a variable access) evaluates to an object, and said object is passed to a function, no copy/clone is made.
Call By Value [of the Reference]
While the terminology "Call By Value [of the Reference]" is often used to describe the behavior, it should be noted that JavaScript does not have "references" (or "non-reference" values) in the sense of Java/C# so this terminology is subtly misleading - at least it's not saying Call By Reference, with it's various connotations, and many people understand a low-explanation.
In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function .. If the function or procedure is able to assign values to its parameters, only its local copy is assigned — that is, [any variable] passed into a function call is unchanged in the caller's scope when the function returns.
Because only a "reference" to an object is passed (and not a copy/clone of said object), the semantics are merely that of Call By Sharing. However, I avoid this terminology in JavaScript because then it brings in unnecessary implementation details and also introduces a divide in how implementations pass objects vs primitive values.
The description "call-by-value where the value is a reference" is common (but should not be understood as being call-by-reference); another term is call-by-sharing.
Thus, when I'm talking about calling conventions in JavaScript,
I prefer to use Call By Sharing to discuss the behavior and I avoid Call By [Value/Reference] as they have too many different "meanings" and drag in unnecessary implementation details.
Primitive values like numbers, strings, etc aren't passed by reference, only objects. For example:
var myObj = {
value: "Hello"
};
function change(localObj) {
localObj.value = "Bye";
}
change(myObj);
console.log(myObj.value) // Prompts "Bye"
I'm writing a function that checks if arguments are zero, and it doesn't seem to work correctly. Note: Using Chrome as my browser, but this code should be cross-browser supported.
// check all arguments, and make sure they aren't zero
function zeroCheck(arg1, arg2) {
var i, argsLen = arguments.length;
for (i = 0; i <= argsLen; i += 1) {
if (arguments[i] === 0) {
// This is where it doesn't behave as I expected
arguments[i] = 1; // make arg1 = 1
}
}
console.log(arg1); // arg1 = 0
}
zeroCheck(0, 2);
I was expecting arg1 to be equal to 1, but it is still equal to 0.
From the ECMA-262 spec:
"For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values."
But if you read the technical details of how the arguments object is set I think you'll find it is based on how many arguments are actually passed to the function when it is called, not how many named arguments are declared, so using arguments and a loop to check the value of each named parameter might not work if they're not all passed in. Though in your case if you're testing specifically for 0 it should work since parameters that are not passed will be undefined rather than 0.
Having said that, exactly how the arguments object actually behaves depends on the browser. Chrome doesn't follow the spec.
Though some browsers appear to work the way you want (Chrome and Firefox), it isn't obvious to me from the ECMAScript spec that it will always be this way. It makes it sounds like the arguments array is probably just a reference to the named arguments in non-strict mode and it specifically says that the two should have no connection to one another in strict mode (in other words what you want to do is specifically NOT supposed to work in strict mode).
You can see in this jsFiddle http://jsfiddle.net/jfriend00/bG5xp/ that Chrome appears to implement it as the spec describes. There is linkage between arguments[0] and arg1 in non strict mode and there is no linkage between them in strict mode. A careful reading of the spec doesn't say that javascript is required to have linkage between the two in non-strict mode, but it does make it sound like it is likely. If you wanted to rely on that and you were sure you never needed your code to work in strict mode, then you would have to test a bunch of browsers to see if the behavior you desire is widely supported.
It is also not clear from the spec if the arguments array is always meant to be modifiable though that seems more likely given that it's implemented with a javascript object (not an actual array).
The safe way to modify the arguments array is to make a copy first and modify the copy. That will, of course, not modify any named arguments. You could modify those manually if you wanted to.
A common way to make a copy of the arguments array is:
var args = Array.prototype.slice.call(arguments, 0);
One generally uses either the arguments array or the named arguments and not both since any named argument is also in a known position in the arguments array so you don't really need to worry about a named argument changing value when you modify the arguments array.
Try it like this. arg1 with value 0 evaluates to false/falsy, so you can use this shortcut boolean evaluation:
function zeroCheck(arg1,arg2) {
arg1 = arg1 || 1;
console.log(arg1); //=> 1
}
zeroCheck(0,2);
A generic function to check for all arguments (returns an Array)
function zeroCheckArgs(args){
return [].slice.call(args).map(function(a){return a || 1;});
}
//more conservative
function zeroCheckArgsAlt(args){
var retArgs = [];
for (var i=0;i<args.length;i+=1){
retArgs.push(args[i] || 1);
}
return retArgs;
}
function some(){
var args = zeroCheckArgs(arguments);
console.log(args);
}
function someAlt(){
var args = zeroCheckArgsAlt(arguments);
console.log(args);
}
some(1,0,0,12,12,14,0,1); //=> [1, 1, 1, 12, 12, 14, 1, 1]
someAlt(1,0,0,12,12,14,0,1); //=> [1, 1, 1, 12, 12, 14, 1, 1]
It works for me, check this example fiddle
#nnnnnn -
"For non-strict mode functions the array index (defined in 15.4) named
data properties of an arguments object whose numeric name values are
less than the number of formal parameters of the corresponding
function object initially share their values with the corresponding
argument bindings in the function’s execution context. This means that
changing the property changes the corresponding value of the argument
binding and vice-versa. This correspondence is broken if such a
property is deleted and then redefined or if the property is changed
into an accessor property. For strict mode functions, the values of
the arguments object‘s properties are simply a copy of the arguments
passed to the function and there is no dynamic linkage between the
property values and the formal parameter values."
Your citation actually answers my original question. The reason that my code as posted below does not work as expected is because I was actually using "strict" mode.
// check all arguments, and make sure they aren't zero
function zeroCheck(arg1,arg2) {
var i, argsLen = arguments.length;
for (i = 0; i <= argsLen; i += 1) {
if (arguments[i] === 0) {
// This is where it doesn't behave as I expected
arguments[i] = 1; // make arg1 = 1
}
}
console.log(arg1); // arg1 = 0
}
zeroCheck(0,2);
It worked in for xdazz, Jeroen Moons, and jFriend00 - because they did not include the strict:
http://jsfiddle.net/nSJGV/ (non-strict)
http://jsfiddle.net/HDjWx/ (strict)
As a new javascript developer, I have spent some time with this code snippit from Chapter 6 of Eloquent Javascript, I am still trying to understand the following code example :
function negate(func) {
return function(x) {
return !func(x);
};
}
var isNotNaN = negate(isNaN);
document.writeln(isNotNaN(NaN));
Where it particular loses me is the following line, I just don't understand the call in general and where the variable/value for NaN comes from:
document.writeln(isNotNaN(NaN));
I think xdazz pretty much covered it, but since you said you still don't get it maybe it would help to hear the explanation in somebody else's words.
This line:
var isNotNaN = negate(isNaN);
...declares a variable isNotNan that is assigned equal to the result of a call to the negate() function, passing isNan as a parameter.
That parameter isNan is actually a function as described by MDN, but negate() would accept any function as a parameter, you could say for example var isNotFinite = negate(isFinite);.
Now the negate() function actually creates and returns another function, so after that line runs isNotNan references that returned function, which means you can call it as isNotNan(someVal).
So then the line:
document.writeln(isNotNaN(NaN));
... calls isNotNan() and passes it NaN as a parameter, and the result is written out to the document.
"I just don't understand...where the variable/value for NaN comes from"
NaN is a property of the global object. To oversimplify, it is a constant provided to you by the JS environment.
Regarding how the negate() function works, it relies on the concept of "closures", which means that functions declared inside negate() have access to its variables and parameters even after negate() completes. You'll notice that the returned function references the func parameter. So when you call the returned function via isNotNaN() it can still access that original func parameter that is set to the isNan function.
The effect is kind of like doing this:
var isNotNaN = function(x) {
return !isNan(x);
};
negate take a function as parameter, and returns a new function which returns the opposite result of the original function.
NaN is A value representing Not-A-Number.
NaN is a property of the global object.
The initial value of NaN is Not-A-Number — the same as the value of
Number.NaN. In modern browsers, NaN is a non-configurable,
non-writable property. Even when this is not the case, avoid
overriding it.
NaN is a property of the global object, So it is window.NaN.
And note typeof NaN returns number.