this总结,mark一下:
Object中的this:
Object方法中的this,指向的就是该对象,即谁调用this就指向谁,与C#等服务器语言的思想比较一致。
1 let 2 demo = { 3 name: "dqhan", 4 action: function () { 5 console.log(this); //{name: "dqhan", action: ƒ} 6 (function () { 7 console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 8 // "use strict"; 9 // console.log(this);//undefined 10 })(); 11 } 12 }; 13 demo.action();
demo对象调用action,action中的this指向的就是demo,action内部的自执行函数this则指向的是window,严格模式下为undefined。可以写个深层次的demo来看下会不会影响this的指向
1 let 2 demo = { 3 name: "dqhan", 4 action: function () { 5 console.log(this) //{name: "dqhan", action: ƒ, innerDemo: {…}} 6 }, 7 innerDemo: { 8 name: 'innerDqhan', 9 action: function () { 10 console.log(this)//{name: "innerDqhan", action: ƒ} 11 } 12 } 13 }; 14 demo.action(); 15 demo.innerDemo.action();
事实证明不会影响this的指向,这种方式的定义以及调用不参与原型链,不涉及this指向改变的问题。
函数中的this:
匿名函数中,函数体内的this指向为window,严格模式下为undefined。
1 function demo(){ 2 console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 3 // "use strict" 4 // console.log(this);//undefined 5 } 6 demo();
1 foo = 'outer' 2 function demo() { 3 this.foo = 'inner'; 4 // "use strict"; 5 // this.foo = 'inner';//error 6 } 7 console.log(foo);//outer 8 demo(); 9 console.log(foo);//inner
foo在不加var,let(ES6)下自动挂载window下,调用demo后在函数内部将foo重新赋值。严格开发下this为undefined报错。
构造函数中的this:
提到this常常想到的是构造函数,写个简单的demo如下
1 function Demo() { 2 this.name = "dqhan"; 3 this.action = function () { 4 console.log(this)//Demo {name: "dqhan", action: ƒ} 5 }; 6 }; 7 8 let 9 demo = new Demo(); 10 demo.action(); 11 console.log(demo.name);//dqhan
调用demo内的action,action中的this指向构造函数的实例化对象,原因是什么呢?这里需要了解一下let demo = new demo();到底发生了什么。
1 //action1 2 let 3 demo = new Demo(); 4 //action2 5 let 6 demo = {}; 7 demo.__proto__ = Demo.prototype; 8 Demo.call(demo);
js中new一个实例化对象的过程等价于action2的代码,最后一步通过call方法(apply,bind)将demo对象中的this传递到了Demo构造函数中,从而将构造函数中没有定义在原型中的属性与方法都定义到了demo 对象中,这就是为什么构造函数中的this会是实例化对象的原因。另外我们可以将属性或者方法都定义在原型中
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function () { 5 console.log(this)//Demo {name: "dqhan", action: ƒ} 6 }; 7 8 let 9 demo = new Demo(); 10 console.log(demo.name);//dqhan
我们都清楚,构造函数类似于一个简单工厂模式,我们可以通过一个构造函数生成很多其他对象,我们将属性或者方法定义在原型中,这样可以达到原型共享的目的。
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function () { 5 console.log(this)//Demo {name: "dqhan", action: ƒ} 6 }; 7 let 8 demo = new Demo(), 9 demo1 = new Demo(), 10 demo2 = new Demo(); 11 demo.__proto__ === demo1.__proto__;//true 12 demo1.__proto__ === demo2.__proto__;//true
当对象非常多的是时候,可以节约内存。
当函数内嵌套匿名函数
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function () { 5 console.log(this);//Demo {name: "dqhan", action: ƒ} 6 (function () { 7 console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 8 // "use strict"; 9 // console.log(this)//undefined 10 })(); 11 }; 12 let 13 demo = new Demo(); 14 demo.action();
定义在构造函数内的方法在传递的时候,实例化对象不会跟着一起传过去
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function () { 5 console.log(this); 6 7 }; 8 function foo(method){ 9 method(); 10 }; 11 let 12 demo = new Demo(); 13 foo(demo.action);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function (method) { 5 console.log(this); 6 method(); 7 }; 8 Demo.prototype.actionCallBack = function () { 9 console.log(this); 10 } 11 let 12 demo = new Demo(); 13 demo.action(demo.actionCallBack); 14 //Demo {name: "dqhan"} 15 //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
这两种情况都是将实例化对象中的方法当成参数进行传递。但是在执行函数中,this的上下文已经发生改变。解决方式可以通过bind,apply,call等改变上下文的方式。
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function (method) { 5 console.log(this); 6 method() 7 }; 8 Demo.prototype.actionCallBack = function () { 9 console.log(this); 10 } 11 let 12 demo = new Demo(); 13 demo.action(demo.actionCallBack.bind(demo)); 14 // Demo {name: "dqhan"} 15 // Demo {name: "dqhan"}
1 function Demo() { 2 this.name = "dqhan"; 3 }; 4 Demo.prototype.action = function () { 5 console.log(this); 6 (function () { 7 console.log(this); 8 }).apply(this); 9 }; 10 let 11 demo = new Demo(); 12 demo.action(); 13 // Demo {name: "dqhan"} 14 // Demo {name: "dqhan"}
setTimeout中的延迟函数中this
1 let 2 obj = { 3 timerAction: function () { 4 console.log(this); 5 } 6 }; 7 function foo(method) { 8 method(); 9 }; 10 obj.timerAction(); 11 foo(obj.timerAction); 12 setTimeout(obj.timerAction, 0); 13 // {timerAction: ƒ} 14 // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 15 // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
之前看过一篇关于setTimeout使用时延迟函数自动挂载window上。今天总结了一下,发现这种方式个人觉得可以理解成,以函数当做参数进行传递this都是传递不过去的。如果简单的写一个函数,那么问题就更不存在了,匿名函数本身就是挂载window下,没有争议了。