这里总结js中一个重点——this。
js中函数的this,并不是指向函数本身或者某个作用域,而是指向对象。简单地说,哪个对象调用该函数,则该函数里的this就指向这个对象。但实际写代码时会遇到更复杂的情况。
this的复杂,原因是它取决于函数在代码中被调用的位置而不是声明的位置,也就是说this并不遵循词法作用域,而是要看运行时的上下文。
this的绑定规则主要有4种。当然,还会有个别特例。但是只要能理解这几种绑定规则,写出具有this风格的代码便不是问题。
1 默认绑定。如果函数是独立调用,即直接使用不带任何修饰的函数引用进行调用的,那么就是默认绑定。默认绑定下,如果使用非严格模式,this会绑定全局对象,浏览器中是window对象。如果使用严格模式(strict mode),则全局对象讲无法使用默认绑定,则this会绑定到undefined。
例:
//非严格模式
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
//严格模式
function foo() {
"use strict";
console.log( this.a );
}
var a = 2;
foo(); // TypeError: this is undefined
2 隐式绑定。当一个函数被当做引用属性添加到一个对象obj中或者这个函数(方法)本身就是在obj中定义,当函数的调用是通过obj对象的属性的形式调用时,函数调用中的this会被绑定到obj对象。注意,对象属性引用链中只有最后一层会影响调用位置。
例:
function foo() {
console.log( this.a );
}
var obj2 = {
a: 2,
foo: foo
};
var obj1 = {
a: 1,
obj2: obj2
};
obj1.obj2.foo(); // 2
即,只用管直接调用函数的那个对象,this就是绑定在这个对象上的。
隐式绑定有两个情况会导致隐式丢失,即this没有绑定在相应的绑定对象上,而是会采用默认绑定,即绑定到全局对象或undefined上。这两种情况是:
一 将函数赋值给变量
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性
bar(); // "oops, global"
上面的代码中,bar引用的是函数foo本身。即var bar = obj.foo 是把等号右边的结果赋给等号左边的变量,本质上调用的是返回的函数本身,所以最后函数的调用是不带任何修饰的函数调用,this为默认绑定。
有一种情况要注意识别:
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2
(p.foo = o.foo)(),这样的直接调用,实际上是调用等号右边的返回值,即foo,所以结果是2。
如果是p.foo = o.foo;p.foo(),则返回4,相当于分两步,最后调用的是p的foo方法。
二 函数作为参数传递
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a 是全局对象的属性
setTimeout( obj.foo, 100 ); // "oops, global"
上面这段代码中,obj.foo被当做回调函数传入定时器函数。这里面相当于是一次赋值。所以函数调用后,里面的this是默认绑定。
setTimeout() 函数实现和下面的伪代码类似:
function setTimeout(fn,delay) {
// 等待 delay 毫秒
fn(); // <-- 调用位置!
}
3 显式绑定
使用call,apply,bind这三个函数中的任意一个来讲函数的this绑定到指定的对象。
call和apply的用法相同,唯一不同的就是参数传递,apply函数的参数接受的是数组。(这也是apply函数的一个特殊用法,即遇到需要把数组分成一个个参数的情况时,可以用apply函数,这个函数用法不展开讲了)。
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
// 简单的辅助绑定函数
function bind(fn, obj) {
return function() {
return fn.apply( obj, arguments );
};
}
var obj = {
a:2
};
var bar = bind( foo, obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5
bind函数将foo函数的this强制绑定在obj对象上。这里还有一点注意,上面的bind是一个简单的辅助绑定函数,但是却能体现bind函数的原理,即bind函数作为一个包装的函数,调用它返回真正处理绑定的函数,所以调用bar函数并传入参数时才将foo函数的绑定在obj。
4 new绑定
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2
使用new来进行构造函数调用产生新对象,则这个新对象会绑定到函数调用的this。
通过以上4种情况可以判断函数在某个调用位置的this指向。上面4中情况的优先级从高到低分别是:
1 new 调用
2 call或者apply(或者bind)调用
3 上下文对象调用,
4 默认调用
即如果在调用位置有两种情况同时发生,this的绑定对象取决于优先级高的一种情况。
欢迎互相交流,互相学习。前端开发QQ群:711357426
JavaScript语法——this
原文:https://www.cnblogs.com/emptylee/p/9332862.html