细看javascript创建对象模式的诞生,具体的脉络为:不使用任何模式——工厂模式——构造函数模式——原型模式——组合使用构造函数模式——动态原型模式——寄生构造函数模式——稳妥构造函数模式。每一种模式都是为了解决一定的问题而诞生的,都有自己的缺陷和优势。下面我们来一一介绍:

一、不使用任何模式

  javascript中创建对象的方式有以下两种:

 //使用new Object构造函数
     var person = new Object();
     person.name = "Lillian";
     person.age = 24;
     person.sayName = function(){
         return person.name;
     }

 //使用对象字面量
     var person = {
         name:"Lillian",
         age:24,
         sayName:function(){
             return name;
         }
     };

二、使用工厂模式  

  当要同时创建多个对象时,使用这两种方式都会产生大量重复的代码,为了解决这个问题,工厂模式应运而生:

 //工厂模式
 function createPerson(name , age){
     var o = new Object();
     o.name = name;
     o.age = age;
     o.sayName = function(){
         return this.name;
     }
     return o;
 }

 var person1 = createPerson("Lillian",24);

  通过工厂模式,只需要一行代码,就能创建一个对象,但是工厂模式存在一个问题:无法检测实例的类型。

三、使用构造函数模式

 //构造函数模式
 function Person(name, age){
     this.name = name;
     this.age = age;
     this.sayName = function(){
         return this.name;
     }
 }
 var person1 = new Person("Lillian", 24);
 //检测实例类型
 alert(person1 instanceof Person); //true
 alert(person1 instanceof Object);  //true

  使用构造函数模式,同样可以一行代码创建一个对象实例,并且可以检测实例类型,这也是构造函数模式胜过工厂模式的地方。

四、原型模式

  使用构造函数模式的问题是,每一个实例都具有一些相同的属性和方法,创建实例时,这些属性和方法会重复创建;而使用原型模式,可以将这些属性和方法放在原型对象中,这样以这个对象为原型的实例,都共享原型的属性和方法,不需要单独创建。

 //原型模式
 function Person(){

 }
 Person.prototype.name = "Lillian";
 Person.prototype.age = 24;
 Person.prototype.sayName = function(){
     alert(this.name);
 }

 // person1 和 person2 共享以上原型的属性和方法
 var person1 = new Person();
 person1.sayName();

 var person2 = new Person();
 person2.sayName();

  这里创建的函数和它的原型对象,以及实例是怎么联系起来的呢?

  无论什么时候,只要创建了一个新函数,函数就会默认带上一个叫做prototype的属性,这个属性指向函数的原型对象;而原型对象也会自动获得一个叫做constructor的属性,指向这个新函数(存在多个函数时,指向所有prototype属性指向该原型的函数);函数的实例当然也带上了prototype属性;这样它们就连接了起来。

  在现实中是没有办法访问prototype属性的,我们可以通过isPrototypeOf函数来确定对象之间是否存在这种关系:

 alert(Person.prototype.isPrototypeOf(person1)); //true

  当代码搜索属性时,它会现在实例中找这个名字的属性,如果找到就返回,没有找到则在原型对象中搜索(因此,可以在实例中重新定义属性和方法来覆盖原型中的属性和方法)。那么,我们怎么知道,一个属性,它是在原型中定义的,还是在实例中定义的呢?判断给定属性是在实例中,有现成的函数:hasOwnProperty();判断给定属性是在原型中,没有现成的函数,这里用到hasOwnProperty函数和in操作符实现:

 // hasOwnProperty():给定属性在实例中时,才会返回true
 // in 操作符:函数存在给定属性,无论是在实例还是原型中,都返回true
 //以下函数实现判断属性是否存在于原型中
 function hasPrototypeProperty(object, name){
     return (name in object) && !(object.hasOwnProperty(name));
 }

  使用对象字面量的方式,可以更加方便的定义原型,不过注意,需要手动指定原型的constructor属性。

     function Person(){

     }
     Person.prototype = {
         constructor:Person,
         name:"Lillian",
         age: 24,
         sayName:function(){
             alert(this.name);
         }
     };

  另外,原型具有动态性,对原型的修改,会立即反应在它constructor属性所指的对象上,但修改不包括重写整个原型。

  原型模式相比构造函数模式,具有共享属性和方法的优点,但是这也带来了问题:当原型的某个对象修改了共享的属性时,所有的对象的属性也都相应修改了。

五、组合使用构造函数模式和原型模式

  哐哐哐~~~使用构造函数和原型混合而成的模式,是目前ECMAScript中使用最广泛、认可度最高的一种自定义模式!!构造函数用于定义实例自己的属性,原型用于定义共享的方法,如下:

 function Person(name , age){
     this.name =  name;
     this.age = age;
 }
 Person.prototype = {
     constructor:Person,
     sayName:function(){
         alert(this.name);
     }
 };

 var person1 = new Person("Lillian", 24);
 var person2 = new Person("Matthew", 23);
 person1.sayName();
 person2.sayName();

六、动态原型模式

  动态原型模式,与构造函数和原型结合的模式类似,只是它通过检查是否存在需要的函数,再来决定是否动态创建原型。

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

七、寄生构造函数模式

  这种模式不推荐使用,除了使用new操作符,把包装函数叫做构造函数之外,它其实和工厂模式是一模一样的(寄生构造函数这个名称,可以想象为:工厂模式寄生在构造函数里面):

 function Person(name , age){
     var o = new Object();
     o.name =  name;
     o.age = age;
     o.sayName = function(){
         alert(this.name);
     }
     return o;
 }
 var person1 = new Person("Lillian", 24);

八、稳妥构造函数模式

  稳妥构造函数定义了一个稳妥对象,所谓的稳妥对象,是指没有公共属性,而且其方法也不会引用this对象。稳妥对象适合在对安全要求性比较高的环境来使用(这些环境禁止使用this和new),或者防止数据被其他应用程序更改的场合。它和寄生构造函数模式非常类似,只是去掉了this;创建实例时,也不使用new操作符,这样,对属性的引用,只能通过定义的函数了。

 function Person(name , age){
     var o = new Object();
     o.name =  name;
     o.age = age;
     o.sayName = function(){
         alert(name);
     }
     return o;
 }
 var person1 = Person("Lillian", 24);
 person1.sayName();

 


   以上是ECMAScript中定义的7种创建对象的模式。另外,对象的属性,其实也并不简单,属性都具有4个描述其行为的特性:

 // Configurable:是否可以通过delete删除属性而重新定义属性
 // Enumerable:是否可以通过for-in循环返回属性
 // Writable:是否可以修改属性的值
 // Value:包含这个属性的数据值
 // 使用Object.defineProperty()函数来修改属性的默认特性,如下配置name属性不可更改
 var person = { };
 Object.defineProperty(person, "name",{
     writable:false,
     value:"Lillian"
 });
 alert(person.name);//"Lillian"
 person.name = "Matthew";
 alert(person.name);//"Lillian"

《JAVASCRIPT高级程序设计》创建对象的七种模式的更多相关文章

  1. JavaScript高级特性-创建对象的九种方式

    1. 对象字面量 通过这种方式创建对象极为简单,将属性名用引号括起来,再将属性名和属性值之间以冒号分隔,各属性名值对之后用逗号隔开,最后一个属性不用逗号隔开,所有的属性名值对用大括号括起来,像这样: ...

  2. javascript继承(二)—创建对象的三种模式

    一.工厂模式 function createPerson(name,age){ var o = {}; o.name = name; o.age = age; o.sayHi = function() ...

  3. JavaScript高级程序设计:第七章

    函数表达式 1.函数表达式的特征: 定义函数的方式有两种:一种是函数声明,另一种就是函数表达式.函数声明的语法是这样的: function  functionName(arg0,arg1,arg2){ ...

  4. 《javascript高级程序设计》笔记七

    第五章 引用类型(三) 今天首先说的就是Function类型.下面就是定义函数的两种方法,第一种使用函数声明语法定义,第二种使用函数表达式定义.这两种定义函数的方式几乎没有什么区别. function ...

  5. 《javascript高级程序设计》第七章 递归recursion

    7.1 递归7.2 闭包 7.2.1 闭包与变量 7.2.2 关于this 对象 7.2.3 内存泄漏 7.3 模仿块级作用域7.4 私有变量 7.4.1 静态私有变量 7.4.2 模块模式 7.4. ...

  6. javascript 创建对象的7种模式

    使用字面量方式创建一个 student 对象: var student = function (){ name : "redjoy", age : 21, sex: women, ...

  7. 《Javascript高级程序设计》阅读记录(七):第七章

    <Javascript高级程序设计>中,2-7章中已经涵盖了大部分精华内容,所以摘录到博客中,方便随时回忆.本系列基本完成,之后的章节,可能看情况进行摘录. 这个系列以往文字地址: < ...

  8. JavaScript 创建对象的七种方式

    转自:xxxgitone.github.io/2017/06/10/JavaScript创建对象的七种方式/ JavaScript创建对象的方式有很多,通过Object构造函数或对象字面量的方式也可以 ...

  9. JavaScript中创建对象的5种模式

    构造函数模式 实现方式: function Person(name, age, job) { this.name = name; this.age = age; this.job = job; thi ...

随机推荐

  1. Ubuntu Server 14.04 & Apache2.4 虚拟主机、模块重写、隐藏入口文件配置

    环境: Ubuntu Server 14.04 , Apache2.4 一.Apache2.4 虚拟主机配置 01. 新建一份配置文件 在apache2.4中,虚拟主机的目录是通过/etc/apach ...

  2. H5手机开发锁定表头和首列(惯性滚动)解决方案

    前端时间移动端在做表格的时候需要这个功能,由于还有实现类似原生的惯性滚动功能,于是使用了iscroll插件. iscroll插件下载地址:iscroll5 该功能demo github地址: http ...

  3. HDU 5620 KK's Steel

    想了一下发现是斐波那契数列.....水题 #include <stdio.h> #include <algorithm> #include <string.h> # ...

  4. 1、手把手教你Extjs5(一)搭建ExtJS5环境

    Ext JS 5 的主要特性包括: 新的数据绑定方式 新增支持 MVVM 模式,并且依然支持 MVC 模式 对手持设备更友好,针对触屏设备进行优化 新的主题 Crisp / Neptune Touch ...

  5. R语言实战(四)回归

    本文对应<R语言实战>第8章:回归 回归是一个广义的概念,通指那些用一个或多个预测变量(也称自变量或解释变量)来预测响应变量(也称因变量.效标变量或结果变量)的方法.通常,回归分析可以用来 ...

  6. asp.net-mvc验证码 asp.net-mvc c#验证码

    验证码看不清换一组 写一个类 public class ValidateCode { public ValidateCode() { } /// <summary> /// 验证码的最大长 ...

  7. S3C2440硬件IIC详解

    S3C2440A RISC微处理器可以支持一个多主控IIC 总线串行接口.一条专用串行数据线(SDA)和一条专用串行时钟线(SCL)传递连接到IIC总线的总线主控和外设之间的信息.SDA和SCL线都为 ...

  8. [转]六款常用的linux C/C++ IDE

    之前在windows下开发习惯啦,linux改用vim开发代码,但是前期还是不熟悉看代码效率感觉有点低.由于看代码需要各种跳转查找我个人觉得还是IDE方便些,以前在windows下就挺喜欢使用code ...

  9. TabLayout学习笔记

    配合ViewPager使用,基本布局如下: <?xml version="1.0" encoding="utf-8"?> <LinearLay ...

  10. PHPEXCEL实例-导出EXCEL

      PHPExcel 是相当强大的 MS Office Excel 文档生成类库,当需要输出比较复杂格式数据的时候,PHPExcel 是个不错的选择. <?php /* * 导出EXCEL *  ...