《javascript高级程序设计》第六章 读书笔记 之 javascript对象的几种建立方式

1、工厂模式

工厂模式:使用字面量和object构造函数会有不少重复代码,在此基础上改进
图片描述
解决了多个类似对象的问题,但没有解决对象识别的问题(即怎样知道一个对象的类型)segmentfault

2、构造函数模式

图片描述
与工厂模式建立对象的不一样之处:没有显示建立对象,直接将属性和方法赋给this对象,没有return语句。默认return的是this对象。
构造函数自己也是函数,只是能够用来建立对象,因此借鉴自其余面向对象语言,构造函数始终应该以一个大写字母开头,非构造函数用一个小写字母开头,用于区别构造函数与其余普通函数。
new操做符建立对象实例,经历4个步骤:
一、建立一个新对象
二、讲构造函数的做用域赋给新对象(因此此时this指向这个新对象)
三、执行构造函数中的代码(为这个新对象添加属性)
四、返回新对象
上面的实例a又一个constructor(构造函数)属性指向Person。
图片描述
相比较工厂模式的有点:有constructor属相,能够标志为一种特性的类型。
但实际用来检测对象类型,instanceod更方便些,因此instanceof比较的是constructor属性。
三种使用构造函数建立对象的方法:
图片描述数组

call和apply的做用都是在某个特殊对象的做用域中调用Person()函数。那么上例中,otherPerson的做用域中调用Person函数,this指向otherPerson对象,执行构造函数中的内容,this.name指otherPerson.name=‘shirley’
构造函数模式的缺点:每建立一个实例都要执行一遍构造函数的语句,每一个实例有不一样的属性值很正常,也有许多内容如出一辙的方法,这些方法重复建立(实际是new function实例,因此person1.sayname!=otherPerson.sayname。由于sayName方法是不一样实例,引用地址不一样)则显得冗余。
很明显,若是实例引用同一个sayName实例(同一个方法)就可以解决上述问题。
图片描述
Person的sayName引用的都是同一个sayName函数,即全局变量中的sayName函数。浏览器

3、原型模式

利用每一个函数都有的一个prototype(原型)属性。这个属性是一个指针,指向一个对象,这个对象的用途是包含能够由特定类型的全部实例共享的属性和方法。(解决了构造函数模式的缺点)
prototype就是经过调用构造函数而建立的那个对象实例的原型对象。(就是所建立的对象的原型,例如:var person1=new Person(’linda‘,15)person1的原型为Person。otherPerson=new Object() otherPerson的原型为Object)
例子:
图片描述
判断一个对象的prototype是否指向某对象
图片描述
访问一个对象的prototype属性
图片描述
Firef、Safari、Chrome中支持一个属性__proto__能够访问到prototype
注意: JavaScript 中任意对象都有一个内置属性 [[Prototype]] ,在ES5以前没有标准的方法访问这个内置属性,可是大多数浏览器都支持经过__proto__来访问。如下统一使用__proto__来访问 [[Prototype]],在实际开发中是不能这样访问的。(摘自:https://segmentfault.com/a/11...
ES5中增长了一个新方法,Object.getPrototyOf()
图片描述
“原型最初只包含constructor属性”即,对象的constructor保存在原型属性中。
对象实例不能改变原型中的值,因此当咱们试图改变原型中的值时,会在实例中新添加一个相同名称的属性。当咱们访问这个属性时,就会优先返回实例中的属性,这就是覆盖了原型的属性。
那么咱们怎么肯定一个属性是来自对象实例仍是来自对象的原型,使用Object对象的hasOwnProperty()方法能够检测属性是否存在于对象实例中,若存在,则访问的属性一定是来自对象实例,由于当访问一个属性时,先搜索对象属性若不存在才会去搜索对象的原型属性的。
图片描述
delete能够删除实例的属性,但不能删除对象原型中的属性。
对象、构造函数(constructor)和原型(Prototype)的联系:
以下图
图片描述安全

person1和person2实例中的prototype属性中保存的是Person的原型,原型里有constructor属性又指向Person。因此对象和constructor之间是经过原型联系起来的。app

肯定属性是原型中的属性:
in操做符只要经过对象可以访问到属性就返回true,不论是实例的属性仍是原型中的属性,因此经过in操做符返回true儿hasOwnProperty()返回false就能够肯定属性是原型中的属性。函数

用字面量法定义Person的prototype属性:
图片描述
会形成constructor属性再也不指向Person
咱们知道,没建立一个函数,就会同时建立它的prototype对象,这个对象也会自动得到constructor属性。使用字面量定义prototype会重写这个对象,所以constructor会变成新的对象的constructor属性(指向object构造函数)。
打印person2显示:
图片描述
红框内没有constructor属性。咱们知道person2.constructor会寻找person2对象中的constructor对象中的constructor对象,person2实例对象中没有,寻找原型中(红框)也没有,继续寻找prototype的原型对象即object对象,因此,person2.constructor===Object true;
图片描述
原型模式建立对象是在函数构造模式的基础上解决共有方法和属性的,那么函数构造模式是为了解决字面量法的没法判断是哪一个对象的问题而出现,怎么判断?经过对象的constructor属性判断,如今原型的constructor都指向对象,就把这个优点抹去了,因此出现下面这样的方法来保存这个特性。
图片描述
这样作与原来的差异是:constructor属性的[[Enumberable]]特性被设置为true,原来是false(不可枚举)。因此若是使用兼容EXMAScript5的JavaScript引擎,可使用Object.defineProperty()
图片描述
原型具备动态性。
构造函数的原型改变会当即反映到全部实例中,但若是是从新写一个原型对象则不会了this

图片描述
图片描述
缘由:person1的构造函数会自动指向一个原型对象,而保存的是这个原型对象的指针,新建一个prototype对象后,在堆内存中开辟了一个新的对象空间,在person2中保存的是这个新对象的引用指针,因此二者不一样。
原型模式不多会单独使用,由于全部属性都是共享的,但实力通常都是要有属于本身的所有属性的。原型模式没法作到,因此这是原型模式的缺点。spa

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

建立自定义类型的最多见方式,构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
图片描述
结果每一个人实例都有本身的一份实例属性的副本,同时又共享着对方法的引用,最大限度地节省了内存。这种方式还支持向构造函数传递参数。(既有构造函数模式的优势又有原型模式的优势)prototype

5、动态原型模式

在构造函数中判断是否存在sayName函数,若是不存在添加到原型中,下图建立了两次对象,调用两次构造函数,但if的判断只执行一次,在第一次执行。3d

图片描述

6、寄生构造函数模式

与工厂模式在写法上红框圈出不一样以外如出一辙。叫法上把Person函数叫作构造函数,其余无区别
图片描述
适用情境:
能够在特殊的状况下用来为对象建立构造函数。假如咱们想建立一个具备额外方法的特殊数组。
图片描述

7、稳妥构造函数模式

稳妥对象:没有公共属性,并且其方法也不引用this的对象。
稳妥对象最适合在一些安全的环境中(这些环境中会禁止是使用this和new),或者在防止数据被其余应用程序(如Mashup程序)改动时使用。
稳妥构造函数与寄生构造函数相似的模式。不一样点:一、新建立对象的实例方法不引用this,二、不适用new操做符调用构造函数。

图片描述因此,使用稳妥构造函数模式建立的对象与构造函数之间没有关系,没法用instanceod判断所属类型。之因此稳妥,是由于除了sayName方法外部没法对传入构造函数中的原始数据进行访问。即便能够给这个对象添加方法或数据成员。使用环境:某些安全执行环境下使用(ADsafe和Caja)

相关文章
相关标签/搜索