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,这是完全动态的。