前端萌新自用,仅供参考,错误之处还请指正,谢谢。
与其他语言相比,JavaScript中this的表现有些不同,并且在严格模式和非严格模式下也有差异。
this是什么?
this是函数在运行时产生的内部变量,无法在函数外部被访问,this
不能在执行期间被赋值。在绝大多数情况下,函数的调用方式决定了this的指向(运行时绑定),所以每次调用函数,this的指向都可能不同。
this的指向:
1.全局上下文
无论是否在严格模式下,在全局执行环境中(在任何函数体外部),this都指向全局对象。
(可以使用globalThis获取全局对象,无论是否在全局上下文中)
2.默认绑定
在非严格模式中,在全局环境中定义函数person,this默认绑定到window。(可以这样理解:person()全局模式下省略了window. ,补全后为window.person(),this指向调用的对象所以指向window。)
var name = '123'
function person() {
console.log(this) //window
return this.name
}
console.log(person()) //123
这里换成let name = '123',在第一次运行时打印空白,改为var后改回let 又打印123,不知道为什么。(let不会绑定全局作用域,所以改为let后,window中并没有name这个变量,所以this.name也就是window.name才没有值)
在严格模式下,如果进入执行环境时,没有设置this的值,则this默认为undefined。
var name = '123'
function person (){
'use strict';
console.log(this); //undefined
return this.name
}
console.log(person()) //Uncaught TypeError: Cannot read property 'name' of undefined
3.隐式绑定
函数作为某个对象的方法进行调用时,this指向这个对象。
let obj = {
name:'123',
getName() {
return this.name
}
}
console.log(obj.getName()) //123
而且这样的行为不会受到函数定义方式或者定义位置的影响,无论是在定义对象obj的同时将getName函数定义为成员getName,还是先定义getName函数,之后在附属到obj.a,都是一样的结果。
let obj = {
name:'123'
}
function getName() {
return this.name
}
obj.a = getName
console.log(obj.a()) //123
同样,this的指向只受最近成员引用的影响,下面代码中,将getName方法作为obj.b的c方法,在这次执行期间,函数中的this
将指向obj.b
。事实证明,这与他是对象 obj
的成员没有多大关系,最近的引用才是最重要的。
let obj = {
name:'123'
}
function getName() {
return this.name
}
obj.a = getName
obj.b = {
name:'456',
c:getName
}
console.log(obj.b.c()) //456
4.new 绑定
通过new关键字生成一个实例对象时,this指向这个实例对象。
function Animal () {
this.name = 123
}
let a = new Animal()
console.log(a.name); //123
构造函数中有return时,会根据return的内容不同而出现变化:
当构造函数中return一个非对象时,this仍然指向实例对象。(a为执行构造函数后的实例对象)
function Animal () {
this.name = 123
return '456'
}
let a = new Animal()
console.log(a.name); //123
console.log(a) //Animal(name:'123')
当构造函数return一个对象时,this指向这个对象。 (a为返回的对象)。
function Animal () {
this.name = 123
return {name:'456'}
}
let a = new Animal()
console.log(a.name); //456
console.log(a) //{name:'456}
虽然null也是一个对象,但是return null,this仍然指向实例对象。
function Animal () {
this.name = 123
return null
}
let a = new Animal()
console.log(a.name); //123
console.log(a) //Animal(name:'123')
5.显式修改
apply、call、bind这三个函数都可以改变调用函数的对象,它们的第一个参数就是改变后调用函数的对象,所以,this指向第一个参数。
let a ={
name :'123',
getName() {
return this.name
}
}
let b ={
name :'456'
}
console.log(a.getName.call(b)); //456
console.log(a.getName.apply(b)); //456
console.log(a.getName.bind(b)()); //456
6.箭头函数
MDN:在箭头函数中,this
与封闭词法环境的this
保持一致。
我的理解,箭头函数的this指向箭头定义时最近外层的this。下面代码中,箭头函数中的this在定义时就确定了,而输出的不同是由于,箭头函数都指向最近外层中的this,也就是bar中的this,而b=a.bar()中,bar作为a的方法被调用,this指向a,所以箭头函数的this也指向a;b=a.bar,bar并未执行,而是在c()()中执行,这时bar中的this指向window,则箭头函数也指向window。因为bar中this的不同才导致了箭头函数中this的指向不相同。
let a ={
name :'123',
bar: function() {
var x = (() => this);
return x;
}
}
let b = a.bar()
console.log(b()); //{name:'123,bar:f}
let c = a.bar
console.log(c()()); //window
MDN中的描述,链接:this - JavaScript | MDN