JavaScript in this-You don't know the JavaScript roll up reading notes (iii)

Source: Internet
Author: User

What is this?

This is bound at run time, not at the time of writing, and its context depends on the various conditions when the function is called. The binding of this and the position of the function declaration have no relation, only depends on how the function is called. When a function is called, an activity record is created (sometimes called an execution context). This record contains information about where the function was called (the call stack), the calling method of the function, the parameters passed in, and so on. This is one of the attributes of the record, which is used during the execution of the function.

Call the location with the call stack:

The call location is where the function is called in the code (not the declared location).

Let's take a look at what the call stack is and where it is called:

function baz() {    // 当前调用栈是:baz    // 因此,当前调用位置是全局作用域    console.log( "baz" );    bar(); // <-- bar 的调用位置}function bar() {    // 当前调用栈是baz -> bar    // 因此,当前调用位置在baz 中    console.log( "bar" );    foo(); // <-- foo 的调用位置}function foo() {    // 当前调用栈是baz -> bar -> foo    // 因此,当前调用位置在bar 中    console.log( "foo" );}baz(); // <-- baz 的调用位置
This binding rule 1. Default bindings:
function foo() {    console.log( this.a );}var a = 2;foo(); // 2

In the code above, the default binding for this is applied to the function call, so this is a pointer to the global object (in non-strict mode).

So how do we know that the default bindings are applied here? You can see how foo () is called by analyzing the call location. In Code, foo () is called directly using a function reference without any adornments, so you can only use the default binding and you cannot apply another rule.

If you use strict mode, the global object will not be able to use the default binding, so this strict binds to undefined:

function foo() {    "use strict";    console.log( this.a );}var a = 2;foo(); // TypeError: this is undefined

Here is a subtle but very important detail, although the binding rule of this is entirely dependent on the call location, but only if Foo () is running under non-strict mode, the default binding can bind to the global object, regardless of where in strict mode foo () is called:

function foo() {    console.log( this.a );}var a = 2;(function(){    "use strict";    foo(); // 2})();
2. Implicit binding:
function foo() {    console.log( this.a );}var obj = {    a: 2,    foo: foo};obj.foo(); // 2

When Foo () is called, its foothold points to the Obj object. When a function refers to a context object, the implicit binding rule binds this to the context object in the function call. Because this is bound to obj when Foo () is called, THIS.A and obj.a are the same.

The object property reference chain has only the topmost or last layer that affects the call location

Implicit loss

One of the most common problems with this binding is that a function that is implicitly bound loses the bound object, which means it applies a default binding, which binds this to a global object or undefined, depending on whether it is a strict pattern.

function foo() {    console.log( this.a );}var obj = {    a: 2,    foo: foo};var bar = obj.foo; // 函数别名!var a = "oops, global"; // a 是全局对象的属性bar(); // "oops, global"

Although bar is a reference to Obj.foo, in fact it refers to the Foo function itself, so bar () at this point is actually a function call without any adornments, so the default binding is applied.

3. Explicit binding:

As we have just seen, in parsing implicit binding, we must include a property in an object that points to a function, and indirectly reference the function by this property to bind this indirectly (implicitly) to the object. So what if we don't want to have a function reference inside an object and want to force a call to a function on an object?

The "All" functions in JavaScript have some useful features (which are related to their [[prototypes]]), which we'll describe in detail later, and can be used to solve this problem. Specifically, you can use the call (..) of the function and the Apply (..) method. Strictly speaking, JavaScript's hosting environment sometimes provides some very special functions that do not have these two methods. But such functions are rare, and most of the functions provided by JavaScript and all the functions you create yourself can use the call (..) and apply (..) methods.

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

With Foo.call (..), we can force the this to be bound to obj when we call foo.

explicit binding still does not solve the lost binding problem we put forward , which can be solved by the following methods:

Hard binding

    function foo() {        console.log( this.a );    }    var obj = {        a:2    };    var bar = function() {        foo.call( obj );    };    bar(); // 2    setTimeout( bar, 100 ); // 2    // 硬绑定的bar 不可能再修改它的this    bar.call( window ); // 2
4. New binding:

Using new to invoke a function, or when a constructor call occurs, the following actions are performed automatically.

    1. Create (or construct) an entirely new object.

    2. This new object will be executed [[prototype]] connected.
    3. This new object is bound to this of the function call.

    4. If the function does not return another object, the function call in the new expression automatically returns the new object.

      function foo(a) {    this.a = a;}var bar = new foo(2);console.log( bar.a ); // 2
Priority: New Binding > Explicit binding > Implicit binding judgment this:
    1. Is the function called in new (new binding)? If so, this binds to the newly created object.

      var bar = new Foo ()

    2. is the function called by call, apply (explicit binding), or hard bind? If so, this binds to the specified object.

      var bar = Foo.call (OBJ2)

    3. is the function called (implicitly bound) in a context object? If so, this binds to the context object.

      var bar = Obj1.foo ()

    4. If not, use the default bindings. If in strict mode, bind to undefined, otherwise bind to the global object.

      var bar = foo ()

Binding exception 1. The This is ignored

Passing null or undefined as this binding object to call, apply, or bind, these values are ignored at invocation and are actually applied by default binding rules.

function foo() {    console.log( this.a );}var a = 2;foo.call( null ); // 2
More secure ths

A "more secure" approach is to pass in a special object that binds this to the object without any side effects on your program. Just like the network (and the army), we can create a "DMZ" (demilitarized zone, demilitarized zone) object-it's an empty non-commissioned object.

function foo(a,b) {    console.log( "a:" + a + ", b:" + b );}// 我们的DMZ 空对象var ? = Object.create( null ); //此处的?不会创建Object.prototype 这个委托,所以它比{}“更空”// 把数组展开成参数foo.apply( ?, [2, 3] ); // a:2, b:3// 使用bind(..) 进行柯里化var bar = foo.bind( ?, 2 );bar( 3 ); // a:2, b:3
2. Indirect references

Another note is that it is possible (intentionally or unintentionally) to create an "indirect reference" to a function, in which case the call to this function applies the default binding rule.

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
3. Soft binding (not discussed here) this lexical (this of arrow functions)
function foo() {    // 返回一个箭头函数    return (a) => {        //this 继承自foo()        console.log( this.a );    };}var obj1 = {    a:2};var obj2 = {    a:3};var bar = foo.call( obj1 );bar.call( obj2 ); // 2, 不是3 !

An arrow function created internally by Foo () captures this of the call Foo (). Because the This of the Foo () binding to Obj1,bar (the reference arrow function) is also bound to obj1, the binding of the arrow function cannot be modified. (New is not!) )

JavaScript in this-You don't know the JavaScript roll up reading notes (iii)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.