I have heard different opinions about the usage of var at a situation like this:
function(maybeUndefined) {
if(typeof maybeUndefined === 'undefined')
var maybeUndefined = 'bob';
}
Is it necessary to notate var, or not, because maybeUndefined is an argument of function?
You do not need the var in this case, as mayBeUndefined is already allocated within the scope of the function (hint: listing argument variables in a function definition causes those variables to be declared locally). That var is therefore completely optional, though completely pointless (and a drain on readability).
Example:
function func ( arg1, arg2 ) {
var local1, local2;
function nested1 () {}
function nested2 () {}
// other code
}
Here we have a function declaration. When this declaration is parsed into a function object, a lexical environment (= scope) is created for that function with the following bindings:
arg1
arg2
local1
local2
nested1
nested2
this
arguments
(Notice how there also are two special, built-in bindings: this and arguments. These are always created for all function objects.)
These names are defined as local bindings. (This process is specified in "Declaration binding instantiation". Warning: this algorithm is not meant to be read by humans :-)) Therefore, when a name is defined as a parameter, it is not necessary to declare it as a local variable. This mechanism is independent of whether a value (argument) is passed for that parameter when the function is invoked.
So, even if you invoke the function like so:
func(123);
the name arg2 will still be defined (as a binding in the function's environment), although its value will initially be undefined for that particular invocation.
Btw, if you use the strict language (recommended!), function environments are static which means that the above bindings are garanteed to be the only bindings in the function's environment. The default language, on the other hand, provides certain mechanisms to, dynamically, add/remove bindings from the function's environment. Example:
(function () {
// the name "temp" does not exist as a binding in the function's environment
eval('var temp');
// now it does
delete temp;
// and it's gone again
}());
You should not use var again, it is bad for readability, and the variable will already be scoped locally as a result of being an argument.
Also, you should note that it is not a part of this. this will only be scoped to the function object if the new keyword has been used, and as you do not have a named function, that seems unlikely in this case. Without new, this refers to window (or is undefined if use strict; is used), of which your variable is definitely not a part of as a result of the argument having a local scope.
Interfacing
Including a function argument is effectively the same as scoping a variable (in other words, it's effectively the same thing as defining a function-level reference using the var keyword). The main reason for providing function arguments (in JavaScript) is for your own interfacing preference.
The arguments object
Arguments may still be passed to functions without parameters, and will still be accessible in the 'hidden' arguments object -- which is sort of a "pseudo-array" (if you will), in that it is functionally an array, but is not equipped with the same APIs JavaScript equips the Array (pseudo-type) with:
// The following functions do the same thing, but one is "more readable"
function foo() {
return arguments;
}
function bar(baz, qux) {
return arguments;
}
Evaluation (interface) vs Execution (implement)
When both functions are evaluated (on file 'load'), the arguments object is undefined in every function definition; the object doesn't become "defined" until the function body executes the code therein; to visualize that using pseudo-code, it'd look something like this:
// Function bodies (as objects)
foo : {
arguments : new Array // [undefined]
__proto__ : Empty() // the super-object that allows this object to inherit "functionality"
}
bar : {
arguments : new Array(baz, qux) // [undefined, undefined]
__proto__ : Empty()
}
Function invocation
So when you invoke a function, it "implements" or "executes" its body (its "object"). When it does that, if the objects that have been pushed into the arguments object are defined, then the function can reference them. If not, a reference error will be thrown, logging that the variables are undefined in that scope.
In short:
It isn't necessary to interface function-scope-level variables (aka "private members") using var because the language already attaches the arguments object to all function body objects.
More reading:
JavaScript Memoization: "Function-caching" multiple arguments for better performance:
http://decodize.com/javascript/javascript-memoization-caching-results-for-better-performance/
Related
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 have recently been trying to learn javascript and have a couple of questions.
When you create a function expression:
var greet = function(){
console.log('Hi');
}
Is that creating a function object and having the variable "greet" point to that function object in memory?
My second question if you have a function like this:
function log(a){
console.log(a);
}
Then you make a call to that function:
log(greet); //greet is the function expression declared above.
So I know that when a function object is created there are two properties that are given to the object. The name (if provided, otherwise anonymous) and a code property which stores the code contained inside the parentheses of the function. Now I am a little confused on where the parameter "a" in the log function gets attached to in a function object. Is "a" just another property of the function object log and it simply just points to the memory address of anything that is passed into the log function? Where in this case it was a function expression called greet. Any input would be appreciated. Thank you!
When a function is called as in:
log(greet)
then the identifier log is resolved in the current execution context and, if not found, is searched along the scope chain, ending at the global execution context. If not found, an error is thrown.
In this case, log has been defined using a function declaration so it exists in the global scope so is found. Its value is checked to make sure it's callable (again, if not, an error is thrown) if it is, it's called.
In the call, the identifier greet is resolved and its value passed to the function. If greet can't be resolved (i.e. it doesn't exist on the scope chain), an error is thrown. In this case, it resolves to a reference to the function assigned to greet.
When log is executed, a new execution context is created. The function declaration for log defines a formal parameter a (in its formal parameter list), so a is created as a local variable for log. The values in the call are passed to identifiers in the formal parameter list in order, so the value of greet is assigned to a. Note that initialisation and creation of a new execution context occurs every time a function is called.
The same process is followed when calling:
console.log(a);
so that within console.log, the reference to greet is passed as the first parameter, so it now references the greet function.
The behaviour of console.log is entirely implementation dependent so the internals are unknown, but for functions most tend to just call the function's toString method.
It's a handy feature of ECMAScript that an arguments object is created of the arguments passed to functions, so the values passed are always available as numeric properties of the arguments object if there is no parameter for them to be assigned to. So console.log doesn't have to define any formal parameters, it can just loop over its arguments object and process the passed values in turn.
If functions are objects, where does the function's body go?
Let me clarify what I am confused about. Functions are objects, okay. I can think of an object as a hash map consisting of string keys and arbitrarily typed values. I can do this:
function Square(size) {
Rectangle.call(this, size, size);
}
Square.prototype = new Rectangle();
I just treated Square like a regular object and messed with its prototype property by assigning a new value to it. However, if functions are just objects (or hash maps for that matter), where is the function's body (in this example Rectangle.call(this, size, size);) being stored?
I figured it must be stored as the value of some property, something like the following maybe:
console.log(Square.executableBody); // "Rectangle.call(this, size, size);"
Obviously, this is not the case. Interestingly, while reading "The Principles of Object-Oriented JavaScript" by Nicholas C. Zakas, I stumbled upon this:
[...] functions are actually objects in JavaScript. The defining characteristic of a function - what distinguishes it from any other object - is the presence of an internal property named [[Call]]. Internal properties are not accessible via code [...] The [[Call]] property is unique to functions and indicates that the object can be executed.
This might be the property I was looking for above. It does not go into detail, though. Is the function's body actually stored within the [[Call]] property? If so, how does execution work? Unfortunately I was unable to find out more about [[Call]], Google mostly came up with information on a function's call method...
Some clarification would be much appreciated! :)
It becomes the value of another internal property, called [[Code]]:
13.2 Creating Function Objects
Given an optional parameter list specified by FormalParameterList, a body specified by FunctionBody, a Lexical Environment specified by Scope, and a Boolean flag Strict, a Function object is constructed as follows:
[...]
Set the [[Code]] internal property of F to FunctionBody.
If so, how does execution work?
Calling a function basically calls the internal [[Call]] method, which is described in http://es5.github.io/#x13.2.1. I guess the important step is:
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property.
Basically, for all practical purposes you can consider the function in its entirety to be the object. You can study the JS spec or JS engine source code to learn about how the function body is actually stored in an internal property on the object, but this won't really help you understand how it works as a JS programmer. You can see the body as a string by evaluating fn.toString. You cannot otherwise access the body other than to execute it or bind to it or call other methods on Function.prototype. However, because it's an object, it can also have properties attached to it like any other object.
Why would I want to attach a property to a function? Here is an example of a memoization function (deliberately simplified):
function memoize(fn) {
var cache = {};
function memoized(x) {
return x in cache ? cache[x] : cache[x] = fn(x);
};
memoized.clear = function() { cache = {}; };
return memoized;
}
So we are placing a function clear as a property on the returned function. We can use this as:
memofied = memoize(really_long_calculation);
result = memofied(1); // calls really_long_calculation
result = memofied(1); // uses cached value
memofied.clear(); // clear cache
result = memofied(1); // calls really_long_calculation again
The function is enough of an object that Object.defineProperty can be called on it, allowing us to write the memoization function above as follows, if we really wanted to:
function memoize(fn) {
var cache = {};
return Object.defineProperty(function (x) {
return x in cache ? cache[x] : cache[x] = fn(x);
}, 'clear', {value: function() { cache = {}; } });
}
(since Object.defineProperty returns the object.) This has the advantage that clear takes on the default non-enumerable and non-writeable properties, which seems useful.
I could even use a function as the first (prototype) argument to Object.create:
someobj = Object.create(function() { }, { prop: { value: 1 } });
but there's no way to call the function serving as prototype. However, its properties will be available in the prototype chain of the created object.
When you invoke a top-level function in Javascript, the this keyword inside the function refers to the default object (window if in a browser). My understanding is that it's a special case of invoking the function as method, because by default it is invoked on window (as explained in John Resig's book, Secrets of the JavaScript Ninja, page 49). And indeed both invocations in the following code are identical.
function func() {
return this;
}
// invoke as a top-level function
console.log(func() === window); // true
// invoke as a method of window
console.log(window.func() === window); // true
So far so good... Now here is the part I don't understand:
When a function is nested in another function and invoked without specifying an object to invoke on, the this keyword inside the function also refers to window. But the inner function cannot be invoked on window (see code below).
function outerFunc() {
function innerFunc() {
return this;
}
// invoke without window.* - OK
console.log(innerFunc() === window); // true
// invoke on window
//window.innerFunc(); - error (window has no such method)
console.log(window.innerFunc) // undefined
}
outerFunc();
It makes perfect sense that the nested function isn't available on window, as it is after all nested... But then I don't understand why the this keyword refers to window, as if the function was invoked on window. What am I missing here?
EDIT
Here is a summary of the great answers below and some of my follow up research.
It is incorrect to say that invoking a function "normally" is the same as invoking it as a method of window. This is only correct if the function is defined globally.
The function context (the value of the this keyword) does not depend on where / how the function is defined, but on how it is being invoked.
Assuming that the code is not running in in strict mode, Invoking a function "normally" will have the function context set to to window (when running in a browser, or the corresponding global object in other environments).
An exception to the above rules is the use of bind to create a function. In this case even if the function is invoked "normally", it could have a context other than window. That is, in this case the context is determined by how you create the function, rather than how you invoke it. Although strictly speaking this isn't accurate, because bind creates a new function that internally invokes the given function using apply. The context of that new function will still be determined by the way it's invoked, but it shields the context of the function it internally invokes by using apply.
By invoking "normally" I refer to the following simple way of invocation:
myFunction();
To complete the picture, here is a brief coverage of other ways of invocation and the corresponding context:
As a property of an object (method) - the context is the object
Using apply or call - the context is specified explicitly
With the new operator (as a constructor) - the context is a newly created object
Feel free to update the above as necessary, for the benefit of people with similar questions. Thanks!
You can call any function that is in scope with functionName(). Since you haven't called it on an object, it will be called in the context of the default object (window). (IIRC, it will be called in the context of undefined if you are in strict mode).
The default object for context has nothing to do with where a function is defined or what scope that function appears in. It is simply the default object.
If a function is a property of an object, you can call it as reference.to.object.function(), and it will be called in the context of object instead of the default object.
Other things that change the context are the new keyword and the apply, call, and bind methods.
In JavaScript, when a function is invoked without an explicit context, the context is the global object. In the case of web browsers, the global object is window.
Additionally, JavaScript has functional scope, so any variables or functions within a function are not accessible in a scope outside of that function. This is why you can't access window.innerFunc.
Whether a function is nested inside another one has nothing to do with the value of this when the function is called. The only things that matter are:
If the function is "found" by traversing a property on an object, then the value of this will be a reference to that object:
someObject.prop( whatever );
It doesn't matter how the function was declared.
If you use call() or apply() to invoke a function, then the value of this is taken from the first argument to whichever of those functions you use.
If you've created a bound wrapper for the function with bind(), then the value of this will be as requested when bind() was called.
If you're calling a function as a constructor with new, then this will refer to the newly-created object instance.
Otherwise, this is either a reference to the global context, or else it's undefined (in "strict" mode or in an ES5-compliant runtime).
The "location" in the code where a function is defined does matter, of course, in that the scope includes whatever symbols it includes, and those are available to the function regardless of how a reference to it is obtained.
It does not depend where the function is declared but how it is called:
var obj = {
f: function() {
return this;
}
}
var f = obj.f;
console.log(obj.f()) // obj
console.log(f()) // window/default obj
Or in other words. The syntax obj.f() executes the function with this=obj while f() executes the function with this=window. In JavaScript the caller specifies the value of this.
When you define func in the global scope, it actually is assigned as a property of the window object. That is, the window object holds all globally scoped variables. (*) Therefore, func and window.func represent the same thing. innerFunc is defined inside a function scope and is not available outside of that scope. Therefore, window.innerFunc is (still) undefined.
However, the this context is determined by how you call the function. When you call a method like obj.method(), the this context is set to obj. On the other hand, you can also call the method on its own:
var f = obj.func;
f(); // in this call: this === window
In this case, you're not calling a function on an object and thus the this context is set to the default. The default however is the global scope and as stated above, this is represented by window.
You can always override the this context by using Function.prototype.call() or Function.prototype.apply() which take a this context as first argument. For example:
var f = obj.func;
f.call(obj); // in this call: this == obj
(*) Note that this only applies to JavaScript running inside a browser. In other environments, this may differ. For example, in Node.js the GLOBAL variable holds the global scope.
"The this keyword always refers to the object that the containing function is a method of."
Great, sounds simple enough, but here's what I'm wondering about...
For example:
function func1() {
function func2() {
alert(this == window); // true
}
func2();
alert(this == window); // true
}
func1.func3 = function () {
alert(this == window); // false
alert(this == func1); // true
};
func1();
func1.func3();
Now, since func1 is actually a method of the global (window) object (a function object assigned to the property func1 of the global object) it makes sense that this inside func1 refers to the global object, and since func3 is a method of func1's function object it makes sense that this inside func3 refers to func1's function object.
The thing that bothers me is func2. I know that this inside a nested function is also supposed to reference the global object, but I'm not sure why since func2 is NOT a method of the global object. As far as I understand (and this is the part I might be completely wrong about) func2 is a method of func1's call (activation / variable) object. Now, if I'm right about this (and I'm not sure that I am) then shouldn't this inside func2 refer to func1's call object instead of the global object?
So, I guess my question would be: Is a nested function a method of the call (activation) object of the function it is nested in, and if so, shouldn't this refer to that call object instead the global object?
The this keyword always refers to the object that the containing function is a method of.
No. Unfortunately, it is not easy as that. The documentation of the this keyword at MDN gives a good overview. It is set to the object when the function is called as a method on it, but there are other possibilies. The default is that this is undefined when it is called without anything special, like you do with func1 and func2. For sloppy (non-strict) mode functions undefined (and null) are not used though, this does point to the global object (window in browsers) for them in that case - what you are observing.
But it could also point to fresh object instances when the function is called as a constructor (with the new keyword), or to an event target (like a DOM element) when used as a handler. Last, but not least, it could be set manually with call, apply or bind…
this has nothing to do with nesting. Nesting function declarations/expressions only affects the scope ("privacy", availability) of variables. While the variable scope of a function never changes, the value of this can be different on every invocation - it is more like an extra argument.
The meaning of the this keyword inside a function depends on the way the function is invoked. There are 4 different function invocation patterns in JavaScript.
function invocation pattern foo()
method invocation pattern o.foo()
constructor invocation pattern new foo
call/apply pattern foo.apply(...) or foo.call(...)
Only in #2 is it the case that this inside the function refers to the object of which the function is a method.
You are invoking func2() with the function invocation pattern. When doing so, this refers to the global object.
As suggested by #Bergi, see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this for more detail on the meaning of this and the different function invocation patterns.
but I'm not sure why since func2 is NOT a method of the global object.
Any thing defined inside a function is local to the scope of that function. So func2 belongs to the local scope of func1 and therefore is not attached to window.
In Javascript, the value of this is generally based on how you call the function. When you call a function without any leading object, this is usually set to the global parent object, which is window.
You can explicitly set the value of this in three ways:
myObj.func(a, b); //this set to myObj implicitly because myObj is the parent
func.call(myObj, a, b); //this set to myObj explicitly; the first argument
//to call sets the value of this for that function
func.apply(myObj, [a, b]); //this set to myObj explicitly; the first argument
//to apply also sets the value of this for that
//function.
this can be a tricky concept. MDN has a good article about this.