【上一篇】:JavaScript对象内部属性及其特性总结segmentfault
先在内部 显示地建立一个临时对象,根据接收的参数来构建(赋值属性和方法)该对象,并返回该对象。
缺点:没有解决对象识别的问题(即没法确认一个对象的类型)。
function PersonFactory (name, age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function(){ console.log(this.name) } return o; } var p1 = PersonFactory(); var p2 = PersonFactory(); p1 instanceof Object; // true p2 instanceof Object; // true p1 instanceof PersonFactory; // false 没法识别具体对象类型 p2 instanceof PersonFactory; // false
- 函数名首字母通常大写(如:Person,借鉴OO语言命名习惯)区别于其余函数;
- 构造函数自己也是函数,只不过能够用来参加对象而已;
- 每一个新建的实例对象都有一个
constructor
属性,该属性指向构造函数自身Person
;构造函数也能够被当作普通函数来调用;浏览器
- 在全局做用域中调用一个函数时,
this
对象老是指向Global
对象(浏览器中即window
对象)- 【优势】自定义构造函数能够将它的实例标识为一种特定的类型;
- 【缺点】构造函数的主要问题是,每一个方法都要在每一个实例上从新建立一遍;
- 建立(隐式地)一个新对象;
- 将构造函数的新对象赋值给新对象(此时
this
指向这个新对象);- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象(该构造函数的实例);
- 没有显示地建立对象;
- 直接将属性和方法赋值给
this
对象;- 没有
return
语句;- 优势:能够确认具体对象类型;
function Person (name, age){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); } } // 当作普通函数 var p1 = new Person('Tom', 20); var p2 = new Person('Greg', 30); p1 instanceof Object; // true p2 instanceof Object; // true p1 instanceof PersonFactory; // true 能够确认具体对象类型 p2 instanceof PersonFactory; // true // 做为普通函数调用 Person('Green', 30); // 属性和方法都被添加到window对象了 window.sayName(); // 'Green' // 在另外一个对象的做用域中调用 var obj = new Object(); Person.call(obj , 'Jim', 23); obj .sayName(); // 'Jim'
- 构造函数变为空函数;
- 将全部属性和方法都添加到了构造函数的
prototype
属性中;
- 不一样:新对象的属性和方法由全部实例共享(p1和p2访问的都是同一组属性和同一个函数);
function Person(){} Person.prototype.name = 'Tom'; Person.prototype.age = 24; Person.prototype.sayName = function(){ console.log(this.name); } var p1 = new Person(), p2 = new Person(); p1.sayName();// 'Tom' p2.sayName();// 'Tom' console.log(p1.sayName === p2.sayName);// true
- 每建立一个函数,就会同时建立它的
prototype
对象,该prototype
对象也会自动得到constructor
属性。- 用对象字面量形式建立的对象,直接赋值给函数的原型对象(
Person.prototype
),本质上彻底重写了其prototype
对象,- 所以
constructor
属性也就变成了新对象的constructor
属性(指向Object
构造函数),再也不指向Person
函数。- 此时
instanceof
操做符能够返回正确结果,但经过constructor
已经没法肯定对象类型了。
function Person(){} Person.prototype = { // construtor : Person, // 须要从新指设constructor属性 name : 'Tom', age : 24, sayName : function(){ console.log(this.name); } } var p = new Person(); console.log(p instanceof Object); // ture console.log(p instanceof Person); // ture console.log(p.construtor == Object); // ture console.log(p.construtor == Person); // false
constructor
以上述方式重设constructor
属性会致使它的[[Enumerable]]
特性被设置为true
;
默认状况下,原生的constructor
属性是不可枚举的;
所以可利用Object.defineProperty()
重设;
Object.defineProperty(Person.prototype, 'constructor', { enumerable : false, value : Person });
定义安全
- 组合使用构造函数模式和原型模式;
- 构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性;
优势:函数
- 每一个实例都会有本身的一份实例属性的副本,同时又共享着对方方法的引用,最大限度节省了内存;
- 这种混成模式支持向构造函数传递参数;
- 目前使用最普遍、认同度最高的一种自定义类型的方法,能够说是用来定义引用类型的一种默认模式;
// 实例属性均在构造函数中定义 function Person(name, age){ this.name = name; this.age = age; this.friends = ['Nicholas', 'Jim']; } // 由全部实例共享属性constructor和方法则是在原型中定义的 Person.prototype = { construtor: Person, sayName: function(){ console.log(this.name); } } var p1 = new Person('Tom', 25); var p2 = new Person('Greg', 26); p1.friends.push('Tony'); console.log(p1.friends); // ["Nicholas", "Jim", "Tony"] console.log(p2.friends); // ["Nicholas", "Jim"] console.log(p1.friends === p2.friends); // false console.log(p1.sayName === p2.sayName); // true
定义:this
- 动态原型模式把全部信息都封装在了构造函数中;
- 经过在构造函数中初始化原型(仅在必要的状况下,好比第一次新建实例时);
- 经过检查某个应该存在(原型中)的方法是否有效,来决定是否须要初始化原型;
- 优势:保持了同时使用构造函数和原型的特色;
- 下段代码中只会在初次调用构造函数时才会执行,此后原型已经完成初始化,无需再作修改;
- 这里对原型所作对修改,可以当即在全部实例中获得反映;
if
语句检查的能够是初始化以后应该存在的任何属性或方法,检查其中一个便可;
function Person(name, age){ // 属性 this.name = name; this.age = age; // 方法 if(typeof this.sayName != 'function'){ Person.prototype.sayName = function(){ console.log(this.name); } } }
- 【定义】: 基本思想是建立一个函数,该函数的做用仅仅是封装建立对象的代码,而后再返回新建立的对象。
【特色】:spa
- 返回的对象与构造函数或者与构造函数的原型属性之间没有关系;
- 寄生构造函数返回的对象与在寄生构造函数外部建立的对象没有什么不一样;
- 不能依赖
instanceof
操做符来肯定对象类型;
- 除了使用
new
操做符并把使用的包装函数叫作构造函数以外,该模式和工厂模式实际上是如出一辙的;
- 从表面上看,很像典型的构造函数;
- 构造函数在不返回值的状况下,默认会返回新对象实例;
而寄生构造函数经过在构造函数的末尾加一个
return
语句,重写了调用构造函数时返回的值;prototype
- 此时返回的对象的
__proto__
属性指向Object;
function Person(name, age){ // 建立临时新对象 var o = new Object(); // 初始化该对象 o.name = name; o.age = age; o.sayName = function(){ console.log(this.name); } // 返回该临时新对象 return o; } var p1 = new Person('Tom', 25); var p2 = new Person('Greg',30); console.log(p1 instanceof Object); // true console.log(p1 instanceof Person); // false console.log(p1.sayName == p2.sayName); // false console.log(p1.constructor == Object); //true
所谓 稳妥对象,就是指没有公共属性,并且其方法也不引用this
的对象。
稳妥对象最适合在一些安全的环境中(这些环境会禁用this
和new
),或者防止数据被其余应用程序改动时调用。
与寄生构造函数相似,但又不一样:code
- 一是新建立的对象实例方法不引用
this
;- 二是不使用
new
操做符调用构造函数;
function Person (name, age){ var o = new Object(); // 可定义私有变量和函数 // ... // 新建立的对象实例方法未引用this; o.sayName = function(){ console.log(name) } return o; } var p = Person('Tom', 23); p.sayName(); // 'Tom' console.log(p instanceof Person); // false
- 除了
sayName()
方法外,没有别的方法能够访问其数据成员;- 即便有其余代码给这个对象添加方法或数据成员,也不可能有别的办法访问传入到构造函数中的原始数据;
- 与寄生构造函数模式相似,使用稳妥构造函数模式建立的对象与构造函数之间也没有关系(故
instanceof
操做符对这种对象也无心义);