虽然Object构造函数或对象字面量都可以用来创建单个对象,但是这些方法有明显的缺点:使用同一个接口创建很多对象,会产生大量重复代码。因此人们开始使用工厂模式。

工厂模式

这种模式抽象了创建具体对象的过程

function createPerson(name,age){var o = new Object();o.name = name;o.age = age;o.sayName = function(){alert(this.name);};return o;
}var person1 = new createPerson("liaojin",18);
var person2 = new createPerson("xiaoguan",20);

函数createPerson()能够根据接受的参数来构建一个包含所有必要信息的Person对象。可以无数次的调用这个函数,而每次它都会返回一个包含两个属性以个方法的对象。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。

构造函数模式

使用构造函数将上述例子重写

function Person(name,age){this.name = name;this.age = age;this.sayName = function(){alert(this.name);};
}var person1 = new Person("liaojin",18);
var person2 = new Person("xiaoguan",20);

在这个例子中,Person()函数取代了createPerson()函数。注意到Person()中的代码与createPerson()的不同之处:
1.没有显示的创建对象
2.直接将属性和方法赋值给了this对象
3.没有return语句
要创建Person新实例,必须使用new操作符。这种方式会经理以下四个步骤:
1.创建一个新对象
2.将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
3.执行构造函数中的代码(为这个新对象添加属性)
4.返回新对象
person1和person2分别保存着Person的一个不同实例。这两个对象都有一个constructor属性,该属性指向Person。

alert(person1.constructor == Person);//true
alert(person2.constructor == Person);//true

对象的constructor属性最初是用来表示对象类型的,但是检测对象类型还是instanceof更可靠一些。这个例子中创建的所有对象即是Object的实例,同时也是Person的实例。
创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型;person1和person2之所以同时是Object的实例,是因为所有对象均继承自Object.

将构造函数当做函数

构造函数与其他函数唯一的区别就在于调用他们的方式不同。
任何函数只要通过new操作符来调用,那他就可以作为构造函数;而任何函数如果不通过new操作符来调用,那他跟普通函数没有区别。
如上述例子中的Person()函数可以通过下列任何一种方式来调用。

//当做构造函数调用
var person = new Person("liaojin",18);
person.sayName();//liaojin//作为普通函数调用
Person("lihua",12);
window.sayName();//lihua//在另一个对象的作用域调用
var o = new Object();
Person.call(o,"xiaoguan",20);
o.sayName();//xiaoguan

构造函数的问题

构造函数模式虽然好用,但是也有缺点。使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍。如同this.sayName =new function(){alert(this.name);};在上面的构造函数中sayName()的方法,person1和person2虽然都调用了这个方法,但是调用的并不是同一个Function实例。因此不同实例的同名函数是不相等的

alert(person1.sayName == person2.sayName);//false

然而创建两个完成同样任务的Function实例的确没有必要;因此可以通过吧函数定义转移到构造函数外部来解决这个问题

function Person(name,age){this.name = name;this.age = age;this.sayName = sayName;
}
function sayName(){alert(this.name);
}
var person1 = new Person("liaojin",18);
var person2 = new Person("xiaoguan",20);

在构造函数内部,我们将sayName属性设置为指向全局的sayName函数,由于sayName包含的是指向函数的指针,person1,person2共享了一个sayName函数,解决了两个函数做同样一件事的问题。
可是随即有产生了新的问题:在全局作用域定义的函数实际上只能被某个对象调用,这让全局函数优点名不副实。如果对象需要定义很多方法,那么就需要定义多个全局函数,于是自定义的引用类型就没有封装性可言了,因此产生了原型模式。

原型模式

我们所创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途就是包含可以由特定类型的所有实例共享的属性和方法prototype就是通过调用构造函数而创建的那个对象实例的原型对象。可以让所有对象的实例共享它所包含的属性和方法。

function Person(){}
Person.prototype.name = "liaojin";
Person.prototype.age = 18;
Person.prototype.sayName = function(){alert(this.name);
};var person1 = new Person();
Person1.sayName();//liaojin
var person2 = new Person();
Person2.sayName();//liaojinalert(person1.sayName == person2.sayName);//true

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

构造函数用于定义实例属性,而原型模式用于定义方法和共享的属性。这样每个实例都会有自己的实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。

function Person(name,age){this.name = name;this.age = age;this.friends = ["lucy","lily"];
}Person.prototype = {constructor:Person,sayName:function(){alert(this.name);}
}
var person1 = new Person("liaojin",18);
var person2 = new Person("xiaoguan",20);person1.friends.push("lihua");
alert(person1.friends);//lucy,lily,lihua
alert(person2.friends);//lucy,lily
alert(person1.friends == person2.friends);//false
alert(person1.sayName == person2.sayName);//true

动态原型模式

有其他面向对象经验开发的人员看到独立的构造函数和原型时,很可能会肥肠困惑,动态原型模式就是解决这个问题的一个方案。

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

这里只在sayName()方法不存在的情况下才会将它添加到原型中。这段代码只会在初期调用才会执行。

寄生构造函数模式

这个模式可以在特殊的情况下用来为对象创建构造函数。假设我们想创建一个具有额外方法的特殊数组。由于不能直接修改Array构造函数,因此可以使用这个模式。

function SpecialArray(){var values = new Array();values.push.apply(values,arguments);values.toPipedString = function(){return this.join("|");};return values;
}
var colors = new SpecialArray["red","blue","green"];
alert(colors.toPipedString());//red|blue|green

说明:关于寄生构造函数模式,首先返回的对象与构造函数或者与构造函数的原型属性之间没有关系;构造函数返回的对象与在构造函数外部创建的对象没有什么不同。因此不能依赖instanceof操作符来确定对象的类型。

稳妥构造函数模式

所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象。稳妥对象最适合在一些安全的环境中(禁止使用this和new的环境),或者在防止数据被其他应用程序改动时使用。与寄生构造函数类似的模式;但有两点不同:1.新创建对象的实例方法不引用this;2.不使用new操作符调用构造函数;

function Person(name,age){var o = new Object();o.sayName = function(){alert(name);};return o;
}//使用
var friend = Person("liaojin",18);
friend.sayName();//liaojin

这样变量person中保存的是一个稳妥对象,而除了调用sayName()方法外,没有别的方法可以访问其数据成员,即使有其他代码会给这个对象添加方法或数据成员,但也不可能有别的办法访问传入到构造函数中的原始数据,非常适合在某些安全执行环境下使用。
与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间也没有什么关系,因此instanceof操作符对这种对象也没有什么意义

javascript创建对象相关推荐

  1. JavaScript创建对象的6种方式

    JavaScript创建对象简单的说,无非就是使用内置对象(Object)或各种自定义对象,当然还可以用JSON,但写法有很多种,也能混合使用. 1.对象字面量的方式 person = {name : ...

  2. Javascript创建对象几种方法解析

    Javascript创建对象几种方法解析 Javascript面向对象编程一直是面试中的重点,将自己的理解整理如下,主要参考<Javascript高级程序设计 第三版>,欢迎批评指正. 通 ...

  3. javascript创建对象方法总结

    javascript创建对象方法的总结. 对象是什么? js中对象是"无序属性的集合,其属性可以包含基本值,对象或者函数",简单来说,它就是一个名值对,有key和value,val ...

  4. JavaScript创建对象的4种方法

    JavaScript 创建对象的4种方法 所谓对象就是用来帮助你完成一些事情是,对象是有特征和行为的,是具体特指的某一个事物.使用对象可以使程序更加整洁 通过Object()方法来创建 Object( ...

  5. JavaScript创建对象的7大模式

    在JavaScript中,创建对象有7大模式,分别是工厂模式.构造函数模式.原型模式.组合使用构造函数模式和原型模式.动态原型模式.寄生构造函数模式.稳妥构造函数模式.下面针对这7种模式展开讲解. 工 ...

  6. JavaScript创建对象的两种方法和遍历对象的属性

    创建新对象有两种不同的方法: 定义并创建对象的实例 使用函数来定义对象,然后创建新的对象实例 1.定义并创建对象的实例 var person=new Object(); person.firstnam ...

  7. JavaScript创建对象–如何在JS中定义对象

    Objects are the main unit of encapsulation in Object-Oriented Programming. In this article, I will d ...

  8. [转载]javascript创建对象的几种方式

    原文链接:http://qingfeng825.iteye.com/blog/1935648 1. 工厂方法:能创建并返回特定类型对象的工厂函数(factory function). function ...

  9. javascript创建对象 1

    对象是什么 从JavaScript定义上讲对象是无序属性的集合,其属性可以包含基本值.对象或函数.也就是说对象是一组没有特定顺序的属性,每个属性会映射到一个值上,是一组键值对,值可以是数据或对象. 最 ...

  10. javascript创建对象的几种方式 .

    // 1. 工厂方法:能创建并返回特定类型对象的工厂函数(factory function). function createCar(sColor){ var car = new Object(); ...

最新文章

  1. 安装kafka过程及出现的问题解决
  2. 转录组分析_高级转录组分析和R数据可视化
  3. python的类变量与实例变量以及__dict__属性
  4. vb.net 机器学习-候选消除法
  5. Building Seam 2.0 Application with NetBeans 6.1
  6. 坑爹的UICollectionView
  7. java .jvp文件_GitHub - eddylapis/jvppeteer: Headless Chrome For Java (Java 爬虫)
  8. 第五章 循环结构课内反思
  9. 程序员如何利用 Python 解决女朋友不看天气的坏习惯?
  10. ipv6的NDP协议有哪些功能,是如何进行工作的
  11. Android自定义View里面获取宽高及dp和px间的转换
  12. 图片处理——使用NDK添加文字和图片水印
  13. Mac删除Python缓存文件
  14. 3d布衣天下1手机调试html,真精华布衣天下3d
  15. 领扣LintCode算法问题答案-1485. 圣杯咒语
  16. Tableau字符串拼接
  17. IBM:金融的话语权仍掌握在银行手中
  18. CentOS7下collectd简单安装使用
  19. Java实现短信验证码最佳实践
  20. Android 录制桌面视频 screenrecord

热门文章

  1. java jsch_java使用JSCH实现SFTP文件管理
  2. mysql 连接 查询 连表查询
  3. Unity easyTouch移动代码(参考)
  4. 目标检测---Segmentation Is All You Need
  5. LeetCode 268. Missing Number--Python解法--数学题
  6. Debian/Ubuntu让apt使用代理
  7. linux下清理信号量,Linux下kill的信号量列表
  8. oracle10gr2 x86,Oracle10gR2 On RHEL5 x86安装技术文档(英文原版)
  9. 学会这两样高级用户,让你成为 Git老手
  10. 快速入门分库分表概念原理