【问题标题】:JavaScript class and invocation contextJavaScript 类和调用上下文
【发布时间】:2012-02-13 08:15:17
【问题描述】:

谁能帮我解释一下为什么第一个例子有效,而第二个无效。

示例 1:

// Define a class
function Foo(name) {
  var self = this;

  this.name = name;
  this.greeting = function() {
    console.log('Hello ' + self.name);
  }
}

var foo = new Foo('foo');
foo.greeting();

var greeting = foo.greeting;
greeting();

输出:

Hello foo
Hello foo

示例 2:

// Define a class
function Foo(name) {
  this.name = name;
}

// Greeting
Foo.prototype.greeting= function () {
  console.log('Hello ' + this.name);
}

var foo = new Foo('foo');
foo.greeting();

var greeting = foo.greeting;
greeting();

输出:

Hello foo
Hello undefined

我的猜测是因为第一个示例使用了闭包,所以它保留了对 name 局部变量的引用,但第二个示例没有,并且由于在没有对象上下文的情况下调用 greeting() 方法,它默认为undefined.

【问题讨论】:

标签: javascript class object closures


【解决方案1】:

this 的解析延迟到 JavaScript 中的执行时间。

通过将foo.greeting 设置为greeting,然后执行greeting(),您将在全局上下文中执行greeting();其中this 指向window除非您在严格模式下运行 而不是您的Foo 实例。因此,在greeting() 内部,它正在寻找window.name;并返回undefined.

更详细的解释见this on MDC

【讨论】:

  • 它也不回答 OP 的问题。
【解决方案2】:

在JavaScript中有四种调用函数的方式,每一种方式都会改变函数内部this的值:

  1. 作为全局函数调用:greeting()this 的值是全局 window 对象(在浏览器中)。

  2. 作为某个对象的方法foo.greeting()this 的值是 . 运算符左侧的对象实例 (foo)。

  3. 作为构造函数new greeting()this 的值是从函数创建并隐式返回的新对象。这用于创建新对象。

  4. 使用 callapplygreeting.apply(someVal, someArgs)this 的值是作为第一个参数 (someVal) 传递的对象。

任何函数都可以以这四种方式中的任何一种方式执行(尽管并非所有函数都应该在其中一些方式中执行)。

在第一种情况下,您正在执行方法调用:

var foo = new Foo('foo');
foo.greeting();

...所以this 在函数内部是foo。在第二种情况下,您正在执行全局函数调用:

var greeting = foo.greeting;
greeting();

...所以this 在函数内部是window

编辑:注意@jAndy 的回答指出了在这种情况下更突出的问题,即greeting 在第一个示例中关闭了self(不管它如何调用),但在第二个中没有(这使得 如何 函数被称为相关)。

【讨论】:

  • @Matt - 非常正确,尽管bind 没有调用函数;它创造了一个。
  • 无论如何它都不回答 OP 的问题。
  • @jAndy - 哈!所以它没有。好电话。
  • @jAndy - 留下我的答案只是因为它仍然与 OP 的第二个示例相关。此外,还添加了一条指向您的答案的注释。
【解决方案3】:

第二个greeting() 在全局范围内执行,因此this 是窗口对象(函数执行的范围相同,window.name 未定义)。如果您通过apply()call() 传递上下文,它会再次起作用,例如。

var greeting = foo.greeting;
greeting.apply(foo);

【讨论】:

    【解决方案4】:

    许多答案,都有有用且正确的信息,但没有一个能正确解释行为。

    在您的第一个示例中,它只记录 Hello foo 两次,因为您正在创建一个引用 this 对象的变量 self。然后 self 变量在您的 greeting function 中关闭。因此,您可以随心所欲地调用该函数,它将始终访问 self.name 而不是 this.name,因此它始终相同。

    您在prototype 示例中没有这样做。在那里您可以直接访问this.name,然后如何调用该函数确实很重要(请参阅@lwburk 答案)。

    同样,即使您将第一个示例称为

    foo.greeting.call( window );
    

    它仍然会访问封闭的self 变量并记录Hello foo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-29
      • 2021-10-13
      • 2013-01-07
      • 1970-01-01
      • 2015-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多