我正在玩不同的方法来调用一个函数,该函数是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'指定为全局对象
答案 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
,这是以这种方式设计的,因为允许typeof
和delete
运算符与< 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
对象并运行其函数,从而获得运行函数的上下文,Object
,foo
对象。 / 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)()创建新范围,但它没有任何效果。