美文网首页深究JavaScript
咚咚咚!我是谁?JavaScript细节之this学习整理

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

作者: oneSailboat | 来源:发表于2020-02-21 18:45 被阅读0次

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(){} ,但为什么结果会不一样呢?其实就是因为两者的执行环境不同.

  • o.fn 执行的时候,解释器先有 o的内存地址找到 fn 的内存地址,所以 o.fn() 的执行环境是 o,既然执行环境是 o ,那么 this 就是 othis.s 就等于 "obj"
  • fn 执行的时候,解释器直接从浏览器的全局栈内存下找到fn 的内存地址,所以fn() 的执行环境是 window ,而 window 的属性 s 是和当前作用域的变量 s双向绑定的,所以 this.s 就是window.s 就是 "window"

上述其实是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
  • name是有this绑定到实例上的属性,当执行new执行构造函数时,会默认开辟一块堆内存(实例),执行到this语句时会把属性加入这个堆内存,执行完之后将堆内存的地址赋给等号前的变量。
  • nFn函数的私有变量,和实例没有关系
  • toStringObject的方法,通过原型链继承,f1也可以得到这个方法,in可以检测对象是否有这个属性或方法,无论是绑定在this还是原型链上继承来的,所以返回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

相关文章

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

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

  • 2021-01-14

    午夜,十二点 “咚咚咚!!” “谁啊?” “咚!咚!咚” “到底是谁啊!” “送外卖的!” 门外传来一声微弱的声音...

  • 咚 咚咚 咚咚咚

    彷佛又失恋了一次。 手机嗡嗡响起,“别对我好了,有人追我了,我想相处,接触看看。” 我握着方向盘,笑了,沉默了。 ...

  • 唯有热爱,才能长久

    1 “听说QMZ最近要回国了,他已经报考了GRE,你最近开始准备了吗?” 咚、咚、咚、咚咚、咚咚、咚咚、咚咚咚、咚...

  • 诗与画——鼓

    在每一支民乐曲中 我寻找你的声音 在每个音符中 我捕捉你的存在 咚 咚 咚咚嗒 你是节奏的魂啊 咚咚咚咚 咚咚咚 ...

  • 红山轶事(十四)

    “咚咚咚咚——咚,咚咚咚咚——咚”,拨浪鼓有节奏地一响,操着外地口音的小货郎又来走街串巷。小货郎是当时比...

  • 成人学琴为什么

    “咚-咚咚咚---,咚-咚咚咚---。”楼上又在练钢琴了,弹的是《小汤普森》的小乐曲。 半年来,楼上的邻居每天都会...

  • 无人聆听 第一章

    咚~咚~咚咚咚 间隔一两秒秒有节奏的敲打,无形气息蔓延开来。 咚咚~咚咚~咚咚咚 略带烦躁的拍击加快...

  • 咚咚咚,是谁?

    壹 一到下午就想听歌,不带歌词的那种。 这样子,思绪就可以无限制蔓延开去了。 私以为,当你向别人寻求建议的时候,其...

  • 咚咚咚,是谁

    「本文参与主题写作咚咚咚[https://www.jianshu.com/p/167a6ec96944]」 “咚咚...

网友评论

    本文标题:咚咚咚!我是谁?JavaScript细节之this学习整理

    本文链接:https://www.haomeiwen.com/subject/wwkhqhtx.html