牢牢记住 this 的 五种情况

简介: 在全局上下文中,严格默认 this 为 undefined,非严格模式下,this 为 window。块级作用域的 this 是继承所在上下文中的 this 。在函数的私有上下文中,this 情况多种多样。

网络异常,图片无法展示
|


前言


在全局上下文中,严格默认 this 为 undefined,非严格模式下,this 为 window。块级作用域的 this 是继承所在上下文中的 this 。在函数的私有上下文中,this 情况多种多样。

注意 this 并不是执行上下文,EC 是执行上下文,this 是执行主体。


1. 元素的事件


给元素的某个事件行为绑定方法,事件触发,方法执行,此时方法中的 this 一般都是当前元素本身。


// DOM0
 btn.onclick = function anonymous() {
    console.log(this); // this指向元素本省
 }
 // DOM2
 btn.addEventListener('click', function anonymous() {
     console.log(this); // this指向元素本省
 }, false);
 // DOM2-ie中
 btn.attachEvent('onclick', function anonymous() {  
    // <= IE8
     console.log(this); // this -> window 特殊情况
 })


2. 普通函数执行


普通函数执行,它里面的 this 取决于执行方法前面是否有“点”,有“点”,“点”前面是谁,this 就是谁,前面没有“点”,非严格模式 this 是 window,严格模式是 undefined。


3. 构造函数执行


构造函数执行,this 执行当前类的实例。


function Func() {
    this.name = "F";
    console.log(this); //=>构造函数体中的THIS在“构造函数执行”的模式下,是当前类的一个实例,并且THIS.XXX=XXX是给当前实例设置的私有属性
}
Func.prototype.getNum = function getNum() {
    // 而原型上的方法中的THIS不一定都是实例,主要看执行的时候,“点”前面的内容
    console.log(this);
};
let f = new Func;
f.getNum();
f.__proto__.getNum();
Func.prototype.getNum(); 


4. 箭头函数


箭头函数中没自身的this,所用的 this 都是上下文中的 this 。


  • 箭头函数没有this
  • 箭头函数没有prototype
  • 箭头函数没有constructor
  • 箭头函数不能被new执行
  • 箭头函数没有arguments,如果想用实参集合只能使用...args。


普通函数执行:


  • 形成私有上下文 (和AO)
  • 初始化作用域链
  • 初始化THIS
  • 初始化ARGUMENTS
  • 形参赋值
  • 变量提升
  • 代码执行


箭头函数执行:

  • 形成私有上下文 (和AO)
  • 形参赋值
  • 代码执行
  • 代码执行的时候遇到 this 直接找上级上下文中的 this。


let obj = {
    i: 0,
    // func:function(){}
    func() {
        // THIS:OBJ
        let _this = this;
        setTimeout(function () {
            // THIS:WINDOW 回调函数中的THIS一般都是WINDOW(但是有特殊情况)
            _this.i++;
            console.log(_this);
        }, 1000);
    }
};
obj.func();


5. call/apply/bind


call/apply

- 第一个参数就是改变 this 的指向,写谁就是谁,在非严格模式下,null/undefined 指向的是 window。
- call/apply 的唯一区别就是,传递参数不一样,apply 第二个参数是数组,call的参数是一个一个传递。
- call 的性能要比 apply 好一些(尤其是传递给函数的参数超过三个的时候)

bind

-  call/apply都是改变this的同时就把函数执行了,但是bind不是立即执行函数,属于预先改变this和传递一些内容,利用的是柯理化的思想。

这里提到这个 call/apply/bind 在面试中也常也会被问到关于如何自己实现这三个方法,其实不难,只要理解这三个方法就可以手写他们了。


apply源码-手写apply源码


~(function(proto){
  function apply(content, args) {
    if (content === undefined || contetn === null) {
      content = window;
    } else {
      content = Object(content);
    }
    content.$fn = this;
    var res = content.$fn(...args);
    delete content.$fn;
    return res;
  }
  proto.apply = apply;
})(Function.prototype)


call源码-手写call源码


~(function(proto){
  function call(content, args) {
    if (content === undefined || contetn === null) {
      content = window;
    } else {
      content = Object(content);
    }
    content.$fn = this;
    var res = content.$fn(...args);
    delete content.$fn;
    return res;
  }
  proto.call = call;
})(Function.prototype)


bind源码-手写bind源码


~(function(proto) {
    function bind(content) {
        if(content === undefined || content === null) {
            content = window;
        }
        // 获取实参集合
        var args = [].slice.call(arguments, 1);
        // 最后要执行的函数
        var _this = this;
        return function anonymous() {
            var amArgs = [].slice.call(arguments, 0);
            _this.apply(content, args.concat(amArgs));
        }
    }
    proto.bind = bind;
})(Function.prototype);
~(function(proto) {
    function bind(content = window, ...args) {
        if (content === null) {
            content = window;
        }
        return (...amArgs) => {
            // 经测试apply的性能在三个参数以上是没有call好的
            this.call(content, ...args.content(amArgs));
        }
    }
    proto.bind = bind;
})(Function.prototype);
目录
相关文章
|
2月前
|
弹性计算
阿里云ECS云服务器8核16G配置收费价格,多种ECS实例CPU及费用清单
阿里云8核16G云服务器价格因实例类型而异。计算型c9i约743元/月,一年6450元(7折);通用算力型u1仅673元/月,一年4225元(5.1折)。实际价格享时长折扣,详情见ECS官网。
|
9月前
|
传感器 人工智能 监控
可穿戴设备在运动领域的应用:科技让运动更智能
可穿戴设备在运动领域的应用:科技让运动更智能
484 9
|
4月前
|
安全 Linux iOS开发
Tenable Nessus 10.9.3 (macOS, Linux, Windows) - 漏洞评估解决方案
Tenable Nessus 10.9.3 (macOS, Linux, Windows) - 漏洞评估解决方案
498 0
Tenable Nessus 10.9.3 (macOS, Linux, Windows) - 漏洞评估解决方案
|
9月前
|
人工智能 前端开发 算法
AI程序员全面上线!10分钟就能完成整个开发过程!
AI程序员全面上线!10分钟就能完成整个开发过程!
|
JavaScript 前端开发 Java
模板字符串和普通字符串的性能差异大吗?
总体而言,模板字符串和普通字符串的性能差异并非在所有场景下都非常显著,但在一些复杂的、对性能要求较高的场景中,模板字符串可能会展现出一定的优势。不过,在实际开发中,性能并非是选择使用哪种字符串的唯一考量因素,代码的可读性、可维护性以及开发效率等同样重要。
261 63
|
传感器 算法 机器人
定点 CPU 在哪些领域有应用
定点CPU主要应用于对成本和功耗敏感的嵌入式系统中,如消费电子、汽车电子、工业控制和物联网设备等,因其结构简单、效率高而受到青睐。
|
存储 缓存 Dragonfly
如何进行容器镜像加速?| 深度揭秘阿里云 Serverless Kubernetes(3)
容器相比虚拟机最突出的特点之一便是轻量化和快速启动。相比虚拟机动辄十几个 G 的镜像,容器镜像只包含应用以及应用所需的依赖库,所以可以做到几百 M 甚至更少。但即便如此,几十秒的镜像拉取还是在所难免,如果镜像更大,则耗费时间更长。
1789 0
如何进行容器镜像加速?| 深度揭秘阿里云 Serverless Kubernetes(3)
|
5G 文件存储
手机云存储空间已满用免费不限速阿里云盘替代
手机云存储空间已满用免费不限速阿里云盘替代
2401 0
手机云存储空间已满用免费不限速阿里云盘替代
|
API iOS开发
苹果.tbd格式的文件介绍、生成和使用
早在2015年苹果推出了Xcode7的时候,.tbd文件也随之产生,它的出现取代了我们熟悉的 .dylib。 那么.tbd文件到底是什么呢?有什么用?怎么用?接下来我们一点一点来揭开它的面纱。
苹果.tbd格式的文件介绍、生成和使用