1、使用Object构造函数或对象字面量建立对象安全
var person = new Object()
person.name = 'adhehe';
person.age = 23;
//...
//或
var person = {
name:'adhehe',
age:23,
//...
}
缺点:使用同一个接口建立不少的对象,会产生大量的重复代码。函数
2、工厂模式this
这种模式抽象了建立具体对象的过程。用函数来封装以特定接口建立对象的细节。spa
function createPerson(name,age){
//将建立的具体细节封装起来,最后返回一个对象 var o = new Object(); o.name = name; o.age = age; o.getName = function(){ return this.name; } return o; } var person1 = createPerson('adhehe',23); var person2 = createPerson('Jhone',45);
缺点:虽然解决了建立多个类似对象的问题,但没有解决 对象识别的问题,即怎么知道一个对象的类型prototype
3、构造函数模式指针
构造函数能够用来建立特定类型的对象。如Object、Array等。也能够建立自定义构造函数。code
function Person(name,age){ this.name = name; this.age = age; this.getName = function(){ return this.name; } } var person1 = new Person('adhehe',23); var person2 = new Person('Jhone',45);
以new关键字建立Person的实例,经历如下4个步骤:对象
instanceof 操做符 能够检测对象的类型blog
//以person为例 console.log(person1 instanceof Person) console.log(person2 instanceof Person) console.log(person1 instanceof Object) console.log(person2 instanceof Object) //都输出 true
构造函数与普通函数的惟一区别是:调用的方式不一样。只要经过new操做符调用,它就是构造函数。接口
缺点:每一个方法都要在每一个实例上从新建立一遍。
//以上面 person为例 person1.getName == preson2.getName //false
4、原型模式
建立的每一个函数都有一个prototype(原型)属性,它是一个指针,批向一个对象,而这个对象的用途就是:包含能够共享的属性和方法,给那些特定类型的全部实例。
function Person(){} Person.prototype.name = 'adhehe' Person.prototype.age = 23 Person.prototype.getName = function(){ return this.name; } var preson1 = new Person() var preson2 = new Person() console.log(person1.getName()) console.log(person2.getName()) //都返回 adhehe person1.getName == person2.getName //true
一、理解原型对象
只要建立了函数,就会为该函数建立一个prototype属性,这个属性指向函数的原型对象。
全部原型对象都会自动得到一个constructor属性(构造函数),这个属性指向prototype属性所在的函数的指针。
当调用构造函数建立一个实例后,实例内部将包含一个指针(__ptoto__),指向构造函数的原型对象。
Person.prototype.constructor == Person
person1.constructor == Person
person2.constructor == Person
person1.__proto__ == Person.prototype
person2.__proto__ == Person.prototype
isPrototypeOf()方法 肯定对象之间是否存在原型关系
Person.prototype.ifPrototypeOf(person1) //true Person.prototype.ifPrototypeOf(person2) //true
Object.getPrototypeOf()方法 是ECMAScript5新增的检测方法
Object.getPrototypeOf(person1) == Person.prototype //true Object.getPrototypeOf(person2) == Person.prototype //true
每当读取某个对象中的某个属性时,首先搜索该对象自己,再搜索该对象指向的原型对象。若是在实例对象中某个属性名与原型中的一个属性同名,该属性将会屏蔽原型中的属性。
function Person(){} Person.prototype.same = 1; var person1 = new Person() var person2 = new Person()
person1.same = 2; console.log(person1.same) //2 console.log(person2.same) //1
使用delete操做符 能够彻底删除实例属性,从而可以从新访问原型中的属性。
//接上例 delete person1.same; console.log(person1.same) //1
hasOwnProperty()方法能够检测一个属性是存在于实例中,仍是存在于原型中。
person1.hasOwnProperty('name') // true person1.hasOwnProperty('hello') //false
二、in 操做符
有两种方式使用:
单独使用:经过对象可以访问指定属性时返回true,不管该属性存在于实例仍是原型中。
"name" in person1 //true
同时使用 hasOwnProperty()方法和 in 操做符,就能够确认该属性究竟是存在于对象中,仍是存在于原型中。
function has(obj,name){ return !obj.hasOwnProperty(name) && (name in obj); } //in为true,hasOwnProperty()返回false,就能够肯定属性是在原型中
for-in 循环:返回全部可以经过对象访问的、可枚举的属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。屏蔽了原型中不可枚举的属性的实例属性也会在for-in循环中返回。
Object.keys()方法 能够取得对象上全部可枚举的实例属性。
function Person(){} Person.prototype.name = 'adhehe' Person.prototype.age = 23 Person.prototype.getName = function(){ return this.name; } var keys = Object.keys(Person.prototype) console.log(keys) // "name,age,getName" var person1 = new Person() person1.name = 'Rob' var person1Keys = Object.keys(person1) console.log(person1Keys) //"name"
Object.getOwnPropertyNames()方法 能够获得全部实例属性,不管它是否可枚举。
var keys = Object.getOwnPropertyNames(Person.prototype); console.log(keys) //"constructor,name,age,getName"
三、更简单的原型语法
function Person(){} Person.prototype = { name:'adhehe', age:23, getName:function(){ return this.name } }
在这里,constructor属性再也不指向Person。能够 将constructor属性值设置回适当的值
function Person(){} Person.prototype = { constructor:Person, name:'adhehe', age:23, getName:function(){ return this.name } }
以上面这种方式重设constructor属性会致使它的Enumerable特性被设置为true。默认状况下原生的constructor是不可枚举的。可使用Object.defineProperty()修改
function Person(){} Person.prototype = { name:'adhehe', age:23, getName:function(){ return this.name } } Object.defineProperty(Person.prototype,'constructor',{ enumberable:false, value:Person })
四、原型的动态性
对原型对象的修改都可以当即 从实例上反映出来。能够随时为原型添加属性和方法。
var o = new Person(); Person.prototype.sayHi = function(){ //... } o.sayHi() //没有问题
可是,若是重写原型对象,则会切断 构造函数与最初原型之间的联系。实例中的指针仅指向原型,而不指向构造函数。
function Person(){} var o = new Person(); Person.prototype = { constructor:Person, name:'adhehe', age:23, getName:function(){ //.... } } o.getName() // 报错
五、原生对象的原型
全部原生的引用类型,都在其构造函数的原型上定义了方法。
咱们也能够在原生对象的原型上定义新的方法或修改原型,但不推荐这么作。
缺点:
function Person(){} Person.prototype = { constructor:Person, name:'adhehe', age:23, friends:['a','b'], getName:function(){ //... } } var o1 = new Person() var o2 = new Person() o1.friends.push('c') console.log(o1.friends) //a,b,c console.log(o2.friends) //a,b,c //两个对象实例的friends返回了相同的值
5、构造函数模式 与 原型模式 组合
function Person(name,age){ this.name = name; this.age = age; this.friends = ['a','b'] } Person.prototype = { constructor:Person, getName:function(){ //... } } var o1 = new Person('adhehe',23); var o2 = new Person('Greg',45); o1.friends.push('c'); console.log(o1.friends) //a,b,c console.log(o2.friends) //a,b console.log(o1.friends === o2.friends) //false console.log(o1.getName === o2.getName) //true
6、动态原型模式
在构造函数中初始化原型(仅在必要的状况下),它保持了同时使用构造函数和原型的优势。
它只会在初次调用构造函数时才会执行,此后,原型已经完成初始化,不须要再作什么修改。
使用动态原型模式时,不能使用对象字面量重写原型。会切断现有实例与新原型之间的联系。
function Person(name,age){ this.name = name; this.age = age; if(typeof this.getName != 'function'){ Person.prototype.getName = function(){ //... } } } var o = new Person('adhehe',23) o.getName()
7、寄生构造函数模式
建立一个函数,该函数的做用仅仅是封装建立对象的代码,而后再返回新建立的对象。
这个模式与工厂模式是如出一辙的,不一样的是这里使用 new 操做符建立实例对象,并把包装函数叫做构造函数。
function Person(name,age){ var o = new Object(); o.name = name; o.age = age; o.getName = function(){ //... } return o; } var person1 = new Person('adhehe',23) person1.getName();
缺点:返回的对象与构造函数或构造函数的原型属性之间没有任何关系,因此不能依赖 instanceof 操做符来肯定对象类型。在有其余模式可用的状况下,不推荐使用这种模式
8、稳妥构造函数模式
稳妥对象:指的是没有公共属性,其方法也不引用 this 的对象。
稳妥对象 最适合在一些安全的环境中,或者在防止数据被其余应用程序改动时使用。
此模式 与 寄生构造函数相似的模式,有两点不一样:
function Person(name,age){ var o = new Object(); //在这里定义私有变量与属性 o.getName = function(){ return name; } return o; } var person1 = Person('adhehe',23) person1.getName() //adhehe //在这种模式建立的对象中,除了使用getName()方法以外,没有其余办法能够访问name
缺点:与寄生构造函数模式相似,返回的对象与构造函数或构造函数的原型属性之间没有任何关系,因此不能依赖 instanceof 操做符来肯定对象类型。