了解 Javascript 调用函数和返回函数但稍后执行它之间的区别
我试图理解 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);
生成:
- Arf
- Arf
- undefined
- Arf
- undefined
在 JSFiddle 上: http://jsfiddle.net/D6Vdg/1/
所以看来,关闭一个函数会导致它删除它的上下文。好的。但为什么 (dog.woof)();
有效呢?
弄清楚这里发生的事情有点令人困惑。显然有一些核心语义我还没有理解。
I'm trying to understand the difference between foo.bar()
and var fn = foo.bar; fn();
I've put together a little example, but I dont totally understand why the failing ones actually fail.
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);
Which produces:
- Arf
- Arf
- undefined
- Arf
- undefined
On JSFiddle: http://jsfiddle.net/D6Vdg/1/
So it appears that snapping off a function causes it to remove it's context. Ok. But why then does (dog.woof)();
work?
It's all just a bit confusing figuring out whats going on here. There are obviously some core semantics I'm just not getting.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
问题出在上下文和
this
关键字上。函数本质上并不“属于”对象。例如,我可以创建一个 cat 对象并复制 woof 函数:
现在
cat.woof
会给我“meow”。由于复制和重新分配函数的灵活性,var fnWoof = dog.woof;
将fnWoof
与dog
解除关联 - 它没有语境。因此,上下文和this
关键字默认为window
。由于window
没有bark
属性,因此您会得到undefined
。如果你给窗口一个 bark 属性:
那么你的代码将会工作(尽管是错误的):
为了使其按预期工作,你可以传入上下文explicity:
The problem is with context and the
this
keyword.Functions don't inherently "belong" to an object. For example, I can create a cat object and copy the woof function over:
Now
cat.woof
will give me "meow". Because of this flexibility of functions to be copied and re-assigned,var fnWoof = dog.woof;
disassociatesfnWoof
fromdog
- it has no context. Therefore the context, and thethis
keyword, defaults towindow
. Sincewindow
doesn't have abark
property, you getundefined
.If you give window a bark property:
Then your code will work (although erroneously):
To make it work as expected, you can pass in the context explicity:
dog.woof
必须在Dog
实例的上下文中运行,因为它依赖于this.bark
,正如您似乎理解的那样将那些失败的
woof
替换为woof2
它可以在任何地方运行至于
(dog.woof)();
与var fnWoof 的情况= 狗.woof; fnWoof();
这有点违反直觉。区别在于任务。第一种情况仍然将其视为属于dog
运行,而第二种情况则不然。赋值时间需要woof
并将其放入不同的常量中,而不仅仅是访问它。dog.woof
has to be run in the context of an instance ofDog
because it depends onthis.bark
, as you seem to understnadIf you replace those failing
woof
withwoof2
it could run anywhereAs for the case
(dog.woof)();
vsvar fnWoof = dog.woof; fnWoof();
it is kind of counterintuitive. The difference is the assignment. The first case still runs it as belonging todog
, whereas the second does not. It is assignment time that takeswoof
and puts it into a different constant, not merely accessing it.在
foo.bar()
中,调用该函数时将foo
的值作为this
的值。使用 var fn = foo.bar; fn(); 该函数以
null
作为this
的值进行调用,当this
时,该函数会自动强制转换为全局对象被评估。规范的相关部分如下。特别参见 7。如果它是属性引用(即像
ab
或a[b]
这样的表达式),则 thisValue 将成为属性引用的基础。11.2.3 函数调用
产生式 CallExpression : MemberExpression Arguments 的计算如下:
In
foo.bar()
, the function is called with the value offoo
as the value ofthis
.With
var fn = foo.bar; fn();
the function is called withnull
as the value ofthis
which is automatically coerced to the global object whenthis
is evaluated.The relevant portion of the spec is below. See especially 7. If it's a property reference (i.e. an expression like
a.b
ora[b]
), then thisValue becomes the base of the property reference.11.2.3 Function Calls
The production CallExpression : MemberExpression Arguments is evaluated as follows:
这是一段特别令人困惑的代码,原因有很多,我将尝试解释一下。
首先... setTimeOut 方法有点像 PITA,如下所述: http://ifhere.org/javascript
您遇到的
setTimeout(dog.woof, 0);
问题是因为 setTimeOut,而不是您的代码(也不完全是您的代码)。主要问题是
dog.woof
正在执行,而bark
的值未定义,它未定义的原因是因为您将函数本身传递为参数,而不是附加到变量dog 的函数。在两者中:
您
传递的是函数定义,而不是实例化对象及其关联函数。
This is a particularly confusing bit of code for a number of reasons that I'll try to explain.
First... the setTimeOut method is a bit of a PITA as explained here: http://ifhere.org/javascript
The issue you're having with the
setTimeout(dog.woof, 0);
is because of setTimeOut, not your code (well not entirely your code).The main issue tho is that the
dog.woof
is getting executed, it's the value ofbark
that is undefined and the reason it's undefined is because you are passing the function itself as the parameter, not the function as it is attached to the variable dog.in both:
and
you are passing the function definition as opposed to the instantiated object and it's associated function.