原文地址:http://www.moye.me/2014/11/21/也说this/
Any sufficiently advanced technology is indistinguishablefrom magic.
—Arthur C.Clarke
老爷子所言不虚,各种技术里都有黑魔法,比如javaScript,就有着像this这样的奇葩存在。
this是什么?大概能得到的答案有:
哪种解释是对的呢?来看段代码:
function foo() { console.log(this.a);}var a = 2;var obj = {a: 1};foo(); // 2 (在Node下是undefined)foo.call(obj); // 1obj.foo = foo;obj.foo(); // 1
在这段代码中,this 呈现了三种可能:
看起来是要有无限可能的节奏……好在我提前找到了这本书:
To learn this, you first have to learn what this is not, despite anyassumptions or misconceptions that may lead you down those paths.this is neither a reference to the function itself, nor is it a referenceto the function’s lexical scope.
this is actually a binding that is made when a function is invoked, andwhat it references is determined entirely by the call-site where thefunction is called.
this 实质上是一种绑定(binding)机制,只关乎函数被调用时所处的 上下文(context),而不关心它在哪里被定义。举个粟子:
function foo(something) { this.a = something;}var obj1 = { foo: foo};var obj2 = {};obj1.foo( 2 );console.log( obj1.a ); // 2obj1.foo.call( obj2, 3 );console.log( obj2.a ); // 3var bar = new obj1.foo( 4 );console.log( obj1.a ); // 2console.log( bar.a ); // 4
this做为一个被绑定的context,甚至与函数依附的对象无关,通过obj1.foo.call( obj2, 3 )
一句我们能看清:这个context被引入,函数既可以读也可以修改它,但这里涉及到一个优先级问题,即:为什么 obj1绑定的this.a 没有被foo()改写,却是 obj2的 this.a?
绑定 this 的形式大概有以下几种,它们的优先级如下排列:
var bar = new foo();
var bar = foo.call( obj2 );
var bar = obj1.foo();
var bar = foo();
对于闭包惯用的self = this
技俩,You Don't Know JS一书是不提倡的,它的建议是:
Embrace this-style mechanisms completely, including usingbind(..)where necessary, and try to avoid self = this...
Function.prototype.bind,它的实现看起来是这样的:
if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError( "Function.prototype.bind - what is trying " + "to be bound is not callable" ); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () { }, fBound = function () { return fToBind.apply( (this instanceof fNOP && oThis ? this : oThis), aArgs.concat(Array.prototype.slice.call(arguments)) ) }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; };}
更多文章请移步我的blog新地址:http://www.moye.me/
新闻热点
疑难解答