JavaScript类和调用上下文

JavaScript类和调用上下文,javascript,class,object,closures,Javascript,Class,Object,Closures,有人能帮我解释一下为什么第一个例子有效,而第二个却不行 例1: 输出: Hello foo Hello foo Hello foo Hello undefined 例2: 输出: Hello foo Hello foo Hello foo Hello undefined 我猜是因为第一个示例使用闭包,所以它保留了对name局部变量的引用,但第二个示例不是,并且由于调用greeting()方法时没有对象上下文,它默认为undefined此的解析延迟到JavaScript中的执行时间 通过将

有人能帮我解释一下为什么第一个例子有效,而第二个却不行

例1: 输出:

Hello foo
Hello foo
Hello foo
Hello undefined
例2: 输出:

Hello foo
Hello foo
Hello foo
Hello undefined

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

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

通过将
foo.greeting
设置为
greeting
,然后执行
greeting()
,您正在全局上下文中执行
greeting()
;其中,
指向
窗口
,除非您是在严格模式下运行,而不是您的
Foo
实例。因此,在
greeting()
中,它正在查找
窗口;并返回未定义的


有关更详细的说明,请参见。

在JavaScript中有四种调用函数的方法,每种方法都会更改函数中此
的值:

  • 作为一个全局函数调用:
    greeting()
    的值是全局
    窗口
    对象(在浏览器中)

  • 作为某个对象上的方法:
    foo.greeting()
    this
    的值是
    操作符(
    foo
    )左侧的对象实例

  • 作为构造函数
    新问候语()
    this
    的值是一个新对象,它是由函数创建并隐式返回的。这用于创建新对象

  • 使用
    呼叫
    应用
    问候语。应用(someVal,someArgs)
    this
    的值是作为第一个参数传递的对象(
    someVal

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

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

    var foo = new Foo('foo');
    foo.greeting();
    
    …因此,
    是函数内部的
    foo
    。在第二种情况下,您正在执行全局函数调用:

    var greeting = foo.greeting;
    greeting();
    
    …因此
    是函数内部的
    窗口

    Edit:注意@jAndy的回答,该回答指出了本例中更突出的问题,即在第一个示例中,
    问候语
    结束于
    自我
    (无论如何调用),但在第二个示例中不结束(这使得函数的调用方式相关)。

    第二个问候语()在全局作用域上执行,因此相应地,
    是窗口对象(与执行函数的作用域相同,
    window.name
    随后未定义)。如果您通过
    apply()
    call()
    传递上下文,它将再次工作,例如

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

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

    在第一个示例中,它只记录两次
    Hello foo
    ,因为您正在创建一个变量
    self
    ,该变量引用
    对象。然后,该
    self
    变量将在
    问候语函数中关闭。因此,您可以随意调用该函数,它总是访问
    self.name
    ,而不是
    this.name
    ,因此它总是一样的

    原型
    示例中没有这样做。在这里,您可以直接访问
    this.name
    ,然后了解如何调用该函数非常重要(请参见@lwburk answer)

    所以再说一遍,即使你把第一个例子叫做

    foo.greeting.call( window );
    

    它仍将访问closured
    self
    变量并记录
    Hello foo

    了解有关此
    的更多信息:。。。然后@Matt-非常正确,尽管
    bind
    不调用函数;它创造了一个。它无论如何也不能回答OPs的问题。@jAndy-Hah!所以它没有。好主意。@jAndy-留下我的答案只是因为它仍然与OP的第二个例子有关。此外,还添加了一条指向您的答案的注释。它也不能回答OPs问题。