详解 javascript对象创建模式

创建模式

在javascript中,主要有以下几种创建模式:

工厂模式
构造函数模式
原型模式
组合模式
动态原型模式
寄生构造函数模式
稳妥构造模式

工厂模式

工厂模式是软件工程领域一种广为人知的设计模式。javascript实现方式:

function createPerson(name, obj, job) {
    var o = new Object();
    o.name = name;
    o.obj = obj;
    o.job = job;
    o.sayName = function() {
      alert(this.name);
    }
    return o;
  }

  var person1 = createPerson("Nicholas", 29, "software Enginner");
  var person2 = createPerson("Greg", 27, "Doctor");

工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别问题

构造函数模式

function Person(name, age, job) {
    this.name = name;
    this.age = name;
    this.job = name;
    this.sayName = function () {
      alert(this.name);
    }
  }

  var person1 = new Person("Nicholas", 29, "Software Engineer");
  var person2 = new Person("Greg", 27, "Doctor");

  person1 instanceof Person; // true
  person1 instanceof Object; // true

  person2 instanceof Person; // true
  person2 instanceof Object; // true

new操作符实现原理请查看文章附录

不同于工厂模式,构造函数模式

没有显示创建对象

直接将属性和方法赋值给了this对象

没有return语句

解决了对象识别问题

但是构造函数模式同样存在问题,就是每个方法都要在每个实例上重新申明一遍。person1和person2都有一个名为 sayName() 的方法,但那两个方法不是同一个Function实例。(在javascript中,函数实质上也是对象,因此每定义一个函数,也就是实例化一个对象。)

通过吧函数定义转移到构造函数外部可以解决这个问题:

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
  }
  function sayName() {
    alert(this.name);
  }
  var person1 = new Person("Nicholas", 29, "Software Engineer");
  var person2 = new Person("Greg", 27, "Doctor");

但这种方式又带来了一个新的问题,我们在全局创建了一个全局函数。

需要注意一点,按照惯例,构造函数始终应该以一个大写字母开头,而非构造函数应该以一个小写字母开头。这主要用于区别构造函数和非构造函数,因为构造函数本身也是函数。

原型模式

我们创建的每个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途可以由特定类型的所有实例共享的属性和方法。

函数原型对象请查看附录

通过原型模式创建对象,我们不必在构造函数中定义对象实例的信息,同时实例化多个对象,每个对象不会再申明一个新的函数。

可以看到, person1.sayName 和 person2.sayName 都指向了同一个函数。

但是原型模式的缺点也是显而易见的。

首先原型模式省略了构造函数模式传递参数这一环节,结果导致所有实例的初始值在默认情况下都是相同的属性值。

更重要的是,因为将属性和方法都放置在原型对象上,实质上原型上的属性是 被所有实例所共享的 。对于包含基本值的属性还表现正常,改变属性值,只是在实例上添加一个同名属性。但对于引用类型值的属性来说,这可能是个灾难。

function Person() {}

  Person.prototype = {
    constructor: Person,
    name: "Nicholas",
    age: 29,
    job: "Software Engineer",
    friends: ["shelby", "Court"],
    sayName: function() {
      alert(this.name);
    }
  };

  var person1 = new Person();
  var person2 = new Person();

  person1.friends.push("Van");

  person1.friends; // ["shelby", "Court", "Van"]
  person2.friends; // ["shelby", "Court", "Van"]

组合模式

创建自定义类型最常见的方式,就是组合使用构造函数模式和原型模式。构造模式用于定义实例属性,而原型模式用于定义方法和共享属性。

这样,每个实例都会有自己的一份实例属性副本,但同时又共享方法的引用。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
  }

  Person.prototype.sayName = function() {
    alert(this.name);
  }

  var person1 = new Person("Nicholas", 29, "Software Enginner");
  var person2 = new Person("Greg", 27, "Doctor");

  person1.friends.push("Van");

  person1.firends; // ["Shelby", "Court", "Van"];
  person2.firends; // ["Shelby", "Court"]

  person1.firends === person2.firends; // false
  person1.sayName === person2.sayName; // true

动态原型模式

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;

    if (typeof this.sayName != "function") {
      Person.prototype.sayName = function() {
        alert(this.name);
      }
    }
  }

寄生构造函数模式

寄生模式的基本概念就是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象。

function Person(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job.

    o.sayName = function() {
      alert(this.name);
    }
  }

  var person1 = new Person("Nicholas", 29, "Software Engineer");
  person1.sayName(); // "Nicholas"

看起来,除了使用new操作符之外,这个模式和工厂模式其实是一模一样的。
这个模式可以在特殊的情况下用来作为对象创建构造函数。
假设我们需要一个具有额外方法的特殊数组类型。由于不能直接修改Array构造函数,因此可以使用这个模式。

  function SpecialArray() {
    var values = [];

    values.push.push(values, arguments);
    values.toPipedString = function() {
      return this.join("|");
    }

    return values;
  }

  var colors = new SpecialArray("red", "blue", "green");
  colors.toPipedString(); // "red|blue|green"

该模式主要缺点:
返回的对象和构造函数或构造函数的原型属性间没有关系,不·能依赖instanceof来确定对象类型。
在其他模式能够使用的情况下,尽量不要使用这种模式。

稳妥构造函数模式

  function Person(name, age, job) {
    var o = new Object();
    var name = name;
    var age = age;
    var job = jbo;

    o.sayName = function() {
      alert(name);
    }
  }

  var person1 = Person("Nicholas", 29, "Software Enginner");
  firend.sayName(); // "Nicholas"
  1. 附录
  2. new 操作符

new操作符实际上会经历4个步骤:

  1. 创建一个空的简单JavaScript对象(即**{}**);
  2. 链接该对象(设置该对象的constructor)到另一个对象 ;
  3. 将步骤1新创建的对象作为**this**的上下文 ;
  4. 如果该函数没有返回对象,则返回**this**。
  function new(func) {
    var o = {};
    o.__proto__ = func.prototype;
    var result = func.apply(o, arguments);
    return typeof result === "object" ? object : o;
  }

函数原型对象

理解原型对象

无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个construtor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。

在创建了一个自定义的构造函数之后,其原型对象只会取得construtoe属性,至于其他属性,则都是从Object继承而来。当调用构造函数创建一个新实例时,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象,这个指针叫[[Prototype]]。在多数浏览器中,每个对象都支持一个属性__proto__来调用[[Prototype]]。

虽然所有实现都无法直接访问[[Prototype]],但可以通过isPrototype方法来确定对象之间是否存在关系。

我们测试了person1和person2,都返回了true。因为他们内部都有一个指向Person.prototype的指针。

Object.getPrototype()可以返回对象的原型对象。

每当代码读取某个对象的属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先会从对象本身开始,如果在实例中找到了对应的属性,则返回该属性的值。如果没找到,则继续搜索指针指向的原型对象。这也是为什么我们在person1和person2两个实例中,并没有定义sayName这个属性,但仍能够正常使用。
我们在调用person1.sayName()是,会执行两次搜索。首先,解析器会问:“实例person1有sayName属性吗?”,答:“没有”。然后他继续搜索,再问:“person1的原型有sayName属性吗?”,答:“有”。于是,它就读取保存在原型中的函数。

虽然我们能够通过实例访问原型的属性,但却不能重新原型的属性。
如果我们在实例上添加属性名,而这个属性名又与原型中的属性名相同,即我们希望在实例中重写属性。

  function Person() {}
  Person.prototype.name = 'Nicholas';

  var person1 = new Person();
  var person2 = new Person();

  person1.name === person2.name; // true
  person1.name = 'Greg';

  person1.name === person2.name; // false
  person1.name; // 'Greg'
  person2.name; // 'Nicholas'

  person1.__proto__.name; // 'Nicholas'

事实上,当我们重写原型属性时,只是在实例上添加了一个新属性。当我们把实例上的属性删除后,又会暴露出原型属性。

  delete person1.name;
  person1.name; // 'Nicholas'

使用hasOwnProperty()函数能判断属性是否在实例上。

  person1.hasOwnProperty('name'); // false
  person1.name = 'Greg';
  person1.hasOwnProperty('name'); // true

以上就是详解 javascript对象创建模式的详细内容,更多关于Java 创建模式的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解js创建对象的几种方式和对象方法

    这篇文章是看js红宝书第8章,记的关于对象的笔记(第二篇). 创建对象的几种模式: 工厂模式: 工厂是函数的意思.工厂模式核心是定义一个返回全新对象的函数. function getObj(name, age) { let obj = {} obj.name = name obj.age = age return obj } let person1 = getObj("cc", 31) 缺点:不知道新创建的对象是什么类型 构造函数模式: 通过一个构造函数,得到一个对象实例. 构造函数和

  • JS 创建对象的模式实例小结

    本文实例总结了JS 创建对象的模式.分享给大家供大家参考,具体如下: 1.工厂模式 抽象了创建具体对象的过程,创建了一种函数,封装特定的接口创建对象的细节. 新建一个对象 定义属性和方法 return刚新建的对象 function createPerson(name, age, job) { var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.sayHi = function() { congsol

  • JS自定义对象创建与简单使用方法示例

    本文实例讲述了JS自定义对象创建与简单使用方法.分享给大家供大家参考,具体如下: <html> <head> <title>js自定义函数</title> <meta charset="UTF-8"/> <script type="text/javascript"> //创建自定义对象 //方法一: // var obj=new Object(); //方法二 var obj={}; obj.n

  • JavaScript创建对象的四种常用模式实例分析

    本文实例讲述了JavaScript创建对象的四种常用模式.分享给大家供大家参考,具体如下: 这里介绍了javascript中创建对象常用的几种模式,包括:工厂模式,构造函数模式,原型模式,组合构造函数与原型的模式,动态原型模式. 一.工厂模式 看如下代码: function getMySon(name,sex){ var o={}; o.name=name; o.sex=sex; o.sayName = function(){ alert(this.name); } return o; } so

  • js 创建对象的多种方式与优缺点小结

    目录 早期创建方式 工厂模式 构造函数模式 构造函数模式优化 原型模式 构造函数和原型模式组合 动态原型模式 寄生构造函数模式 稳妥构造函数模式 早期创建方式 var obj = new Object() obj.name ='xxx' obj.age = 18 或使用对象字面量 var o1 = { name: 'xxx', say: () => {} } var o2 = { name: 'xxx', say: () => {} } 缺点:使用同一个接口创建很多对象,会产生大量重复代码 工

  • JavaScript 面向对象程序设计详解【类的创建、实例对象、构造函数、原型等】

    本文实例讲述了JavaScript 面向对象程序设计.分享给大家供大家参考,具体如下: 类的创建于实例对象 工厂模型创建对象 function CreatePerson ( name,sex,age ) { var obj = new Object(); obj.name = name; obj.sex = sex; obj.age = age; obj.sayName = function () { console.log( this.name ); } return obj; } var p

  • JavaScript 对象创建的3种方法

    目录 1.对象字面量 2.new 关键字创建对象 3.使用 Object.create() 创建对象 4. 使用扩展操作符:... 5.使用Object.assign()方法 6.简写属性 7.简写方法 前言: 在 JavaScript中,对象是一组有属性名和属性值组成的无序集合,对象的创建可以通过对象字面量.new 关键字 和Object.create()函数来创建. 1.对象字面量 let obj = {} // 空对象 let obj2 = {a:1, b:2} let obj3 = {"

  • 原生JavaScript创建不可变对象的方法简单示例

    本文实例讲述了原生JavaScript创建不可变对象的方法.分享给大家供大家参考,具体如下: Javascript是一种灵活的语言,你可以重新定义任何东西,但是当项目变得复杂时,我们会发现可变数据结构的问题.随着JavaScript的最新版本的发布这种情况发生了改变.现在可以创建不可变的对象了.本文介绍如何用三种不同的方法来做. 对象的不变性意味着我们不希望对象在创建后即以任何方式更改(将它们设置为只读类型). 假设我们需要定义一个 car 对象,并在整个项目中使用它的属性来执行操作.我们不能允

  • JS创建自定义对象的六种方法总结

    1.创建一个 Object 实例 var person = new Object(); person.name = "rose"; person.age = 18; person.job = "actor"; person.sayName = function () { console.log(this.name); }; console.log(person); 2.对象字面量 var person = { name: "rose", age:

  • 详解 javascript对象创建模式

    创建模式 在javascript中,主要有以下几种创建模式: 工厂模式 构造函数模式 原型模式 组合模式 动态原型模式 寄生构造函数模式 稳妥构造模式 工厂模式 工厂模式是软件工程领域一种广为人知的设计模式.javascript实现方式: function createPerson(name, obj, job) { var o = new Object(); o.name = name; o.obj = obj; o.job = job; o.sayName = function() { al

  • js对象实例详解(JavaScript对象深度剖析,深度理解js对象)

    这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕. 平时发的文章基本都是开发中遇到的问题和对最佳解决方案的探讨,终于忍不住要写一篇基础概念类的文章了. 本文探讨以下问题,在座的朋友各取所需,欢迎批评指正: 1.创建对象 2.__proto__与prototype 3.继承与原型链 4.对象的深度克隆 5.一些Object的方法与需要注意的点 6.ES6新增特性 下面反复提到实例对象和原型对象,通过构造函数 new

  • 详解JavaScript如何创建一个非自动播放的GIF网络组件

    目录 一些很可爱的测试数据 构建Web组件 逻辑 结果 今天,我将向您展示如何创建一个允许您的用户决定是否要播放 gif 的 Web 组件!让我们开始吧. 一些很可爱的测试数据 这里用的gif是小骆驼和猫的这种可爱互动: 哇,太可爱了!我可以看一天这个 构建 Web 组件 对于这个 Web 组件,我们需要一些东西: 画布(“缩略图”所在的位置) 一张图片(实际的 gif) 标有“gif”的标签 一些造型 让我们这样做: const noAutoplayGifTemplate = document

  • JavaScript对象创建模式实例汇总

    本文实例总结了JavaScript对象创建模式.分享给大家供大家参考,具体如下: 在JavaScript中创建对象是很容易的,可以使用对象字面量或者构造函数.常用的创建对象的模式有以下几种: 一. 工厂模式 工厂模式抽象了具体对象的过程,用函数来封装以特ing接口创建对象的细节. 如下: function createAnimal(name, age) { var o = new Object(); o.name = name; o.age = age; o.sayName = function

  • 详解Java对象创建的过程及内存布局

    一.对象的内存布局 对象头 对象头主要保存对象自身的运行时数据和用于指定该对象属于哪个类的类型指针. 实例数据 保存对象的有效数据,例如对象的字段信息,其中包括从父类继承下来的. 对齐填充 对齐填充不是必须存在的,没有特别的含义,只起到一个占位符的作用. 二.对象的创建过程 实例化一个类的对象的过程是一个典型的递归过程. 在准备实例化一个类的对象前,首先准备实例化该类的父类,如果该类的父类还有父类,那么准备实例化该类的父类的父类,依次递归直到递归到Object类. 此时,首先实例化Object类

  • 详解JavaScript对象类型

    JavaScrtip有六种数据类型,一种复杂的数据类型(引用类型),即Object对象类型,还有五种简单的数据类型(原始类型):Number.String.Boolean.Undefined和Null.其中,最核心的类型就是对象类型了.同时要注意,简单类型都是不可变的,而对象类型是可变的.  什么是对象  一个对象是一组简单数据类型(有时是引用数据类型)的无序列表,被存储为一系列的名-值对(name-value pairs).这个列表中的每一项被称为 属性(如果是函数则被称为 方法).  下面是

  • 详解JavaScript对象和数组

    许多高级编程语言都是面向对象的,比如C++.C#和Java等高级程序设计语言,那么一种面向对象语言有哪些基本要求呢?下面我们就通宿地说一下面向对象的一些知识. 一种面向对象语言需要向开发者提供四种基本能力: (1)封装:把相关的信息(无论数据或方法)存储在对象中的能力 (2)聚集:把一个对象存储在另一个对象内的能力 (3)继承:由另一个类(或多个类)得来类的属性和方法的能力 (4)多态:编写能以多种方法运行的函数或方法的能力 由于ECMAScript支持这些要求,因此可被是看做面向对象的.在EC

  • 详解JavaScript对象的深浅复制

    前言 从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性. 在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的constructor属性,是否对每一种数据类型(JavaScript常见的数据类型有String,Number,Boolean,Data,RegExp,Array,Funtion,Object)都实现正确的复制.项目中,我们可以根据实际情况,决定需要实现什

  • 详解JavaScript对象序列化

    一.什么是对象序列化? 对象序列化是指将对象的状态转换为字符串(来自我这菜鸟的理解,好像有些书上也是这么说的,浅显易懂!): 序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程(来自"百度百科-序列化",学术性强,略显高端): 二.为什么会有对象序列化? 世间万物,都有其存在的原因.为什么会有对象序列化呢?因为程序猿们需要它.既然是对象序列化,那我们就先从一个对象说起: var obj = {x:1, y:2}; 当这句代码运行时,对象obj的内容会

  • 详解JavaScript的策略模式编程

    我喜欢策略设计模式.我尽可能多的试着去使用它.究其本质,策略模式使用委托去解耦使用它们的算法类. 这样做有几个好处.他可以防止使用大条件语句来决定哪些算法用于特定类型的对象.将关注点分离开来,因此降低了客户端的复杂度,同时还可以促进子类化的组成.它提高了模块化和可测性.每一个算法都可以单独测试.每一个客户端都可以模拟算法.任意的客户端都能使用任何算法.他们可以互调.就像乐高积木一样. 为了实现策略模式,通常有两个参与者: 该策略的对象,封装了算法. 客户端(上下文)对象,以即插即用的方式能使用任

随机推荐