前言
在JavaScript语言中存在一个this
关键词,这个关键词指的是函数运行时所在的环境。由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this
就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
前一个系列的作用域讲过,作用域运用的是词法作用域,意味着是编写时确定的,但this与其工作原理完全不同,它的指向并不是编写时确定的,而是运行时确定。
仅仅是“规则”
之前在阅读 You Don’t Know JS系列的: this & Object Prototypes中,将this的指向总结了几条规则:
函数调用方式与内部
this
指针关系:
- 直接调用:函数内部
this
指向全局对象window
- 通过对象使用点来调用:函数内部this指向调用对象
- 触发事件调用函数:函数内部的
this
指向触发事件的对象 - 以
new
的方式来调用:函数内部this
指向本次函数执行时对应的一个匿名对象(以new的方式创建的函数,函数名的首字母一般以大写字母开始) - 通过
call
的方法来间接调用方法:函数内部this指向call
方法的第一参数对象,我们可以创建结构相同,但内容不同的对象
不仅仅是“规则”
参考了上面的规则发现,this
的指向无论如何都逃脱不了上面的5大原则,那它们之前是否存在一定的规律呢,或者说是什么来决定this
的指向的。
通常我们会对一下例子的结果没法准确的确定this
指向:
1 | var name = 'zhou'; |
上面的输出结果会是什么呢:
1 | obj.say(); // 输出shaw |
为什么这里obj.say
和say
的输出结果会不一致呢?下面我们来一探究竟。
this
的指向与数据在内存里的数据结构有关:
上面案例里的obj
对象是如何在内存中存储的呢
1 | obj.say-> { |
实际上say
函数并没有存储在obj
对象中,它只存储了say
函数的地址。
我们直接通过obj.say
来调用函数,与obj.say
赋值给say
变量调用完全不同,因为obj
中存储的是say函数
的地址,我们进行赋值操作时直接将say函数地址直接赋值过去了,而不是我们想象的将obj.say
引用赋值过去。