你什么时候在Javascript闭包中使用return语句?

时间:2011-09-10 05:56:58

标签: javascript scope closures

考虑这个第一个Javascript片段,它只使用var和this来声明范围:

var Bro = function() {
    var self = this;
    this.storyName = "story"; // public
    var storyType = "cool"; // private

    // private function
    var composeStory  = function() {
        return storyType + ' ' + self.storyName;
    };

    // privileged function
    this.tellStory = function() {
        console.log(composeStory() + ' bro!');
    };
};

与使用return语句的相比,并稍微修改范围:

var Bro = function() {
    var self = this;
    this.storyName = "story"; // private?
    var storyType = "cool"; // private

    // private function
    var composeStory = function() {
        return storyType + ' ' + self.storyName;
    };

    // privileged variables/functions
    return {
        storyName: this.storyName,
        tellStory: function() {
            console.log(composeStory() + ' bro!');
        }
    };
}

我的问题是:

  1. 你会在第一种方法中使用第二种方法,或者这只是一种风格上的东西?
  2. 为什么第二个示例中的this.storyName是私有的,即使我在this上设置了它?
  3. 我必须声明var self = this;才能访问两个私有函数中的this范围。 Javascript框架如何使this对象在其函数内可访问?
  4. 在第二个示例中,return语句中的storyName属性可以正确访问this范围。为什么它可以这样做,当私人功能不能?

3 个答案:

答案 0 :(得分:0)

我将在第三个问题上回答。他们使用callapply方法可用于所有函数,这些函数将第一个参数作为函数执行的上下文。

this.message = "hello ";
var function(argument) {
    console.log(this.message + argument);
}
function.call(this, "world!");
function.apply(this, ["world!"]);

更简洁的例子see jQuery source

答案 1 :(得分:0)

问题4:在JS中,this具有功能范围,而不是块范围。

因此,在第二个示例中,在函数composeStory中,this具有函数composeStory的范围,而不是Bro的对象实例的范围。因此,您必须将this保存为self,因为this的含义已更改。

(事实上,在函数composeStory中,this通常是window,或者是严格模式undefined。如果插入

alert(this === window); 

composeStory函数中,它会提醒“true”。如果你插入

"use strict"; 
alert(typeof this === "undefined"); 

它将再次警告“真实”。进一步查看here。)

在第二个示例的return语句中,this不在函数内。所以this仍然引用包含函数,即正在创建的Bro的实例。

答案 2 :(得分:0)

Javascript中没有“私人”和“公共”这样的东西。您所看到的是对象的属性与闭包捕获的变量之间的区别。闭包捕获变量可用于隐藏状态,但它们将其隐藏在附加到闭包作用域中创建的函数的不同对象上,而不是在返回的对象上,就像在其他语言中一样。考虑到这一点,我会回答你的问题,

1)我不会使用任何一种形式,但它们在风格上相似,都使用闭包捕获。但是请注意,第一个使用构造函数模式,第二个使用工厂模式。第一个只有在调用Bro之前使用new关键字才有效。第二个将忽略new创建的对象,而不是对象文字创建的对象,但你可以安全地调用它而不用新的前缀。

2)storyName不是私有的,它设置在不同的对象上。当一个函数被调用前缀为new时,会创建一个新对象并将其作为“this”参数传入。这是您通过“this.storyName”设置的对象。然后丢弃此对象,以支持您在文字中创建的对象。您没有看到storyName,因为它没有在返回的对象上设置。

3)你可以在像self这样的闭包变量中捕获它,或者在函数上使用bind将它绑定到原始的。我更喜欢自己关闭捕获。

4)这仍然在范围内,因为您正在构造函数中执行。