我正在尝试理解foo.bar()
和var fn = foo.bar; fn();
我已经把一个小例子放在一起,但我不完全理解为什么失败的那些实际上失败了。
var Dog = function() {
this.bark = "Arf";
};
Dog.prototype.woof = function() {
$('ul').append('<li>'+ this.bark +'</li>');
};
var dog = new Dog();
// works, obviously
dog.woof();
// works
(dog.woof)();
// FAILS
var fnWoof = dog.woof;
fnWoof();
// works
setTimeout(function() {
dog.woof();
}, 0);
// FAILS
setTimeout(dog.woof, 0);
产生:
在JSFiddle上:http://jsfiddle.net/D6Vdg/1/
因此,看起来捕捉一个函数会导致它删除它的上下文。好。但是为什么(dog.woof)();
会起作用?
只是有点混乱,弄清楚这里发生了什么。显然有一些我没有得到的核心语义。
答案 0 :(得分:5)
问题在于上下文和this
关键字。
函数本身并不属于对象。例如,我可以创建一个cat对象并将woof函数复制到:
var cat = {
bark: "meow",
woof = Dog.prototype.woof
};
现在cat.woof
会给我“喵”。由于要复制和重新分配函数的这种灵活性,var fnWoof = dog.woof;
将fnWoof
与dog
取消关联 - 它没有上下文。因此,上下文和this
关键字默认为window
。由于window
没有bark
属性,因此您获得undefined
。
如果你给窗口一个树皮属性:
window.bark = "Arf";
然后你的代码会起作用(虽然错误):
fnWoof(); // "Arf"
为了使其按预期工作,您可以传递上下文 explicity :
fnWoof.call(dog);
答案 1 :(得分:0)
在foo.bar()
中,调用函数时将值foo
作为this
的值。
使用var fn = foo.bar; fn();
时,使用null
作为this
的值调用该函数,该值在评估this
时自动强制转换为全局对象。
规范的相关部分如下。特别参见7.如果它是属性引用(即a.b
或a[b]
之类的表达式),则thisValue将成为属性引用的基础。
生产CallExpression:MemberExpression Arguments的计算方法如下:
一个。如果IsPropertyReference(ref)为true,则将thisValue设为GetBase(ref)。
湾否则,ref的基础是一个环境记录,所以让thisValue成为调用GetBase(ref)的ImplicitThisValue具体方法的结果。
答案 2 :(得分:0)
dog.woof
必须在Dog
的实例上下文中运行,因为它取决于this.bark
,因为您似乎已经知道了
Dog.prototype.woof2 = function() {$('ul').append('<li>'+ 'arf' +'</li>'); };
如果您将失败的woof
替换为woof2
,则可以随处运行
对于案例(dog.woof)();
vs var fnWoof = dog.woof; fnWoof();
,它有点违反直觉。不同之处在于作业。第一种情况仍然将其视为属于dog
,而第二种情况则不属于woof
。分配时间需要{{1}}并将其置于不同的常量中,而不仅仅是访问它。
答案 3 :(得分:0)
这是一个特别令人困惑的代码,出于多种原因,我将尝试解释。
首先...... setTimeOut方法有点像PITA,如下所述:http://ifhere.org/javascript
您使用setTimeout(dog.woof, 0);
时遇到的问题是因为setTimeOut,而不是您的代码(完全不是您的代码)。
主要问题是dog.woof
正在执行,它是未定义的bark
的值以及它未定义的原因是因为您将函数本身作为参数传递,而不是功能,因为它附加到变量狗。
两者:
var fnWoof = dog.woof;
和
setTimeout(dog.woof, 500);
您正在传递 函数定义 ,而不是实例化对象及其相关函数。