《JavaScript设计模式》——9.7 Prototype(原型)模式

    xiaoxiao2024-07-03  110

    本节书摘来自异步社区《JavaScript设计模式》一书中的第9章,第9.7节, 作者: 【美】Addy Osmani 译者: 徐涛 更多章节内容可以访问云栖社区“异步社区”公众号查看。

    9.7 Prototype(原型)模式

    “四人组”称Prototype模式为一种基于现有对象模板,通过克隆方式创建对象的模式。

    我们可以认为Prototype模式是基于原型继承的模式,可以在其中创建对象,作为其他对象的原型。prototype对象本身实际上是用作构造函数创建每个对象的蓝图。如果所用构造函数的原型包含一个名为name的属性(代码样例如下),那么由同样的构造函数创建的每个对象也会有同样的属性(见图9-6)。

    如果查看现有(非JavaScript)文献对该模式的定义,我们可能会再一次发现对类的引用。现实情况是,原型继承避免和类(Class)一起使用。理论上没有“定义”的对象,也没有核心的对象。我们仅是创建现有功能对象的拷贝。

    使用Prototype模式的其中一个好处是,我们获得的是JavaScript其本身所具有的原型优势,而不是试图模仿其他语言的特性。与其他设计模式一起使用时,情况并非总是如此。

    模式不仅是一种实现继承的简单方法,它也可以带来性能提升:在一个对象中定义一个函数,它们都是由引用创建(因此所有子对象都指向相同的函数),而不是创建它们自己的单份拷贝。

    如同ECMAScript5标准所定义的,那些有趣的、真正的原型继承要求使用Object.create(我们在本节的前面曾看到过)。Object.create创建一个对象,拥有指定原型和可选的属性(例如Object.create(prototype, optionalDescriptorObjects))。

    在下面的示例中可以看到它的演示:

    var myCar = { name: "Ford Escort", drive: function () { console.log("Weeee. I'm driving!"); }, panic: function () { console.log("Wait. How do you stop this thing?"); } };

    // 使用Object.create实例化一个新car

    var yourCar = Object.create(myCar);

    // 现在可以看到一个对象是另外一个对象的原型

    console.log(yourCar.name);

    Object.create还允许我们轻松实现差异继承等高级概念,通过差异继承,对象可以直接继承自其他对象。我们之前已经了解到,Object.create允许我们使用第二个提供的参数来初始化对象属性。例如:

    var vehicle = { getModel: function () { console.log("The model of this vehicle is.." + this.model); } }; var car = Object.create(vehicle, { "id": { value: MY_GLOBAL.nextId(), // writable:false, configurable:false 默认值 enumerable: true }, "model": { value: "Ford", enumerable: true } });

    在这里,可以使用对象字面量在Object.create的第二个参数上初始化属性,并且对象字面量采用的语法与Object.defineProperties和Object.defineProperty方法所使用的语法相似,我们之前已经了解过这些方法。

    值得注意的是,在枚举对象的属性以及在hasOwnProperty()检查中包装循环内容时(Crockford推荐),原型关系可能会引起麻烦。

    如果希望在不直接使用Object.create的情况下实现Prototype模式,我们可以按照上面的示例模拟该模式,如下所示:

    var vehiclePrototype = { init: function (carModel) {![图像说明文字](/api/storage/getbykey/inlineimage?key=1505687bf25eb899163d) this.model = carModel; }, getModel: function () { console.log("The model of this vehicle is.." + this.model); } }; function vehicle(model) { function F() { }; F.prototype = vehiclePrototype; var f = new F(); f.init(model); return f; } var car = vehicle("Ford Escort"); car.getModel();

    这个方案不允许用户以同样的方式定义只读属性(因为如果不小心,vehiclePrototype可能会被改变)。最后一种可供选择的Prototype模式实现可以是这样的:

    var beget = (function () { function F() { } return function (proto) { F.prototype = proto; return new F(); }; })();

    我们可以从vehicle函数引出这个方法。请注意,这里的vehicle模仿了一个构造函数,因为Prototype模式不包含任何初始化的概念,而不仅是将对象链接至原型。

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)