一 , this的默认绑定
当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象.
一个例子
function fire () {
// 我是被定义在函数内部的函数哦!
function innerFire() {
console.log(this === window)
}
innerFire(); // 独立函数调用
}
fire(); // 输出true
//即使函数innerFire是包含在函数fire里面的,但是由于函数innerFire是独立调用,所以函数innerFire内的this还是指向window.
二 , this的隐式绑定
当函数被一个对象“包含”的时候,我们称函数的this被隐式绑定到这个对象里面了,这时候,通过this可以直接访问所绑定的对象里面的其他属性
第一个例子
var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
//函数fire包含在对象obj里,所以this就隐式绑定到对象obj.this就可以访问obj的属性.
第二个例子
// 我是第一段代码
function fire () {
console.log(this.a)
}
var obj = {
a: 1,
fire: fire
}
obj.fire(); // 输出1
// 我是第二段代码
var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
//这个例子说明了函数被定义在对象内部和外部没有任何区别.也说明了this绑定是动态的(在运行时绑定而不是书写时)
隐式绑定丢失的问题
一个例子
var obj = {
a: 1, // a是定义在对象obj中的属性 1
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 2
var fireInGrobal = obj.fire;
fireInGrobal(); // 输出 2
可以这么理解,函数在成为对象的属性的时候,是具有独立性的.打个比方就像当初波兰加入了华约,波兰是华约的一份子,但他并不是华约缔造的.后来苏联解体,华约的一部分*范围,不是全部(俄罗斯就不是)变成了北约的*范围了.于是波兰加入了北约,和新的大哥混了.回到这个函数,对象obj
就是华约,函数fire
就是波兰,属性a:1
就是俄罗斯.现在,曾经的华约*范围obj.fire
变成了以世界警察fireInGrobal
为首的北约的地盘,于是波兰加入北约,听候大哥fireInGrobal
的差遣.大哥问,谁才是老大?fireInGrobal()
,波兰高呼Americana = 2
.
其实多数情况下,是不会发生this绑定丢失的,只有一种情况下会丢失,函数没有执行,当做值传递了。不管是赋值操作,还是当做回调函数的参数传递。
三 , this的显示绑定
在上一个例子中,fireInGrobal()
和obj.fire
调用的结果是不同的,在赋值过程中,this绑定丢失了.call就是为了解决这个问题的.
call的基本使用方式: fn.call(object)
fn : 上一例子中的 fireInGrobal
**object : 上一例子中的 obj
**
作用 : 大哥问谁是老大,波兰说是俄罗斯(重新把this
绑定回obj
)
一个例子
var obj = {
a: 1, // a是定义在对象obj中的属性
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量
var fireInGrobal = obj.fire;
fireInGrobal(); // 输出2
fireInGrobal.call(obj); // 输出1
每次执行都要加入call
吗?很麻烦.我们可以这样改一下
var obj = {
a: 1, // a是定义在对象obj中的属性
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量
var fn = obj.fire;
var fireInGrobal = function () {
fn.call(obj) //硬绑定
}
fireInGrobal(); // 输出1
如果使用bind
,会更简单
//上一个例子中的代码
var fireInGrobal = function () {
fn.call(obj) //硬绑定
}
//可以简化为
var fireInGrobal = fn.bind(obj);
call和bind的区别是:在绑定this到对象参数的同时:
1.call将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数
3.当然还有apply,他们的区别是这样的:
- 他们的作用一模一样,区别在于传入参数形式不同.
- apply接受两个参数,第一个指定this对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply把这个集合中的元素作为参数传递给被调用的函数.
var func = function( a, b, c ){
alert([a,b,c]); //输出[1,2,3]
};
func.apply( null, [ 1, 2, 3 ] );
- call传入的参数不固定,与apply相同的是,第一个参数也是代表函数体内的this指向,从第二个参数开始往后,每个参数被依次传入函数.
var func = function( a, b, c ){
alert([a,b,c]); //输出[1,2,3]
};
func.call( null, 1, 2, 3 );
- 当使用call或apply的时候,如果第一个参数是null,this会指向默认宿主对象,在浏览器中就是window.
四 , new绑定
执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象.
例子
function foo (a) {
this.a = a;
}
var a1 = new foo (1);
var a2 = new foo (2);
var a3 = new foo (3);
var a4 = new foo (4);
console.log(a1.a); // 输出1
console.log(a2.a); // 输出2
console.log(a3.a); // 输出3
console.log(a4.a); // 输出4
如果构造函数显式使用return
返回一个对象,那么调用表达式的值就是这个对象
var obj = {a:1};
function fn(){
this.a = 2;
return obj;
}
var test = new fn();
console.log(test);//{a:1}