原型
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。不必再构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。
function Box(){} //创建一个构造函数 Box.prototype.name = 'Lee'; //在原型里 Box.prototype.age = 100; Box.prototype.run = function(){ //在原型里添加方法 return this.name + this.age + '运行中...'; }
原型声明方式 图:
实例化方法:不同的实例它们的地址是不一样的,是唯一的。
原型方法:对象里的原型地址共享的,大家都一样。
在原型模式声明中,多了两个属性,这两个属性都是创建对象是自动生成的。
__proto__:
属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。
constructor:
1、构造属性,可以获取构造函数本身
2、作用是被原型指针定位,然后得到构造函数本身
3、其实就是用来让对象实例对应原型对象的
ps:IE浏览器在脚本访问—__proto__会不能识别。
问:判断一个对象实例(对象引用)是不是指向原型对象?
答:Object.prototype.isPrototype(obj)
ps:只要实例化对象,都会自动指向原型
问:如何判断属性是在构造函数的实例里,还是在原型里?
答:
box.hasOwnProperty('name'); //判断构造函数的实例中是否存在指定属性
alert('name' in box); //返回true or false 无论在实例中还是原型中,只要存在指定属性,就返回true
function isProperty(object,propety){ //构造函数名,属性名 return !object.hasOwnProperty(property) && (propety in object); }
字面量方式创建原型
function Box(){} Box.prototype = { name:'Lee', age:100, run:function(){ return this.name + this.age + '运行中...'; } }
ps:字面量创建原型对象,使用constructor属性不会指向构造函数,而会指向object。
因为Box.prototype={};这种写法其实就是创建了一个新对象。而每创建一个函数,就会同时创建它prototype,这个对象也会自动获取constructor 属性。所以,新对象的constructor 重写了Box 原来的constructor,因此会指向新对象,那个新对象没有指定构造函数,那么就默认为Object。
问:如何让字面量方式的constructor指向构造函数呢?
答:
Box.prototype={ constructor:Box //强制指向构造函数 }
ps:重写会切断之前的原型。所以在声明前就要指向构造函数。
拓展:
原型对象不仅仅可以在自定义对象的情况下使用,而ECMAScript 内置的引用类型都可以使用这种方式,并且内置的引用类型本身也使用了原型。alert(Array.prototype.sort); //sort 就是Array 类型的原型方法 alert(String.prototype.substring); //substring 就是String 类型的原型方法 String.prototype.addstring = function () { //给String 类型添加一个方法 return this + ',被添加了!'; //this 代表调用的字符串 }; alert('Lee'.addstring()); //使用这个方法
原型的缺点:
1、初始化不能传参
2、在第一个实例修改后, 保持了共享
解决方法:组合构造函数+原型模式
function Box(name,age){ //将所有信息封装到函数体内
this.name = name;
this.age = age;
if(typeof this.run != 'function'){ //仅在第一次调用的初始化
Box.prototype.run = function(){
return this.name+ this.age+'运行中...';
}
}
}
当第一次调用构造函数时,run()方法发现不存在,然后初始化原型。当第二次调用,就不会初始化,并且第二次创建新对象,原型也不会再初始化了。这样及得到了封装,有实现了原型方法共享,并且属性都保持独立。
ps:使用动态原型模式,要注意一点,不可以在使用字面量的方法重写原型,因为会切断实例和新原型之间的联系。