This is the fifth day of my participation in Gwen Challenge

Why use this

Here’s an example:

function identity() {
    return this.name.toUpperCase();
}
 
function speak() {
    return "Hello, i'm " + identity.call(this);
}
 
var me = {
    name: 'rod chen'
}
 
var you = {
    name: "others in Aug"
}
 
console.log(identity.call(me));  //ROD CHEN
console.log(identity.call(you)); //OTHERS IN AUG
 
console.log(speak.call(me));     //Hello, i'm ROD CHEN  
console.log(speak.call(you));    //Hello, i'm OTHERS IN AUG
Copy the code

The result of the output is obvious. As mentioned in the previous article about the use of call, the first argument is the value of this passed into the function. This code can reuse identify() and speak() in different context objects (me and you), if we don’t apply this, then identity and speak display is passed in as a context object, as follows

function identity(context) {
    return context.name.toUpperCase();
}
 
function speak(context) {
    return "Hello, i'm " + identity(context);
}
 
var me = {
    name: 'rod chen'
}
 
var you = {
    name: "others in Aug"
}
 
console.log(identity(me));
console.log(identity(you));
 
console.log(speak(me));
console.log(speak(you));
Copy the code

Conclusion: This provides a more elegant way to implicitly “pass” an object reference, so the API can be designed to be cleaner and easier to reuse. As usage patterns become more complex, passing context objects explicitly can clutter up your code. Using this does not

Reference

Github.com/mqyqingfeng…

ECMAScript types are divided into language types and specification types. ECMAScript language types are something developers can manipulate directly using ECMAScript. Undefined, Null, Boolean, String, Number, and Object. Canonical types are equivalent to meta-values, which are used to describe ECMAScript language structures and ECMAScript language types algorithmatically. Specification types include: Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, and Environment Record. Don’t understand? It doesn’t matter, just know that there are other types in the ECMAScript specification that only exist in the specification and are used to describe the underlying behavioral logic of the language.

The Reference type is used to explain operations such as DELETE, Typeof, and assignment

Reference is a Specification Type, an abstract Type that exists only in the Specification. They exist to better describe the underlying behavioral logic of the language, but they do not exist in actual JS code.

composition

This paragraph describes the composition of Reference, which consists of three parts:

  • base value
  • referenced name
  • strict reference

But what are these?

We simply understand:

Base value is the object where the property is or EnvironmentRecord, The value can only be undefined, an Object, a Boolean, a String, a Number, or an environment record.

Referenced name is the name of an attribute.

var foo = 1;

// Reference is:
var fooReference = {
    base: EnvironmentRecord,
    name: 'foo'.strict: false
};
Copy the code
var foo = {
    bar: function () {
        return this; }}; foo.bar();// foo

// Reference is:
var BarReference = {
    base: foo,
    propertyName: 'bar'.strict: false
};
Copy the code



methods

  • GetBase: Returns the base value of reference.
  • IsPropertyReference: Returns true if the base value is an object.
  • GetValue: Returns a specific value



How do I determine the value of this

The function call step

  1. Make ref to explain the result of executing MemberExpression.
  2. The func for GetValue (ref).
  3. Have argList generate an internal list of argument values to interpret the results of the Arguments execution (see 11.2.4).
  4. If Type(func) is not Object, a TypeError exception is raised.
  5. If IsCallable(func) is false, a TypeError exception is raised.
  6. If Type(ref) is Reference then if IsPropertyReference(ref) is true then make thisValue GetBase(ref). Otherwise, the base value of ref is the result of an environment record entry that makes thisValue the ImplicitThisValue concrete method of calling GetBase(ref)
  7. Otherwise, if Type(ref) is not Reference. ThisValue is undefined.
  8. Returns the result of calling func’s [[Call]] built-in method, passing thisValue as this and the list argList as the argument list

MemberExpression

  • PrimaryExpression // See chapter 4 of the JavaScript Authority guide for the original expression.
  • FunctionExpression // Function definition expression
  • MemberExpression [Expression] // Attribute access Expression
  • Memberexpression. IdentifierName // Attribute access expression
  • New MemberExpression Arguments // Object creation expression

This is the left side of the method call.

function foo() {
    console.log(this)
}

foo(); / / MemberExpression is foo

function foo() {
    return function() {
        console.log(this)
    }
}

foo()(); // MemberExpression 是 foo()

var foo = {
    bar: function () {
        return this;
    }
}

foo.bar(); / / MemberExpression foo bar
Copy the code


Determine the type of ref

The first step is to calculate ref, and the seventh step is to determine whether ref is a reference type.

var value = 1;

var foo = {
  value: 2.bar: function () {
    return this.value; }}/ / sample 1
console.log(foo.bar());
/ / sample 2
console.log((foo.bar)());
/ / sample 3
console.log((foo.bar = foo.bar)());
/ / sample 4
console.log((false || foo.bar)());
/ / example 5
console.log((foo.bar, foo.bar)());
Copy the code


Foo.bar () this is property access. According to 11.2.1 Property Accessors last step:

Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

A reference type is returned: a reference of the reference type is returned with a baseValue of baseValue and a reference name of propertyNameString with strict mode tag

var Reference = {
  base: foo,
  name: 'bar'.strict: false
};
Copy the code

Then go back to [function call](function call) step 6, step 7,

  • If Type(ref) is Reference then if IsPropertyReference(ref) is true then make thisValue GetBase(ref). Otherwise, the base value of ref is the result of an environment record entry that makes thisValue the ImplicitThisValue concrete method of calling GetBase(ref)
  • Otherwise, if Type(ref) is not Reference. ThisValue is undefined.

Here, because foo is an object, IsPropertyReference(ref) is true. So the value of this is GetBase(ref) is foo.

(foo.bar)() grouping expression rules are as follows:

  1. Returns the result of executing Expression, which may be of type Reference

The result here is fo as above.

(foo.bar = foo.bar)() involves simple assignment as follows:

  1. Let lref be the result of interpreting LeftH and SideExpression.
  2. Make rref interpret the result of executing AssignmentExpression.
  3. Make rval GetValue (rref).
  4. Throws a SyntaxError if the following conditions are true:
    • Type (lref) for Reference
    • IsStrictReference (lref) is true
    • Type(GetBase(lref)) is the environment record entry
    • GetReferencedName(lref) is “eval” or “arguments”
  5. Call the PutValue (lref rval).
  6. Returns the rval.

The return value here is the third step, GetValue. This is a concrete return value. Based on the above value, we get the value of this as undefined, which is implicitly loaded as the window object in non-strict mode.


(false | | foo bar) () and (foo, bar, foo bar) () the value of the return values are to getValue. So this is going to be the same thing.

Take a look at the final result:

var value = 1;

var foo = {
  value: 2.bar: function () {
    return this.value; }}/ / sample 1
console.log(foo.bar()); / / 2
/ / sample 2
console.log((foo.bar)()); / / 2
/ / sample 3
console.log((foo.bar = foo.bar)()); / / 1
/ / sample 4
console.log((false || foo.bar)()); / / 1
/ / example 5
console.log((foo.bar, foo.bar)()); / / 1
Copy the code



Common function

function foo() {
    console.log(this)
}

foo(); 
Copy the code

This is a parsing identifier

The result of evaluating an identifier is always a value of type Reference with its referenced name component equal to the Identifier String.

Explains that the result of executing an Identifier must be an object of reference type whose reference name attribute has a value equal to the Identifier string.

So what is baseValue? The result of resolving the identifier is a GetIdentifierReference.

  1. If lex is the value null, then**
    1. Return a value of type Reference whose base value is undefined, whose referenced name is name, and whose strict mode flag is strict.
  2. Let envRec be lex’s environment record.
  3. Let exists be the result of calling the HasBinding(N) concrete method of envRec passing name as the argument N.
  4. If exists is true, then
    1. Return a value of type Reference whose base value is envRec, whose referenced name is name, and whose strict mode flag is strict.
  5. Else
    1. Let outer be the value of lex’s outer environment reference.
    2. Return the result of calling GetIdentifierReference passing outer, name, and strict as arguments.
  1. If lex is null, then:
    1. Returns an object of type reference with undefined base value, name of reference, and strict mode identifier.
  2. Make envRec the environment data for LEX.
  3. Call the HasBinding(N) concrete method of envRec with name as parameter N and set EXISTS as the result of the call.
  4. If exists is true then:
    1. Returns an object of type reference with the base value envRec, the name of the reference, and the strict schema identifier value strict.
  5. Otherwise:
    1. Make outer a reference to lex’s external environment.
    2. Call GetIdentifierReference with outer, name, and struct parameters and return the result of the call.

In this case, the window object returns:

var fooReference = {
    base: EnvironmentRecord,  // Maybe undefined
    name: 'foo'.strict: false
};
Copy the code

No matter which of the two values base has, that is not Object. According to the rules above:

  • If Type(ref) is Reference then if IsPropertyReference(ref) is true then make thisValue GetBase(ref). Otherwise, the base value of ref is the result of an environment record entry that makes thisValue the ImplicitThisValue concrete method of calling GetBase(ref)
  • Otherwise, if Type(ref) is not Reference. ThisValue is undefined.

This is the value of ImplicitThisValue. This value returns undefined. So this is undefined.

What is this

Thisbinding for execution context. This is where the function is currently called. This is the concept description. The following is just to analyze what thisBinding is in various cases through the above. This provides a more elegant way to implicitly “pass” an object reference, so the API can be designed to be cleaner and easier to reuse. As usage patterns become more complex, passing context objects explicitly can clutter up your code. Using this does not

A function call

Refer to the ordinary functions mentioned above

The call, the apply

var person = {
  name: "axuebin".age: 25
};
function say(job){
  console.log(this.name+":"+this.age+""+job);
}
say.call(person,"FE"); // axuebin:25
say.apply(person,["FE"]); // axuebin:25
Copy the code


call

Call (thisArg [, arg1 [, arg2…]]) when calling call on a func object with thisArg and optional arg1, arg2, etc. Take the following steps:

  1. If IsCallable(func) is false, a TypeError exception is raised.
  2. Make argList an empty list.
  3. If the method is called with more than one argument, each argument is inserted as the last element of argList in left-to-right order, starting with arg1.
  4. Call func’s [[Call]] internal method with thisArg as this and argList as argument list, and return the result.

The length attribute of the call method is 1.

The value of this is the value passed to thisArg.

apply

  1. If IsCallable(func) is false, a TypeError exception is raised
  2. If argArray is null or undefined
    1. Returns the result of the [[Call]] internal method that provides thisArg as this and calls func with an empty argument list.
  3. If Type(argArray) is not Object, a TypeError exception is raised.
  4. Let len be the result of calling argArray’s [[Get]] inner method with “length” as an argument.
  5. For n for ToUint32 (len).
  6. Make argList an empty list.
  7. The index is 0.
  8. Repeat as long as index < n
    1. Make indexName for ToString (index).
    2. Let nextArg be the result of calling argArray’s [[Get]] internal method with indexName as an argument.
    3. Insert nextArg into argList as the last element.
    4. Set index to index + 1.
  9. Call func’s [[Call]] internal method with thisArg as this and argList as argument list, and return the result.

The length attribute of the Apply method is 2.

Note that the thisArg value passed in outside is modified to become this. ThisArg is undefined or null when it is replaced with a global object, all other values are applied ToObject and the result is this value, this is a change introduced in version 3.

function [[call]]

The [[Call]] internal method that calls function. When calling the [[Call]] inner method of function object F with a this value and a list of arguments, do the following:

  1. Use F’s [[FormalParameters]] internal property value, parameter list args, 10.4.3 to create a new execution environment for the function code, with funcCtx as the result.
  2. Let result be FunctionBody (that is, the [[Code]] internal property of F) to explain the result of execution. If F has no [[Code]] internal attribute or FunctionBody whose value is empty, result is (normal, undefined, empty).
  3. Exit the funcCtx execution environment and restore to the previous execution environment.
  4. If result.type is a throw, result.value is thrown.
  5. Result. value is returned if result.type is return.
  6. Otherwise, result.type must be normal. Returns undefined.

10.4.3 rules for executing function code:

When the control flow enters the execution environment of the function code based on a function object F, thisArg provided by the caller, and argumentList provided by the caller, the following steps are performed:

  1. If the function code is in strict mode, set this binding to thisArg.
  2. Otherwise if thisArg is null or undefined, set this to be bound as a global object.
  3. Otherwise, if the result of Type(thisArg) is not Object, set this to ToObject(thisArg).
  4. Otherwise set this to bind to thisArg.
  5. In F [[Scope]] internal attribute to invoke NewDeclarativeEnvironment parameters, and order localEnv as the result of a call.
  6. Let the lexical environment be localEnv.
  7. Set the variable environment to localEnv.
  8. Let code be the value of the [[code]] internal property of F.
  9. Perform the define binding initialization steps using the function codes code and argumentList as described in 10.5.


bind

var person = {
  name: "axuebin".age: 25
};
function say(){
  console.log(this.name+":"+this.age);
}
var f = say.bind(person);
console.log(f());
Copy the code

ThisArg is passed in to set this.

Arrow function

Runtime Semantics: Evaluation

An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. 

Arrow functions are not bound to this, arguments, super(ES6), or new.target(ES6), which follow the closed lexical context that contains the current arrow function.

function foo() {
   setTimeout( () = > {
      console.log("args:".arguments);
   },100);
}

foo( 2.4.6.8 );
// args: [2, 4, 6, 8]
Copy the code


Statement definition correction

  1. The arrow function this is bound to the parent function foo, which is not. Because the arrow function doesn’t do any binding inside.
  2. Local variable this

The following example illustrates the local variable this

function foo() {
   var self = this;
   setTimeout(function() {
      console.log("id:" + this.id);
   },100);
}

foo.call( { id: 42});// id:undefined
Copy the code

Why undefined? Because setTimeout is a property of a Windows object. This points to the window.

Then I modified it:

function foo() {
   var self = this;
   setTimeout(function() {
      console.log("id:" + self.id);
   },100);
}

foo.call( { id: 42});// id:42
Copy the code

This is because the execution of self to function is a closed function environment that outer points to that contains the current function. This has nothing to do with this. The js-scope chain js-execution context

Mention it here: “Because this is local anyway”. This is determined by the this binding rule that the function executes.

As a method of an object

See also: foo. Bar function call parsing above

As a constructor

[[construct]]

  1. Make obJ a newly created ECMAScript native object.
  2. Set all internal methods for OBJ as per 8.12.
  3. Set obj’s [[Class]] internal method to “Object”.
  4. Set the [[Extensible]] internal method of OBJ to true.
  5. Let proto call the value of the [[Get]] internal property of F with the parameter “prototype”.
  6. If Type(proto) is Object, set obj’s [[Prototype]] internal property to proto.
  7. If Type(proto) is not Object, set obj’s [[Prototype]] internal property to the standard built-in Object Prototype Object described in 15.2.4.
  8. Call [[Construct]] with args as the argument list. Call F with [[Call]] as the internal property.
  9. If Type(result) is Object, result is returned.
  10. Returns the obj

We can see that this is bound to the currently created object.

As a DOM event handler

This refers to the element that triggered the event, which is the DOM node to which the initial event handler is bound.

var ele = document.getElementById("id");
ele.addEventListener("click".function(e){
  console.log(this);
  console.log(this === e.target); // true
})
Copy the code

It might not be easy to know here. From the literature:

The event listener is appended to target’s event listener list 

interface EventTarget {
  constructor();

  undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {});
  undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {});
  boolean dispatchEvent(Event event);
};

callback interface EventListener {
  undefined handleEvent(Event event);
};

dictionary EventListenerOptions {
  boolean capture = false;
};

dictionary AddEventListenerOptions : EventListenerOptions {
  boolean passive = false;
  boolean once = false;
};
Copy the code

The EventTarget attribute is a first-level attribute, so the event. callback execution of this refers to the EventTarget. Of course the concrete implementation is not seen

Button.onclick = foo That’s a good way to understand it.

This priority

Now we can determine which rule is applied to a function at a particular call location based on priority. It can be judged in the following order:

  1. Is the function called in new (new binding)? If so, this binds to the newly created object.
var bar = new foo()
Copy the code
  1. Is the function called by call, apply (explicit binding), or hard binding? If so, this binds to the specified object.
var bar = foo.call(obj2)
Copy the code
  1. Is the function called in a context object (implicitly bound)? If so, this binds to that context object.
var bar = obj1.foo()
Copy the code
  1. If neither, use the default binding. If in strict mode, it is bound to undefined, otherwise it is bound to global objects.
var bar = foo()
Copy the code

Conclusion: New calls > Call, apply, bind calls > Function calls on objects > normal function calls

/ / source example: if the wind is https://juejin.cn/post/6844903746984476686#heading-12
var name = 'window';
var person = {
    name: 'person',}var doSth = function(){
    console.log(this.name);
    return function(){
        console.log('return:'.this.name); }}var Student = {
    name: 'rod'.doSth: doSth,
}
// Plain function call
doSth(); // window
// A function call on an object
Student.doSth(); // 'rod'
// call and apply
Student.doSth.call(person); // 'person'
new Student.doSth.call(person); // Uncaught TypeError: Student.doSth.call is not a constructor
Copy the code

Let me just say this last line because. The operator has precedence over new. So here is student.dosth. Call as the constructor for new. But because the call method is executed, the funC [[call]] method is executed. To drop new, call the [[Construct]] property

yanhaijing.com/es5/#323

The call of the call

When calling the call method on a func object with thisArg and optional arg1, arg2, etc., do the following:

  1. If IsCallable(func) is false, a TypeError exception is raised.
  2. Make argList an empty list.
  3. If the method is called with more than one argument, each argument is inserted as the last element of argList in left-to-right order, starting with arg1.
  4. Call func’s [[Call]] internal method with thisArg as this and argList as argument list, and return the result.


With reference to:

www.cnblogs.com/vajoy/p/490… Github.com/axuebin/art… Github.com/mqyqingfeng… Es5. Making. IO / # x13.2.1 www.ecma-international.org/ecma-262/6…. Juejin. Cn/post / 684490…