美文网首页
再探原型模式

再探原型模式

作者: 鑫的盒蛋真厉害 | 来源:发表于2018-11-08 16:55 被阅读0次

再探原型模式

一切都是对象

在JavaScript这门语言中,获取对象的唯一途径就是克隆,而JavaScript中的根对象是Object.prototype,我们遇到的每一个对象实际上都是从这个Object.prototype克隆而来的。但我们并不需要关系克隆的细节,因为这是引擎内部负责实现的,我们只需要调用var obj1 = new Object()或者var obj2 = {},内部引擎就会从Object.prototype上克隆一个对象出来。所以可以这么说:在JavaScript中,一切都是对象。

原型模式

我们先来看一下下面这2行代码

function F() {}
var f = new F()

这段简单的代码包含了好几个概念:

  1. 构造函数
  2. prototype属性
  3. constructor属性
  4. __proto__属性
  5. new操作符

所谓的构造函数其实就是普通的函数,叫作构造函数仅仅是告诉我们:这个函数将来是被用作创建对象的。

在JavaScript中,每一个函数都有天然的拥有5个属性:length, name, arguments, caller, prototype。

image

PS: 几个获取对象属性名的API

Object.keys(obj) // 获取obj的属性名(无法获取Symbol属性)
Object.getOwnPropertyNames(obj)  // 获取obj的属性名(无法获取Symbol属性)
Object.getOwnPropertySymbols(obj)  // 获取obj的Symbol属性名
Reflect.ownKeys(obj)  // 获取obj所有类型的键名,包括常规键名和 Symbol 键名。

函数的prototype属性指向一个对象,这个对象在创建函数的时候自动生成,并且拥有一个constructor属性,constructor属性指向这个函数。

在上面的那2行代码中,f是构造函数F()生成的对象,通过设置构造函数的prototype实现原型继承的时候,除了根对象Object.prototyp,任何对象都有一个内部属性[[Prototype]],它指向这个构造函数的原型

《javaScript高级程序设计(第三版)P148》

当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性) ,指向构造函数的原型对象。ECMA-262 第 5 版中管这个指针叫 [[Prototype]] 。虽然在脚本中没有标准的方式访问 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每个对象上都支持一个属性__proto__ ;而在其他实现中,这个属性对脚本则是完全不可见的。

image

但是现在__proto__属性已在ES6中标准化,现在更推荐使用Object.getPrototypeOf/Reflect.getPrototypeOf 和Object.setPrototypeOf/Reflect.setPrototypeOf来读写[[Prototype]]。

__proto__的读取器(getter)暴露了一个对象的内部 [[Prototype]] :

  1. 对于使用对象字面量创建的对象,这个值是 Object.prototype。
  2. 对于使用数组字面量创建的对象,这个值是 Array.prototype。
  3. 对于functions,这个值是Function.prototype。
  4. 对于使用 new fun 创建的对象,其中fun是由js提供的内建构造器函数之一(Array, Boolean, Date, Number, Object, String 等等),这个值总是fun.prototype。
  5. ==对于用js定义的其他js构造器函数创建的对象,这个值就是该构造器函数的prototype属性。==(这是最常见的形式)

__proto__ 的设置器(setter)允许对象的 [[Prototype]]被变更。前提是这个对象必须通过 Object.isExtensible(): 进行扩展,如果不这样,一个 TypeError 错误将被抛出。要变更的值必须是一个object或null,提供其它值将不起任何作用。

默认情况下,对象是可扩展的:即可以为他们添加新的属性。以及它们的__proto__ 属性可以被更改。Object.preventExtensions,Object.seal 或 Object.freeze 方法都可以标记一个对象为不可扩展(non-extensible)。

// 新对象默认是可扩展的.
var empty = {};
Object.isExtensible(empty); // === true

// ...可以变的不可扩展.
Object.preventExtensions(empty);
Object.isExtensible(empty); // === false

// 密封对象是不可扩展的.
var sealed = Object.seal({});
Object.isExtensible(sealed); // === false

// 冻结对象也是不可扩展.
var frozen = Object.freeze({});
Object.isExtensible(frozen); // === false

那么new操作符做了什么事情呢?通过new调用构造函数实际上经历了4步:

  1. 创建一个新对象
  2. 将this指向这个新对象
  3. ==执行构造函数(为新对象添加属性)==
    (PS: 这就是为什么使用new来实现继承会导致额外的构造函数调用,戳这里见详情:额外的构造函数调用
  4. 返回这个对象

理解new操作符

为了理解new操作符,我们自己动手模拟一个new(或者说,假如没有new,我们该如何实现创建对象?)

function Point(x, y) {
    this.x = x
    this.y = y
}

Point.prototype.getLength = function () {
    let {x, y} = this
    return Math.sqrt(x * x + y * y)
}

function defineClass(initializer) {
    return function f(...args) {
        f.prototype = initializer.prototype    // 确保instanceof正确
        let obj = Object.create(initializer.prototype)  //创建一个新队对象
        initializer.apply(obj, args)    // 将this指向这个对象,并执行构造函数
        return obj    // 返回这个对象
    }
}

var p1 = defineClass(Point)(3, 4)
var p2 = new Point(5, 12)
console.log([p1.x, p1.y, p1.getLength(), p1 instanceof Point])
console.log([p2.x, p2.y, p2.getLength(), p2 instanceof Point])
// [3, 4, 5, true]
// [5, 12, 13, true]

其他

Object.create

这里用到了Object.create。关于Object.create的相关内容移步这里:

关于Object.create的那点事

相关文章

  • 再探原型模式

    再探原型模式 一切都是对象 在JavaScript这门语言中,获取对象的唯一途径就是克隆,而JavaScript中...

  • 初始设计模式之原型模式

    原型模式是什么? 原型模式怎么用?浅拷贝深拷贝 原型模式再理解 一、原型模式是什么? ​ 原型模式是一种创建型设计...

  • 了解原型模式

    原型模式(Prototype Pattern)是首先创建一个原型对象,再通过复制这个原型对象来创建更多同类型的对象...

  • 第3章 创建型模式-原型模式

    一、原型模式简介 二、原型模式的优点 ■ 三、原型模式的使用场景 ■ 四、原型模式的实例

  • 设计模式之原型模式(Prototype 模式)

    引入原型模式 原型模式的实例 为什么需要使用原型模式 引入原型模式 如果读者很熟悉javascript的话,对原型...

  • 设计模式之原型模式(创建型)

    [TOC] 模式定义 原型模式(Prototype Pattern):原型模式是提供一个原型接口,提供原型的克隆,...

  • 原型模式C++

    原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 原型模式结构图 原型模式基本代码 原型...

  • 设计模式:原型

    原型模式基本介绍原型模式的实现源码中的原型模式记录 原型模式基本介绍 定义:用原型实例指定创建对象的种类,并通过复...

  • js集成

    原始继承模式--原型链 2:借用构造函数 3:共享构造原型 4:圣杯模式原型链; 构造函数; 共享原型; 圣杯模式...

  • 关于JavaScript创建对象的多种方式

    JavaScript创建对象的方法 工厂模式 构造函数模式 原型模式 组合使用构造函数模式和原型模式 动态原型模式...

网友评论

      本文标题:再探原型模式

      本文链接:https://www.haomeiwen.com/subject/mpwwxqtx.html