最近看了一些javascript相关的知识,打算整理一下
一、全局执行上下文中的this
console.log(this)
上面这个打印结果是:
全局执行上下文中的this是指向window对象的
二、函数执行上下文中的this
function foo() {
console.log(this)
}
foo()
上方这段代码的打印结果是:
再看下下面这段代码,它的打印结果也是window对象
function bar() {
console.log(this)
}
function foo() {
bar()
}
foo()
以上的示例说明,在默认情况下调用一个函数,其执行上下文中的this也是指向window对象的
2.1 如何指定函数执行上下文中的this
看以下示例代码,同一个函数,由于调用的方式不同,它内部的this指向了不同的对象。
在一个函数的执行上下文中,this由该函数的调用者提供,由调用函数的方式来决定其指向。
var a = 10;
var obj = {
a : 20
}
function foo() {
console.log(this)
console.log(this.a)
}
foo();
foo.call(obj);
打印结果是:
如果想要指定函数执行上下文中的this,可以使用call/apply/bind
这三种函数
2.1.1 call/apply
指定this
当使用call/apply
时,表示会执行该函数,并且函数内部的this指向call/apply
的第一个参数。这两个方法传递参数的形式不同,call
方法第一个参数是为函数内部指定this指向,后续的参数则是函数执行时候需要的参数,一个一个传递。apply
方法的第一个参数含义与call
方法相同,而函数执行需要的参数,以数组形式传递。
var a = 10;
var obj = {
a : 20
}
function foo(b, c) {
console.log(this.a + b + c)
}
foo(10, 10);
foo.call(obj, 10, 10);
foo.apply(obj, [10, 10]);
打印结果是:
30
40
40
在javascript里面,数组里的每一项可以是任何类型的数据,所以当上方的foo函数需要的参数是不同类型的时候,apply
方法也可以使用数组来传递参数。如下方示例代码。
var a = 10;
var obj = {
a : 20
}
function foo(b, c, d) {
console.log(this.a + b + c)
console.log(d)
}
foo(10, 10, 't');
foo.call(obj, 10, 10, 'test call');
foo.apply(obj, [10, 10, 'test apply']);
打印结果是:
30
t
40
test call
40
test apply
2.1.2 bind
指定this
bind
方法也可以指定函数内部的this指向,但是函数并不会立即执行,而是返回一个新的函数,这个新的函数与原函数有共同的函数体,且新函数的参数与this指向都已经被绑定。
看下面的示例代码:
function foo(b, c) {
console.log(this.a + b + c);
}
var a = 10;
var obj = {
a : 20
}
var _foo = foo.bind(obj, 4, 5);
console.log(_foo);
console.log(_foo === foo);
_foo();
_foo(1, 2);
打印结果是:
可以看到最后一行代码_foo(1, 2)
的打印结果是29,这是因为参数被绑定,所以重新传入参数是无效的
2.1.3 通过对象调用方法设置
var a = 10
var obj = {
a : 20,
showA : function() {
console.log(this.a)
}
}
obj.showA()
以上代码打印结果为:
20
这可以说明,使用对象来调用其内部的一个方法,该方法的this是指向对象本身的。但是如果对象的内部方法被赋值给了一个全局变量,使用该全局变量执行函数时,this又指向了window对象。看下面的示例代码:
var a = 10
var obj = {
a : 20,
showA : function() {
console.log(this.a)
}
}
var fn = obj.showA
fn()
以上代码打印结果为:
10
2.1.5 通过构造函数设置
在javascript里面创建对象有很多种方式,以下代码是通过构造函数创建对象
var a = 10
function Test() {
this.a = 20
}
var obj = new Test()
当执行new Test()
的时候,javascript引擎做的事情相当于下面这些:
var tempObj = {} // 创建一个空对象
Test.call(tempObj) // 指定Test执行上下文的this并执行Test函数
return tempObj // 返回tempObj对象
2.2 this的缺陷
缺陷一、2.2.1 嵌套函数中的this不会从外层函数中继承
var a = 10
var obj = {
a : 20,
showA : function() {
console.log(this.a);
function bar() {
console.log(this.a)
}
bar()
}
}
obj.showA()
打印结果是:
20
10
本来以为bar函数里面的this是继承外层的showA函数的,但实际上不是。实际表明,bar函数里的this是全局window对象。
为了解决这个问题,有两种方法,第一种方法是:可以用一个self变量来存储this。第二种方法是:使用箭头函数来实现嵌套函数
方法一:可以用一个self变量来存储this
var a = 10
var obj = {
a : 20,
showA : function() {
console.log(this.a);
var self = this
function bar() {
console.log(self.a)
}
bar()
}
}
obj.showA()
以上代码打印结果是:
20
20
方法二:使用箭头函数来实现嵌套函数
var a = 10
var obj = {
a : 20,
showA : function() {
console.log(this.a);
var bar = () => {
console.log(this.a)
}
bar()
}
}
obj.showA()
以上代码打印结果是:
20
20
关于箭头函数可以看廖雪峰的这篇。
箭头函数与this:
-
箭头函数默认绑定外层this
-
箭头函数不能用call方法修改里面的this