JavaScript避免new关键字

JavaScript avoiding new keyword

本文关键字:关键字 new 避免 JavaScript      更新时间:2023-09-26

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

提到避免使用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;
}

Factory Cons:

  • 它使用更多的内存,因为创建的对象不共享原型的方法。
  • 为了继承,工厂需要从另一个对象复制所有的方法,或者把那个对象放在新对象的原型上。
  • 仅仅因为遗漏了一个新关键字就放弃原型链是违背语言精神的。

避免new以防止万一您忘记的问题是可以理解的。但我不太明白的是,他们说工厂示例占用更多内存,因为它没有使用原型函数。所以为什么不用这样的东西呢?

我的解决方案:

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

问题:我是否错过了一些使这不是一个更好的解决方案?我的解决方案是否删除了列出的工厂方法的缺点,为什么或为什么没有?

好,让我们以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();

在谷歌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();
};

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

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__在技术上是一个隐藏的只读属性(尽管有些浏览器允许您写入它)。它只用于显示幕后发生的事情,不应该在实际代码中使用。