这个JS库的模式有什么问题吗?

时间:2013-02-09 22:55:55

标签: coding-style javascript

我当然对javascript的内部工作知之甚少,但需要创建一个库并想学习(因此在这里问)。我理解使用闭包并导出到窗口不会污染全局命名空间,但除此之外,它让我感到困惑。

(function() {
    var Drop = window.Drop = function() { 

        var files = [];

        var add = function(word) {
              files.push(word);    
              return files;
        }

        return {
            files: files,
            add: add
        }
    }
})()


// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;

// Each has their own state which is what I want.
a.add("file1");
b.add("file2");
c.add("file3");
  • 为什么所有三种“初始化”方式都相同?
  • 究竟是什么让他们拥有自己的状态?
  • 是否可以使用返回语法替代Drop?
  • 上的那些函数
  • 是否只有一个更好的最佳实践方法来创建这样的自包含库?

我在网上搜索过,但发现这个主题的一致性很差。

2 个答案:

答案 0 :(得分:2)

  1. 第一种方式(Drop())只是正常调用该函数,因此this是全局对象(浏览器环境中为window)。它做了它的东西然后返回一个对象,正如你所期望的那样。

    第二种方式(new Drop())创建一个新的Drop对象,并执行设置为该对象this的构造函数。但是,您不能在任何地方使用this并返回从对象文字创建的对象,因此会丢弃Drop对象,而是返回对象文字。

    第三种方式(new Drop)在语义上与第二种方式相同;这只是一种语法差异。

  2. 它们都有自己的状态,因为每次调用Drop时,它都有自己的一组局部变量,不同于对Drop的任何其他调用的局部变量。

  3. 您可以将代码转换为使用普通new语法和原型。这有一些优点:即,您只需为add调用创建Drop函数一次而不是一次。您修改后的代码可能如下所示:

    function Drop() {
        this.files = [];
    }
    Drop.prototype.add = function(word) {
        this.files.push(word);
        return this.files;
    };
    

    但是,通过这样做,您将无法在没有new的情况下调用它。但是,有一种解决方法:您可以将其添加为function Drop内的第一行:

    if(!(this instanceof Drop)) {
        return new Drop();
    }
    

    因为当您使用new调用它时,this将是Drop,当您在没有new的情况下调用它时,this将成为其他内容与Drop相比,您可以看到this是否为Drop,如果是,则继续初始化;否则,请使用new重新启动它。

    还有另一种语义差异。请考虑以下代码:

    var drop = new Drop();
    var adder = drop.add;
    adder(someFile);
    

    您的代码将在此处运行。基于原型的代码不会,因为this将是全局对象,而不是drop。这也有一个解决方法:在构造函数的某个地方,你可以这样做:

    this.add = this.add.bind(this);
    

    当然,如果您的图书馆的消费者不打算将该功能从对象中拉出来,您将不需要这样做。此外,您可能需要为没有它的浏览器提取Function.prototype.bind

  4. 没有。这都是品味问题。

答案 1 :(得分:1)

  • 为什么所有三种“初始化”方式都相同?

// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;

在JavaScript中使用new来调用函数时,函数内的this值将成为新对象。

但他们在你的情况下是相同的原因是你根本没有使用this。您正在使用 object literal 语法创建单独的对象,而是返回它,因此new没有任何影响。


  • 究竟是什么让他们有能力拥有自己的状态?

因为每个函数调用都会生成一个新对象,所以每个调用的每个对象都完全不同。

在每个Drop调用中重新创建分配给对象的函数,因此在封闭变量作用域上创建闭包。因此,每次调用的files数组都可以连续访问每个调用中的函数。


  • 是否可以使用返回语法替代Drop上的这些函数?

是。将函数和数组分配给this,然后删除return语句。但这将要求使用new。或者,将函数放在.prototype的{​​{1}}对象上,它们将在使用Drop创建的所有实例之间共享,但保持数组分配给new构造函数,以便它不被共享。

对于引用数组的原型函数,它们将使用this


  • 是否只有一个更好的最佳实践方法来创建这样的自包含库?

JavaScript非常灵活。有很多方法可以解决单个问题,每个问题都有自己的优点/缺点。一般来说,它可以归结为利用闭包原型继承或两者的某种组合。


这是一个完整的原型继承版本。此外,外部this.files未被使用,因此我将添加一个变量以利用它。

(function() {})()