JS简记-this

this的绑定和函数声明的位置没有任何关系(这是与词法作用域最大的不同),取决于函数的调用方式,函数不同的调用方式,决定了函数内this的绑定对象。

函数有4种不同的调用方式:

function foo(){
    //...
}
foo()//1
var o = Object.create(null);
o.foo = foo;
o.foo();//2
foo.call(window)//3,或者foo.apply(window)
new foo()//4

 第一种调用foo()会进行默认绑定,即foo中的this会绑定到全局对象(window)上。

function foo(){
    console.log(this.a);
}
var a = 1;//全局作用域声明的变量,会自动成为全局对象的属性
foo();//1

如果使用“use strict”则会绑定到undefined。

function foo2(){
    "use strict"
    console.log(this.a);
}
foo2();//TypeError,如果不使用use strict则会输出undefined

第二种隐式绑定,即通过对象调用函数,使得函数内的this绑定在该对象上。

function foo(){
    console.log(this.a);
}
var o = {
    a: 1,
    foo: foo
};
o.foo();//1

第三种显式绑定,即通过call、apply将函数与指定对象进行绑定(实际上就是将this绑定到指定对象上)。

function foo(){
    console.log(this.a);
}
var o = {
    a: 1
}
foo.call(o);//or foo.apply(o)

call和apply在绑定后会立即调用,且原函数的绑定策略并没有随之改变,准确的说应该是一种显示临时绑定,bind则会新生成一个函数,该函数会绑定在指定对象上,且绑定策略无法再被修改。

function foo(b, c){
    console.log(this.a, b, c);
}
var o = {
    a: 1
}
var b = 2;
var c = 3;
var bar = foo.bind(o, b);//柯里化
bar(c);//1 2 3
bar.call(window, c);//1 2 3,this仍然绑定在o上

第四种new绑定,即通过new关键字来调用函数,调用过程会发生以下逻辑:

1. 创建(或者说构造)一个全新的对象。
2. 这个新对象会被执行[[原型]]连接。
3. 这个新对象会绑定到函数调用的this。
4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

function foo(){
    this.a = 1;
    this.b = function(){
        console.log(this.a);//如果直接输出a,则会抛ReferenceError,注意区分词法作用域和this
    };
}//函数最终没有返回对象,则在new调用时,返回new自动生成的对象。
var o = new foo();
o.b();//1

优先级:new>显式>隐式>默认

ES6中引入了一个新的this策略,“箭头函数”,将this绑定在父级this所指的对象上,这个策略有点儿类似继承,也有点儿类似词法作用域(即向父级查找,注意,不是向父级作用域查找this,this不在作用域范畴内)。

function foo(){
    return () => {
        console.log(this.a);
    };
}
var o = {a: 1};
var bar = foo.call(o);
bar();//1,虽然这里采用“默认绑定”形式来调用函数,但该函数使用“=>”,将this绑定在了声明位置的父级函数的this所指对象上。

注意,这里所有的绑定规则都是在运行时动态绑定的,即便是“箭头函数”也是通过父级函数在运行时绑定this后,“箭头函数”才会绑定this,这是完全动态的。

posted @ 2018-05-01 01:49  holoyong  阅读(94)  评论(0编辑  收藏  举报