详解JavaScript中的 this 指向
2018-02-06 01:27
633 查看
this是在运行时进行绑定的,并不是在在编译时绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用位置。
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文),而this就是这个记录的一个属性。
this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
调用位置:
既然this的指向完全取决于函数的调用位置,那么,怎么才能找到函数的调用位置呢?
function a(){
//a的调用栈为:a
b(); //b的调用位置
}
function b(){
//b的调用栈为: a--->b
c(); //c的调用位置
}
function c(){
//c的调用栈为: a--->b---->c
console.log("123");
}
a(); //a的调用位置
你可以把调用栈想象成一个函数调用链,当然你也可以直接用JavaScript调试器查看函数的调用栈。然后找到栈中的第二个元素,这就是真正的调用位置。
this的绑定规则:
上面也已经提到,this是在函数调用时发生的绑定,它指向什么完全取决于函数的调用位置。也就是说,this的绑定规则完全取决于调用位置。
1. 默认绑定
非严格模式下,this 指向 window, 严格模式下 this 指向 undefined。
独立函数调用,就使用的是默认绑定规则。(无法使用其他规则时就会使用默认规则)
function foo(){
console.log(this.a);
}
var a = 2;
foo(); //2
2. 隐式绑定
当函数被调用时,它的前面加上了obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); //2
隐式丢失:
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo;
var a = 3;
bar(); //3
注:虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,此时的bar其实是一个不带任何修饰符的函数调用,因此使用了默认规则。
function foo(){
console.log(this.a);
}
function doFoo(fn){
//fn其实引用的的是foo
fn();
}
var obj = {
a: 2,
foo: foo
};
var a = 3;
doFoo( obj.foo ); //3
注:这里需要注意,传参其实就是进行赋值操作。结果是一样的,没有区别。
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: f
4000
oo
};
var a = 3;
setTimeout( obj.foo, 100); // 3
3. 显示绑定:
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
foo.call(obj); //2
通过foo.call(),我们可以在调用foo时强制把它的this绑定到obj上。
当然,还可以通过appay和bind方法也可以显示的将this绑定到obj上,可以看我后面的文章。
4. new绑定
首先,我先重新定义一下JavaScript中的“构造函数”,在JavaScript中,构造函数只是一些使用new操作符时调用的函数。他们并不会属于某个类,也不会实例化一个类。它们只是被new操作符调用的普通函数而已。
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1. 创建(或者说构造)一个全新的对象。
2. 这个新对象会被执行[[Prototype]]连接。
3. 这个新对象会绑定到函数调用的this.
4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
function foo(a){
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); //2
四种绑定规则的优先级:
new绑定 > 显示绑定 > 隐式绑定 > 默认绑定
判断this:
1.函数是否在new中调用(new绑定),如果是的话this绑定的是新创建的对象。
2. 函数是否通过call,apply(显示绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对 象。
3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。
4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象
当然,凡事都有例外,上面所说的适用于绝大多数情况,但也有一些例外:
如果你把null或者undefined作为this的绑定对象传入call,apply,bind,这些值在调用时会被忽略,实际应用的是默认的绑定规则。
function foo(){
console.log(this.a);
}
var a = 2;
foo.call(null); //2
箭头函数:
箭头函数并不是使用function关键字定义的,而是使用被称为“胖箭头”的操作符=>定义的,箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。也就是说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。
function foo(){
return (a) => {
console.log(this.a);
};
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
var bar = foo.call(obj1);
bar.call(obj2); //2 , 不是3!!!
注:还有一点需要注意,箭头函数的绑定无法被修改。(new也不行)
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文),而this就是这个记录的一个属性。
this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
调用位置:
既然this的指向完全取决于函数的调用位置,那么,怎么才能找到函数的调用位置呢?
function a(){
//a的调用栈为:a
b(); //b的调用位置
}
function b(){
//b的调用栈为: a--->b
c(); //c的调用位置
}
function c(){
//c的调用栈为: a--->b---->c
console.log("123");
}
a(); //a的调用位置
你可以把调用栈想象成一个函数调用链,当然你也可以直接用JavaScript调试器查看函数的调用栈。然后找到栈中的第二个元素,这就是真正的调用位置。
this的绑定规则:
上面也已经提到,this是在函数调用时发生的绑定,它指向什么完全取决于函数的调用位置。也就是说,this的绑定规则完全取决于调用位置。
1. 默认绑定
非严格模式下,this 指向 window, 严格模式下 this 指向 undefined。
独立函数调用,就使用的是默认绑定规则。(无法使用其他规则时就会使用默认规则)
function foo(){
console.log(this.a);
}
var a = 2;
foo(); //2
2. 隐式绑定
当函数被调用时,它的前面加上了obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); //2
隐式丢失:
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo;
var a = 3;
bar(); //3
注:虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,此时的bar其实是一个不带任何修饰符的函数调用,因此使用了默认规则。
function foo(){
console.log(this.a);
}
function doFoo(fn){
//fn其实引用的的是foo
fn();
}
var obj = {
a: 2,
foo: foo
};
var a = 3;
doFoo( obj.foo ); //3
注:这里需要注意,传参其实就是进行赋值操作。结果是一样的,没有区别。
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: f
4000
oo
};
var a = 3;
setTimeout( obj.foo, 100); // 3
3. 显示绑定:
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
foo.call(obj); //2
通过foo.call(),我们可以在调用foo时强制把它的this绑定到obj上。
当然,还可以通过appay和bind方法也可以显示的将this绑定到obj上,可以看我后面的文章。
4. new绑定
首先,我先重新定义一下JavaScript中的“构造函数”,在JavaScript中,构造函数只是一些使用new操作符时调用的函数。他们并不会属于某个类,也不会实例化一个类。它们只是被new操作符调用的普通函数而已。
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1. 创建(或者说构造)一个全新的对象。
2. 这个新对象会被执行[[Prototype]]连接。
3. 这个新对象会绑定到函数调用的this.
4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
function foo(a){
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); //2
四种绑定规则的优先级:
new绑定 > 显示绑定 > 隐式绑定 > 默认绑定
判断this:
1.函数是否在new中调用(new绑定),如果是的话this绑定的是新创建的对象。
2. 函数是否通过call,apply(显示绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对 象。
3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。
4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象
当然,凡事都有例外,上面所说的适用于绝大多数情况,但也有一些例外:
如果你把null或者undefined作为this的绑定对象传入call,apply,bind,这些值在调用时会被忽略,实际应用的是默认的绑定规则。
function foo(){
console.log(this.a);
}
var a = 2;
foo.call(null); //2
箭头函数:
箭头函数并不是使用function关键字定义的,而是使用被称为“胖箭头”的操作符=>定义的,箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。也就是说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。
function foo(){
return (a) => {
console.log(this.a);
};
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
var bar = foo.call(obj1);
bar.call(obj2); //2 , 不是3!!!
注:还有一点需要注意,箭头函数的绑定无法被修改。(new也不行)
相关文章推荐
- JavaScript严格模式下关于this的几种指向详解
- JavaScript面向对象(一)——JS OOP基础与JS 中This指向详解
- 详解JavaScript中this的指向
- 详解JavaScript中this的指向问题
- 第149天:javascript中this的指向详解
- javascript中this的指向详解
- javascript中this指向详解
- JavaScript面向对象(一)——JS OOP基础与JS 中This指向详解
- javascript this关键字指向详解
- javascript中this指向详解
- 用最简单的方法判断JavaScript中this的指向
- JavaScript中this的详解
- JavaScript中this指针指向的彻底理解
- 通俗易懂的javascript中的this指向问题和call()、apply()用法的讲解
- 针对JavaScript中this指向的简单理解
- JavaScript 之 this 详解
- javascript的this指向问题深度解析
- JavaScript-this的指向
- 图解javascript中this指向
- javascript中的this详解