1,prototype属性:
只有构建函数才有原型,它的prototype属性才有意义,它指向函数的原型,函数本身作为对象是由Function构建的(所以函数的_proto_都指向Function.protype);
对象有隐性的_proto_属性,指向自己的构建函数的原型;函数原型拥有Constructor属性,指向原型对应的构建函数;
原型链正是基于_proto_建立起来的,构建函数构建对象时,_proto_会指向函数的prototype属性;
字面量对象由Object函数构建,所以普通对象的_proto_指向Object的原型,Object.prototype值为空。
有如下推论:
函数的prototype属性只有该函数作为构造器构造一个对象时才有意义,他所指向的对象保存了构造出来的新对象所继承的属性;
一切函数对象的构造函数都是 Function,没有new 关键字就是普通函数,此时没有prototype属性;
当一个函数被声明时,这个函数的prototype属性的constructor属性值是这个函数的自身,函数对象的constructor就是来源于这里,在原型链中一级一级归宿,最终的constructor指向最上层的构造函数;假设函数的对象的prototype已经指向一个字面量对象或者函数对象,则指向的这个对象的constructor就是函数对象的constructor;
重写原型对象会切断现有原型与任何之前存在过的对象实例之间的联系,他们引用的是最初的原型(_proto_保存的值不会改变);
可以通过对象访问原型中的属性值,但不能重写,重写会屏蔽原型中的属性值;
2,组合使用构造器模式和原型模式(原型模式值都是统一的,而且不能改写值):
function Person(name, age, job){
this.name = name; //这里的this很关键,没有它,这里的属性将成为函数作用域内部的变量,外部没法访问。
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor: Person, //这里很关键,可以使constructor属性指向我们需要的实例,默认指向Object
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
3,使用动态原型模式(在构造函数中添加原型)中,不能使用对象字面量重写原型,会切断现有实例与新原型之间的联系;
效果和上面一致,只是原型和构造函数都放在同一个代码块里面。
4,new关键字的作用:
1.第一步,创建一个空对象。
var prince={}
2.第二步,将构造函数Prince()中的this指向新创建的对象prince。
3.第三步,将prince的_proto_属性指向Prince函数的prototype,创建对象和原型间关系
4.第四步,执行构造函数Prince()内的代码。
下面是六种基本继承方法:
1,原型链继承:利用原型指向另一个类型的实例,层层递进,最终形成原型链。
弊端:1,包含引用类型值的原型属性(上层对象的属性会成为下层对象的原型属性)会被所有实例共享;
2,在创建子类型的实例时,不能向超类型的构造函数中传递参数。
2, 类继承:在子类的构造函数中调用超类的构造函数,好处是可以传递参数,而且所有的属性都不是原型属性。
弊端:1,方法都在构造函数中定义,因此函数无法复用(每个实例对象都有一个函数实例,而不是共享);
2,在超类的原型中定义的方法,对于子类不可见(普通调用,所以和超类的原型间没有建立联系,参考new的作用)。
3,组合继承:结合原型链继承和类继承。用原型链实现对超类原型属性和方法的继承,用构造函数实现实例属性的继承。
事实上,这种继承模式会调用两次超类的构造函数,第二次调用会使实例属性屏蔽掉同名的原型属性。但是这是使用最多的继承模式,缺点可以忽略。
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); //第二次调用,类继承,name不是原型属性
this.age = age;
}
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
4,原型式继承:
function object(o){
function F(){}
F.prototype = o;
return new F();
}
5,寄生式继承:
function createAnother(original){
var clone = object(original);
clone.sayhi = function(){
alert("hi");
}
return clone;
}
6,寄生组合式继承:客服上面的缺点。
利用下面这个方法,原型链只继承超类的prototype,这样可以避免子类原型中出现冗余的超类的实例属性和方法。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //create object
prototype.constructor = subType; //augment object
subType.prototype = prototype; //assign object
}
只有构建函数才有原型,它的prototype属性才有意义,它指向函数的原型,函数本身作为对象是由Function构建的(所以函数的_proto_都指向Function.protype);
对象有隐性的_proto_属性,指向自己的构建函数的原型;函数原型拥有Constructor属性,指向原型对应的构建函数;
原型链正是基于_proto_建立起来的,构建函数构建对象时,_proto_会指向函数的prototype属性;
字面量对象由Object函数构建,所以普通对象的_proto_指向Object的原型,Object.prototype值为空。
有如下推论:
函数的prototype属性只有该函数作为构造器构造一个对象时才有意义,他所指向的对象保存了构造出来的新对象所继承的属性;
一切函数对象的构造函数都是 Function,没有new 关键字就是普通函数,此时没有prototype属性;
当一个函数被声明时,这个函数的prototype属性的constructor属性值是这个函数的自身,函数对象的constructor就是来源于这里,在原型链中一级一级归宿,最终的constructor指向最上层的构造函数;假设函数的对象的prototype已经指向一个字面量对象或者函数对象,则指向的这个对象的constructor就是函数对象的constructor;
重写原型对象会切断现有原型与任何之前存在过的对象实例之间的联系,他们引用的是最初的原型(_proto_保存的值不会改变);
可以通过对象访问原型中的属性值,但不能重写,重写会屏蔽原型中的属性值;
2,组合使用构造器模式和原型模式(原型模式值都是统一的,而且不能改写值):
function Person(name, age, job){
this.name = name; //这里的this很关键,没有它,这里的属性将成为函数作用域内部的变量,外部没法访问。
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor: Person, //这里很关键,可以使constructor属性指向我们需要的实例,默认指向Object
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
3,使用动态原型模式(在构造函数中添加原型)中,不能使用对象字面量重写原型,会切断现有实例与新原型之间的联系;
效果和上面一致,只是原型和构造函数都放在同一个代码块里面。
4,new关键字的作用:
1.第一步,创建一个空对象。
var prince={}
2.第二步,将构造函数Prince()中的this指向新创建的对象prince。
3.第三步,将prince的_proto_属性指向Prince函数的prototype,创建对象和原型间关系
4.第四步,执行构造函数Prince()内的代码。
下面是六种基本继承方法:
1,原型链继承:利用原型指向另一个类型的实例,层层递进,最终形成原型链。
弊端:1,包含引用类型值的原型属性(上层对象的属性会成为下层对象的原型属性)会被所有实例共享;
2,在创建子类型的实例时,不能向超类型的构造函数中传递参数。
2, 类继承:在子类的构造函数中调用超类的构造函数,好处是可以传递参数,而且所有的属性都不是原型属性。
弊端:1,方法都在构造函数中定义,因此函数无法复用(每个实例对象都有一个函数实例,而不是共享);
2,在超类的原型中定义的方法,对于子类不可见(普通调用,所以和超类的原型间没有建立联系,参考new的作用)。
3,组合继承:结合原型链继承和类继承。用原型链实现对超类原型属性和方法的继承,用构造函数实现实例属性的继承。
事实上,这种继承模式会调用两次超类的构造函数,第二次调用会使实例属性屏蔽掉同名的原型属性。但是这是使用最多的继承模式,缺点可以忽略。
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); //第二次调用,类继承,name不是原型属性
this.age = age;
}
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
4,原型式继承:
function object(o){
function F(){}
F.prototype = o;
return new F();
}
5,寄生式继承:
function createAnother(original){
var clone = object(original);
clone.sayhi = function(){
alert("hi");
}
return clone;
}
6,寄生组合式继承:客服上面的缺点。
利用下面这个方法,原型链只继承超类的prototype,这样可以避免子类原型中出现冗余的超类的实例属性和方法。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //create object
prototype.constructor = subType; //augment object
subType.prototype = prototype; //assign object
}