动态原型模式是由构造函数和原型模式组合而成的,那么构造函数是怎样的呢:
function Box(name){
this.name = name;
this.call = function(){
alert('your name is '+ this.name)
}
}
var box = new Box('obama');
这是一个典型的构造函数,通过使用new函数,实例化一个box对象,那么为什么可以通过使用new操作符实例化对象呢,其实在使用new操作符的同时,系统会执行以下操作;
var box = new Object();
box.__proto__ = Box.prototype;
Box.call(box);
//执行函数代码
return box;
首先默认生成一个对象,继承构造函数Box的原型,然后把函数的作用域绑定在这个对象上,在执行函数,最后返回这个对象,因此每个实例对象都是一个独立的对象,我们知道每个对象都是不相等的;
var box1 = new Box('a');
var box2 = new box('a');
box1.call == box2.call //false
原型模式中,
function Bar(){};
Bar.prototype = {
constructor:Box,
age:100,
call:function(){
alert('your age is' + this.age)
}
}
我们都知道使用字面量的写法,会默认生成Object对象,因此要强制把constructor属性指向Bar,执行的过程是先看自身有没有这个属性,有就执行,不管原型里是否还有,如果没有就继续查找原型,有就执行,没有就报错,如何判断是自身属性还是原型里的属性呢;
var bar = new Bar();
bar.name = 'obama';
bar.hasOwnProperty('name'); //true
//hasOwnProperty 只会判断自身是否有这个属性,原型是否有无法判断;
'name' in bar; //true
// in这个方法更近一步能判断不管自身还是原型有属性(当然是可以枚举的属性)
//通过这两个方法我们可以判断原型中是否有属性
function isProperty(object,property){
return !object.hasOwnProperty(property) && (property in object);
}
重点!!原型是会重写的,这和JS里其他的对象一样,后面的会覆盖前面的,还有个问题是如果原型中修改属性,一个实例对象就会改写这个值,导致其他的实例对象都会改变!!
function Box(){
}
Box.prototype = {
constructor:Box,
boxs:['box1','box2','box3'],
name:'bigBox'
}
var box1 = new Box();
var box2 = new Box();
box1.name = 'first box';
console.log(box1.name); //'first box'
console.log(box2.name); //'bigbox'
box1.boxs.push('box4');
console.log(box1.boxs); //["box1", "box2", "box3", "box4"]
console.log(box2.boxs); //["box1", "box2", "box3", "box4"]
很难理解为什么box1修改name属性就不会重写原型,而修改boxs属性就会重写原型,两者的差别就在于一个是赋值,一个是查找,打个比方,
a向b借了100元,那么a就得到了100元,不是a的父亲,爷爷得到了100元,所以赋值即给a添加不论是属性还是方法收益的只有a,不会给a的父亲,爷爷其他人也赋值,但是如果b找a 还的话,如果找不到a就可以找a 的父亲爷爷等其他人,这个意思是是说,只要是赋值,就只作用在赋值对象上,但是查找就不同,可以一直追溯到其他人,上面的例子,
box1.boxs.push(”box4′),可以这么理解,首先是查找,box1.boxs,不然如何push呢,自身属性没有,但是原型上有,有就OK直接操作push,但是这个操作是对象是所有对象共享的,所以一旦修改就改变了!
基于以上的问题,那么动态原型模式就是把共享的使用原型,不共享的使用构造函数,
function Box(){
this.name:'bigBox';
this.boxs = ["box1", "box2", "box3"];
};
Box.prototype = {
constructor:Box,
num:function(){
console.log(this.boxs.length);
}
}
//或者写在一起
function Box(){
this.name:'bigBox',
this.boxs = ["box1", "box2", "box3"];
if(typeof this.run != 'function'){
Box.prototype.num = function(){
console.log(this.boxs.length);
}
}
}
//因为构造函数执行时,里面的代码都会执行一遍,而原型有一个就行,不用每次都重复,所以仅在第一执行时生成一个原型,后面执行就不必在生成,所以就不会执行if包裹的函数,
//其次为什么不能再使用字面量的写法,我们都知道,使用构造函数其实是把new出来的对象作用域绑定在构造函数上,而字面量的写法,会重新生成一个新对象,就切断了两者的联系!