// explicit property definition of // the global object this.a = 10; // global.a = 10 console.log(a); // 10 // implicit definition via assigning // to unqualified identifier b = 20; console.log(this.b); // 20 // also implicit via variable declaration // because variable object of the global context // is the global object itself var c = 30; console.log(this.c); // 30
var foo = {x: 10}; var bar = { x: 20, test: function () { console.log(this === bar); // true console.log(this.x); // 20 this = foo; // error, can't change this value console.log(this.x); // if there wasn't an error, then would be 10, not 20 } }; // on entering the context this value is // determined as "bar" object; why so - will // be discussed below in detail bar.test(); // true, 20 foo.test = bar.test; // however here this value will now refer // to "foo" – even though we're calling the same function foo.test(); // false, 10
function foo() { console.log(this); } foo(); // global console.log(foo === foo.prototype.constructor); // true // but with another form of the call expression // of the same function, this value is different foo.prototype.constructor(); // foo.prototype
这和对象上定义的方法相似,this的值不总是为那个对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var foo = { bar: function () { console.log(this); console.log(this === foo); } }; foo.bar(); // foo, true var exampleFunc = foo.bar; console.log(exampleFunc === foo.bar); // true // again with another form of the call expression // of the same function, we have different this value exampleFunc(); // global, false
所以调用表达式是如何影响this的值?为了完全的理解如何影响this值,我们需要了解一种内部类型– 引用类型( Referece type ).
var fooReference = { base: global, propertyName: 'foo' }; var barReference = { base: global, propertyName: 'bar' };
为了从引用类型的到对象真正的值,还需要经过getValue方法,伪代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
function GetValue(value) { if (Type(value) != Reference) { return value; } var base = GetBase(value); if (base === null) { throw new ReferenceError; } return base.[[Get]](GetPropertyName(value));
其中的内部方法[[Get]]返回这个对象属性的真正值,这和从原型链上获取属性的分析相同.
1 2
GetValue(fooReference); // 10 GetValue(barReference); // function object "bar"
属性访问器也有两种类型:点标记(当提前知道属性名为一个合理的标识符名时),或者方括号标记:
1 2
foo.bar(); foo['bar']();
在返回的中间计算过程中,我们可以得到也可以得到引用类型的值
1 2 3 4 5 6
var fooBarReference = { base: foo, propertyName: 'bar' }; GetValue(fooBarReference); // function object "bar"
function foo() { console.log(this); } foo(); // global, because var fooReference = { base: global, propertyName: 'foo' }; console.log(foo === foo.prototype.constructor); // true // another form of the call expression foo.prototype.constructor(); // foo.prototype, because var fooPrototypeConstructorReference = { base: foo.prototype, propertyName: 'constructor' };
其他this值例子:
1 2 3 4 5 6 7 8 9 10 11 12
function foo() { console.log(this.bar); } var x = {bar: 10}; var y = {bar: 20}; x.test = foo; y.test = foo; x.test(); // 10 y.test(); // 20
try { throw function () { console.log(this); }; } catch (e) { e(); // __catchObject - in ES3, global - fixed in ES5 } // on idea var eReference = { base: __catchObject, propertyName: 'e' }; // but, as this is a bug // then this value is forced to global // null => global var eReference = { base: global, propertyName: 'e' };
同样的也发生在具名函数表达式递归调用中.
1 2 3 4 5 6 7
(function foo(bar) { console.log(this); !bar && foo(1); // "should" be special object, but always (correct) global })(); // global
构造器函数中的this值
和this相关的更多是在构造函数中this值.
1 2 3 4 5 6 7
function A() { console.log(this); // newly created object, below - "a" object this.x = 10; } var a = new A(); console.log(a.x); // 10