JavaScript类和调用上下文

rea*_*ess 4 javascript closures class object

有人可以帮我解释为什么第一个例子有效,但第二个例子没有.

例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();
Run Code Online (Sandbox Code Playgroud)

输出:

Hello foo
Hello foo
Run Code Online (Sandbox Code Playgroud)

例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();
Run Code Online (Sandbox Code Playgroud)

输出:

Hello foo
Hello undefined
Run Code Online (Sandbox Code Playgroud)

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

jAn*_*ndy 6

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

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

你不要在你的prototype例子中这样做.在那里,你直接访问this.name,然后它是的确很重要如何将调用该函数(见@lwburk答案).

所以,即使你把第一个例子称为

foo.greeting.call( window );
Run Code Online (Sandbox Code Playgroud)

它仍然可以访问闭包self变量和日志Hello foo.


Way*_*ett 5

有四种方法可以在JavaScript中调用函数,每种方法都会更改this函数内部的值:

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

  2. 作为某种对象的方法:foo.greeting().值this.operator(foo)左侧的对象实例.

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

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

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

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

var foo = new Foo('foo');
foo.greeting();
Run Code Online (Sandbox Code Playgroud)

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

var greeting = foo.greeting;
greeting();
Run Code Online (Sandbox Code Playgroud)

...所以thiswindow在函数内部.

编辑:请注意@ jAndy的答案,指出在这种情况下,更突出的问题,这是greeting关闭了self在第一个例子(不管它怎么叫),但在第二个没有做(这则使得如何调用该函数相关).


Mat*_*att 2

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

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

更详细的解释请参见thisMDC