如何使用工厂函数编写JavaScript

时间:2016-09-17 12:16:26

标签: javascript

我正在阅读this article关于尝试在JavaScript中模仿OOP的危险,并且有以下内容:

  

在JavaScript中,工厂函数只是构造函数   减去new要求,全球污染危险和尴尬   限制(包括恼人的首字母大写字母   惯例)。

     

JavaScript不需要构造函数,因为任何   函数可以返回一个新对象。使用动态对象扩展,   对象文字和Object.create(),我们拥有一切   需要 - 没有任何混乱。并且this表现得像它一样   任何其他功能。乌拉!

我是否正确地假设我们应该替换此代码:

function Rabbit() {
    this.speed = 3;
}

Rabbit.prototype = {
    this.getSpeed = function() {
        return this.speed;
    }
}

var rabbit = new Rabbit();

有了这个:

function RabbitFactory() {
    var rabbit = {
        speed: 3
    };

    Object.setPrototypeOf(rabbit, {
        getSpeed: function() {
            return this.speed;
        }
    })

    return rabbit;
}

var rabbit = RabbitFactory();

6 个答案:

答案 0 :(得分:6)

基本上我会区分3种在JS中创建对象的方法:

  • 构造

以下是3个例子(考虑你的兔子的一个)

// class
class Rabbit {
  constructor() {
    this.speed = 3; 
    // it would be so nice to have just 'static const speed = 3;' instead of
    // using constructor for that
  }
  getSpeed() {
    return this.speed;
  }
}
let rabbit1 = new Rabbit();

// constructor
function ConstructorRabbit(){ }
ConstructorRabbit.prototype.speed = 3;
ConstructorRabbit.prototype.getSpeed = function() {
  return this.speed;
};
let rabbit2 = new ConstructorRabbit();

// factory
const rabbitProto = {
  speed: 3,
  getSpeed() {
    return this.speed;
  }
};
function factoryRabbit () {
  return Object.create(rabbitProto);
}
let rabbit3 = factoryRabbit();

我不确定有多少专业人士只使用工厂来创建对象,但我可能会挑出一个。正如文章中提到的,如果我们引用非常着名的“Design Patterns”,那么我们应该更喜欢对象组合而不是类继承。我完全赞同这个假设,因此回到JS和ES6类,我们可以说原型委托可能在某些情况下比继承更好。

但是,我们也不应该忘记这一点(正如文章中所提到的)声明:“它的实施方式并不重要根本,除非它实施得不好”。我想说,这个是一个非常好的。

答案 1 :(得分:3)

我不喜欢这些答案,因为他们使用this关键字。你可以完全避免这种情况,仍然使用这样的工厂函数:

function createRabbit() {
    var speed = 3;
    return {
        getSpeed: function() {
            return speed;
        }
    }
}

var rabbit = createRabbit();
console.log(rabbit.getSpeed());

这家伙有一篇很好的文章:http://radar.oreilly.com/2014/03/javascript-without-the-this.html

答案 2 :(得分:1)

不,那是错的。您不应该使用Object.setPrototypeOf,更好地使用Object.create(尽管结果没有区别)。如果你每次都从一个对象文字创建原型,它就失去了它的所有共享优势,所以你应该完全放弃它或者将它移到函数之外以使它成为静态的。编写工厂函数的正确方法是

const protoRabbit = {
    getSpeed: function() {
        return this.speed;
    }
};
function createRabbit() {
    var rabbit = Object.create(protoRabbit);
    rabbit.speed = 3;
    return rabbit;
}

var rabbit = createRabbit();

答案 3 :(得分:1)

最简单的模式是:

function RabbitFactory() {
  return {
    speed: 3,
    getSpeed() { return this.speed; }
  };
}

var rabbit = RabbitFactory();

答案 4 :(得分:1)

尽管问题的名称与工厂功能有关,但这里的许多答案都建议使用Constructor Functions

工厂函数如下所示:

const RabbitFactory = () => {
  const speed = 3;
  const GetSpeed = () => speed;
  return { GetSpeed }
}
const rabbit = RabbitFactory();
rabbit.GetSpeed() // -> 3
rabbit.speed // -> undefined!

我更喜欢Factory函数而不是构造函数,原因是:

  • 您无需弄乱原型
  • 您不需要使用Object构造函数
  • 使您能够选择工厂中的私人物品和公共物品
    (在我的示例中,速度是私有的,这是一个好习惯。如果要读取Rabbit的速度值,请使用GetSpeed吸气剂)

答案 5 :(得分:0)

这篇文章听起来像道格拉斯·克罗克福德演讲。无论如何,它提到了这种模式。

function RabbitFactory(){
rabbit = Object.create({ getSpeed: function() {
                                     return this.speed;
                                   }
                       });
rabbit.speed = 3;
return rabbit;
}
ES6中引入了

setPrototypeOf / getPrototypeOf__proto__属性,而Object.create()是ES5功能。 setPrototypeOf / getPrototypeOf__proto__适用于子类,但不应与Object.create()一起使用

我会继续使用构造函数。