书说---this
This是什么
A书:一种机制,提供优雅的方式隐式传递对象的引用。
B书:this总是指向一个对象
C书:this是调用上下文(即对象)
this是传递对象的引用,各书只是用不同方式去表达出来
This的绑定
A书:与函数的声明和位置无关,取决于函数的调用方式
B书:不是在函数声明时的环境,是动态绑定的--在运行时基于函数的执行环境
C书:函数的四种调用机制的不同,就能判断每种调用类型的this
this的指向:不是根据词法作用域,是根据函数的调用方式,才决定指向谁!
清楚函数的调用方式,你还会被this骗吗
作为对象的方法调用
1 //当函数作为对象的方法被调用时,this 指向该对象: 2 var obj = { 3 a: 1, 4 getA: function(){ 5 alert ( this === obj ); // 输出:true 6 alert ( this.a ); // 输出: 1 7 } 8 }; 9 obj.getA();
作为函数调用
1 window.name = 'globalName'; 2 var getName = function(){ 3 return this.name; 4 }; 5 console.log( getName() ); // 输出:globalName
顶级对象默认是window,严格模式默认undefined。(我理解:所以函数调用可以理解作为为window对象的方法调用)
作为构造器调用
1 //构造器调用 2 var MyClass = function(){ 3 this.name = 'sven'; 4 }; 5 6 var obj = new MyClass(); 7 alert ( obj.name ); // 输出:sven
call和apply调用
1 //方法的借用,apply/call方法接收第一个参数就是this的指向 2 var obj1 = { 3 name: 'sven', 4 getName: function(){ 5 return this.name; 6 } 7 }; 8 var obj2 = { 9 name: 'anne' 10 }; 11 console.log( obj1.getName() ); // 输出: sven 12 console.log( obj1.getName.call( obj2 ) ); // 输出:anne
绑定的规则
显式绑定:函数new、call和apply的调用
隐式绑定:作为对象方法调用,作为函数调用
A书:优先级---new > call/apply > 对象方法 > 普通函数
call/apply > 对象方法
1 function foo() { 2 console.log( this.a ); 3 } 4 var obj1 = { 5 a: 2, 6 foo: foo 7 }; 8 var obj2 = { 9 a: 3, 10 foo: foo 11 }; 12 obj1.foo(); // 2 13 obj2.foo(); // 3 14 obj1.foo.call( obj2 ); // 3 15 obj2.foo.call( obj1 ); // 2
总结:看函数的调用,才是this指向的关键
在隐式下,调用方法属于那个对象,this就指向那个对象
this的”丢失“
经常被this搞混乱是:函数作为对象调用还是作为函数调用
因为在属性的调用、变量的赋值间切换,由原来的对象调用-变-函数调用
对象属性引用链(多个对象调用):this指向上一级
1 function foo() { 2 console.log( this.a ); 3 } 4 var obj2 = { 5 a: 42, 6 foo: foo 7 }; 8 var obj1 = { 9 a: 2, 10 obj2: obj2 11 }; 12 obj1.obj2.foo(); //42
赋值的是目标函数的引用:默认绑定顶级对象
1 function foo() { 2 console.log( this.a ); 3 } 4 var a = 2; 5 var o = { a: 3, foo: foo }; 6 var p = { a: 4 }; 7 o.foo(); // 3 8 (p.foo = o.foo)(); // 2 9 //赋值表达式p.foo = o.foo 的返回值是目标函数的引用,换句话就是调用foo()
你只是知道this,不代表你this都做得对。当this与其他一起使用,就不只有this的规则还有其他规则
注意:纸上得来终觉浅,终知此事要躬行
只有实践过的知识才最深刻。
ABC书:《你不知道的js》上、《js设计模式与开发实践》、《js忍者秘籍》