如果你开始写着构造函数或者类,但是写着写着,你发现需要工厂函数的灵活性,这个时候你不能简单的就改改简单改改函数一走了之。
不幸的是,你是个JavaScript程序员,构造器改造成工厂函数是一个大手术:
// 原来的实现: // class Car { // drive () { // console.log('Vroom!'); // } // } // const AutoMaker = { Car }; // 工厂函数改变的实现: const AutoMaker = { Car (bundle) { return Object.create(this.bundle[bundle]); }, bundle: { premium: { drive () { console.log('Vrooom!'); }, getOptions: function () { return ['leather', 'wood', 'pearl']; } } } }; // 期望中的用法是: const newCar = AutoMaker.Car('premium'); newCar.drive(); // 'Vrooom!' // 但是因为他是一个库 // 许多地方依然这样用: const oldCar = new AutoMaker.Car(); // 如此就会导致: // TypeError: Cannot read property 'undefined' of // undefined at new AutoMaker.Car
在上面例子里面,我们从一个类开始,最后把它改成来一个可以根据特定的原型来创建对象的工厂函数,这样的函数可以广泛应用于接口抽象和特殊需求定制。
4. 使用构造器让 instanceof 有可乘之机
构造函数和工厂函数的不同就是 instanceof 操作符,很多人使用 instanceof 来确保自己代码的正确性。但是说实话,这是有很大问题的,建议避免 instanceof 的使用。
instanceof 会说谎。
// instanceof 是一个原型链检查 // 不是一个类型检查 // 这意味着这个检查是取决于执行上下文的, // 当原型被动态的重新关联, // 你就会得到这样令人费解的情况 function foo() {} const bar = { a: 'a'}; foo.prototype = bar; // bar是一个foo的实例吗,显示不是 console.log(bar instanceof foo); // false // 上面我们看到了,他的确不是一个foo实例 // baz 显然也不是一个foo的实例,对吧? const baz = Object.create(bar); // ...不对. console.log(baz instanceof foo); // true. oops.
instanceof 并不会像其他强类型语言那样做检查,他只是检查了原型链上的对象。
在一些执行上下文中,他就会失效,比如你改变了 Constructor.prototype 的时候。
又比如你开始些的是一个构造函数或者类,之后你又将它拓展为一个另一个对象,就像上面改写成工厂函数的情况。这时候 instanceof 也会有问题。
总而言之, instanceof 是另一个构造函数和工厂函数呼唤的大改变。
用类的好处
- 一个方便的,自包含的关键字
- 一个唯一的权威性方法在JavaScript来实现类。
- 对于其他有class的语言开发经验的开发者有很好的体验。
用类的坏处
构造器所有的坏处, 加上: