了解 Javascript 调用函数和返回函数但稍后执行它之间的区别

发布于 2024-10-11 07:39:51 字数 811 浏览 3 评论 0原文

我试图理解 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

请爱~陌生人 2024-10-18 07:39:51

问题出在上下文和 this 关键字上。

函数本质上并不“属于”对象。例如,我可以创建一个 cat 对象并复制 woof 函数:

var cat = {
    bark: "meow",
    woof = Dog.prototype.woof
};

现在 cat.woof 会给我“meow”。由于复制和重新分配函数的灵活性,var fnWoof = dog.woof;fnWoofdog 解除关联 - 它没有语境。因此,上下文和 this 关键字默认为 window。由于 window 没有 bark 属性,因此您会得到 undefined

如果你给窗口一个 bark 属性:

window.bark = "Arf";

那么你的代码将会工作(尽管是错误的):

fnWoof(); // "Arf"

为了使其按预期工作,你可以传入上下文explicity

fnWoof.call(dog);

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:

var cat = {
    bark: "meow",
    woof = Dog.prototype.woof
};

Now cat.woof will give me "meow". Because of this flexibility of functions to be copied and re-assigned, var fnWoof = dog.woof; disassociates fnWoof from dog - it has no context. Therefore the context, and the this keyword, defaults to window. Since window doesn't have a bark property, you get undefined.

If you give window a bark property:

window.bark = "Arf";

Then your code will work (although erroneously):

fnWoof(); // "Arf"

To make it work as expected, you can pass in the context explicity:

fnWoof.call(dog);
心如狂蝶 2024-10-18 07:39:51

dog.woof 必须在 Dog 实例的上下文中运行,因为它依赖于 this.bark,正如您似乎理解的

Dog.prototype.woof2 = function() {$('ul').append('<li>'+ 'arf' +'</li>'); }; 

那样将那些失败的 woof 替换为 woof2 它可以在任何地方运行

至于 (dog.woof)();var fnWoof 的情况= 狗.woof; fnWoof(); 这有点违反直觉。区别在于任务。第一种情况仍然将其视为属于 dog 运行,而第二种情况则不然。赋值时间需要 woof 并将其放入不同的常量中,而不仅仅是访问它。

dog.woof has to be run in the context of an instance of Dog because it depends on this.bark, as you seem to understnad

Dog.prototype.woof2 = function() {$('ul').append('<li>'+ 'arf' +'</li>'); }; 

If you replace those failing woof with woof2 it could run anywhere

As for the case (dog.woof)(); vs var fnWoof = dog.woof; fnWoof(); it is kind of counterintuitive. The difference is the assignment. The first case still runs it as belonging to dog, whereas the second does not. It is assignment time that takes woofand puts it into a different constant, not merely accessing it.

浮生未歇 2024-10-18 07:39:51

foo.bar() 中,调用该函数时将 foo 的值作为 this 的值。
使用 var fn = foo.bar; fn(); 该函数以 null 作为 this 的值进行调用,当 this 时,该函数会自动强制转换为全局对象被评估。

规范的相关部分如下。特别参见 7。如果它是属性引用(即像 aba[b] 这样的表达式),则 thisValue 将成为属性引用的基础。

11.2.3 函数调用

产生式 CallExpression : MemberExpression Arguments 的计算如下:

  1. 列表项
  2. 令 ref 为计算 MemberExpression 的结果。
  3. 令 func 为 GetValue(ref)。
  4. 令 argList 为计算参数的结果,生成参数值的内部列表(参见 11.2.4)。
  5. 如果 Type(func) 不是 Object,则抛出 TypeError 异常。
  6. 如果 IsCallable(func) 为 false,则抛出 TypeError 异常。
  7. 如果 Type(ref) 是 Reference,则

a.如果 IsPropertyReference(ref) 为 true,则让 thisValue 为 GetBase(ref)。

b.否则,ref 的基础是环境记录,因此让 thisValue 为调用 GetBase(ref) 的 ImplicitThisValue 具体方法的结果。

In foo.bar(), the function is called with the value of foo as the value of this.
With var fn = foo.bar; fn(); the function is called with null as the value of this which is automatically coerced to the global object when this 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 or a[b]), then thisValue becomes the base of the property reference.

11.2.3 Function Calls

The production CallExpression : MemberExpression Arguments is evaluated as follows:

  1. List item
  2. Let ref be the result of evaluating MemberExpression.
  3. Let func be GetValue(ref).
  4. Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).
  5. If Type(func) is not Object, throw a TypeError exception.
  6. If IsCallable(func) is false, throw a TypeError exception.
  7. If Type(ref) is Reference, then

a. If IsPropertyReference(ref) is true, then Let thisValue be GetBase(ref).

b. Else, the base of ref is an Environment Record so Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).

清旖 2024-10-18 07:39:51

这是一段特别令人困惑的代码,原因有很多,我将尝试解释一下。

首先... setTimeOut 方法有点像 PITA,如下所述: http://ifhere.org/javascript

您遇到的 setTimeout(dog.woof, 0); 问题是因为 setTimeOut,而不是您的代码(也不完全是您的代码)。

主要问题是 dog.woof 正在执行,而 bark 的值未定义,它未定义的原因是因为您将函数本身传递为参数,而不是附加到变量dog 的函数。

在两者中:

var fnWoof = dog.woof;

setTimeout(dog.woof, 500);

传递的是函数定义,而不是实例化对象及其关联函数。

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 of bark 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:

var fnWoof = dog.woof;

and

setTimeout(dog.woof, 500);

you are passing the function definition as opposed to the instantiated object and it's associated function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文