资讯专栏INFORMATION COLUMN

原型模式

ad6623 / 1033人阅读

摘要:原型模式与基于原型继承的对象系统原型模式不单是一种设计模式,也被称为一种编程范型。写一个函数实现的功能获取构造器,也就是创建一个新对象,并将原型指向构造器的原型。

原型模式与基于原型继承的 JavaScript 对象系统

原型模式不单是一种设计模式,也被称为一种编程范型。原型模式又一个重要的特性就是,当对象无法响应某个请求时,就会把该请求委托给它的原型。

使用克隆的原型模式

从设计模式的角度讲,原型模式是用于创建对象的一种模式,如果我们想要创建一个对象,一种方法是先指定它的类型,然后通过类来创建这个对象。原型模式选择了另一种方式,不再关心对象的类型,而是找到一个对象,然后通过克隆来创建一个一摸一样的对象。
但原型模式的真正目的并非在于需要得到一个一摸一样的对象,而是提供一种便捷的方式去创建某个类型的对象,克隆只是创建这个对象的过程和手段。

Object.create

ECMAScript 5 提供了Object.create来克隆一个对象,严格来说是创建一个新对象,使用现有的对象来提供新创建的对象的__proto__

const Coder = function() {
  this.name = "Ashin";
  this.age = 18;
  this.gender = "male";
};

const cloneCoder = Object.create(Coder);

console.log(cloneCoder);
console.log(cloneCoder.name);
console.log(cloneCoder.age);
console.log(cloneCoder.gender);

手动实现 Object.create:

const objCreate = function(obj) {
  const F = function() {};
  F.prototype = obj;
  return new F();
};

const cloneCoder = objCreate(Coder);

console.log(cloneCoder);
console.log(cloneCoder.name);
console.log(cloneCoder.age);
console.log(cloneCoder.gender);

Object.prototype

事实上,JavaScript 中的根对象是 Object.prototype 对象,它是一个空对象。我们在 JavaScript 遇到的每个对象,都是从 Object.prototype 对象克隆而来的, Object.prototype 对象就是它们的原型。

const o1 = new Object();
const o2 = {};

// 用 ES5 提供的 Object.getPrototypeOf 来查看两个对象的原型
console.log(Object.getPrototypeOf(o1) === Object.prototype); // true
console.log(Object.getPrototypeOf(o2) === Object.prototype); // true
new 运算符

运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。new 关键字会进行如下的操作:

创建一个空的简单 JavaScript 对象(即{});

链接该对象(即设置该对象的构造函数)到另一个对象 ;

将步骤 1 新创建的对象作为 this 的上下文 ;

如果该函数没有返回对象,则返回 this。

先看一段代码:

function Person(name) {
  this.name = name;
}
Person.prototype.getName = function() {
  return this.name;
};

const p = new Person("Ashin");

console.log(p); // Person {name: "Ashin"}
console.log(p.name); // Ashin
console.log(p.getName()); // Ashin
console.log(Object.getPrototypeOf(p) === Person.prototype); // true

强调一下,在 JavaScript 中没有类的概念。这里的 Person 并不是类,而是函数构造器。当使用 new 运算符调用函数时,此时的函数就是一个构造器。用 new 运算符来创建对象的过程,是通过克隆 Object.prototype 来得到新的对象(但实际上并不是每次都真正地克隆了一个新的对象),再进行一些其他的额外操作的过程。

写一个函数实现 new 的功能:

const _new = function() {
  const Constructor = [].shift.call(arguments); // 获取构造器,也就是 Person
  const obj = Object.create(Constructor.prototype); // 创建一个新对象,并将原型(__proto__) 指向构造器的原型 (Constructor.prototype)。
  const ret = Constructor.apply(obj, arguments); // 将新建的对象作为this的上下文执行构造器
  return typeof ret === "object" ? ret : obj; // 如果构造器没有返回对象则返回新建的对象
};

const p2 = _new(Person, "Ashin");

console.log(p2); // Person {name: "Ashin"}
console.log(p2.name); // Ashin
console.log(p2.getName()); // Ashin
console.log(Object.getPrototypeOf(p2) === Person.prototype); // true
(原型)继承

先来看一段典型的“原型风格”:

function Parent(name) {
    this.name = name;
}

Parent.prototype.showInfo = function() {
    console.log(this.name);
}


function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}

// 注意!下面执行后没有 Bar.prototype.constructor 了 
// 如果你需要这个属性的话可能需要手动修复一下它
Child.prototype = Object.create(Parent.prototype);

// 多态
Child.prototype.showInfo = function() {
    Parent.prototype.showInfo.call(this);
    console.log(this.age);
}

Child.prototype.dance = function() {
    console.log(this.name + " dance");
}

var tom = new Child("Tom", 10);
tom.showInfo()
tom.dance()
console.log(tom)
参考

曾探. JavaScript设计模式与开发实践 (图灵原创) (Chinese Edition)
你不知道的JavaScript(上卷)
MDN Web 文档

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106769.html

相关文章

  • 理解JavaScript的核心知识点:原型

    摘要:首先,需要来理清一些基础的计算机编程概念编程哲学与设计模式计算机编程理念源自于对现实抽象的哲学思考,面向对象编程是其一种思维方式,与它并驾齐驱的是另外两种思路过程式和函数式编程。 JavaScript 中的原型机制一直以来都被众多开发者(包括本人)低估甚至忽视了,这是因为绝大多数人没有想要深刻理解这个机制的内涵,以及越来越多的开发者缺乏计算机编程相关的基础知识。对于这样的开发者来说 J...

    iKcamp 评论0 收藏0
  • JS函数的工厂模式、构造函数模式原型模式的区别

    摘要:于是就有了构造函数和原型模式混合模式组合使用构造函数模式和原型模式创建自定义类型最常见的方式,就是组合模式。 创建对象 JS有六种数据数据类型,其中五种属于基本数据类型:Null、Boolean、undefined、String、Number。而其它值都是对象。数组是对象,函数是对象,正则表达式是对象。对象也是对象。 来看一下对象的定义: 无序属性的集合,其属性可以包含基本值、对象、或...

    william 评论0 收藏0
  • 读《javaScript高级程序设计-第6章》之封装类

    摘要:创建构造函数后,其原型对象默认只会取得属性至于其他的方法都是从继承来的。上图展示了构造函数的原型对象和现有的两个实例之间的关系。所有原生的引用类型都在其构造函数的原型上定义了方法。 第6章我一共写了3篇总结,下面是相关链接:读《javaScript高级程序设计-第6章》之理解对象读《javaScript高级程序设计-第6章》之继承 工厂模式 所谓的工厂模式就是,把创建具体对象的过程抽象...

    seal_de 评论0 收藏0
  • JS基础之数据类型、对象、原型原型链、继承

    摘要:就是通过调用构造函数而创建的那个对象实例的原型对象。构造函数模式可以创建自定义引用类型,可以像创建内置对象实例一样使用操作符。 数据类型: 简单数据类型:Undefined、Null、String、Number、Boolean、Symbol 复杂数据类型:Object // Undefined:声明,但未初始化 // Null:空对象指针 typeof操作符(检测基本数据类型): ...

    LucasTwilight 评论0 收藏0
  • JavaScript_高程三_02

    摘要:实例中的指针仅指向原型,而不指向构造函数。调用构造函数时会为实例添加一个指向最初原型的或者而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。 面向对象的程序设计 ECMA-262定义对象:无序属性的集合,其属性可以包含基本值,对象或者函数。普通理解:对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射一个值。 每个对象都是基于一个引用类型创建...

    hidogs 评论0 收藏0
  • 理解js对象

    摘要:将构造函数的作用域赋值给新对象因此指向了新对象执行构造函数的代码为这个新对象添加属性返回对象最初是用来标识对象类型的。但提到检测对象类型,还是使用将构造函数当作函数构造函数与其他函数唯一区别。 创建对象 虽然Object构造函数与对象字面量都能创建单个对象, 但这些方式都有明显的缺点: 使用同一个接口创建很多对象, 会产生大量重复代码。 var obj = {}; //对象字面量 va...

    zhouzhou 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<