'this'是Javascript中的全局对象的情况

时间:2010-11-28 03:27:23

标签: javascript

我正在玩不同的方法来调用一个函数,该函数是Javascript中Object的一个属性,并查看哪个类型的调用将'this'设置为Object,并将'this'设置为Global Object

这是我的测试代码:

var foo = {
  bar: function(){ 
    console.log('this:' + this);
  }
}

console.log('calling foo.bar()');
foo.bar();

console.log('\ncalling (foo.bar)()');
(foo.bar)();

console.log('\ncalling f=foo; f.bar()');
f = foo; f.bar();

console.log('\ncalling f=foo.bar; f()');
f = foo.bar; f();

console.log('\ncalling (f=foo.bar)()');
(f = foo.bar)();

这就是结果:

calling foo.bar()
this:[object Object]

calling (foo.bar)()
this:[object Object]

calling f=foo; f.bar()
this:[object Object]

calling f=foo.bar; f()
this:[object global]

calling (f=foo.bar)()
this:[object global]

我的问题是,为什么f=foo.bar; f();(f=foo.bar)();将'this'指定为全局对象

4 个答案:

答案 0 :(得分:10)

了解this对函数调用的隐式行为的关键,依赖于知道Reference Type如何工作。

引用类型包含两个组件(在ECMAScript 3中),基础对象属性名称(在ECMAScript 5中,它严格标志的第三个组成部分 - 我将在稍后讨论严格模式 - (1))。

function is invoked时,通过获取引用的基础对象(通过内部this操作)隐式确定GetBase值。

例如,在foo.bar引用中,基础对象foo属性名称"bar":< / p>

foo.bar(); // `this` will point to `foo`

当您执行任务时,引用将丢失,我们不再拥有基础对象属性名称,我们只有

(f=foo.bar)(); // `this` will point to the global object

仅在分配时不会发生,它与使用内部GetValue操作的其他操作一起发生:

// `this` will point to the global object    
(0, foo.bar)();   // The Comma Operator
(0 || foo.bar)(); // Binary Logical Operators
(1 && foo.bar)();
// etc..

例如,如果用括号括起引用(正式称为The Grouping Operator),则不会发生这种情况:

(foo.bar)(); // `this` will point to `foo`

分组运算符(再次,括号;)在内部不使用GetValue,这是以这种方式设计的,因为允许typeofdelete运算符与< em>带括号的表达式:

delete (foo.bar);

如果分组运算符使用GetValue,则delete运算符将无法获取基础对象删除属性bar的位置。

返回隐式this值,有一些棘手的情况,例如,使用with语句:

with (foo) {
  bar(); // `this` will refer to `foo` !
}

如您所见,在with块内调用bar();仍会将this值绑定到foo对象。

引用未设置this值,它来自当前的环境记录(我稍后可能会写一些关于它的内容)由with声明引入。

另外,正如您可能注意到的,对于非引用this值将指向全局对象,例如:

(function () {})(); // this will point to the global object

我们只有,而不是引用(请记住,引用是已解析的名称绑定)。


(1) 注意:在ECMAScript 5 严格模式上,this值为undefined 全部所描述的案例,this值隐式设置为Global对象。

这是一个安全措施,主要是因为人们在调用构造函数时经常忘记使用new运算符,导致不良行为和对全局范围的污染。

例如:

function Foo () {
  this.prop = 'foo';
}
Foo(); // no `new` operator, boom!

如您所知,Foo引用没有直接基础对象this将指向全局对象,它将无意中创建一个属性它

在严格模式下,代码只会为您提供TypeError,因为this值为undefined

同样你可能还记得在开始时我提到过参考类型有第三个组件,strict标志。

您的原始示例:

(f=foo.bar)();

可能甚至不能在严格模式下工作,因为不允许对未声明的标识符(例如f )的分配(例如),(另一种避免全局对象污染的安全措施)。

更多信息:

答案 1 :(得分:3)

在前3个示例中,您使用foo对象并运行其函数,从而获得运行函数的上下文,Objectfoo对象。 / p>

在最后两个示例中,您将foo.bar函数复制到变量f并执行它。在这种情况下,函数从全局上下文执行,而不是从foo Object上下文执行。  它与声明和运行

相同
  function f() { 
    console.log('this:' + this);
  }

答案 2 :(得分:3)

答案 3 :(得分:2)

前三种情况和后两种情况之间的区别在于您将条形函数存储在变量中。函数不“知道”它们是对象的属性。所以在最后两种情况下,你只是调用常规函数。

在最后两种情况下,您可以通过使用Function.call或function.apply使“this”引用“foo”

f.call(foo)

通过呼叫和应用,您可以控制您正在呼叫的功能中“this”所指的内容。

虽然函数不知道它们是否附加到某个对象上,但它们确实知道它们声明的范围。你可以根据它做很多有用的东西。在最后一个示例中,您通过执行(f = foo.bar)()创建新范围,但它没有任何效果。