JavaScript this 关键字
本文最后更新于 2024年6月7日 下午
我接触过Python这门语言,Python中也是用
this关键字实现了面向对象的某些概念。JavaScript中也有异曲同工之妙,所以见到this时我并不是很陌生,但是没想到JavaScript中的this的注意事项却比Python中的多得多,而且很让人头大。JavaScript真是一门混乱的语言! 🥱
属性
指向对象
简单来说:this用来指代属性或方法当前所在的对象。
1 | |
有的语境下this可能不指代任何对象,如下函数中出现this关键字,但是在这个函数未被调用的情况下,this不指代任何对象。
1 | |
这时候JavaScript中的this游离于对象之外,任意一个函数的定义中的都可能出现this关键字。this指向的对象取决于他调用的对象,例如:
1 | |
describe本为在对象A中定义的方法,将B对象的describe方法也指向内存中的相同位置,但因为调用其的对象不同,导致结果的不同。换句话也可以理解为他所处的环境(上下文),而环境的判断方式为——寻找this关键字的左邻最近对象。例如:
1 | |
再看一个稍复杂的例子:
1 | |
指向window
距离包含this的函数m的最左临近对象为b,所以this所指的对象为b,b中不存在属性p,所以输出undefined。
但是也会出现不存在最左临近对象的情况,这时候this所指的就是顶层对象window。
1 | |
这时候可以采用“严格模式”,“严格模式”下函数中的this不允许被指为window,不然则会报错。
1 | |
使用场合
-
全局环境
1
2
3
4
5
6this === window // true
function f() {
console.log(this === window);
}
f() // true -
构造函数
1
2
3var Obj = function (p) {
this.p = p;
}; -
对象中方法
1
2
3
4
5
6var obj ={
foo: function () {
console.log(this);
}
};
obj.foo() // obj
注意
多层嵌套下的this
下面的例子有些复杂,我想了一会。
1 | |
可以对其进行如下的变体:
1 | |
可以发现f2被声明定义之后调用,调用时它不存在最左临近对象,因此调用它的是window。
换一种思路,f2被调用的情况不属于构造函数也不属于对象的方法,因此一定是全局环境。两种方法得出的结论是一致的。
数组中的this
与上面同理,调用其的是window,不展开说了。
1 | |
回调函数中的this
1 | |
此时调用函数的对象为DOM元素,也即this的指向对象。
绑定this的方法
call()
函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。
call方法的参数,应该是一个对象。如果参数为空、null和undefined,则默认传入全局对象。
1 | |
如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法。
1 | |
call方法还可以接受多个参数。call的第一个参数就是this所要指向的那个对象,后面的参数则是函数调用时所需的参数。
1 | |
apply()
apply方法的作用与call方法类似。唯一的区别就是,它接收一个数组作为函数执行时的参数,使用格式如下:
1 | |
bind()
bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
1 | |
bind()也可以接收多个参数,这些参数将会绑定原函数的参数。
注意&用法
-
bind每次运行就返回一个新函数,所以下面的用法是无效的。1
2element.addEventListener('click', o.m.bind(o));
element.removeEventListener('click', o.m.bind(o)); -
与回调函数结合,解决
this指向的问题。1
2
3
4
5
6
7
8
9
10
11
12
13
14var counter = {
count: 0,
inc: function () {
'use strict';
this.count++;
}
};
function callIt(callback) {
callback();
}
callIt(counter.inc.bind(counter));
counter.count // 1若不这样做,
callback调用时的this指向即为window。