Home  >  Article  >  Web Front-end  >  Detailed explanation of the usage of this in Javascript

Detailed explanation of the usage of this in Javascript

不言
不言forward
2019-03-23 09:36:422385browse

This article brings you a detailed explanation of the usage of this in Javascript. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Before understanding this in javascript, first understand the scope.

Scopes are divided into two types:

1. Lexical scope: The engine searches for variables with name identifiers in the current scope or nested subscopes. (How and where the engine searches. The definition process occurs during the code writing phase)
2. Dynamic scope: a scope that is dynamically determined at runtime.

The difference between lexical scope and dynamic scope is: Lexical scope is determined when writing code or definition; dynamic scope is determined at runtime.

Binding rules for this

This is bound when called, depending on the calling location of the function. It can be known from this that under normal circumstances (in non-strict mode), this will bind the object according to the context of the function call (call stack).

1. Default binding

Default binding: Default binding means that in non-strict mode and no other binding rules are used, this is called according to the function (call stack) Context to bind objects (global objects). (In strict mode, undefined is bound)

For example:

function foo() {
    console.log(this.a);
};
function bar() {
    var a = 3;
    foo();
}
var a = 2;
bar();  //调用栈在全局作用域,this绑定全局对象

运行结果为: 2
//加上"use strict"运行结果则会变成this is undefined

When the function is called here, the default binding is used, and the context of the function call (call stack) is the global scope. , so this is bound to the global object (global).

eg2:
function foo() {
    console.log(this.a)
};
var a = 2;
(function() {
    "use strict"
    foo();
})();

运行结果为: 2

Note here: For default binding, what determines the this binding object is not whether the calling location is in strict mode, but whether the function body is in strict mode (if the function body is in strict mode, this binding is undefined; Otherwise this is bound to the global object). In addition: Although it is possible to bind strict mode and non-strict mode, it is best not to mix them.

Indirect references generally apply default binding rules.

eg:
function foo() {
    console.log(this.a);
};
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo();   //3
(p.foo = o.foo)();  //2

The return value of the assignment expression p.foo = o.foo directly refers to the target function foo.

2. Implicit binding

Implicit binding: called by the context object, bound to the context object.

For example:

function foo() {
    console.log(this.a);
};
var obj = {
    a: 2,
    foo: foo
};
obj.foo();    //2
foo();        //undefined

In this code, foo() is added to the obj object as a reference attribute. When obj calls this reference attribute function, it will use the reference attribute context. this will be bound to the obj object. (Strictly speaking, this function does not belong to the obj object, but only serves as a reference attribute). Belongs to implicit binding.

The direct execution of the foo() function below is not a reference to the obj object, so the context object is the global object. Therefore this is bound to undefined. Belongs to the default binding.

Only the upper or last layer in the object reference chain plays a role in the calling location.

Note:

Implicitly bound functions will lose the bound object. At this time it will apply the default binding, binding this to the global object or undefined, depending on whether it is strict mode.
eg:

function foo() {
    console.log(this.a);
};
var obj = {
    a: 2;
    foo: foo
}
var bar = obj.foo;
var a = 'biubiubiu';
bar();

运行结果:"biubiubiu"

Analysis: It seems that bar is a reference to obj.foo. In fact, bar directly refers to function foo, which is a simple function call, so it is actually the default binding.

Parameter passing is implicit assignment, so when it is passed into the function, it will also be implicitly assigned.
eg:

function foo() {
    console.log(this.a);
};
var obj = {
    a: 2,
    foo: foo
};
function bar(fn) {
    fn();
};
var a = "biubiubiu";
bar(obj.foo);

运行结果: "biubiubiu"

Analysis: In fact, the parameters are also implicitly assigned, but the parameters are passed into the function and executed in the function. At this time, the function foo is also directly referenced, so it is also a simple function call, using the default binding.

Pass the function into the language built-in function. (Basically similar to the above situation, change the self-declared function to the language's built-in function) It is common for the callback function to lose this, and the function that calls the callback function may also modify this.

3. Explicit binding

Explicit binding: Directly bind this to the specified object. Most functions in Javascript and functions you create can use these two explicit binding methods.

1, .call()
2, .apply()
These two binding methods, the first parameter is the object bound to this. (If the parameter passed in is a primitive value (string type, Boolean type, numeric type), the primitive value will be converted into an object form (new String, new Boolean, new Number). This is called : Packing)

For example:

function foo() {
    console.log(this.a);
};
var obj = {
    a: 2
};
foo.call(obj);

运行结果: 2

However, displaying binding does not solve the problem of binding loss. At this time a new friend comes - hard binding (bind).

3. .bind() (Hard binding is a common scenario, so es5 provides the built-in method Function.prototype.bind.)
bind() will Returns a new encoding function, binds this to the specified parameters, and calls the function.

Give a chestnut:

function foo(e) {
    console.log(this.a + e);
    return this.a + e;
};
var obj = {
    a: 2
}
var bar = foo.bind(obj); //新编码函数
var b = bar(3); // 2 3
console.log(b); // 5

bind() There is also a function: will be used for Parameters other than the parameters bound to this are passed to the underlying function ( partially applies , which is a type of "currying").

这里涉及到一个概念:把null或者undefined作为this的绑定对象传入call、apply、bind,这些值在调用的时候会被忽略,实际应用默认绑定规则。
应用场景:
1、使用apply()展开一个数组,并作为参数传递给一个函数。
2、bind()对参数进行柯里化(预先设置一些参数)。

举个栗子:

function foo(a,b) {
    console.log("a:" + a + ",b:" + b);
};
//数组“展开”成参数
foo.apply(null,[2,3]);  //a:2,b:3
//bind()柯里化
var bar = foo.bind(null,2);
bar(3);  //a:2,b:3

解析:传入一个参数作为this绑定对象,如果不传则使用占位符(null),此时会使用默认绑定规则。

上面这个例子可能会产生一定的副作用,如果需要运用这种场景并且更加安全。可以创建一个空对象(可以用任意喜欢的名字来命名)。

var ∅ = Object.create(null);
//上面这个例子就可以改写为:
foo.apply(∅,[2,3]); //a:2,b:3
var bar = foo.bind(∅,2);
bar(3);  //a:2,b:3

注意:硬绑定之后不能使用隐式绑定和显式绑定对this进行修改
在这里介绍一种软绑定的方法softBind()检查this绑定到全局对象或者undefined后,绑定this到指定的默认对象。绑定后效果和硬绑定一样,但是保留隐式绑定或者显式绑定修改this的能力。

四、new绑定

Javascript中的new机制与面向类语言的完全不同。在Javascript中,构造函数只是一些使用new操作符时被调用的函数,不属于一个类,也不会实例化一个类。称为对函数的“构造调用”。

举个栗子:

function foo(a) {
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a); //2

使用new的过程会创建一个全新的对象,this会绑定这个新对象。如果函数没有返回其他对象,则new表达式函数调用会返回该新对象。(这个新对象会连接prototype)

四种绑定规则的优先级为:new>显式>隐式>默认

箭头函数

箭头函数是根据外层作用域(函数或全局)来决定this。(词法作用域取代this机制)
箭头函数this会绑定调用时的对象,且箭头函数的绑定无法修改(new也不行)。

其实可以理解为,箭头函数的this在词法上继承的是它所在的作用域(函数或全局)的this,而它继承的函数作用域的this绑定的是在该函数调用上下文对象,所以箭头函数的this间接的绑定在调用上下文对象。

简述: 箭头函数this(绑定作用域this)-- 作用域this(绑定在调用上下文对象)。

故:箭头函数this == 调用的上下文对象

举个栗子:

function foo() {
    setTimeout(function() {
        //这里的this在词法上继承自foo()
        console.log(this.a);
    },100);
};
var obj = { a: 2 };
foo.call(obj);  //2

其实这个栗子也等价于:

function foo() {
    var that = this;  //lexical capture of this
    setTimeout(function() {
        console.log(self.a)
    },100);
}
...与上面一样

所以,有两种风格:this风格(四种规则)词法作用域风格(that = this和箭头函数)可供使用。使用时尽量避免混用,否则会造成难以维护的后果。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!

The above is the detailed content of Detailed explanation of the usage of this in Javascript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete