在JavaScript中创建函数对象有什么好处/缺点?

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

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

在视频后,我在他的书“JavaScript的好部分”第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关键字,并且我可能会采用它的功能模式。 但这是我能看到你为什么要这么做的唯一原因。 请问我能获得更多的信息,为什么一个人会比另一个更好或更差?


好吧,我会试着在这里回答我自己的问题,并提供我收到的信息以及我在提问后收集的其他资料。

TL; DR:

它们都是有用的,并且可以实现大部分相同的事情。 构造函数可以访问它们的原型,这非常有用,因为它意味着它们在用构造函数创建的所有子项中都具有“全局”值。 这既有用又有潜在危险,因为您可以重写构造函数属性给孩子一个同名的属性 - 使访问原型值变得更加困难。

在调用构造函数时会遗忘new关键字,但可以通过添加"use strict";来轻松修复"use strict"; 在构造函数内部,如果你忘记了new关键字,它会抛出一个错误。

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

我从所有这些中学到的是,当你可以同时使用两个选项时,选择一个就太愚蠢了。 他们都有自己的长处和短处,人们需要记住道格拉斯克罗克福德只是一个人,而不是JavaScript上帝。 (这将是布兰登艾希,哈哈!)


@Domenic接受的答案在JavaScript中,构造函数和函数返回的对象之间有什么不同? 让我对两种对象创建方法之间的差异和相似性有了一些见解。

构造函数

使用new关键字创建新对象与派生自它的构造器对象之间的链接。 构造函数是新对象的原型,新对象是原型对象的实例。

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

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

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

Constructor.prototype.color = 'yellow';

现在,使用构造函数对象创建的每个对象都可以访问.color属性,而不.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引擎内运行得更慢,因为对象不再共享相同的“隐藏类”但我没有足够的知识来进入。 用V8打破JavaScript速度限制

原型仍然可以访问。 通过现在已弃用的.__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

我学会了很多搜索和写作,希望别人也能学到一两样东西。

参考文献:

在JavaScript之间,构造函数和函数返回的对象之间有什么区别?

构造函数与工厂函数

现在该开始使用JavaScript严格模式了

链接地址: http://www.djcxy.com/p/40847.html

上一篇: What are the benefits / drawbacks of functional object creation in JavaScript?

下一篇: Crockford's Prototypal inheritance