细看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. HDU 2489 Minimal Ratio Tree 最小生成树+DFS

    Minimal Ratio Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  2. Struts1、2种如何防止表单重复提交和两者的区别

    使用token指令牌就行了.在进入标签之前的action中通过saveToken方法保存指令牌.在表单提交后的action中判断这个token是否存在,如果存在允许插入,并通过resetToken把t ...

  3. Python之路【第三篇】:模块

    定义: 包:包含__init__.py文件.模块(也是.py文件) 当包被其它模块调用时,首先会执行该包下的__init__文件 包含有模块,包可以有多级 模块的导入: import from...i ...

  4. 如何理解java的引用传递

    1. 数组的引用传递 public class TestArray { public static void changeAry1(int[] ary){ int[] ary1 = {9,9,9}; ...

  5. Lazy Load, 延迟加载图片的 jQuery 插件 - NeoEase

    body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...

  6. Express 简介

    Express 简介 Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速 ...

  7. (简单) FZU 2150 Fire Game ,Floyd。

    Problem Description Fat brother and Maze are playing a kind of special (hentai) game on an N*M board ...

  8. 全方位分析Objcetive-C Runtime 分类: ios技术 2015-03-11 22:29 77人阅读 评论(0) 收藏

    本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 简介 与Runtime交互 ...

  9. bootstrap tab标签页

    <ul id="myTab" class="nav nav-tabs"> <li class="active"> & ...

  10. php 模式

    设计模式1.单例模式类的计划生育1.让该类在外界无法造对象2.让外界可以造一个对象,做一个静态方法返回对象3.在类里面通过静态变量控 class Dog { static $dx; public $t ...