资讯专栏INFORMATION COLUMN

this总结【1】—— this概览

MyFaith / 674人阅读

摘要:是什么这个单词是一个代词,所以应该是指代某些东西搞清楚的关键之处,就是要搞清楚指代了什么那么到底指代了什么呢就像你平时指着一个苹果说指着一个香蕉说同样,也会因为情况的不同而不同在中按照常规理解,的值是什么取决于函数如何被调用然而,的值是什么

1. this是什么

this这个单词是一个代词,所以this应该是 指代某些东西
搞清楚this的关键之处,就是要搞清楚this指代了什么

那么this到底指代了什么呢?
就像你平时
指着一个苹果说 this is an apple
指着一个香蕉说 this is a banana

同样,this也会因为情况的不同而不同

在JavaScript中
按照常规理解,this的值是什么取决于函数如何被调用
然而,this的值是什么完全取决于对应函数被call时传入的第一个参数,而这一般是由js提前就预置好的

2. 函数如何被调用 2.1 常规理解
注意:这种方法可以判断一般情况下的this是什么

判断this值就看函数是怎么被调用的[函数有全局调用方法调用]

this指向调用它的距离最近的那一个

    // 例子
    function fn() {
        console.log(this)
    }

    let obj = {
        a: "",
        fn: fn
    }

    // 场景一
    fn() // window[浏览器] or global[node]

    // 场景二
    obj.fn() // obj

    // 场景一:全局调用
    // 场景二:方法调用

function VS method

function xx(){...} 是function

method某个对象下面的方法 如 obj = {fn:function(){...}} obj.fn() 叫做方法[method]

更详细的说明请看深入浅出面向对象和原型【概念篇1】
    // test1
    function fn() {
        console.log(this)
    }

    let obj1 = {
        wrapper: {
            a: "a",
            fn: fn
        }
    }
    obj1.wrapper.fn() // ?
    // fn()是被当做wrapper的方法被调用的,所以this是wrapper
    // this指向调用它的距离最近的那一个

    // test2
    function executeCallback(cb) {
        cb()
    }

    executeCallback(obj1.wrapper.fn)
    // this是全局变量
    // 因为executeCallback函数是把cb当成全局函数进行调用的
    // 不像是obj.cb(),若是obj.cb()就是方法调用了
按照常规理解已经可以解决大部分的面试、笔试题了,但如果想究this之根本,还需要通过call
2.2 用call理解
注意:通过对call的初步理解,你可以知道this的值为什么是这样的,但这种思维不方便你猜this

首先,我们要清楚this在函数中的位置

    function fn1([this], parameter) {
        // this就是隐藏的第一个参数,而且永远是第一个参数
        console.log(this)
    }

其次,我们要知道call的语法

    fun.call(thisArg, arg1, arg2, ...)

OK,现在我们要知道你在使用call的时候
call传入的第一个参数可以指定(改变)fn1的第一个参数,也就是隐藏的this

所以,为什么直接全局调用fn1时,打印出来的是window呢?
因为js已经帮你call了

    // 你写的代码
    fn1()

    // 在你写上面代码的时候,js帮你写了一行你看不到的代码
    fn1().call(undefined)

    // 你可能回问:这样打出来的值应该是undefined呀
    // 但浏览器有个机制
    // 如果你传的 thisArg 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)
我们重新来看待一下全局调用和方法调用,以及js是如何用call指定this的
    // 例子
    function fn() {
        console.log(this)
    }

    let obj = {
        a: "",
        fn: fn
    }

    // 场景一
    fn() // window[浏览器] or global[node]
    // js帮你写的代码
    fn().call(undefined)

    // 场景二
    obj.fn() // obj
    // js帮你写的代码
    obj.fn().call(obj)
小测试(小陷阱)
    let module = {
        x: 42,
        getX: function () {
            return this.x;
        }
    }

    let retrieveX = module.getX;
    console.log(retrieveX()); // undefined
    console.log(module.getX()) // 42
2.3 严格模式下的this
严格模式下只需要注意一点就行,其它情况下与非严格模式相同

全局作用域里函数中的this是undefined

function test() {
    "use strict"
    console.log(this) 
}
test() // undefined

所以,在使用构造函数时如果忘了加new,this不再指向全局对象,而是报错,因为这就是函数的全局调用

let People = function (name) {
    "use strict"
    this.name = name
}
People() // Cannot set property "name" of undefined
3.几种复杂情况中的this 3.1 数组中的this
function fn() {
    console.log(this)
}

arr[fn, fn2, fn3]

arr[0]() // ??

// answer:arr

// 解析
// 数组也是对象的一种
// arr[0]() 可以看做 arr.0().call(arr)
3.2 嵌套函数中的this
// 例子一
function fn0() {
    function fn() {
        console.log(this);
    }

    fn();
}

fn0(); // fn中this是全局变量

// 例子二
let a = {
    b: function () {
        console.log(this) // {b:fn}
        function xx() {
            console.log(this) // window
        }
        xx()
    }
}
a.b()
3.3 setTimeout、setInterval中的this
document.addEventListener("click", function (e) {
    console.log(this);
    setTimeout(function () {
        console.log(this); // 这里的this是全局变量
    }, 200);
}, false);
3.4 事件中的this
document.querySelector("div").addEventListener("click",function (e) {
    console.log(this) // 
}) // 事件里的this指向的是触发事件的DOM节点
3.5 使用new时的this

请看深入浅出面向对象和原型【番外篇——重新认识new】

4.总结

如果几种复杂情况下的this你看完了,你应该会有疑惑
为啥我明白了全局调用和方法调用,但this的值仍然和我推断的不一样呢?

我说过了,this的值是call的第一个参数,js已经给很多this进行call了

所以,总结一下

this的值是什么,你别猜,很可能会和你想的不一样

console出来或者去看文档、看源码才是最稳妥的选择

如果你非要猜,就套用一下我这篇博客写到的这几种情况

如果你怕猜错,又要用到this,很简单,直接用bind去强制指定this

关于call/apply/bind 请看this总结【2】—— call/apply和bind
5.参考

this 的值到底是什么?一次说清楚

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92865.html

相关文章

  • this总结【2】—— call/apply和bind

    摘要:和概览我们要将归为一类,单独归为一类三者的共同点是都可以指定和都是绑定在的原型上的,所以的实例都可以调用这三个方法至于为什么,看完这篇文章你就懂了如果你不懂什么是实例的话,请移步深入浅出面向对象和原型概念篇深入浅出面向对象和原型概念篇第一个 1.call/apply和bind概览 我们要将call/apply归为一类,bind单独归为一类 三者的共同点是都可以指定this call/...

    wudengzan 评论0 收藏0
  • Vue动态加载异步组件

    摘要:目前采用动态加载异步组件的方式来实现小组件之间的通信。内容使用过的都应该知道的动态加载组件通过来绑定需要加载的组件。总结本篇主要借助的动态组件和打包单文件来实现动态加载异步组件,通过的事件总线挂载在上来实现平级组件之间的通信。 背景: 目前我们项目都是按组件划分的,然后各个组件之间封装成产品。目前都是采用iframe直接嵌套页面。项目中我们还是会碰到一些通用的组件跟业务之间有通信,这种...

    awesome23 评论0 收藏0
  • 基于以太坊的视频直播平台 Livepeer白皮书中文概览

    摘要:说明的视频片段分发现在没做出什么成果作者还提了一句,协议有望成为直播内容的传播协议。仿佛也没能掩饰住不知道怎么分发视频片段的尴尬说了这么多,看了代码发现视频片段还是通过分发总结最终将建立一个可扩展的,即用即付的直播网络 Background Livepeer旨在构建带有激励机制的视频直播分布式网络 Blockchain 以太坊 智能合约和交易基于Ethereum以太坊网络 DP...

    Eric 评论0 收藏0
  • ES6指北【2】—— 箭头函数

    摘要:箭头函数基本语法函数语法具名函数匿名函数三句话第一句话声明第二句话声明匿名函数第三句话把匿名函数赋值给箭头函数语法特点只能做赋值,不能做声明第一种写法完全写法不省略参数个数,不省略函数体花括号参数个数函数体内语句个数第二种写法省略参数括号参 1.箭头函数基本语法 1.1 ES3 函数语法 // 具名函数 function xxx(arg1, arg2) { console.lo...

    DobbyKim 评论0 收藏0

发表评论

0条评论

MyFaith

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<