JS this总结

  • 概念:
    什么是this,即函数执行上下文。this是在函数执行的时候才被确定的,而不是函数定义的时候,这就会出现一个问题就是this是会根据使用环境发生改变的。总结如下:
  • Object中的this:
let
    demo = {
        name: "dqhan",
        action: function () {
            console.log(this); //{name: "dqhan", action: ƒ}
            (function () {
                console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
                // "use strict";
                // console.log(this);//undefined
            })();
        }
    };
demo.action();

demo对象调用action,action中的this指向的就是demo,action内部的自执行函数this则指向的是window,严格模式下为undefined。可以写个深层次的demo来看下会不会影响this的指向。

let
    demo = {
        name: "dqhan",
        action: function () {
            console.log(this) //{name: "dqhan", action: ƒ, innerDemo: {…}}
        },
        innerDemo: {
            name: 'innerDqhan',
            action: function () {
                console.log(this)//{name: "innerDqhan", action: ƒ}
            }
        }
    };
demo.action();
demo.innerDemo.action();

事实证明不会影响this的指向,这种方式的定义以及调用不参与原型链,不涉及this指向改变的问题。

  • 函数中的this:

function demo() {
    console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
    // "use strict"
    // console.log(this);//undefined

}
demo();
foo = 'outer'
function demo() {
    this.foo = 'inner';
    // "use strict";
    // this.foo = 'inner';//error
}
console.log(foo);//outer
demo();
console.log(foo);//inner

foo在不加var,let(ES6)下自动挂载window下,调用demo后在函数内部将foo重新赋值。严格开发下this为undefined报错。

  • 构造函数中的this:
function Demo() {
    this.name = "dqhan";
    this.action = function () {
        console.log(this)//Demo {name: "dqhan", action: ƒ}
    };
};

let
    demo = new Demo();
demo.action();
console.log(demo.name);//dqhan

调用demo内的action,action中的this指向构造函数的实例化对象,原因是什么呢?这里需要了解一下let demo = new demo();到底发生了什么。

//action1
let
    demo = new Demo();
//action2
let
    demo = {};
demo.__proto__ = Demo.prototype;
Demo.call(demo);

js中new一个实例化对象的过程等价于action2的代码,最后一步通过call方法(apply,bind)将demo对象中的this传递到了Demo构造函数中,从而将构造函数中没有定义在原型中的属性与方法都定义到了demo 对象中,这就是为什么构造函数中的this会是实例化对象的原因。另外我们可以将属性或者方法都定义在原型中。

function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function () {
    console.log(this)//Demo {name: "dqhan", action: ƒ}
};

let
    demo = new Demo();
console.log(demo.name);//dqhan

我们都清楚,构造函数类似于一个简单工厂模式,我们可以通过一个构造函数生成很多其他对象,我们将属性或者方法定义在原型中,这样可以达到原型共享的目的。

function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function () {
    console.log(this)//Demo {name: "dqhan", action: ƒ}
};
let
    demo = new Demo(),
    demo1 = new Demo(),
    demo2 = new Demo();
demo.__proto__ === demo1.__proto__;//true
demo1.__proto__ === demo2.__proto__;//true

当对象非常多的是时候,可以节约内存。

  • 当函数内嵌套匿名函数
function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function () {
    console.log(this);//Demo {name: "dqhan", action: ƒ}
    (function () {
        console.log(this);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
        // "use strict";
        // console.log(this)//undefined
    })();
};
let
    demo = new Demo();
demo.action();

定义在构造函数内的方法在传递的时候,实例化对象不会跟着一起传过去

function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function () {
    console.log(this);
    
};
function foo(method){
    method();
};
let
    demo = new Demo();
foo(demo.action);//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function (method) {
    console.log(this);
    method();
};
Demo.prototype.actionCallBack = function () {
    console.log(this);
}
let
    demo = new Demo();
demo.action(demo.actionCallBack);
//Demo {name: "dqhan"}
//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

这两种情况都是将实例化对象中的方法当成参数进行传递。但是在执行函数中,this的上下文已经发生改变。解决方式可以通过bind,apply,call等改变上下文的方式。

function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function (method) {
    console.log(this);
    method()
};
Demo.prototype.actionCallBack = function () {
    console.log(this);
}
let
    demo = new Demo();
demo.action(demo.actionCallBack.bind(demo));
// Demo {name: "dqhan"}
// Demo {name: "dqhan"}
function Demo() {
    this.name = "dqhan";
};
Demo.prototype.action = function () {
    console.log(this);
    (function () {
        console.log(this);
    }).apply(this);
};
let
    demo = new Demo();
demo.action();
// Demo {name: "dqhan"}
// Demo {name: "dqhan"}

setTimeout中的延迟函数中this

let
    obj = {
        timerAction: function () {
            console.log(this);
        }
    };
function foo(method) {
    method();
};
obj.timerAction();
foo(obj.timerAction);
setTimeout(obj.timerAction, 0);
// {timerAction: ƒ}
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

之前看过一篇关于setTimeout使用时延迟函数自动挂载window上,所以this指向发生改变。今天总结了一下,发现这种方式个人觉得可以理解成,以函数当做参数进行传递this都是传递不过去的。如果简单的写一个函数,那么问题就更不存在了,匿名函数本身就是挂载window下,没有争议了。

  • 匿名函数
   retrieveData(callback) {
        fetchData(data).then(function (res) {
            console.log(this);
            res && callback.call(self, res);
        }).catch(e => {
            console.log(e)
        })
    };

输出结果:window(严格开发模式:undefined)
这里在我使用ES6的时候发现个猫腻

    retrieveData(callback) {
        fetchData(data).then(res => {
            console.log(this);
            res && callback.call(self, res);
        }).catch(e => {
            console.log(e)
        })
    };

上面输出的this是该对象的调用者,并不是我们以为的window(严格开发模式undefined)这里需要mark下,我还没有查具体箭头函数与正常函数的有多少区别,回头单独一篇文章总结。
以后会持续更新总结,如果有理解不到位欢迎纠正,蟹蟹ヾ(◍°∇°◍)ノ゙

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值