this总结

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下,没有争议了。

原文地址:https://www.cnblogs.com/moran1992/p/8515711.html