this
我给自己总结一下,this。“this“是一种动态灵活的机制。它在函数调用时确定,与调用方式有关,而非词法作用域。我这里使用DC的说法对应的另一种说法。即函数的this绑定分为隐式绑定、显式绑定、默认绑定、new绑定。下分别说明:
1、默认绑定。就是不加任何修饰的使用函数。
var foo = function () { console.log(this.a); //global }; var a = "global value";
this在非严格模式下绑定在window上,严格模式下绑定于undefined。当然这要在函数体中使用"use strict";才管用。
2、隐式绑定。这种方式是在函数作为对象方法的时候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";
但是会出现绑定丢失的情况,因为安置传递后变为了默认绑定的形式。
3、显式绑定。我直接指定函数调用的this值,当然直接使用apply、call没有问题,若使用bind方法后还是可以被new绑定改变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);
};
那么如何不让它改变,采用所谓的硬绑定来定。即外加一个包装函数。
一些api可直接指定函数调用的this。
[1 , 2, 3, 23].forEach(function (a) { console.log(a, this.info)}, {info: "outter"}); //结果 1 "outter" 2 "outter" 3 "outter" 23 "outter"
4、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。