JavaScript避免使用新关键字

时间:2014-07-17 21:07:07

标签: javascript new-operator

我正在阅读this页面(特别是工厂部分)。

它提到避免使用new关键字来防止意外遗忘的情况。它建议使用工厂。

Page新的示例:

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

new Bar(); 
Bar(); // These are the same.

Page的工厂示例:

function Foo() {
    var obj = {};
    obj.value = 'blub';

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

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

工厂缺点

  • 它使用更多内存,因为创建的对象不共享原型上的方法。
  • 为了继承,工厂需要从另一个对象复制所有方法或将该对象放在新对象的原型上。
  • 仅仅因为遗漏了新关键字而删除了原型链,这与语言的精神背道而驰。

避免new以防止您忘记的问题是可以理解的。但我不太了解的是,他们说工厂的例子需要更多的内存,因为它没有使用原型功能。那么为什么不使用这样的东西呢?

我的解决方案:

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

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

问题:我错过了一些让这不是更好解决方案的东西吗?我的解决方案是否删除了工厂方法的列出缺点,为什么或为什么不呢?

1 个答案:

答案 0 :(得分:1)

好的,让我们来看new示例:

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有一个名为__proto__的属性。基本上,当您致电b.foo()时,首先浏览器会查找名为foo的方法。如果找不到,则会查看b.__proto__b.__proto__.__proto__,依此类推。

注意:b.__proto__ === Bar.prototype

这意味着如果您反复拨打new Bar(),他们将拥有相同的__proto__,从而节省内存。 (这有副作用,如果你改变Bar.prototype,它将改变Bar __proto__的所有实例。

让我们来看看你的工厂方法:

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

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

这不会节省内存,因为它会创建一个新的prototype,每次一个新的构造函数就会调用Foo()。换句话说,如果

var f1 = new Foo(), f2 = new Foo();

以下返回false:f1.constructor == f2.constructorf1.__proto__ == f2.__proto__。这是什么意思?这意味着f1f2 共享相同的prototype,因此每次都必须复制对象。也许,你可以这样做:

var fooProto = {
  callFoo: function() { alert("test"); }
};
function Foo() {
    var foo = function() {};
    foo.prototype = fooProto;
    return new foo();
};

这将使用与常规构造函数相同的内存量。

边编辑:现代浏览器具有内置函数,在上一个示例中执行类似Foo的操作。您可以使用Object.create(fooProto)(但仅限于较新的浏览器)。

另外,请注意__proto__在技术上是一个隐藏的只读属性(尽管某些浏览器允许您写入它)。它仅用于展示幕后发生的事情,不应该在实际代码中使用。