咱们知道,建立对象能够这样javascript
var person = new Object();
person.name = “Nicholas”;
person.age = 29;
person.job = “Software Engineer”;
person.sayName = function(){ alert(this.name);};
复制代码
这个对象有name, age, job属性,还有一个sayName()的方法。这是你们经常使用的建立对象的方法,能够不断添加新属性,可是若是要建立多个相似的对象的话,就须要不断地重复这段代码,耗费不少内存。java
这时候能够用工厂模式来解决这个问题bash
function createPerson(name, age, job){
var o = new Object(); //1.建立一个空对象并赋值给变量o
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o; //2.返回变量o
}
var person1 = createPerson(“Nicholas”, 29, “Software Engineer”);
var person2 = createPerson(“Greg”, 27, “Doctor”);
复制代码
工厂模式还能够更加简练,好比能够建立一个语法糖,省略掉上一段代码的1和2 这时候便涉及到了Constructor模式了ide
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
var person2 = new Person(“Greg”, 27, “Doctor”);
复制代码
注意constructor老是以大写开头,这是它的书写规范。 相比工厂模式,当咱们用new这个关键字的时候,它帮咱们写了一下步骤:函数
alert(person1 instanceof Person); //true
复制代码
一样的,contructor模式也存在一个问题,在上一段代码中,咱们添加了一个sayName()
的方法优化
this.sayName = function(){
alert(this.name);
};
复制代码
若是须要建立100个不一样的person, 也须要建立100个sayName()
函数.ui
alert(person1.sayName == person2.sayName); //false
复制代码
可是这个函数代码都是同样的,实际上只须要建立一次便可。this
function createPerson(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName(){
alert(this.name);
};
var person1 = createPerson('Nicholas', 29, 'Software Engineer');
var person2 = createPerson('Greg', 27, 'Doctor');
复制代码
若是要建立不少不一样的对象,就必须建立不少不一样的全局方法,很容易产生冲突,这时候另外一种方式就大显身手了(原型)spa
function Person(){ }
Person.prototype.name = “Nicholas”;
Person.prototype.age = 29;
Person.prototype.job = “Software Engineer”;
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //”Nicholas”
var person2 = new Person();
person2.sayName(); //”Nicholas”
alert(person1.sayName == person2.sayName); //true
复制代码
每一个函数建立的时候,它的prototype属性也会被建立,指向一个普通的对象,这个对象会有一个constructor属性,指回这个函数,上面那段代码中 Person.prototype.constrctor
会从新指向Person。而每次建立一个新的实例,实例的__proto__属性会指向这个ProtoTypeprototype
person1.sayName()
的时候,它自己是没有这个方法的,因此会自动到
person1.__proto__
去找,若是尚未,就再上一层,去
person1.__proto__.__proto__
找,直到找到或者返回null为止。 读取
person1
的其余属性也是同样的,若是对象自己没有这个属性,会到它的___proto__去找,也就是
Person.prototype
,若是有的话,就返回这个值,没有的话,会再到
Person.prototype.__proto__
找,因为
Person.prototype
是个普通的对象实例,因此
Person.prototype.__proto__
指向的是
Object.prototype
判断一个属性是否属于自身的对象仍是对象的原型,能够用hasOwnProperty()
判断
原型一样能够用下列代码的方式建立,可是会覆盖掉原来默认的Prototype, 也就没有默认的constructor属性。
function Person(){ }
Person.prototype = {
name : “Nicholas”,
age : 29,
job : “Software Engineer”,
sayName : function () {
alert(this.name); }
};
复制代码
下面这段代码也会运行错误,缘由是当当实例被建立的时候,它的__proto__已经指向了默认的Person.prototype,这个时候你将Person.prototype指向另外一个地址,实例的__proto__是没办法访问到的
function Person(){ }
var person = new Person();
Person.prototype = {
constructor: Person,
name : “Nicholas”,
age : 29,
job : “Software Engineer”,
sayName : function () {
alert(this.name); }
};
person.sayName(); //error
复制代码
__proto__和prototype有什么区别呢,__proto__是在新的实例对象生成的时候,自动绑定到构造函数的prototype上面的,全部的对象都有__proto__属性。prototype则是在建立函数的时候,它的prototype属性也会被建立,指向一个普通的对象,这个对象会有一个constructor属性,指回这个函数。prototype只有函数才有的属性。
常见的建立对象的方式为下列代码,这样避免了共享对象的冲突
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = [“Shelby”, “Court”];
}
Person.prototype = {
constructor: Person,
sayName : function () {
alert(this.name);
}
};
var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
var person2 = new Person(“Greg”, 27, “Doctor”);
person1.friends.push(“Van”);
alert(person1.friends); //”Shelby,Court,Van”
alert(person2.friends); //”Shelby,Court”
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
复制代码
缺点:每次建立一个子实例,父方法会重复构建屡次,而且不会继承父类的prototype
function SuperType(){
this.property = true;
this.run = function() {}
}
function SubType(){
SuperType.call(this)
}
var instance = new SubType();
复制代码
缺点:一个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响到其余子类
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//inherit from SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
复制代码
经过SubType.prototype = new SuperType();
完成了原型的继承。为何要用SuperType
的实例来绑定SubType
的prototype
呢,由于这个实例的__proto__属性会指向SuperType.prototype
, 经过这个方式来继承SuperType
的属性和方法
toString()
和
valueOf()
等函数,也能够直接调用,由于这些函数已经在Object里面定义好了
若是要添加SubType的方法能够
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//inherit from SuperType
SubType.prototype = new SuperType();
//new method
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
//override existing method
SubType.prototype.getSuperValue = function (){
return false;
};
// 下面的方式是错的,SubType.prototype被从新赋值,不可以再访问父函数的方法了
<!--SubType.prototype = {-->
<!-- getSubValue: function (){--> <!-- return this.subproperty;--> <!-- }--> <!--}--> var instance = new SubType(); alert(instance.getSuperValue()); //false 复制代码
原型链存在的问题
function SuperType(){
this.colors = [“red”, “blue”, “green”];
}
function SubType(){ }
//inherit from SuperType
SubType.prototype = new SuperType();
var instance1 = new SubType(); instance1.colors.push(“black”);
alert(instance1.colors); //”red,blue,green,black”
var instance2 = new SubType();
alert(instance2.colors); //”red,blue,green,black”
复制代码
解决办法
function SuperType(){
this.colors = [“red”, “blue”, “green”];
}
function SubType(){ //inherit from SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push(“black”);
alert(instance1.colors); //”red,blue,green,black”
var instance2 = new SubType();
alert(instance2.colors); //”red,blue,green”
复制代码
可是上述方法也存在子对象没法引用父对象prototype中的方法等问题
function SuperType(name){
this.name = name;
this.colors = [“red”, “blue”, “green”];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
//inherit properties
SuperType.call(this, name);
this.age = age;
}
//inherit methods
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType(“Nicholas”, 29); instance1.colors.push(“black”);
alert(instance1.colors); //”red,blue,green,black”
instance1.sayName(); //”Nicholas”;
instance1.sayAge(); //29
var instance2 = new SubType(“Greg”, 27); alert(instance2.colors); //”red,blue,green”
instance2.sayName(); //”Greg”;
instance2.sayAge(); //27
复制代码
上述方法会调用SuperType的constructor方法两次
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); prototype.constructor = subType;
subType.prototype = prototype;
}
function SuperType(name){
this.name = name;
this.colors = [“red”, “blue”, “green”];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
};
复制代码
或者
// Shape - 父类(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父类的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子类(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
复制代码
使用Object.create()是将对象继承到__proto__属性上