concept

Clarify three concepts: name (identifier), entity, and name-bound entity

  • Create name: declaration (Hoist to top of scope)
  1. Function and variable declarations are processed before any code is executed
  2. Function declarations precede variable declarations
let name;
Copy the code

JavaScript parser: preparse + execute

Preparsing: Promotes the declaration to the front of the current scope, only promoting the declaration, not including assignments (so we can mask variables of the same name outside). Note: preparsing is performed in script segments

  • Create entities: literals, function methods, and so on
new Object(a);Copy the code
  • During the operation of a function, names and entities have their own lifetime, which is classified according to the relationship between variables and bound entities: original value model, reference value model
// Reference value model
let name = new Object(a);Copy the code

  • Var declares the scope of the function, and the variable is destroyed when the function exits. Redundant declarations do not report errors and are automatically promoted to the top of the function (combining redundancies).
  • Let declaration block scope, redundant declaration and error, declaration does not automatically promote (must be declared before use)
  • ECMAScript 6: const>let>var

All global variables and functions defined using var become properties and methods of the Window object. The top-level declarations of let and const are not defined in the global context, but have the same effect on scoping. It gets recycled earlier.

scope

We can first understand the life cycle of a scope for a variable and its assignment of values. We can classify scopes differently from different dimensions:

  • Based on function mechanism, it can be divided into static and dynamic scope from the way of variable and bound entity, namely “scope generation mechanism”
  • Second, when it comes to “execution context,” JavaScript has three scopes – functions, modules, and globals

A,

Static scope

Static/lexical scope (spatial nearest) : Scope can be confirmed before running by analyzing the relative location of the name. Few languages use dynamic scope (most recently)

The lexical (static) scope of JavaScript:

  • Only functions in the entire code can be scoped
  • The scope of a function is determined at function definition
  • Functions can access data outside of functions
  • If a variable name is declared in the current scope rule, the outer variable of the same name – temporary dead zone is masked

A way to trick static scopes: eval

The side effect is that the engine cannot optimize for scoped lookups at compile time, resulting in slow code running and being limited in strict mode.

In non-strict mode, the JavaScript engine does not know that eval is dynamically inserted, and eval modiates the lexical context (adding overrides).

function f(str,a) {
    eval(str);
    console.log(a,b);/ / 1 and 3
}

var b = 2;
f('var b = 3; '.1);
Copy the code

In strict mode, eval has its own lexical scope at runtime

function f(str,a) {
    'use strict';
    eval(str);
    console.log(a,b);/ / 1 and 2
}

var b = 2;
f('var b = 3; '.1);
Copy the code

Pseudo-dynamic scope this

In dynamically scoped languages, the object referenced by a variable in a program is determined at runtime based on the control flow information of the program

  • The meaning of the this keyword binding in JavaScript is determined by the caller of the code in which it resides (shaped like a dynamic scope),
  • This is implicitly declared at the top of the function on each call, while other statically scoped variables are declared only once at function declaration time
  • Arguments are similar to JavaScript arguments
  • The this scope is based on the call stack, and unlike the static scope of variable search, the value of this is retrieved in the execution context and not searched in the scope chain.
  • There are three scenarios for binding this: method call, new, and bind\call\apply
const obj = {
    id: 'in obj'.cool: function() {
        console.log(this.id); }}var id = 'in global';

obj.cool();// 'in obj'

setTimeout(obj.cool,100);// 'in global'
Copy the code

The function of an object is called its method, but note that functions never “belong” to an object. The object only gets a reference to the function object


For this we can hope for this

  1. Is some fixed object – hard bound
  2. The default is an object, modifiable – soft binding is supported

This hard binding

Hard binding is a very common pattern

const a = 'in global';
const obj = {
  a:'in obj',}function f() {
  console.log(this.a);
}
const hard = function () {
  f.call(obj);
}

hard(); // in obj
hard.call(window); // in obj
Copy the code

Arrow function

Arrow function: lexical scope of this, this inherits the this call of the outer function in which the definition resides

This soft binding

By default, this no longer refers to a global object (non-strict mode) or undefined (strict mode), but to an object other than both

if (! Function.prototype.softBind) {
  Function.prototype.softBind = function(obj) {
    let fn = this;
    let curried = [].slice.call( arguments.1);
    let bound = function() {
      return fn.apply(
        (!this || this= = = (window || global))? obj :this.// Check function this, obj overridden if undefined or global
        curried.concat.apply(curried, arguments)); }; bound.prototype =Object.create( fn.prototype);
    return bound;
  };
}
Copy the code

Second,

The var, const, let, and function keywords declare variables whose scope is the enclosing function, not declared in any function – outer scope

Based on these rules and the concept of reference environments, there are three types of JavaScript scopes: functions, modules, and globals

Reference context/context: a collection of all currently valid names at a point in time (corresponding to a point in code) that are not specific to a name

Global scope: If the page contains an embedded pane IFrame, the embedded Document and the embedded iframe have different global and Document objects respectively

Module scope: The biggest difference between inserting a JS file directly into a page via the scripts tag and wrapping it as a module is:

  • The top scope of the former is the global scope, and the declaration of variables and functions will pollute the global environment.
  • The latter will form a scope belonging to the module itself, all variables and functions can only be accessed by itself, is not visible to the outside world.

Function scope (execution context)

Scope chain: global scope + function scope, inner function can access all outer function local variables

  • Each context has an associated variable object on which all variables and functions defined in the context reside. The context is destroyed after all code has been executed.
  • The global context is the outermost context, and the object representing the context may be different depending on the js hosting environment. The global context is destroyed when the application exits. Browser-window object
  • Each function call has its own context. The execution flow of THE JS program is controlled by the context stack. When the code execution flow enters the function, its context is pushed to a context stack. There is also a chain of scopes, with the variable object of the executing context at the front.

Active objects and function objects

The function object

  • The prototype property
  • A reference to the executable code of a function
  • When a function object is created, its corresponding active object is activated
  • Functions are nested, and when the nested function object is created, it contains an active object corresponding to the outer function object

A function object that has an “active object reference corresponding to the outer function object”

Function active object

  1. A reference to the corresponding function object
  2. Function parameters, variables, this
  3. Caller’s active object – used for transfer of control after return
  4. Address of subsequent execution instruction – subsequent execution after return

P.s end calls

  • Free variables: used inside and declared outside a function
  • Bound variables: used and declared inside a function (including parameters)

When a new function called by the tail uses free variables, it gains access to its creator’s active object, and tail-recursive optimization is not performed

The scope chain is enhanced

The scope front end temporarily adds a context

  1. Try. Catch: Creates a new object containing the declaration of the error object to be thrown
  2. with
try{
    undefinedF();/ / error
} catch (err) {
    console.log(err);
}

console.log(err);// Cannot access the block scope of the catch
Copy the code

closure

Many JavaScript articles describe closures as the context information remembered by the function returned from a function. This is actually a closure reference, and in a closure reference, the existence of a closure is obvious, as is the case with any JavaScript function created.

Closure: A data structure that binds environment information to the owning function in a function declaration, taking a function-centric view of static scopes

The local name of a function exists on the call stack. Without closure, when an enclosing function returns an enclosing function, the stack frame of the enclosing function is removed and the local name of the enclosing function that can be referenced by the returned enclosing function disappears


A closure is created when the function is defined, but that does not mean that the values of the variables in the closure stay there. The values of the variables in the closure change normally (the nested function takes the active object of the outer function). When the nested function executes, the values of the variables in the reference environment change. For example, var classic event binding

You can intercept the current value by executing a function immediately.


Why is function A already off the call stack, and why can function B still refer to A variable in function A?

Because the variables in function A are stored on the heap. Now the JS engine can use escape analysis to figure out which variables need to be stored on the heap and which on the stack.


Whenever a callback function is used, it still gets the lexical scope when the reference closure is executed outside its lexical scope

> var a ='global';
function f1(){
    console.log(a);
}
function f(f1){
    var a ='in f';
    f1(); //[Log] global
    console.log(a);// in f
}
f(f1);

/ / another
var a ='global';

function f(){
    var a ='in f';
    console.log(a);
}
 
 f(); //[Log] in f

Copy the code

The closure example is referenced

Jquery: Add required methods to the window properties as global exposure. Zepto: Based on return, expose the methods that need to be exposed directly.

function b(temp,x){
    function c (){
        console.log(x);
    }
    if(x<1){
        b(c,1);
    } else {
        temp();
    }
    c();
}

function a(){
}

b(a,0);
Copy the code
let a = 1;
function f(){
	let a = 0;
	return function (b) {
		console.log(a,b);
		returna++ + b++; }}const res = f();
console.log(res(a)); / / 0 + 1
console.log(res(a)); / / 1 + 1
console.log(res(a)); / / 2 + 1
Copy the code

other

Function return value

Note: function returns undefined arrow function by default.

() = >"Return value"() = > {"It's not me, it's undefined."} () => {return "Return value is me."}
Copy the code

Simulate call and apply

I refer to this section

  • Default if this is not passedwindow
  • Passing the this pointer allows the new object to execute the function. Add a function to a new object and then delete it after execution
Function.prototype.myCall = function (context) {
  var context = context || window
  // Add a property to the context
  context.fn = this
  // Take out the parameters after the context
  var args = [...arguments].slice(1)
  varresult = context.fn(... args)/ / delete the fn
  delete context.fn
  return result
}

Function.prototype.myApply = function (context) {
  var context = context || window
  context.fn = this

  var result
  // Need to determine whether to store the second parameter
  // Expand the second argument if it exists
  if (arguments[1]) { result = context.fn(... arguments[1])}else {
    result = context.fn()
  }

  delete context.fn
  return result
}


Function.prototype.myBind = function (context) {
  if (typeof this! = ='function') {
    throw new TypeError('Error')}var _this = this
  var args = [...arguments].slice(1)
  // Return a function
  return function F() {
    // Since we return a function, we can new F(), so we need to determine
    if (this instanceof F) {
      return new_this(... args, ... arguments) }return_this.apply(context, args.concat(... arguments)) } }Copy the code

Practice code style

The object parameter

Having a function with a single parameter that is an object accommodates the parameter variability. This is also the writing style of class

Functional programming

Nested functions + closures make up functional programming in JavaScript