神秘的this
this
在 JavaScript 中是一个非常重要的关键字,它的指向在不同的情况下会有所不同。可以把this
想象成一个"指针",它总是指向当前正在执行的代码所在的对象。
足够先进的技术都和魔法无异 --- Arthur C.Clarke
this又存在于哪里?
1.全局
2.函数体内
this的绑定规则
kotlin
1.默认绑定:当一个函数默认调用时,不带任何修饰符的调用,该函数的this指向window
2.隐式绑定:当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象
3.隐式丢失:当一个函数被多个对象链式调用时,this指向最近的那个对象
4.显式绑定:通过call,apply,bind,将函数的this掰弯一个对象中
5.new绑定:this指向实例对象
没看懂对不对?单看文字没有例子,看不太懂
1.默认绑定:
javascript
当一个函数默认调用时,不带任何修饰符的调用,该函数的this指向window,即指向全局对象
案例一
ini
var a =1
console.log(a);
function foo(){
var b = 1;
console.log(b);
}
foo();//这就是不带任何修饰符的调用
深度解析
scss
//this指代,函数生效的词法作用对象
function foo(){
var a = 1
function bar(){
console.log(this.a); //
}
bar();
//bar在foo的作用域里面生效
//foo的词法作用域是全局
//this指代全局对象即window
}
foo();
升级一下
scss
var a = 1
function foo(){
var a = 2
function bar(){
var a = 3
function baz(){
console.log(this.a);// 打印undefined
}
baz();
//baz在bar的作用域里面生效
//bar的词法作用域是foo
//foo的词法作用域又是全局,所以this指向去全局对象
}
bar();
}
foo();
再升级一下
javascript
var a = 1
function foo(){
var a = 2
function bar(){
var a = 3
function baz(){
console.log(this.a);// 打印undefined
}
return baz;
}
var d = bar();
d() //d即baz在foo中生效,foo的词法作用域是全局。this指代全局对象
}
foo();
奇怪为什么打印的还是undefined
吗?this指向的是全局对象。this.a
表示对象的属性,而全局这个对象中并没有a
这个属性。var a = 1;
a只是一个变量。
小结:默认绑定的就是全局对象
2.隐式绑定:
当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象
javascript
var obj = {
a :1,
foo: foo
}
function foo(){
console.log(this.a);
}
obj.foo()//当一个函数被某个对象所拥有
温馨提示:obj.foo和obj.foo()的区别
obj.foo
得到的是函数 foo
本身,即得到返回值
而 obj.foo()
则是对这个函数进行调用执行,会执行函数内部的代码,在这个例子中就是输出 this.a
的值。
升级一下
yaml
var obj1 = {
name: 'obj1',
method1: function() {
console.log('obj1 method1 this:', this);
}
};
var obj2 = {
name: 'obj2',
method2: obj1.method1
};
obj1.method1();
// obj1 method1 this: { name: 'obj1', method1: [Function: method1]}
obj2.method2();
//obj1 method1 this: { name: 'obj2', method2: [Function: method1]}
当执行 obj1.method1()
时,此时 this
指向 obj1
对象,所以会打印出 obj1
对象本身。
当执行 obj2.method2()
时,这是因为 obj2.method2
是对 obj1.method1
函数的引用,当调用 obj2.method2()
时,实际上是在调用 obj1.method1
函数,并且 this
的值被绑定到了 obj2
对象上。
3.隐式丢失:
当一个函数被多个对象链式调用时,this指向最近的那个对象
javascript
var obj1 = {
name: 'obj1',
method1: function() {
console.log('obj1 method1 this:', this);
}
};
var obj2 = {
name: 'obj2',
method2: obj1
};
obj2.method2.method1()//相当于obj2.obj1.method();被对象链式调用选最近的
//打印obj1 method1 this: { name: 'obj1', method1: [Function: method1] }
对比
javascript
var obj1 = {
name: 'obj1',
method1: function() {
console.log('obj1 method1 this:', this);
}
};
var obj2 = {
name: 'obj2',
method2: obj1
};
obj2.method2.method1()
//obj1 method1 this: { name: 'obj1', method1: [Function: method1] }
javascript
var obj1 = {
name: 'obj1',
method1: function() {
console.log('obj1 method1 this:', this);
}
};
var obj2 = {
name: 'obj2',
method2: obj1.method1
};
obj2.method2()
//obj1 method1 this: { name: 'obj2', method2: [Function: method1]}
第一个就是明显的隐式绑定,对象链式绑定,可以拆分成(obj2.obj1).method()
第二个可以这样拆分,obj2.(obj1.method())
,obj2引用了method方法
4.显式绑定:
通过call,apply,bind,将函数的this掰弯一个对象中
javascript
function myFunction(a, b) {
console.log('this.name:', this.name, ', a:', a, ', b:', b);
}
// 使用 call
const obj1 = { name: 'obj1' };
myFunction.call(obj1, 1, 2);//this.name: obj1 , a: 1 , b: 2
这里使用 call
方法来调用 myFunction
函数。call
方法的第一个参数 obj1
就是明确指定的 this
的值,即让 myFunction
函数内部的 this
指向 obj1
对象。后面的 1
和 2
则是传递给函数的参数。所以在函数内部,this.name
会是 obj1
的 name
值 'obj1'
,a
为 1
,b
为 2
。
ini
// 使用 apply
const obj2 = { name: 'obj2' };
myFunction.apply(obj2, [3, 4]);//this.name: obj2 , a: 3 , b: 4
apply
方法与 call
类似,也是用于指定 this
的指向。不同的是,它的第二个参数是一个数组,数组中的元素就是要传递给函数的参数。所以这里函数内部 this.name
是 obj2
的 name
'obj2'
,a
为 3
,b
为 4
。
ini
// 使用 bind
const obj3 = { name: 'obj3' };
const boundFunction = myFunction.bind(obj3);
boundFunction(5, 6);//this.name: obj3 , a: 5 , b: 6
bind
方法会创建一个新的函数,这个新函数的 this
被永久地绑定为指定的对象(这里是 obj3
)。然后调用这个新函数 boundFunction
时,它内部的 this
就会是 obj3
,参数为 5
和 6
。同样地,this.name
为 obj3
的 name
'obj3'
。
5.new绑定:
this指向实例对象
javascript
function foo(a){
this.a;
}
var bar = new foo(2)
//this指向实例对象
console.log(bar.a);//2