0

我正在查看Arrowlets 源代码,并在顶部附近找到了此部分:

/*
 * 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's 在源代码中的一些用法,似乎这是传递多个参数的另一种方式,但我真的不明白如何。此外,评论指出:

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

但我认为每当使用 , 调用构造函数时newthis都会返回。有人可以向我解释一下吗?

更新

我很难理解为什么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' } }

而不是使用Arrowlets的方法:

> 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' } }

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

4

2 回答 2

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.singleis 不是一个对象,因此new Box返回一个新Box对象并将其分配给Box.single,然后每次调用new BoxorBox返回同一个Box对象。

请注意,也许令人惊讶的是,new不必返回this;它可以通过调用返回任何obj地方(如果,则返回)。例如:typeof(obj) == "object"return objtypeof(obj) != "object"newthis

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

这也是为什么new Box可以使用而不仅仅是Box

a = Box(1);
b = new Box(2);
a === b; // true
于 2013-11-24T17:32:06.877 回答
1

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

Box.single = new Box;

因此,您对“this”的评论/关注仅与这一用途有关。您可以看到 Box 是一个函数,并且 Box 有一个名为 single 的属性。通过上述赋值,Box.single 被设置为指向 Box 函数的实例 - new Box 返回的 'this';

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

Box.single.content = content;

将是无害的/被忽略的/无论你怎么想。“内容”将未定义

new Box;

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

开发人员正在尝试创建一个保留“内容”的单例。目标是使用 Box() 以便将任意数量的参数打包在一起。这与使多参数 JavaScript 函数与作为 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));
    }
}

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

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

这就是正在发生的一切!

于 2013-10-30T01:14:24.330 回答