An attempt at understanding what ECMAScript-6 Function.prototype.bind() actually does - ecmascript-6

This question is a follow-up to this one. For some reason I'm coming back to JS after 7 years and boy, I can hardly recognize the dear old beast.
Purely for educational purpose, I decided to rewrite naive implementations of the various things Function.prototype.bind() allows to do. It's just an exercise to try to understand what's going on and spark a few questions.
I would be happy to stand corrected for all the mistakes and misunderstandings in my examples and comments.
Also, this code is not mine. I got the idea from a blog and only slightly tweaked it, but unfortunately I lost track of the source. If anyone recognizes the original, I'll be happy to give due credit. Meanwhile, I apologize for the blunder.
Naive binding
The initial idea is simply to do what lambda calculus savvies apparently call a "partial application", i.e. fixing the value of the first parameters of a function, that also accepts an implicit "this" first parameter, like so:
Function.prototype.naive_bind = function (fixed_this, ...fixed_args) {
const fun = this; // close on the fixed args and the bound function
return function(...free_args) { // leave the rest of the parameters free
return fun.call(fixed_this, ...fixed_args, ...free_args);
}
}
Binding constructors (1st round)
class class1 {
constructor (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
}
var innocent_bystander = { "huh?":"what?" }
var class2 = class1.naive_bind(innocent_bystander);
class2 (1,2) // exception: class constructor must be invoked with new (as expected)
console.log(new class2(1,2)) // exception: class constructor must be invoked with new (Rats!)
function pseudoclass1 (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
var pseudoclass2 = pseudoclass1.naive_bind(innocent_bystander);
pseudoclass2 (1,2) // same exception (as expected)
console.log(new pseudoclass2(1,2)) // same again (at least it's consistent...)
Tonnerre de Brest ! Apparently the runtime is not happy with a mere wrapper based on Function.prototype.call().
It seems the real bind() is adding the dollop of secret sauce needed to give the generated function the appropriate "constructor" flavour (Apparently by "constructor" the ECMA 262 specification does not mean a class constructor, but any function that can be invoked with "new" and use "this" to populate the properties and methods of a freshly created object)
Binding other functions
var purefunction1 = console.log
var purefunction2 = purefunction1.naive_bind (null, "Sure,", "but")
purefunction2 ("you can still", "bind pure", "functions")
// sure, but you can still bind pure functions
// ...and make animals talk (by binding simple methods)
var cat = { speech: "meow" }
var dog = { speech: "woof" }
var fish= { speech: "-" }
var talk = function(count) { console.log ((this.speech+", ").repeat(count-1) + this.speech + "!") }
talk.naive_bind (cat,1)(); // meow!
talk.naive_bind (dog,1)(); // woof!
talk.naive_bind (cat)(3) // meow, meow, meow!
talk.naive_bind (fish)(10) // -, -, -, -, -, -, -, -, -, -!
// and bind arrow functions
// ("this" is wasted on them, but their parameters can still be bound)
var surprise = (a,b,c) => console.log (this.surprise, a,b,c)
var puzzlement = surprise.naive_bind(innocent_bystander, "don't", "worry");
// "this" refers to window, so we get our own function as first output.
surprise ("where", "am", "I?") // function surprise(a, b, c) where am I?
// the bound value of this is ignored, but the other arguments are working fine
puzzlement("dude") // function surprise(a, b, c) don't worry dude
Apparently, everything works as expected. Or did I miss something?
Binding constructors (2nd round)
We apparently can't get away with passing a wrapper to new, but we can try invoking new directly.
Since the value of this is provided by new, the construction-specialized wrapper has only to worry about real constructor parameters.
Function.prototype.constructor_bind = function (...fixed_args) {
const fun = this;
return function(...free_args) {
return new fun (...fixed_args, ...free_args);
}
}
var class1_ctor = class1.constructor_bind(1);
console.log (class1_ctor(2)) // class1 { p1:1, p2:2 }
var monster = (a,b) => console.log ("boooh", a, b)
var abomination = monster.constructor_bind(1);
console.log (abomination(2)) // exception: fun is not a constructor (as expected)
Well, that seems to cut it. I imagine the real bind() is far safer and faster, but at least we can reproduce the basic functionalities, namely:
providing a fixed value of this to methods
doing partial applications on any legit function, though constructors require a specific variant
edit: questions removed to comply with SO policy.
Replaced by just one, the one that matches the title of this post, and that I tried to explore by providing a naive and possibly erroneous equivalent of what I thought the real function did:
Please help me understand how the native Function.prototype.bind() method works, according to the version 6.0 of the ECMAScript specification.

The only bit you have been missing is the introduction of new.target in ES6, which a) makes it possible to distinguish between [[call]] and [[construct]] in a function and b) needs to be forwarded in the new call.
So a more complete polyfill might look like this:
Function.prototype.bind = function (fixed_this, ...fixed_args) {
const fun = this;
return function(...free_args) {
return new.target != null
? Reflect.construct(fun, [...fixed_args, ...free_args], new.target)
: fun.call(fixed_this, ...fixed_args, ...free_args);
}
}
Some other details would involve that fun is asserted to be a function object, and that the returned bound function has a special .name, an accurate .length, and no .prototype. You can find these things in the spec, which apparently you've been reading already.

Related

Uncaught ReferenceError: (XXXXXXX) is not defined [duplicate]

What is the scope of variables in javascript? Do they have the same scope inside as opposed to outside a function? Or does it even matter? Also, where are the variables stored if they are defined globally?
TLDR
JavaScript has lexical (also called static) scoping and closures. This means you can tell the scope of an identifier by looking at the source code.
The four scopes are:
Global - visible by everything
Function - visible within a function (and its sub-functions and blocks)
Block - visible within a block (and its sub-blocks)
Module - visible within a module
Outside of the special cases of global and module scope, variables are declared using var (function scope), let (block scope), and const (block scope). Most other forms of identifier declaration have block scope in strict mode.
Overview
Scope is the region of the codebase over which an identifier is valid.
A lexical environment is a mapping between identifier names and the values associated with them.
Scope is formed of a linked nesting of lexical environments, with each level in the nesting corresponding to a lexical environment of an ancestor execution context.
These linked lexical environments form a scope "chain". Identifier resolution is the process of searching along this chain for a matching identifier.
Identifier resolution only occurs in one direction: outwards. In this way, outer lexical environments cannot "see" into inner lexical environments.
There are three pertinent factors in deciding the scope of an identifier in JavaScript:
How an identifier was declared
Where an identifier was declared
Whether you are in strict mode or non-strict mode
Some of the ways identifiers can be declared:
var, let and const
Function parameters
Catch block parameter
Function declarations
Named function expressions
Implicitly defined properties on the global object (i.e., missing out var in non-strict mode)
import statements
eval
Some of the locations identifiers can be declared:
Global context
Function body
Ordinary block
The top of a control structure (e.g., loop, if, while, etc.)
Control structure body
Modules
Declaration Styles
var
Identifiers declared using var have function scope, apart from when they are declared directly in the global context, in which case they are added as properties on the global object and have global scope. There are separate rules for their use in eval functions.
let and const
Identifiers declared using let and const have block scope, apart from when they are declared directly in the global context, in which case they have global scope.
Note: let, const and var are all hoisted. This means that their logical position of definition is the top of their enclosing scope (block or function). However, variables declared using let and const cannot be read or assigned to until control has passed the point of declaration in the source code. The interim period is known as the temporal dead zone.
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
Function parameter names
Function parameter names are scoped to the function body. Note that there is a slight complexity to this. Functions declared as default arguments close over the parameter list, and not the body of the function.
Function declarations
Function declarations have block scope in strict mode and function scope in non-strict mode. Note: non-strict mode is a complicated set of emergent rules based on the quirky historical implementations of different browsers.
Named function expressions
Named function expressions are scoped to themselves (e.g., for the purpose of recursion).
Implicitly defined properties on the global object
In non-strict mode, implicitly defined properties on the global object have global scope, because the global object sits at the top of the scope chain. In strict mode, these are not permitted.
eval
In eval strings, variables declared using var will be placed in the current scope, or, if eval is used indirectly, as properties on the global object.
Examples
The following will throw a ReferenceError because the namesx, y, and z have no meaning outside of the function f.
function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
The following will throw a ReferenceError for y and z, but not for x, because the visibility of x is not constrained by the block. Blocks that define the bodies of control structures like if, for, and while, behave similarly.
{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope
In the following, x is visible outside of the loop because var has function scope:
for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)
...because of this behavior, you need to be careful about closing over variables declared using var in loops. There is only one instance of variable x declared here, and it sits logically outside of the loop.
The following prints 5, five times, and then prints 5 a sixth time for the console.log outside the loop:
for(var x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop
The following prints undefined because x is block-scoped. The callbacks are run one by one asynchronously. New behavior for let variables means that each anonymous function closed over a different variable named x (unlike it would have done with var), and so integers 0 through 4 are printed.:
for(let x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined
The following will NOT throw a ReferenceError because the visibility of x is not constrained by the block; it will, however, print undefined because the variable has not been initialised (because of the if statement).
if(false) {
var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised
A variable declared at the top of a for loop using let is scoped to the body of the loop:
for(let x = 0; x < 10; ++x) {}
console.log(typeof x) // undefined, because `x` is block-scoped
The following will throw a ReferenceError because the visibility of x is constrained by the block:
if(false) {
let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped
Variables declared using var, let or const are all scoped to modules:
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
The following will declare a property on the global object because variables declared using var within the global context are added as properties to the global object:
var x = 1
console.log(window.hasOwnProperty('x')) // true
let and const in the global context do not add properties to the global object, but still have global scope:
let x = 1
console.log(window.hasOwnProperty('x')) // false
Function parameters can be considered to be declared in the function body:
function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function
Catch block parameters are scoped to the catch-block body:
try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block
Named function expressions are scoped only to the expression itself:
(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression
In non-strict mode, implicitly defined properties on the global object are globally scoped. In strict mode, you get an error.
x = 1 // implicitly defined property on the global object (no "var"!)
console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true
In non-strict mode, function declarations have function scope. In strict mode, they have block scope.
'use strict'
{
function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped
How it works under the hood
Scope is defined as the lexical region of code over which an identifier is valid.
In JavaScript, every function-object has a hidden [[Environment]] reference that is a reference to the lexical environment of the execution context (stack frame) within which it was created.
When you invoke a function, the hidden [[Call]] method is called. This method creates a new execution context and establishes a link between the new execution context and the lexical environment of the function-object. It does this by copying the [[Environment]] value on the function-object, into an outer reference field on the lexical environment of the new execution context.
Note that this link between the new execution context and the lexical environment of the function object is called a closure.
Thus, in JavaScript, scope is implemented via lexical environments linked together in a "chain" by outer references. This chain of lexical environments is called the scope chain, and identifier resolution occurs by searching up the chain for a matching identifier.
Find out more.
Javascript uses scope chains to establish the scope for a given function. There is typically one global scope, and each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope.
An element in the scope chain is basically a Map with a pointer to its parent scope.
When resolving a variable, javascript starts at the innermost scope and searches outwards.
Variables declared globally have a global scope. Variables declared within a function are scoped to that function, and shadow global variables of the same name.
(I'm sure there are many subtleties that real JavaScript programmers will be able to point out in other answers. In particular I came across this page about what exactly this means at any time. Hopefully this more introductory link is enough to get you started though.)
Old school JavaScript
Traditionally, JavaScript really only has two types of scope :
Global Scope : Variables are known throughout the application, from the start of the application (*)
Functional Scope : Variables are known within the function they are declared in, from the start of the function (*)
I will not elaborate on this, since there are already many other answers explaining the difference.
Modern JavaScript
The most recent JavaScript specs now also allow a third scope :
Block Scope : Identifiers are "known" from the top of the scope they are declared within, but they cannot be assigned to or dereferenced (read) until after the line of their declaration. This interim period is called the "temporal dead zone."
How do I create block scope variables?
Traditionally, you create your variables like this :
var myVariable = "Some text";
Block scope variables are created like this :
let myVariable = "Some text";
So what is the difference between functional scope and block scope?
To understand the difference between functional scope and block scope, consider the following code :
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Here, we can see that our variable j is only known in the first for loop, but not before and after. Yet, our variable i is known in the entire function.
Also, consider that block scoped variables are not known before they are declared because they are not hoisted. You're also not allowed to redeclare the same block scoped variable within the same block. This makes block scoped variables less error prone than globally or functionally scoped variables, which are hoisted and which do not produce any errors in case of multiple declarations.
Is it safe to use block scope variables today?
Whether or not it is safe to use today, depends on your environment :
If you're writing server-side JavaScript code (Node.js), you can safely use the let statement.
If you're writing client-side JavaScript code and use a browser based transpiler (like Traceur or babel-standalone), you can safely use the let statement, however your code is likely to be anything but optimal with respect to performance.
If you're writing client-side JavaScript code and use a Node based transpiler (like the traceur shell script or Babel), you can safely use the let statement. And because your browser will only know about the transpiled code, performance drawbacks should be limited.
If you're writing client-side JavaScript code and don't use a transpiler, you need to consider browser support.
These are some browsers that don't support let at all :
Internet explorer 10 and below
Firefox 43 and below
Safari 9 and below
Android browser 4 and below
Opera 27 and below
Chome 40 and below
ANY version of Opera Mini & Blackberry Browser
How to keep track of browser support
For an up-to-date overview of which browsers support the let statement at the time of your reading this answer, see this Can I Use page.
(*) Globally and functionally scoped variables can be initialized and used before they are declared because JavaScript variables are hoisted. This means that declarations are always much to the top of the scope.
Here's an example:
<script>
var globalVariable = 7; //==window.globalVariable
function aGlobal( param ) { //==window.aGlobal();
//param is only accessible in this function
var scopedToFunction = {
//can't be accessed outside of this function
nested : 3 //accessible by: scopedToFunction.nested
};
anotherGlobal = {
//global because there's no `var`
};
}
</script>
You'll want to investigate closures, and how to use them to make private members.
The key, as I understand it, is that Javascript has function level scoping vs the more common C block scoping.
Here is a good article on the subject.
In "Javascript 1.7" (Mozilla's extension to Javascript) one can also declare block-scope variables with let statement:
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
The idea of scoping in JavaScript when originally designed by Brendan Eich came from the HyperCard scripting language HyperTalk.
In this language, the displays were done similar to a stack of index cards. There was a master card referred to as the background. It was transparent and can be seen as the bottom card. Any content on this base card was shared with cards placed on top of it. Each card placed on top had its own content which took precedence over the previous card, but still had access to the prior cards if desired.
This is exactly how the JavaScript scoping system is designed. It just has different names. The cards in JavaScript are known as Execution ContextsECMA. Each one of these contexts contains three main parts. A variable environment, a lexical environment, and a this binding. Going back to the cards reference, the lexical environment contains all of the content from prior cards lower in the stack. The current context is at the top of the stack and any content declared there will be stored in the variable environment. The variable environment will take precedence in the case of naming collisions.
The this binding will point to the containing object. Sometimes scopes or execution contexts change without the containing object changing, such as in a declared function where the containing object may be window or a constructor function.
These execution contexts are created any time control is transferred. Control is transferred when code begins to execute, and this is primarily done from function execution.
So that is the technical explanation. In practice, it is important to remember that in JavaScript
Scopes are technically "Execution Contexts"
Contexts form a stack of environments where variables are stored
The top of the stack takes precedence (the bottom being the global context)
Each function creates an execution context (but not always a new this binding)
Applying this to one of the previous examples (5. "Closure") on this page, it is possible to follow the stack of execution contexts. In this example there are three contexts in the stack. They are defined by the outer context, the context in the immediately invoked function called by var six, and the context in the returned function inside of var six's immediately invoked function.
i) The outer context. It has a variable environment of a = 1
ii) The IIFE context, it has a lexical environment of a = 1, but a variable environment of a = 6 which takes precedence in the stack
iii) The returned function context, it has a lexical environment of a = 6 and that is the value referenced in the alert when called.
1) There is a global scope, a function scope, and the with and catch scopes. There is no 'block' level scope in general for variable's -- the with and the catch statements add names to their blocks.
2) Scopes are nested by functions all the way to the global scope.
3) Properties are resolved by going through the prototype chain. The with statement brings object property names into the lexical scope defined by the with block.
EDIT: ECMAAScript 6 (Harmony) is spec'ed to support let, and I know chrome allows a 'harmony' flag, so perhaps it does support it..
Let would be a support for block level scoping, but you have to use the keyword to make it happen.
EDIT: Based on Benjamin's pointing out of the with and catch statements in the comments, I've edited the post, and added more. Both the with and the catch statements introduce variables into their respective blocks, and that is a block scope. These variables are aliased to the properties of the objects passed into them.
//chrome (v8)
var a = { 'test1':'test1val' }
test1 // error not defined
with (a) { var test1 = 'replaced' }
test1 // undefined
a // a.test1 = 'replaced'
EDIT: Clarifying example:
test1 is scoped to the with block, but is aliased to a.test1. 'Var test1' creates a new variable test1 in the upper lexical context (function, or global), unless it is a property of a -- which it is.
Yikes! Be careful using 'with' -- just like var is a noop if the variable is already defined in the function, it is also a noop with respect to names imported from the object! A little heads up on the name already being defined would make this much safer. I personally will never use with because of this.
Inline handlers
A very common issue not described yet that front-end coders often run into is the scope that is visible to an inline event handler in the HTML - for example, with
<button onclick="foo()"></button>
The scope of the variables that an on* attribute can reference must be either:
global (working inline handlers almost always reference global variables)
a property of the document (eg, querySelector as a standalone variable will point to document.querySelector; rare)
a property of the element the handler is attached to (like above; rare)
Otherwise, you'll get a ReferenceError when the handler is invoked. So, for example, if the inline handler references a function which is defined inside window.onload or $(function() {, the reference will fail, because the inline handler may only reference variables in the global scope, and the function is not global:
window.addEventListener('DOMContentLoaded', () => {
function foo() {
console.log('foo running');
}
});
<button onclick="foo()">click</button>
Properties of the document and properties of the element the handler is attached to may also be referenced as standalone variables inside inline handlers because inline handlers are invoked inside of two with blocks, one for the document, one for the element. The scope chain of variables inside these handlers is extremely unintuitive, and a working event handler will probably require a function to be global (and unnecessary global pollution should probably be avoided).
Since the scope chain inside inline handlers is so weird, and since inline handlers require global pollution to work, and since inline handlers sometimes require ugly string escaping when passing arguments, it's probably easier to avoid them. Instead, attach event handlers using Javascript (like with addEventListener), rather than with HTML markup.
function foo() {
console.log('foo running');
}
document.querySelector('.my-button').addEventListener('click', foo);
<button class="my-button">click</button>
Modules (<script type="module">)
On a different note, unlike normal <script> tags, which run on the top level, code inside ES6 modules runs in its own private scope. A variable defined at the top of a normal <script> tag is global, so you can reference it in other <script> tags, like this:
<script>
const foo = 'foo';
</script>
<script>
console.log(foo);
</script>
But the top level of an ES6 module is not global. A variable declared at the top of an ES6 module will only be visible inside that module, unless the variable is explicitly exported, or unless it's assigned to a property of the global object.
<script type="module">
const foo = 'foo';
</script>
<script>
// Can't access foo here, because the other script is a module
console.log(typeof foo);
</script>
The top level of an ES6 module is similar to that of the inside of an IIFE on the top level in a normal <script>. The module can reference any variables which are global, and nothing can reference anything inside the module unless the module is explicitly designed for it.
I found that many people new to JavaScript have trouble understanding that inheritance is available by default in the language and that function scope is the only scope, so far. I provided an extension to a beautifier I wrote at the end of last year called JSPretty. The feature colors function scope in the code and always associates a color to all variables declared in that scope. Closure is visually demonstrated when a variable with a color from one scope is used in a different scope.
Try the feature at:
http://prettydiff.com/jspretty.xhtml?c=white&jsscope
See a demo at:
http://prettydiff.com/jspretty.xhtml?c=white&jsscope&s=http://prettydiff.com/lib/markup_beauty.js
View the code at:
http://prettydiff.com/lib/jspretty.js
https://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js
Currently the feature offers support for a depth of 16 nested functions, but currently does not color global variables.
JavaScript have only two type of scope :
Global Scope : Global is nothing but a window level scope.Here, variable present throughout the application.
Functional Scope : Variable declared within a function with var keyword has functional scope.
Whenever a function is called, a variable scope object is created (and included in scope chain) which is followed by variables in JavaScript.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
Scope chain -->
Window level - a and outer function are at top level in scope chain.
when outer function called a new variable scope object(and included in scope chain) added with variable b inside it.
Now when a variable a required it first searches for nearest variable scope and if variable is not there than it move's to next object of variable scope chain.which is in this case is window level.
run the code. hope this will give an idea about scoping
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
Global Scope :
Global variables are exactly like global stars (Jackie Chan, Nelson Mandela). You can access them (get or set the value), from any part of your application. Global functions are like global events (New Year, Christmas). You can execute (call) them from any part of your application.
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
Local Scope :
If you are in the USA, you may know Kim Kardashian, infamous celebrity ( she somehow manages to make the tabloids). But people outside of the USA will not recognize her. She is a local star, bound to her territory.
Local variables are like local stars. You can only access them (get or set the value) inside the scope. A local function is like local events - you can execute only (celebrate) inside that scope. If you want to access them from outside of the scope, you will get a reference error
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
Check this article for in-depth understanding of scope
Just to add to the other answers, scope is a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code. This look-up may be for the purposes of assigning to the variable, which is an LHS (lefthand-side) reference, or it may be for the purposes of retrieving its value, which is an RHS (righthand-side) reference. These look-ups are what the JavaScript engine is doing internally when it's compiling and executing the code.
So from this perspective, I think that a picture would help that I found in the Scopes and Closures ebook by Kyle Simpson:
Quoting from his ebook:
The building represents our program’s nested scope ruleset. The first
floor of the building represents your currently executing scope,
wherever you are. The top level of the building is the global scope.
You resolve LHS and RHS references by looking on your current floor,
and if you don’t find it, taking the elevator to the next floor,
looking there, then the next, and so on. Once you get to the top floor
(the global scope), you either find what you’re looking for, or you
don’t. But you have to stop regardless.
One thing of note that is worth mentioning, "Scope look-up stops once it finds the first match".
This idea of "scope levels" explains why "this" can be changed with a newly created scope, if it's being looked up in a nested function.
Here is a link that goes into all these details, Everything you wanted to know about javascript scope
There are ALMOST only two types of JavaScript scopes:
the scope of each var declaration is associated with the most immediately enclosing function
if there is no enclosing function for a var declaration, it is global scope
So, any blocks other than functions do not create a new scope. That explains why for-loops overwrite outer scoped variables:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
Using functions instead:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
In the first example, there was no block scope, so the initially declared variables were overwritten. In the second example, there was a new scope due to the function, so the initially declared variables were SHADOWED, and not overwritten.
That's almost all you need to know in terms of JavaScript scoping, except:
try/catch introduce new scope ONLY for the exception variable itself, other variables do not have new scope
with-clause apparently is another exception, but using with-clause it highly discouraged (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)
So you can see JavaScript scoping is actually extremely simple, albeit not always intuitive. A few things to be aware of:
var declarations are hoisted to the top of the scope. This means no matter where the var declaration happens, to the compiler it is as if the var itself happens at the top
multiple var declarations within the same scope are combined
So this code:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
is equivalent to:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
This may seem counter intuitive, but it makes sense from the perspective of a imperative language designer.
Modern Js, ES6+, 'const' and 'let'
You should be using block scoping for every variable you create, just like most other major languages. var is obsolete. This makes your code safer and more maintainable.
const should be used for 95% of cases. It makes it so the variable reference can't change. Array, object, and DOM node properties can change and should likely be const.
let should be be used for any variable expecting to be reassigned. This includes within a for loop. If you ever change value beyond initialization, use let.
Block scope means that the variable will only be available within the brackets in which it is declared. This extends to internal scopes, including anonymous functions created within your scope.
Try this curious example. In the example below if a were a numeric initialized at 0, you'd see 0 and then 1. Except a is an object and javascript will pass f1 a pointer of a rather than a copy of it. The result is that you get the same alert both times.
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
There are only function scopes in JS. Not block scopes!
You can see what is hoisting too.
var global_variable = "global_variable";
var hoisting_variable = "global_hoist";
// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);
if (true) {
// The variable block will be global, on true condition.
var block = "block";
}
console.log("global_scope: - block: " + block);
function local_function() {
var local_variable = "local_variable";
console.log("local_scope: - local_variable: " + local_variable);
console.log("local_scope: - global_variable: " + global_variable);
console.log("local_scope: - block: " + block);
// The hoisting_variable is undefined at the moment.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
var hoisting_variable = "local_hoist";
// The hoisting_variable is now set as a local one.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}
local_function();
// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
My understanding is that there are 3 scopes: global scope, available globally; local scope, available to an entire function regardless of blocks; and block scope, only available to the block, statement, or expression on which it was used. Global and local scope are indicated with the keyword 'var', either within a function or outside, and block scope is indicated with the keyword 'let'.
For those that believe there is only global and local scope, please explain why Mozilla would have an entire page describing the nuances of block scope in JS.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
In JavaScript there are two types of scope:
Local scope
Global scope
The Below function has a local scope variable carName. And this variable is not accessible from outside of the function.
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
The Below Class has a Global scope variable carName. And this variable is accessible from everywhere in the class.
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
ES5 and earlier:
Variables in Javascript were initially (pre ES6) lexically function scoped. The term lexically scoped means that you can see the scope of the variables by 'looking' at the code.
Every variable declared with the var keyword is scoped to the function. However, if other function are declared within that function those functions will have access to the variables of the outer functions. This is called a scope chain. It works in the following manner:
When a function look to resolve a variable value it first looks at its own scope. This is the function body, i.e. everything between curly brackets {} (except for variables inside other functions which are in this scope).
If it cannot find the variable inside the function body it will climb up to the chain and look at the variable scope in the function in where the function was defined. This is what is meant with lexical scope, we can see in the code where this function was defined and thus can determine the scope chain by merely looking at the code.
Example:
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';
function outerFunc () {
// outerFunc scope
var foo = 'outerFunc';
var foobar = 'outerFunc';
innerFunc();
function innerFunc(){
// innerFunc scope
var foo = 'innerFunc';
console.log(foo);
console.log(bar);
console.log(foobar);
}
}
outerFunc();
What happens when we are trying to log the variables foo, bar, and foobar to the console is the following:
We try to log foo to the console, foo can be found inside the function innerFunc itself. Therefore, the value of foo is resolved to the string innerFunc.
We try to log bar to the console, bar cannot be found inside the function innerFunc itself. Therefore, we need to climb the scope chain. We first look in the outer function in which the function innerFunc was defined. This is the function outerFunc. In the scope of outerFunc we can find the variable bar, which holds the string 'outerFunc'.
foobar cannot be found in innerFunc. . Therefore, we need to climb the scope chain to the innerFunc scope. It also cannot be found here, we climb another level to the global scope (i.e. the outermost scope). We find the variable foobar here which holds the string 'global'. If it wouldnot have found the variable after climbing the scope chain the JS engine would throw a referenceError.
ES6 (ES 2015) and older:
The same concepts of lexically scope and scopechain still apply in ES6. However a new ways to declare variables were introduced. There are the following:
let: creates a block scoped variable
const: creates a block scoped variable which has to be initialized and cannot be reassigned
The biggest difference between var and let/const is that var is function scoped whereas let/const are block scoped. Here is an example to illustrate this:
let letVar = 'global';
var varVar = 'global';
function foo () {
if (true) {
// this variable declared with let is scoped to the if block, block scoped
let letVar = 5;
// this variable declared with let is scoped to the function block, function scoped
var varVar = 10;
}
console.log(letVar);
console.log(varVar);
}
foo();
In the above example letVar logs the value global because variables declared with let are block scoped. They cease to exist outside their respective block, so the variable can't be accessed outside the if block.
I really like the accepted answer but I want to add this:
Scope collects and maintains a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code.
Scope is a set of rules for looking up variables by their identifier name.
If a variable cannot be found in the immediate scope, Engine consults the next outer containing scope, continuing until is found or until the outermost (a.k.a., global) scope has been reached.
Is the set of rules that determines where and how a variable (identifier) can be looked up. This look-up may be for the purposes of assigning to the variable, which is an LHS (left-hand-side) reference, or it may be for the purposes of retrieving its value, which is an RHS (righthand-side) reference.
LHS references result from assignment operations. Scope-related assignments can occur either with the = operator or by passing arguments to (assign to) function parameters.
The JavaScript engine first compiles code before it executes, and in so doing, it splits up statements like var a = 2; into two separate steps: 1st. First, var a to declare it in that scope. This is performed at the beginning, before code execution. 2nd. Later, a = 2 to look up the variable (LHS reference) and assign to it if found.
Both LHS and RHS reference look-ups start at the currently executing scope, and if need be (that is, they don’t find what they’re looking for there), they work their way up the nested scope, one scope (floor) at a time, looking for the identifier, until they get to the global (top floor) and stop, and either find it, or don’t. Unfulfilled RHS references result in ReferenceError being thrown. Unfulfilled LHS references result in an automatic, implicitly created global of that name (if not in Strict Mode), or a ReferenceError (if in Strict Mode).
scope consists of a series of “bubbles” that each act as a container or bucket, in which identifiers (variables, functions) are declared. These bubbles nest neatly inside each other, and this nesting is defined at author time.
In EcmaScript5, there are mainly two scopes, local scope and global scope but in EcmaScript6 we have mainly three scopes, local scope, global scope and a new scope called block scope.
Example of block scope is :-
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
ECMAScript 6 introduced the let and const keywords. These keywords can be used in place of the var keyword. Contrary to the var keyword, the let and const keywords support the declaration of local scope inside block statements.
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
(function foo() { console.log(foo) })();
console.log(typeof foo); // undefined, because `foo` is scoped to its own expression
//but, like this
(function foo() {
console.log('1:', foo) // function foo
foo = 100
console.log('2:', foo) // function foo, is not 100, why?
})()
There are two types of scopes in JavaScript.
Global scope: variable which is announced in global scope can be used anywhere in the program very smoothly. For example:
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
Functional scope or Local scope: variable declared in this scope can be used in its own function only. For example:
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}

js: one confusing point about 'this' keyword usage between ES5 and ES6

I am currently learning ES6 standard, for the arrow function part, I found a confusing point as following:
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
the above is ES6 standard, and ES5 is as following
function foo() {
setTimeout(function(){
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
In ES5, the output is id:21
In ES6, the output is id:42
I can understand the ES6's result. But very confused with the result from ES5. The call site for foo() function is foo.call({id:42}),so the calling object is {id:42}, but when it executes, the calling object changes to window. How so?
There are a few pieces here. First off, understand that this is essentially an argument that is automatically set by the thing calling the function. That is critical to understand. So in this case, setTimeout is responsible for calling your function and it essentially does fn.call(undefined), so no explicit this is passed in.
Next, your examples:
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
vs
function foo() {
setTimeout(function(){
console.log('id:', this.id);
}, 100);
}
The arrow function case is essentially:
function foo() {
var _this = this;
setTimeout(function(){
console.log('id:', _this.id);
}, 100);
}
So comparing this in the two cases, the first uses the this that foo is called with, and your example code works because you're foo.call({ id: 42 }); explicitly sets than. The second example uses the this that setTimeout passes, which as I mentioned above is undefined.
However, the this that is passed in from .call may not actually be the this that ends up exposed inside the function.
In non-strict code: this is passed straight through, if it is an object, but if it is not an object, this is the global object (window in a browser, global in Node)
In strict code: this is passed straight through unchanged
Since your example code is has not been marked with "use strict";, this means you are hitting this global behavior. This means your two examples are essentially this:
function foo() {
setTimeout(function(){
console.log('id:', window.id); // reads "id" from the global object
}, 100);
}
vs
function foo() {
var _this = this;
setTimeout(function(){
console.log('id:', _this.id); // reads "this" from `foo.call(...)`
}, 100);
}
The last piece here is that your
var id = 21;
is in the global scope, so it is essentially doing window.id = 21. Thus this value carries through.
The main takeaways here that I'd recommend:
Don't execute code in the top-level scope so that your var declarations don't end up on window. This will happen automatically if you use a module system like CommonJS or Webpack's ES6 module syntax. If you do this, your code as-is would log undefined since window.id would not exist.
Always mark your code with "use strict";. This usually is easy. If you're using CommonJS just put it at the top of your file, and if you're using ES6 modules, it will be added automatically because ES6 modules are required to be strict. If you do this, this inside your non-arrow callback would be undefined so this.id would throw an error.
ES5: 'this' is verified until function actually called (i.e., function() or by 'new' keyword). In your case, the callback function inside setTimeout is actually invoked by window object (hence your 'this' turns out to be window object), and window object has 'a' attribute since you declared. That's why it prints out 21.
ES6: 'this' is verified once your function is declared. Hence 'this' points to ANYTHING inside 'call' function. Of course you can try call(window), then you will see 21 is printed out as expected since window has 'a=21' attribute.
This is a really good question and I hope above explanation helps:)

AS3 functions replacing

I used to work on AS2 and make games, and now I wanna learn AS3 and have all its nice features (using Flash CS IDE). Now I m trying to rewrite a function to discard it.
function something():void{
//do something
}
function something():void{}
like this. please help or just give some alternatives, thanks.
What you're trying to do is very illogical - a function should be defined once and exist always. Not only that, but it should definitely always behave the same way, especially considering AS3 does not support overloading.
AS3 introduces the OOP paradigm for you to use - this further emphasises the above - you should create classes which define a fixed collection of properties and methods. This way, the intent of each class in your application is clear, and what you expect something to be able to do won't change.
If you absolutely must be able to delete functions, you can assign them to a dynamic object and remove or redefine them with the delete keyword:
var methods:Object = {
something: function():void
{
trace('Still here.');
}
};
methods.something(); // Still here.
delete methods.something;
methods.something(); // TypeError: something is not a function.
methods.something = function():void
{
// Define new function.
}
Or assign an anonymous function to a variable of type Function, from which point you can set the reference to null:
var something:Function = function():void
{
trace("Still here.");
}
something(); // Still here.
something = null;
something(); // TypeError: value is not a function.
something = function():void
{
// Define new function.
}

Haxe, differentiate anonymous function at runtime

I'm trying to differentiate anonymous functions like:
function() { trace("WOO"); }
from the other ones ('named'?) like
var _FUNC:Dynamic = function() { trace("WOO"); }
The reason I want to do that is because I can't compare between two anonymous functions, because they are two different ones.
To help me make things clearer, consider the following quick example.
var _TEST:Dynamic = function(a:Dynamic):String {
var _TESTA:Dynamic = function() { trace("WOO"); };
var _TESTB:Dynamic = _FUNC;
return (a == _TESTA) + ", " + (a == _TESTB);
}
If I run _TEST(_FUNC);, I'll get back "false, true". Even though they are the same function, they are NOT the same object.
Is there a way to compare those such that functions that they are the same if they perform the same task?
Is there a way to serialize functions? So that maybe I can compare the serialized representations and see if they share the same 'code'.
A few clarifications:
The first two samples you have posted are virtually identical. The only difference is that you have assigned the second to a static var. You could have used a static function directly with the main difference that in that case the function is not changeable If you want to make it so you should add the dynamic modifier.
Starting from the latest version you can have local named functions:
static f() { function a() { trace("hi"); }; a() }
To properly compare methods you should use Reflect.compareMethods(). Sometimes Haxe creates closures around functions and that can break equality.
You can compare function references but not the function bodies. So the answer is no, you can't compare function that are generated in different statements but do the same thing.
You cannot serialize functions.
You can maybe find some platform specific way to deal with this situation or Macro may apply too (to create function signatures) but I think it is easier to redesign your code. Another option is to adopt a lib like hscript for those calls that need to be comparable and serializable.

Can a Flex 3 method detect the calling object?

If I have a method such as:
private function testMethod(param:string):void
{
// Get the object that called this function
}
Inside the testMethod, can I work out what object called us? e.g.
class A
{
doSomething()
{
var b:B = new B();
b.fooBar();
}
}
class B
{
fooBar()
{
// Can I tell that the calling object is type of class A?
}
}
Sorry the answer is no (see edit below). Functions received a special property called arguments and in AS2 it used to have the property caller that would do roughly what you want. Although the arguments object is still available in AS3 the caller property was removed from AS3 (and therefore Flex 3) so there is no direct way you can do what you want. It is also recommeded that you use the [...rest parameter](http://livedocs.adobe.com/flex/3/langref/statements.html#..._(rest)_parameter) language feature instead of arguments.
Here is a reference on the matter (search for callee to find the relevant details).
Edit: Further investigation has shown that it is possible to get a stack trace for the current executing function so if you are lucky you can do something with that. See this blog entry and this forum post for more details.
The basic idea from the blog post is you throw an Error and then catch it immediately and then parse the stack trace. Ugly, but it may work for you.
code from the blog post:
var stackTrace:String;
try { throw new Error(); }
catch (e:Error) { stackTrace = e.getStackTrace(); }
var lines:Array = stackTrace.split("\n");
var isDebug:Boolean = (lines[1] as String).indexOf('[') != -1;
var path:String;
var line:int = -1;
if(isDebug)
{
var regex:RegExp = /at\x20(.+?)\[(.+?)\]/i;
var matches:Array = regex.exec(lines[2]);
path = matches[1];
//file:line = matches[2]
//windows == 2 because of drive:\
line = matches[2].split(':')[2];
}
else
{
path = (lines[2] as String).substring(4);
}
trace(path + (line != -1 ? '[' + line.toString() + ']' : ''));
Is important to know that stackTrace is only available on the debugger version of Flash Player. Sorry! :(
I'd second the idea of explicitly passing a "callingObject" parameter. Unless you're doing really tricky stuff, it should be better for the caller to be able to supply the target object, anyway. (Sorry if this seems obvious, I can't tell what you're trying to accomplish.)
To add to the somewhat ambiguous first paragraph of James: the arguments property is still available inside a Function object, but the caller property has been removed.
Here's a link to the docs: http://livedocs.adobe.com/flex/3/langref/arguments.html
This might help someone, I'm not sure... but if one is using an Event this is possible using the e.currentTarget as follows:
private function button_hover(e:Event):void
{
e.currentTarget.label="Hovering";
}