this使用机制复杂,在开发容易出问题的根本原因在于:this是在运行时绑定,而不是在编写时绑定,this实际值取决于函数调用时的上下文。this的绑定和函数声明的位置没有关系,只取决于函数的调用方式。在JavaScript中,当函数被调用时,会创建一个活动记录(执行时上下文),这个记录包含函数在何处调用、函数的调用方法和传入参数等信息,this会记录其中一个属性。判断this实际绑定值,关键在于分析函数实际调用的位置。
1.说到this,就必须说到call(),apply(),bind(),先提前说一下
共同点: 都是替换函数中不想要的this为想要的对象
何时: 只要一个函数调用时,其中的this不是想要的就可更换
如何:
①. call/apply
强行调用指定函数,并临时替换函数中的this为指定对象
强调: 立刻执行,且仅执行一次
执行时,临时替换时,执行后this恢复原样
如何: 指定函数.call(替换this的对象, 参数值,…..)
如果不传参,默认指向window
call vs apply: 参数值列表
call: 要求传入函数的参数值列表,必须分别传入
apply: 要求传入函数的参数值列表,必须放在数组中整体传入.
②. bind()
什么是: 创建一个和原函数完全相同的函数,并永久绑定函数中的this为指定对象
如何: var 新函数=原函数.bind(替换this的对象,参数值,…)
基于原函数,创建一个新函数,并永久绑定this为指定对象call(),apply(),bind()
2.this的绑定规则
①.new绑定
在JavaScript中使用new调用函数会自动执行下面的操作:
(1)创建(或者说构造)一个全新的对象
(2)对新对象执行原型链接
(3)新对象会被绑定到函数的this
(4)如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象
代码块:
1 | function Book(name, author, isbn) { |
②.隐式绑定:
当对象内部包含一个指向函数的属性,并且在调用时通过这个属性间接引用函数(obj.prop()的形式),那么函数内的this会隐式指向这个对象
代码块:
1 | function foo() { |
③.显示绑定
在某些情况下,我们希望函数内的this绑定在某些指定的对象上,这称为显示绑定。在JavaScript中可以使用call和apply为函数显示指定this绑定。call和apply的第一个参数是一个对象,这个对象会被绑定到this上:
代码块:
1 | function foo() { |
④.默认绑定:
当使用独立函数调用(func()形式),会发生默认绑定,可以把这条规则看成是无法使用其他规则时的默认规则。
代码块:
1 | function foo() { |
3.绑定的优先级
①.默认绑定的优先级最低,因为无法使用其他的绑定规则才会使用默认规则
②.显示绑定优先级高于隐式绑定
代码块:
1 | function foo() { |
3:new绑定优先级高于隐式绑定
代码块:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var obj2 = {};
obj1.foo(2);
console.log(obj1.a); // 2
obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3
var bar = new obj1.foo(4);
console.log(obj1.a); // 2
console.log(bar.a); // 4
4.总结
如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断 this 的绑定对象。
①. 由 new 调用?绑定到新创建的对象。
②. 由 call 或者 apply (或者 bind )调用?绑定到指定的对象。
③. 由上下文对象调用?绑定到那个上下文对象。
④. 默认:在严格模式下绑定到 undefined ,否则绑定到全局对象。
自我测试代码块:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 var myObject = {
foo: "bar",
func: function() {
var self = this;
var foo = "1"
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
}
myObject.func()
console.log('----------')
var func = myObject.func
func()
console.log('----------')
func.call(myObject)