JavaScript中功能对象创建的好处/缺点是什么?

时间:2014-04-18 17:07:56

标签: javascript functional-programming scope private-members

我只是看着道格拉斯·克罗克福德谈论原型继承如何“不是一个好主意”

YouTube 35m55s

我并不真正关心他对JavaScript原型继承的看法,因为它始终存在于语言的一个重要部分。

但我想通过使用他在链接中显示的功能对象创建来了解我正在收获的好处:

// Class Free Object Oriented Programming
function constructior(init) {
    var that = other_constructor(init),
        member,
        method = function () {
            // init, member, method
        };
    that.method = method;
    return that;
}

在视频之后,我在他的书“em>”JavaScript The Good Parts“第5章:继承中重新阅读了关于功能对象创建的部分。

但我真的看不到的差异.. 我可以使用构造函数模式获得私有成员:

function Constructor (value) {
    var private = value;
    this.getPrivate = function () {
        return private;
    }
}
var OBJ1 = new Constructor(5);
var OBJ2 = new Constructor('bacon');

console.log( OBJ1.getPrivate() ); // 5
console.log( OBJ2.getPrivate() ); // bacon

我可以在构造函数模式和功能模式之间发现的唯一差异是省略了new关键字。通过避免使用new关键字,我们可以避免忘记new关键字的错误。

写这个:

var panda = createBear();

而不是:

var panda = new Bear();

让我觉得这主要取决于个人喜好。我可以看到避免new关键字有用,我可能会采用它的功能模式。 但这是我能看到为什么你会这样做的唯一原因。我可以获得更多信息,为什么一个会比另一个更好或更差?

1 个答案:

答案 0 :(得分:3)

好吧所以我会在这里回答我自己的问题,提出我收到的信息以及我在提问后在互联网上收集的其他内容。

TL; DR:

它们既有用又可以实现大致相同的东西。构造函数可以访问它们的原型,这非常有用,因为它意味着它们在使用构造函数创建的所有实例中都具有“全局”值。它既有用又有潜在危险。这很有用,因为构造函数的所有实例都可以访问相同的prototype属性,从而避免重复。危险,因为您可以覆盖构造函数属性 OR 为实例提供相同名称的属性 - 这使得访问原型值变得更加困难。

在调用构造函数时存在忘记new关键字的危险,但是通过在构造函数中添加"use strict";可以很容易地解决这个问题,如果忘记了new,则会抛出错误关键字。

如果您想避免原型及其功能/危险,可以使用工厂 功能。 功能方法的真正有用的特点是你可以返回任何你喜欢的东西。而不是总是构造预定义对象的“child”

我从这一切中学到的是,当你可以使用两者时,选择一个而不是另一个是愚蠢的。他们都有自己的优点和缺点,人们需要记住道格拉斯克罗克福德只是一个人,而不是JavaScript上帝。 (那将是Brandon Eich,大声笑!)


@Domenic在What difference is there in JavaScript between a constructor function, and function returning object which is invoked as a constructor?上接受的回答 给出了一些关于两种对象创建方法之间差异和相似之处的见解。

构造

使用new关键字在新对象和派生自的构造函数对象之间创建链接。构造函数是新Object的Prototype,新Object是Prototype Object的一个实例。

var Constructor = function () {
    this.x = 0;
    this.y = 0;
};
var A = new Constructor();
console.log(A instanceof Constructor ); // true

链接到原型对象意味着我们的新对象可以访问原型属性,而无需将它们存储在对象本身中。这比在每个子对象上创建属性更具内存效率,并且还带有原型制作功能的附加功能。

向对象原型添加属性或方法很简单:

Constructor.prototype.color = 'yellow';

现在,使用Constructor对象创建的每个对象都可以访问.color属性,而无需将其存储在自身内部。

var A = new Constructor();
console.log(A.color); // yellow
console.log(A.hasOwnProperty('color')); // false

由于JavaScript中的对象是动态的,因此意味着您可以“追溯”地向原型添加新属性,并且在更改之前创建的对象仍将“继承”新属性。

var A = new Constructor();
Constructor.prototype.food = 'bacon';
console.log(A.food); // bacon;

Crockford可能提倡反对构造函数模式的一个原因是避免覆盖原型属性或意外地覆盖子对象内原型的命名空间。

Constructor.prototype.number = 5;
A.calculate = function () {
    return A.number * 5;
}
console.log(A.calculate()); // 25

Constructor.prototype.number = 'fishsticks';
console.log(A.calculate()); // NaN

根据我的理解,在创建之后添加属性也会使代码在V8引擎内运行得更慢,因为对象不再共享相同的“隐藏类”但是我知识不足以获得进入那个。 Breaking the JavaScript Speed Limit with V8

仍然可以访问原型。通过现已弃用的.__proto__.或新的Object.getPrototypeOf()方法。

console.log(Object.getPrototypeOf(A.color)); // yellow

Crockford提倡反对使用构造函数的另一个原因是你可能忘记输入new。如果忘记在构造函数前面编写new,它将运行构造函数而不是创建新对象。

var A = Constructor();
console.log(A); // undefined

通过在函数中添加严格的输入可以很容易地解决这个问题,如果忘记了new关键字,就会引发错误。

var Constructor = function () {
    "use strict";
    this.x = 0;
    this.y = 0;
}
var A = Constructor();

console.log(A);
// Uncaught TypeError: Cannot set property 'x' of undefined

工厂职能

我发现这非常直截了当。如果您不想处理new关键字以及构造函数的某些“危险”,则可以使用此方法创建不使用其原型的对象。

function factory () {
    var obj = {
        x: 0,
        y: 0
    }
    return obj;
}
var A = factory(); // {x: 0, y: 0}

除了创建对象之外,当您想要对数据执行某些操作时,这非常方便。

function factory () {
    if ( new Date().getHours() < 8 ) { 
        return "can't create object. Need Coffe!" 
    };
    var obj = {
        x: 0,
        y: 0
    }
    return obj;
}
var A = factory(); // Before 8 am: "can't create object. Need Coffe!"
var A = factory(); // After 8 am: {x: 0, y: 0};

这样做会使原型失去力量/危险。因为该对象没有绑定到一个。

factory.prototype.foo = "bar";
A = factory();
console.log(A.foo); // undefined

这意味着您无法使用它。但这也意味着你不能搞砸它。

总之。

参见 TL; DR

我学到了很多搜索和写作,希望其他人也能学到一两件事。

<强>参考文献:

What difference is there in JavaScript between a constructor function, and function returning object which is invoked as a constructor?

Constructor function vs Factory functions

It’s time to start using JavaScript strict mode