在JavaScript面向对象精要(一)中讲解了一些与面向对象相干的观点和要领,这篇讲讲原型和继承。
组织函数和原型对象
组织函数也是函数,用new
建立对象时挪用的函数,与一般函数的一个区别是,其首字母应当大写。但假如将组织函数看成一般函数挪用(缺乏new
关键字),则应当注重this
指向的题目。
var name = "Pomy";
function Per(){
console.log("Hello "+this.name);
}
var per1 = new Per(); //"Hello undefined"
var per2 = Per(); //"Hello Pomy"
运用new
时,会自动建立this
对象,其范例为组织函数范例,指向对象实例;缺乏new
关键字,this
指向全局对象。
能够用instanceof
来检测对象范例,同时每一个对象在建立时都自动具有一个constructor
属性,指向其组织函数(字面量情势或Object
组织函数建立的对象,指向Object
,自定义组织函数建立的对象则指向它的组织函数)。
console.log(per1 instanceof Per); //true
console.log(per1.constructor === Per); //true
每一个对象实例都有一个内部属性:[[Prototype]]
,其指向该对象的原型对象。组织函数自身也具有prototype
属性指向原型对象。一切建立的对象都同享该原型对象的属性和要领。
function Person(){}
Person.prototype.name="dwqs";
Person.prototype.age=20;
Person.prototype.sayName=function()
{
alert(this.name);
};
var per1 = new Person();
per1.sayName(); //dwqs
var per2 = new Person();
per2.sayName(); //dwqs
alert(per1.sayName == per2.sayName); //true
所以,实例中的指针仅指向原型,而不指向组织函数。ES5供应了hasOwnProperty()
和isPropertyOf()
要领来回响反映原型对象和实例之间的关联
alert(Person.prototype.isPrototypeOf(per2)); //true
per1.blog = "www.ido321.com";
alert(per1.hasOwnProperty("blog")); //true
alert(Person.prototype.hasOwnProperty("blog")); //false
alert(per1.hasOwnProperty("name")); //false
alert(Person.prototype.hasOwnProperty("name")); //true
由于原型对象的constructor
属性是指向组织函数自身,所以在重写原型时,须要注重constructor
属性的指向题目。
function Hello(name){
this.name = name;
}
//重写原型
Hello.prototype = {
sayHi:function(){
console.log(this.name);
}
};
var hi = new Hello("Pomy");
console.log(hi instanceof Hello); //true
console.log(hi.constructor === Hello); //false
console.log(hi.constructor === Object); //true
运用对象字面量情势改写原型对象转变了组织函数的属性,因而constructor
指向Object
,而不是Hello
。假如constructor
指向很主要,则须要在改写原型对象时手动重置其constructor
属性
Hello.prototype = {
constructor:Hello,
sayHi:function(){
console.log(this.name);
}
};
console.log(hi.constructor === Hello); //true
console.log(hi.constructor === Object); //false
应用原型对象的特征,我们能够很轻易的在JavaScript的内建原型对象上增加自定义要领:
Array.prototype.sum=function(){
return this.reduce(function(prev,cur){
return prev+cur;
});
};
var num = [1,2,3,4,5,6];
var res = num.sum();
console.log(res); //21
String.prototype.capit = function(){
return this.charAt(0).toUpperCase()+this.substring(1);
};
var msg = "hello world";
console.log(msg.capit()); //"Hello World"
继承
应用[[Prototype]]
特征,能够完成原型继承;关于字面量情势的对象,会隐式指定Object.prototype
为其[[Prototype]]
,也能够经由历程Object.create()
显现指定,其接收两个参数:第一个是[[Prototype]]
指向的对象(原型对象),第二个是可选的属性描述符对象。
var book = {
title:"这是书名";
};
//和下面的体式格局一样
var book = Object.create(Object.prototype,{
title:{
configurable:true,
enumerable:true,
value:"这是书名",
wratable:true
}
});
字面量对象会默许继承自Object
,更风趣的用法是,在自定义对象之间完成继承。
var book1 = {
title:"JS高等程序设计",
getTitle:function(){
console.log(this.title);
}
};
var book2 = Object.create(book1,{
title:{
configurable:true,
enumerable:true,
value:"JS威望指南",
wratable:true
}
});
book1.getTitle(); //"JS高等程序设计"
book2.getTitle(); //"JS威望指南"
console.log(book1.hasOwnProperty("getTitle")); //true
console.log(book1.isPrototypeOf("book2")); //false
console.log(book2.hasOwnProperty("getTitle")); //false
当接见book2
的getTitle
属性时,JavaScript引擎会实行一个搜刮历程:如今book2
的自有属性中寻觅,找到则运用,若没有找到,则搜刮[[Prototype]]
,若没有找到,则继承搜刮原型对象的[[Prototype]]
,直到继承链末尾。末尾通常是Object.prototype
,其[[Prototype]]
被设置为null
。
完成继承的别的一种体式格局是应用组织函数。每一个函数都具有可写的prototype
属性,默许被自懂设置为继承自Object.prototype
,能够经由历程改写它来转变原型链。
function Rect(length,width){
this.length = length;
this.width = width;
}
Rect.prototype.getArea = function(){
return this.width * this.length;
};
Rect.prototype.toString = function(){
return "[Rect"+this.length+"*"+this.width+"]";
};
function Square(size){
this.length = size;
this.width = size;
}
//修正prototype属性
Square.prototype = new Rect();
Square.prototype.constructor = Square;
Square.prototype.toString = function(){
return "[Square"+this.length+"*"+this.width+"]";
};
var rect = new Rect(5,10);
var square = new Square(6);
console.log(rect.getArea()); //50
console.log(square.getArea()); //36
假如要接见父类的toString()
,能够如许做:
Square.prototype.toString = function(){
var text = Rect.prototype.toString.call(this);
return text.replace("Rect","Square");
}