详解Javascript中的class、构造函数、工厂函数

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

详解Javascript中的class、构造函数、⼯⼚函数
到了ES6时代,我们创建对象的⼿段⼜增加了,在不同的场景下我们可以选择不同的⽅法来建⽴。

现在就主要有三种⽅法来构建对象,class关键字,构造函数,⼯⼚函数。

他们都是创建对象的⼿段,但是却⼜有不同的地⽅,平时开发时,也需要针对这不同来选择。

⾸先我们来看⼀下,这三种⽅法是怎样的
// class 关键字,ES6新特性
class ClassCar {
drive () {
console.log('Vroom!');
}
}
const car1 = new ClassCar();
console.log(car1.drive());
// 构造函数
function ConstructorCar () {}
ConstructorCar.prototype.drive = function () {
console.log('Vroom!');
};
const car2 = new ConstructorCar();
console.log(car2.drive());
// ⼯⼚函数
const proto = {
drive () {
console.log('Vroom!');
}
};
function factoryCar () {
return Object.create(proto);
}
const car3 = factoryCar();
console.log(car3.drive());
这些⽅法都是基于原型的创建,⽽且都⽀持在构造时函数中私有变量的实现。

换句话来说,这些函数拥有着⼤部分相同的特性,甚⾄在很多场景下,他们是等价的。

在 Javascript 中,每⼀个函数都能返回⼀个新的对象。

当它不是构造函数或者类的时候,它就被称作⼯⼚函数。

ES6的类其实是构造函数的语法糖(⾄少现阶段是这样实⾏的),所以接下来讨论的所有内容都适⽤于构造函数的也适⽤于ES6类:
class Foo {}
console.log(typeof Foo); // function
构造函数和ES6类的好处
⼤部分的书会教你去⽤类和构造函数
‘ this ' 是指向新的这个对象的。

⼀些⼈喜欢 new 关键字的可读性
也许还会有⼀些很⼩的细节⽅⾯的差别,但是如果在开发过程中没有问题的话,也不⽤太担⼼。

构造函数和ES6类的坏处
1. 你需要 new 关键字
到了ES6,构造函数和类都需要带 new 关键字。

function Foo() {
if (!(this instanceof Foo)) { return new Foo(); }
}
在ES6中,如果你尝试调⽤类函数没有 new 关键字就会抛出⼀个任务。

如果你要个不⽤ new 关键字的话,就只能使⽤⼯⼚函数把它包起来。

2. 实例化过程中的细节暴露给了外界API
所有的调⽤都紧紧的关联到了构造器的实现上,如果你需要⾃⼰在构造过程中动⼀些⼿脚,那就是⼀个⾮常⿇烦的事情了。

3. 构造器没有遵守 Open / Closed 法则
因为 new 关键字的细节处理,构造器违反 Open / Closed 法则:API应该开放拓展,避免修改。

我曾经质疑过,类和⼯⼚函数是那么的相似,把类函数升级为⼀个⼯⼚函数也不会有什么影响,不过在JavaScript⾥⾯,的确有影响。

如果你开始写着构造函数或者类,但是写着写着,你发现需要⼯⼚函数的灵活性,这个时候你不能简单的就改改简单改改函数⼀⾛了之。

不幸的是,你是个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的语⾔开发经验的开发者有很好的体验。

⽤类的坏处
构造器所有的坏处, 加上:
使⽤ extends 关键字创建⼀个有问题的类,对于⽤户是⼀个很⼤的诱惑。

类的层级继承会造成很多有名的问题,包括 fragile base class(基础类会因为继承被破坏),gorilla banana problem(对象混杂着复杂的上下⽂环境),duplication by necessity(类在继承多样化时需要时时修改)等等。

虽然其他两种⽅法也有可能让你陷⼊这些问题,但是在使⽤ extend 关键字的时候,环境使然,就会把你引导上这条路。

换句话说,他引导你向着⼀个不灵活的关系编写代码,⽽不是更有复⽤性的代码。

使⽤⼯⼚函数的好处
⼯⼚函数⽐起类和构造函数都更加的灵活,也不会把⼈引向错误的道路。

也不会让你陷⼊深深的继承链中。

你可以使⽤很多⼿段来模拟继承
1. ⽤任意的原型返回任意的对象
举个例⼦,你可以通过同⼀个实现来创建不同的实例,⼀个媒体播放器可以针对不同的媒体格式来创建实例,使⽤不同的API,或者⼀个事件库可以是针对DOM时间的或者ws事件。

⼯⼚函数也可以通过执⾏上下⽂来实例化对象,可以从对象池中得到好处,也可以更加灵活的继承模型。

2. 没有复杂重构的担忧
你永远不会有把⼯⼚函数转换成构造函数这样的需求,所以重构也没必要。

3. 没有 new
你不⽤new关键字来新建对象,⾃⼰可以掌握这个过程。

4. 标准的 this ⾏为
this 就是你熟悉的哪个this,你可以⽤它来获取⽗对象。

举个例⼦来说,在 player.create() 中,this指向的是player,也可以通过call和apply来绑定其他this。

5. 没有 instanceof 的烦恼
6. 有些⼈喜欢直接不带new的写法的可读直观性。

⼯⼚函数的坏处
并没有⾃动的处理原型,⼯⼚函数原型不会波及原型链。

this 并没有⾃动指向⼯⼚函数⾥的新对象。

也许还会有⼀些很⼩的细节⽅⾯的差别,但是如果在开发过程中没有问题的话,也不⽤太担⼼。

结论
在我看来,类也许是⼀个⽅便的关键字,但是也不能掩饰他会把毫⽆防备的⽤户引向继承深坑。

另⼀个风险在于未来的你想要使⽤⼯⼚函数的可能性,你要做⾮常⼤的改变。

如果你是在⼀个⽐较⼤的团队协作⾥⾯,如果要修改⼀个公共的API,你可能⼲扰到你并不能接触到的代码,所以你不能对改装函数的影响视⽽不见。

⼯⼚模式很棒的⼀个地⽅在于,他不仅仅更加强⼤,更加灵活,也可以⿎励整个队伍来让API更加简单,安全,轻便。

总结
以上所述是⼩编给⼤家介绍的详解Javascript 中的 class、构造函数、⼯⼚函数,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。

在此也⾮常感谢⼤家对⽹站的⽀持!。

相关文档
最新文档