原型语法
function Person(){
}
Person.prototype={
name:"burning",
age:24,
job:"captain",
sayJob:function(){
console.log(this.job);
}
}
var friend=new Person();
friend.sayJob();
console.log(friend instanceof Object)//true
console.log(friend instanceof Person)//true
console.log(friend.constructor==Person)//false
console.log(friend.constructor==Object)//true
对于前面几种模式,每次添加一个属性都要输入Person.prototype一次,我们可以用这种方法来重写原型对象,但是通过这种方式创建的对象,constructor属性不再指向Person。每次创建函数的时候都会自动获得constructor属性,而我们在这里使用的语法,本质上完全重写了默认的prototype对象,因此constructor属性也就变成了的新对象的constructor属性,不再指向Person。但是呢我们可以通过设置constructor的值来确保通过属性能访问到适当的值,但是呢改变这个属性会使得他的[[Enumerable]]被设置为true。还需要用defineProperty()来设置
defineProperty(Person.prototype,"constructor",{
enumerable:false,
value:Person
})
原型具有动态性,当我们在原型中查找值的过程中,他会开始搜索,我们对原型对象做的所有修改都可以立即反映出来
var friend =new Person()
Person.protototype.sayHi=function(){
console.log("hi");
}
friend.sayHi();
尽管我们能够先创建实例再修改原型,但是当我们重写整个原型对象,那么情况就不一样了,当我们调用构造函数的时候会为实例添加一个指向最初原型的[[Prototype]]指针,把原型修改为另外一个对象就等于切断了原型和构造函数之间的联系,实例中的指针仅指向原型,而不是指向构造函数。
function Person(){
}
var friend=new Person();//创建了一个指针指向初始原型对象
Person.prototype={
constructor:Person,
name:"burning",
age:29,
job:"carry",
sayJob:function(){
console.log(this.job)
}
}//重写过后的初始原型对象并不包含这些属性,所以会报错
//var friend=new Person()在这里创建friend对象就不会报错
friend.sayJob();
原生对象的原型
原型模式的重要性不光体现在创建函数的时候,许多原生的引用类型(如Object、Array、String)都在他们的构造函数原型上定义了方法。
console.log (typeof Array.prototype.sort)//function
console.log (typeof String.prototype.substring)//function
既然他们这些方法是在prototype上定义的,我们自己也可以定义这些方法
String.prototype={
constructor:String,
startsWith:function(text){
console.log(this.indexOf(text));
}
}
var msg="hello,world";
console.log(msg.startsWith("hello"))//true
原型对象也并非没有缺点,他的优点确实在某些方面是很好用的,但是实例一般都是要有属于自己的属性的,而这个问题正是我们很少看到有人单独使用原型模式的原因所在。
我们一般会把构造函数模式和原型模式组合起来使用
构造函数模式用于实例属性,原型模式用于共享属性
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friend=["jack","rose"];
}
Person.prototype={
constructor:Person,
sayName:function(){
console.log(this.name);
}
}
var person1=new Person("burning",24,"carry")
var person2=new Person("ROTK",25,"captain")
person1.friend.push("iceice");
console.log(person1.friend); //["jack", "rose", "iceince"]
console.log(person2.friend); //["jack", "rose"]
动态原型模式
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
if (typeof this.sayName!="function") {
Person.prototype.sayName=function(){
console.log(this.name);
}
};
}
var person1=new Person("ZSMJ",30,"carry");
person1.sayName();//ZSMJ
这里添加了一个判断语句,只有在sayName()方法不存在的情况下,才会给原型添加sayName(),这样即把构造函数和原型模式封装在一个函数中,又解决了共享属性方法的问题。
稳妥构造函数模式
这种模式没有公共属性,也不引用this的对象。
function Person(name,age,job){
var o=new Object();
o.sayName=function(){
console.log(name);
}
return o;
}
var friend=new Person("ROTK",25,"captain");
friend.sayName()//ROTK;
通过这种方法除了sayName()方法外就没有别的方法能够访问到他的数据成员。(适合在安全环境下使用)