深究JavaScript

咚咚咚!我是谁?JavaScript细节之this学习整理

2020-02-21  本文已影响0人  oneSailboat

JavaScript语言里有诸多“反人类”的设计,其中一个就是 this 关键字。今天整理一下最近学习的this用法。

首先,为什么会有 this 这个用法?

JavaScript想要实现这样的理念:

代码执行的结果应该可以随着环境的变化而自动变化

所以就需要执行环境这一概念,某个函数在不同的条件下使用,所产生的结果可能是不同的,例如下面这段代码,

function fn(){
    console.log(this.s);
}
s=“window”;
var obj = {
    s:“obj”,
    fn:fn,
}
var o = obj;
o.fn(); 
fn();
/**
 * output:
 * obj
 * window
 */

o.fnfn 都指向 function fn(){} ,但为什么结果会不一样呢?其实就是因为两者的执行环境不同.

上述其实是this在 function 中的第一个应用,即 方法执行时会得到一个执行环境,执行环境是谁取决于方法前是否有点,有点this就是点前面的对象,没点就是浏览器的window

这条应用在实际环境中比如给某个元素的触发事件,当事件触发方法执行,方法中的this是当前元素本身

下面是在 function 中的第二个应用,this在构造函数执行时,会给创建的实例添加属性,例如以下代码:

function Fn(name, age) {
    var n = 10;
    this.name = name;
    this.age = age + n;
}
var f1 = new Fn("xxx", 20);
var f2 = new Fn("xxx", 30);

console.log('name' in f1) // true
console.log(f1.n); // undefined
console.log('toString' in f1) // true

综上所述,thisfunction的应用可归纳成两点:

  1. 方法执行时会得到一个执行环境,执行环境是谁取决于方法前是否有点,有点this就是点前面的对象,没点就是浏览器的window

  2. 构造函数执行时,this会给创建的实例绑定属性

这么看来this应用的时候会比较固定,但JavaScript也提供了三个方法通过人为方法改变this(在之后的篇章会写到)

等下,为什么总是强调thisfunction中的应用,而不直接说在函数中的应用呢?

因为在ES6推出后,不仅function可以创建函数,箭头函数也可以创建,接下来就是一个神奇的坑了,

箭头函数没有this!!!

什么叫“没有this“?就是说箭头函数执行的时候,不存在一个系统创建好的this变量来实现上面的两条性质

window.name = 'WIN';

// this是当前函数的执行主体,但是箭头函数没有执行主体
// 因为fn所处的执行上下文是window,所以this是window
let fn = n => {
    console.log(this.name);
}

let obj = {
    name: 'OBJ',
    fn:fn,
}

fn(10); // => this: window
obj.fn(10); // => this还是window,因为执行上下文是window

在上面的例子中,this不会因为调用他的方法前面有没有点而变化,因为箭头函数执行的私有作用域中没有this这个变量,所以在执行到含有this的语句时,系统会去它的上级作用域里找,在这段代码中,fn的上级作用域是全局作用域,所以每次执行得到的都是window的name

所以,箭头函数尽量不要用this,因为它和普通函数机制不同,但也不是完全没有应用,例如下面这个需求

需求:1s后把obj的name改成“lz”

箭头函数做法

window.name = 'WIN';

let obj = {
    name: 'syf',
    fn: function () {
        setTimeout(() => {
            console.log(this); // obj
            this.name = "lz";
        }, 1000)
    }
}
obj.fn(); // this是obj

为什么不用function创建fn函数?因为setTimeoutwindow的一个方法,所以在调用setTimeout的时候this总是window,需求没法实现

而在使用箭头函数时,setTimeout作用域中没有this,所以要去上级作用域寻找,就是obj作用域,然后就可以改obj.name

this引申出来的点有三个,之后再补充

  1. call|apply|bind 实现this的修改
  2. 用function创建类和用class创建类的对比
  3. 原型链机制

More Idea?请关注个人博客 syfless

上一篇 下一篇

猜你喜欢

热点阅读