THIS
我给自己总结一下,this。“this“是一种动态灵活的机制。它在函数调用时确定,与调用方式有关,而非词法作用域。我这里使用DC的说法对应的另一种说法。即函数的this绑定分为隐式绑定、显式绑定、默认绑定、new绑定。下分别说明:
默认绑定
就是不加任何修饰的使用函数。 this在非严格模式下绑定在window上,严格模式下绑定于undefined。当然这要在函数体中使用”use strict”;才管用。
var foo = function () {
console.log(this.a); //global
};
var a = "global value";
隐式绑定
这种方式是在函数作为对象方法的时候this变为这个对象,但是会出现绑定丢失的情况,因为安置传递后变为了默认绑定的形式。
var foo = function () {
console.log(this.a); //global
};
var a = "global value";
var obj = {
a: "object",
foo: foo
};
obj.foo(); //"object"
//绑定丢失
var bar = obj.foo;
bar(); //"global value";
//函数传递参数也是按值传递的,从而也会丢失绑定
setTimeout(obj.foo, 1000) //"global value";
显式绑定
我直接指定函数调用的this值,当然直接使用apply、call没有问题,若使用bind方法后还是可以被new绑定改变this值。那么如何不让它改变,采用所谓的硬绑定来定。即外加一个包装函数。一些api可直接指定函数调用的this。
var foo = function () {
console.log(this.a); //global
};
var a = "global value";
var obj = {
a: "object",
foo: foo
};
foo.apply(obj) //"object"
//丢失的例子
foo = function (v) {
this.value = v;
};
var boo = foo.bind(obj);
var bar = new boo("text");
bar.value === "text" //true
obj.value === undefined //true
//加上包装函数使得不可变
var hardbind = function () { //无论如何调用外层函数均不会改变
foo.apply(obj);
};
new绑定(略过)
有趣的问题
有时我们想借用某个方法,但又不在乎this值那可以使用null、undefined作为参数,但实际上却被绑定在全局对象上,这是始料未及的。见例子。
function foo (a) {
this.a = a;
}
foo.apply(null, "where"); //这时的window.a为"where".
那我不想改变任何有用的对象怎么办呢?见例子:
var π = Object.create(null); //我将this定于这里之后,不会对其他任何对象有影响。
我想要一种绑定方式:在默认下不会绑定在undefined或是window,同时又可以在其它绑定下修改this值
(!Function.prototype.softbind) {
Function.prototype.softbind = function (obj) {
var fn = this;
var curried =Array.prototype.slice.call(arguments, 1);
var bound = function () {
return fn.apply((!this || this === window) ? obj : this,
curried.concat.apply(curried, arguments)); //关键步骤
};
bound.prototype = fn.prototype;
return bound;
};
}
var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"};
var foo = function () {
console.log(this.name);
};
var ins = foo.softbind(obj1);
ins(); //"obj1";
obj1.foo = ins;
obj1.foo(); //"obj1";
obj2.foo = obj1.foo;
obj2.foo(); //"obj2", 因为外层函数执行的this是obj2,这时函数执行时的this不变,为obj2。
setTimeout(obj2.foo, 1000); //"obj1",原因是:obj2.foo传入后变为了默认绑定,bound函数执行的this原本应是window(这里没有使用严格模式),关键步骤中将对应的this替换为预先
//的obj1。