JavaScript避免新关键字

JavaScript避免新关键字,javascript,new-operator,Javascript,New Operator,我在读佩奇(尤其是工厂部分) 它提到要避免使用new关键字,以防止意外忘记它。它建议使用工厂 页面的新示例: function Bar() { var value = 1; return { method: function() { return value; } } } Bar.prototype = { foo: function() {} }; new Bar(); Bar(); // These

我在读佩奇(尤其是工厂部分)

它提到要避免使用
new
关键字,以防止意外忘记它。它建议使用工厂

页面的新示例:

function Bar() {
    var value = 1;
    return {
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {
    foo: function() {}
};

new Bar(); 
Bar(); // These are the same.
function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}
var Foo = function () {
    var foo = function () {

    };
    foo.prototype = {
        bar: function () { }
    };
    return new foo();
};
页面的工厂示例:

function Bar() {
    var value = 1;
    return {
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {
    foo: function() {}
};

new Bar(); 
Bar(); // These are the same.
function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}
var Foo = function () {
    var foo = function () {

    };
    foo.prototype = {
        bar: function () { }
    };
    return new foo();
};
工厂缺点

  • 因为创建的对象不共享原型上的方法,所以它使用了更多的内存
  • 为了继承,工厂需要从另一个对象复制所有方法,或者将该对象放在新对象的原型上
  • 仅仅因为遗漏了一个新关键字而放弃原型链,这与语言的精神背道而驰
避免
新的
,以防止您忘记时出现问题,这是可以理解的。但我不太明白的是,他们说工厂示例需要更多内存,因为它没有使用原型函数。那么为什么不用这样的东西来代替呢

我的解决方案:

function Bar() {
    var value = 1;
    return {
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {
    foo: function() {}
};

new Bar(); 
Bar(); // These are the same.
function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}
var Foo = function () {
    var foo = function () {

    };
    foo.prototype = {
        bar: function () { }
    };
    return new foo();
};

问题:我是否遗漏了一些使这不是更好的解决方案的东西?我的解决方案是否消除了工厂方法中列出的缺点,原因是什么?

好的,让我们以
新的
为例:

function Bar() {
    var value = 1;
    // Whoops, sorry
    // As Bergi points out, if you have a return value then that overrides the normal object that is returned by new
    // Didn't even notice you have a return in here!
    /*
    return {
        method: function() {
            return value;
        }
    }
    */
    // This does the same thing (approximately) but now calling "(new Bar()) instanceof Bar" will be true
    this.method = function() {
        return value;
    };
}
Bar.prototype = {
    foo: function() {}
};

var b = new Bar();
在google chrome控制台中,
b
有一个名为
\uuuu proto\uuu
的属性。基本上,当您调用
b.foo()
时,浏览器首先查找名为
foo
的方法。如果没有找到它,它会在
b.\uuuuu-proto\uuuuu
b.\uuuuu-proto\uuuu.\uuuuu
中查找,依此类推


注意:
b.\uuuu proto\uuuu==Bar.prototype

这意味着如果您反复调用
newbar()
,它们都将具有相同的
\uuuu proto\uuuu
,从而节省内存。(这样做的副作用是,如果您对
Bar.prototype
进行变异,它也会更改
Bar
\uu proto\uu
的所有实例)

让我们看看您的工厂方法:

var Foo = function () {
    var foo = function () {

    };
    foo.prototype = {
        bar: function () { }
    };
    return new foo();
};
这不会节省内存,因为每次调用
Foo()
,它都会创建一个新的
原型和一个新的构造函数。换句话说,如果

var f1 = new Foo(), f2 = new Foo();
以下返回false:
f1.constructor==f2.constructor
f1.\uuuu proto\uuuu==f2.\uuuu proto\uu
。这是什么意思?这意味着
f1
f2
共享相同的
原型
,因此每次都必须复制对象。或许,您可以这样做:

var fooProto = {
  callFoo: function() { alert("test"); }
};
function Foo() {
    var foo = function() {};
    foo.prototype = fooProto;
    return new foo();
};
这将使用与常规构造函数相同的内存量

侧边编辑:现代浏览器有一个内置功能,类似上一个示例中的
Foo
。您可以使用
Object.create(fooProto)
(但只能在较新的浏览器中使用)


另外,请注意,
\uuuu proto\uuu
在技术上是一个隐藏的只读属性(尽管有些浏览器允许您对其进行写入)。它只是为了显示幕后的情况,不应该在实际代码中使用。

是的,每次调用工厂方法时都会创建一个新的构造函数。我稍微澄清了我的问题。我知道我的每次都创建了一个新对象,我只是好奇它是否删除了链接站点(我现在的问题中包括了)列出的工厂方法的缺点。或者在这个问题上添加了任何赞成/反对意见。正如所有这些代码片段所显示的,还有更糟糕的事情可能出错。要对抗遗忘的
new
s.1。将
foo
foo.prototype
移动到
foo
函数之外是否可以解决这个问题?2.感谢您解释
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?构造函数
返回一个对象,原型将被忽略。为了清晰起见,您应该始终使用
对象。创建
。如果需要的话,在旧浏览器中填充它。@Bergi(注释1)我说的是第一个示例,您使用
var b=new Bar()。然后
b.。\uuuu proto\uuuu==Bar.prototype
@Shelby115:是的,这会有帮助。实际上,有一个
函数makeFoo(){return new Foo();}
,与
Foo
相反,它可以在没有
new
的情况下使用,这并不少见。请注意,构造函数名称应始终大写。