JavaScript 的this
关键字大家都不陌生,根据this
所在的不同的运行环境,会产生一些容易让人困惑的表现和差异,在没有仔细了解this
之前,我对它的理解非常的生硬和片面,希望大家阅读完这篇内容能够清楚的明白this
的用途。
this 的由来
让我们看一下这个栗子:
var name = 'MyWindow'
function SayHi() {
console.log('Hi, My name is ' + name + '.')
}
var MyJavaScript = {
name: 'MyJavaScript',
sayHi: SayHi,
}
SayHi() // Hi, My name is MyWindow.
MyJavaScript.sayHi() // Hi, My name is MyWindow.
可以看到,当我们想试图输出Hi, My name is MyJavaScript.
的时候,还是输出了window
。因为SayHi
函数里输出的name
变量值必定是沿着当前执行环境的作用域链查找的。
而SayHi
函数被调用时会创建出一个自己的执行环境,执行环境的三大元素
- 变量对象:定义在当前执行环境内可访问的所有变量和方法。
- 作用域链:本质是按照执行环境的嵌套顺序而形成的一组变量对象链。
作用域定义了在某个执行环境下可访问的所有变量和方法,作用域链定义了除当前作用域外还有权访问的父级作用域,按照被嵌套顺序及当前作用域形成一条作用域链。默认当我们访问一个变量或方法时,会按照作用域链由近及远查找,首先找到最近的作用域(即当前作用域)再向外层作用域查找。
作用域链图示
按照作用域嵌套顺序,SayHi
被嵌套在全局执行环境中,在SayHi
函数内部查找name
变量时,自然而然找到的就是外层全局作用域中的name
变量,所以不论如何调用都会输出window
。
那想一想,当我们调用MyJavaScript.sayHi()
时要如何准确输出MyJavaScript
对象的name
属性呢?
噔噔蹬蹬,this
机制就此诞生了!!(自带 bgm)
this
: 被用来指向函数真正的运行环境。
让我们改写一下SayHi
方法:
var name = 'MyWindow'
function SayHi() {
// 此处发生变化
console.log('Hi, My name is ' + this.name + '.')
}
var MyJavaScript = {
name: 'MyJavaScript',
sayHi: SayHi,
}
SayHi() // Hi, My name is MyWindow.
MyJavaScript.sayHi() // Hi, My name is MyJavaScript.
如上图,当我们将name
修改为this.name
后,sayHi
函数当在作为MyJavaScript
对象的某一属性被调用时,准确的输出了当前函数的调用者MyJavaScript
对象的name
属性值。
由此我们可以得知,this
对象的作用就是当函数在不同的执行环境下被调用,让我们能够得到真正调用函数的对象。与函数定义在哪里或者函数作用域无关,只关心函数的调用方式。
以上就是this
对象的前世,下面会整理一些与this
对象相关的必懂知识点,供大家查阅。
一些必懂的知识点
this 是什么
this
是JavaScript
关键字,在非严格模式下,它总是指向一个对象,而具体指向哪个对象是根据函数运行时所在的执行环境动态绑定的。
为什么需要 this
因为函数可以在不同的运行环境中执行,自身调用或作为方法调用,为了得到当前函数真正运行时的所在执行环境,即函数执行时真正的调用对象,this
机制就此诞生了。
this 有什么作用
(同上)指向函数真正的调用对象。
this 的指向
简单调用
全局环境下this
默认指向全局对象,严格模式下则为undefined
,浏览器中则为window
对象。
e.g. func()
=> this
默认指向全局对象 => window
(浏览器下)。
作为对象的方法调用
this
指向由调用方式决定,在函数执行时确定。
e.g. obj.func()
=> this
指向具体调用对象 => obj
。
这里可以理解为obj.f1()
是通过对象obj
找到f1
函数的,则它运行时所在环境就是obj
环境,this
指向obj
。
作为构造函数
当一个函数用作构造函数时(使用new
关键字),它的this
被绑定到正在构造的新对象,并作为构造函数的默认返回值。
this
指向取决于函数返回的对象(默认无初始化值 => undefined
),在类上下文(class
关键字)中则是取决于类的构造函数返回对象(默认返回类中定义的所有属性和方法,不包括静态方法)。
函数上下文默认 this
无初始化值
手动添加属性
函数上下文手动返回
类上下文默认 this
类上下文构造函数手动返回
是不是想回退了??快结束了啊,再坚持一下 👋
箭头函数
我们知道普通函数的this
指向在函数执行时确定,由函数的调用方式决定。
而在 ES6 的箭头函数中,this
指向在函数定义时就确定了,永远指向该函数声明时所在的环境对象,任何其他方式都无法修改this
的指向。
静态方法
因为this
对象代表调用这个函数的对象,而静态方法是属于类的而不是调用对象,静态方法成功加载后,调用对象可能还不存在。因此在静态方法中是找不到this
对象的值的。
匿名函数
匿名函数中this
的指向也是依旧由函数调用方式决定。
foo
作为objA
的方法被调用,this
指向objA
。
foo
被指向objA.foo
所指向的匿名函数,当foo
被简单调用时,this
就指向了全局对象。
setTimeout 和 setInterval
当使用setTimeout
和setInterval
时,回调函数中的this
默认指向window
对象,因为setTimeout
和setInterval
是window
对象提供的方法。
可见,setTimeout
中输出的是window
对象上的count
属性。
真的真的第 99 步了,坚持到底啊 👋
改变 this 指向的几种方法和区别
call
apply
call 和 apply 的区别
call
的参数是直接放进去的,第二第三...第n个参数全都用逗号分隔。
apply
的第二个参数接收的是一个数组,对应传递给被绑定的函数。
bind
bind
用法和call
一致,但是bind
返回的是被绑定的函数,需要做一次额外的手动调用。
到此本文就结束啦,感谢阅读,欢迎点赞 🇨🇳
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。