详解 javascript对象创建模式


Posted in Javascript onOctober 30, 2020

创建模式

在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]]。

详解 javascript对象创建模式

虽然所有实现都无法直接访问[[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 创建模式的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
地震发生中逃生十大法则
May 12 Javascript
js模拟hashtable的简单实例
Mar 06 Javascript
JavaScript在Android的WebView中parseInt函数转换不正确问题解决方法
Apr 25 Javascript
轻松实现Bootstrap图片轮播
Apr 20 Javascript
设置jQueryUI DatePicker默认语言为中文
Jun 04 Javascript
Vue 固定头 固定列 点击表头可排序的表格组件
Nov 25 Javascript
AngularJS执行流程详解
Feb 17 Javascript
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
Oct 18 Javascript
原生JS实现的放大镜特效示例【测试可用】
Dec 08 Javascript
VUE和Antv G6实现在线拓扑图编辑操作
Oct 28 Javascript
JavaScript实例 ODO List分析
Jan 22 Javascript
html中两种获取标签内的值的方法
Jun 16 jQuery
ES6中的Javascript解构的实现
Oct 30 #Javascript
vue video和vue-video-player实现视频铺满教程
Oct 30 #Javascript
Echarts.js无法引入问题解决方案
Oct 30 #Javascript
解决Vue keep-alive 调用 $destory() 页面不再被缓存的情况
Oct 30 #Javascript
vue 通过 Prop 向子组件传递数据的实现方法
Oct 30 #Javascript
微信小程序:报错(in promise) MiniProgramError
Oct 30 #Javascript
vue keep-alive实现多组件嵌套中个别组件存活不销毁的操作
Oct 30 #Javascript
You might like
松下Panasonic RF-B65电路分析
2021/03/02 无线电
php getsiteurl()函数
2009/09/05 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十六)
2014/06/30 PHP
Mac系统下使用brew搭建PHP(LNMP/LAMP)开发环境
2015/03/03 PHP
PHP性能分析工具XHProf安装使用教程
2015/05/13 PHP
php函数传值的引用传递注意事项分析
2016/06/25 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
2018/06/13 PHP
Laravel框架Request、Response及Session操作示例
2019/05/06 PHP
jquery 插件 任意位置浮动固定层
2008/12/25 Javascript
JavaScript 读取元素的CSS信息的代码
2010/02/07 Javascript
jQuery中绑定事件的命名空间详解
2011/04/05 Javascript
关于include标签导致js路径找不到的问题分析及解决
2013/07/09 Javascript
零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门
2014/12/20 Javascript
JavaScript对数字的判断与处理实例分析
2015/02/02 Javascript
浅析JavaScript回调函数应用
2016/05/22 Javascript
微信开发 消息推送实现代码
2016/10/21 Javascript
微信小程序基于Taro的分享图片功能实践详解
2019/07/12 Javascript
vue动态绘制四分之三圆环图效果
2019/09/03 Javascript
[44:37]完美世界DOTA2联赛PWL S3 Forest vs access 第一场 12.11
2020/12/13 DOTA
python多重继承实例
2014/10/11 Python
Python cookbook(数据结构与算法)在字典中将键映射到多个值上的方法
2018/02/18 Python
Python用61行代码实现图片像素化的示例代码
2018/12/10 Python
python http基本验证方法
2018/12/26 Python
Python3.7 pyodbc完美配置访问access数据库
2019/10/03 Python
Python 3.6打包成EXE可执行程序的实现
2019/10/18 Python
在Python中使用K-Means聚类和PCA主成分分析进行图像压缩
2020/04/10 Python
Python 字典中的所有方法及用法
2020/06/10 Python
美国领先的户外服装与装备用品店:Moosejaw
2016/08/25 全球购物
JD Sports意大利:英国篮球和运动时尚的领导者
2017/10/29 全球购物
Shopee越南:东南亚与台湾电商平台
2019/02/03 全球购物
J2EE面试题
2016/03/14 面试题
专科毕业生学习生活的自我评价
2013/10/26 职场文书
服装店营销方案
2014/03/10 职场文书
放飞梦想演讲稿800字
2014/08/26 职场文书
泸县召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
大学迎新生欢迎词
2015/09/29 职场文书