解释这部分Arrowlets源代码

时间:2013-08-17 22:10:11

标签: javascript

我正在查看Arrowlets source code,发现此部分位于顶部附近:

/*
 * Box: a temporary (singleton) place to put stuff. Used as a helper for constructors with variadic arguments.
 */
function Box(content) {
    Box.single.content = content;
    return Box.single;
}
/* JavaScript hackery based on the strange semantics of "new":
 * - Box() assigns Box.single.value, so Box.single has to be defined;
 * - properties can be assigned to numbers (but have no effect);
 * - when Box.single = 1 (or any non-Object), "new Box" returns "this". */
Box.single = 1;
Box.single = new Box;
Box.prototype.toString = function Box$prototype$toString() {
    return "[Box " + this.content + "]";
}

我还查看了源代码中Box的一些用法,看起来这是另一种传递多个参数的方法,但我真的不明白怎么做。此外,评论指出:

  

当Box.single = 1(或任何非对象)时,“new Box”返回“this”。

但我想只要用new调用构造函数,就会返回this。有人可以向我解释一下吗?

更新

我很难理解为什么Box.single必须设置为非对象才能使用此方法,以及使用new运算符获得的技巧。 NodeJS repl的示例:

new并使用非对象

> function Box(content) {
... Box.single.content = content;
... return Box.single;
... }
Box.single = {}; // NOTE: Setting Box.Single to an Object
{}
> //NOTE: Not using the "new" operator at all
undefined
> Box(23)
{ content: 23 }
> Box.single
{ content: 23 }
> Box({'name': 'John'})
{ content: { name: 'John' } }
> Box.single
{ content: { name: 'John' } }

使用new和对象

> function Box(content) {
... Box.single.content = content;
... return Box.single;
... }
undefined
> Box.single = {}; // Setting Box.single to an object
{}
> Box.single = new Box; // Using the new operator
{ content: undefined }
> Box({'name': 'John'})
{ content: { name: 'John' } }
> Box.single
{ content: { name: 'John' } }

与使用箭头

中的方法相反
> function Box(content) {
... Box.single.content = content;
... return Box.single;
... }
undefined
> Box.single = 1; // Setting Box.single to a Non-Object
1
> Box.single = new Box; // Using the new operator
{}
> Box(23)
{ content: 23 }
> Box({'name': 'John'})
{ content: { name: 'John' } }
> Box.single
{ content: { name: 'John' } }

似乎箭头方法只是一种简单的方式来完成简单的事情。我错过了什么?

2 个答案:

答案 0 :(得分:2)

区别在于instanceof

...
Box.single = {};
Box.single = new Box; // with or without this line
Box(1) instanceof Box; // false

...
Box.single = 1;
Box.single = new Box;
Box(1) instanceof Box; // true

在第一种情况下,因为Box.single是一个对象,根据JavaScript规则,new Box上方的调用将返回Box.single,这是一个普通的{}对象。对new BoxBox的每次后续调用都会返回相同的普通对象。

在第二种情况下,Box.single不是对象,因此new Box会返回一个新的Box对象并将其分配给Box.single,并且每次后续调用new Box 1}}或Box返回相同的Box对象。

请注意,或许令人惊讶的是,new不必返回this;它可以通过调用obj返回typeof(obj) == "object" return obj的任何typeof(obj) != "object"(如果new,则this返回function Foo() { this instanceof Foo; // true } function Bar() { this instanceof Bar; // true return new Foo(); } (new Bar) instanceof Bar; // false (new Bar) instanceof Foo; // true )。 E.g:

new Box

这也是为什么可以使用Box而不仅仅是a = Box(1); b = new Box(2); a === b; // true

的原因
{{1}}

答案 1 :(得分:1)

Arrowlets代码从不将此函数与“new”一起使用,除了这一个调用:

Box.single = new Box;

所以你对“this”的评论/关注仅与这一用途有关。你可以看到Box是一个函数,Box有一个叫做single的属性。通过上面的赋值,Box.single被设置为指向Box函数的实例 - 新Box返回的'this';

在将Box()作为构造函数调用之前,需要一些技巧才能使调用成功。在这种情况下,Box.single已设置为值1,因此设置单个内容:

Box.single.content = content;

将无害/忽略/但你想要想到它。 将使用

来定义“内容”
new Box;

呼叫。我们不希望构造函数抛出。因此诡计多端。 从构造函数调用返回后,Box.single被设置为实例化的Box()

开发人员正在尝试创建一个保留“内容”的单例。目标是使用Box()以将任意数量的参数打包在一起。这与使多参数JavaScript函数与Tuples一起工作有关,而Tuples是Arrowlets实现的基础。这里Box用于在数组中有超过2个元素时创建元组:

Tuple.fromArray = function Tuple$fromArray(array) {
    switch (array.length) {
        case 0:
        case 1:
            return array[0];
        case 2:
            return new Pair(array[0], array[1]);
        default:
            return new Tuple(Box(array));
    }
}

当使用下面的构造函数创建元组时,如果传入Box,则框的内容将成为元组的“组件”

function Tuple() {
    if (arguments[0] instanceof Box) {
        var components = arguments[0].content;
    } else {
        [...omitted stuff...]
    }
    /* properties */
    this.components = components;
    this.length = components.length;
}

这就是所有这一切!