在传统的面向对象编程语言中,都有类的概念,类可以从父类继承属性和方法。但是,在ECMAScript5规范中没有类的概念(ECMAScript6规范开始引入),但是继承可以发生在对象之间。
一、原型对象的继承
原型对象继承是JavaScript原生的(默认的)继承方式。
默认情况下,所有对象(包括通过自定义构造函数创建的对象)都间接或直接继承自Object.prototype原型对象。也就是说,Object.prototype原型对象中的属性和方法会被所有对象继承。
(1)直接继承
// var obj = new Object();
var obj = {};
console.log(obj);
// obj的原型对象就是Object.prototype
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
(2)间接继承
var arr = new Array(1,2);
console.log(arr);
// 通过new Array()创建出对象arr,所以arr的原型对象就是Array.prototype
console.log(Object.getPrototypeOf(arr) === Array.prototype); // true
// Array本身也是对象,所以Array.prototype的原型对象就是Object.prototype
console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype); // true
// 原型链:arr.__proto__ ---> Array.prototype.__proto__ ---> Object.prototype
Object.prototype上所有属性和方法:
- hasOwnProperty:检测对象自己的属性列表中是否包含某个属性,如果包含返回true,否则返回false
- isPrototypeOf :检测某个对象是否是另一个对象的原型对象
- propertyIsEnumerable : 检测对象中某个属性是否可枚举
- toLocaleString: 返回符合国情的字符串表示形式(如:打印时间对象时,返回的字符串)
- toString: 返回对象的字符串表示形式
- valueOf: 使用 valueOf 方法获取对象的原始值(如:创建时间对象后获取毫秒值)
二、对象的继承
var obj = {
fname: '赵四'
}
var obj2 = new Object();
obj2.fname = '刘能';
console.log(Object.prototype.isPrototypeOf(obj)); // true
console.log(Object.prototype.isPrototypeOf(obj2)); // true
使用Object.create()可以以某个对象为原型创建对象,同时还可以定义属性的特性
var obj = {
fname: '赵四',
get getFname() {
return this.fname;
}
}
// 使用Object.create()可以以某个对象为原型创建对象,同时还可以定义属性的特性
var obj2 = Object.create(obj, {
'fname': {
enumerable: true,
configurable: false,
writable: true,
value: '刘能'
},
'age': {
enumerable: true,
configurable: false,
writable: true,
value: 20
}
});
console.log(obj2);
console.log(obj2.getFname); // 刘能,从obj继承来的访问器属性,沿着原型链查找
console.log(Object.getPrototypeOf(obj2) === obj); // true
三、构造函数的继承
// 矩形
function Rectangle(width, height){
this.width = width;
this.height = height;
}
// 添加共享属性
Object.defineProperties(Rectangle.prototype, {
getArea: {
enumerable: false,
configurable: false,
writable: false,
value: function(){
return '矩形的面积是:' + (this.width * this.height);
}
}
})
// 正方形
function Square(size){
this.width = size;
this.height = size;
}
// 第一种方式
// Square.prototype.__proto__ = Rectangle.prototype;
// var square = new Square();
// console.log(Object.getPrototypeOf(square) === Square.prototype); // true
// 第二种方式
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
enumerable: false,
configurable: false,
writable: false,
value: Square
}
});
var square = new Square(20);
console.log(square.getArea().replace('矩形', '正方形')); // 正方形的面积是:400
console.log(square.__proto__ === Square.prototype); // true
console.log(Square.prototype.__proto__ === Rectangle.prototype); // true
覆盖父类的方法
// 矩形
function Rectangle(width, height){
this.width = width;
this.height = height;
}
// 添加共享属性
Object.defineProperties(Rectangle.prototype, {
getArea: {
enumerable: false,
configurable: false,
writable: false,
value: function(){
return '矩形的面积是:' + (this.width * this.height);
}
}
})
// 正方形
function Square(size){
this.width = size;
this.height = size;
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
enumerable: false,
configurable: false,
writable: false,
value: Square
},
// 覆盖父类的方法
getArea: {
enumerable: false,
configurable: false,
writable: false,
value: function(){
return '矩形的面积是:' + (this.width * this.height);
}
}
});
var square = new Square(20);
console.log(square.getArea().replace('矩形', '正方形')); // 正方形的面积是:400
console.log(square.__proto__ === Square.prototype); // true
console.log(Square.prototype.__proto__ === Rectangle.prototype); // true
借用父类的方法:
// 矩形
function Rectangle(width, height){
this.width = width;
this.height = height;
}
// 添加共享属性
Object.defineProperties(Rectangle.prototype, {
getArea: {
enumerable: false,
configurable: false,
writable: false,
value: function(){
console.log(this);
return '矩形的面积是:' + (this.width * this.height);
}
}
})
// 正方形
function Square(size){
this.width = size;
this.height = size;
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
enumerable: false,
configurable: false,
writable: false,
value: Square
},
getArea: {
enumerable: false,
configurable: false,
writable: false,
value: function(){
// 调用父类的方法
return Rectangle.prototype.getArea.call(this).replace('矩形', '正方形');
}
}
});
var square = new Square(20);
console.log(square.getArea()); // 正方形的面积是:400
console.log(square.__proto__ === Square.prototype); // true
console.log(Square.prototype.__proto__ === Rectangle.prototype); // true
调用父类的构造函数:
// 矩形
function Rectangle(width, height){
this.width = width;
this.height = height;
}
// 添加共享属性
Object.defineProperties(Rectangle.prototype, {
getArea: {
enumerable: false,
configurable: false,
writable: false,
value: function(){
console.log(this);
return '矩形的面积是:' + (this.width * this.height);
}
}
})
// 正方形
function Square(size){
// this.width = size;
// this.height = size;
Rectangle.call(this, size, size);
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
enumerable: false,
configurable: false,
writable: false,
value: Square
}
});
var square = new Square(20);
console.log(square.getArea().replace('矩形', '正方形')); // 正方形的面积是:400
console.log(square.__proto__ === Square.prototype); // true
console.log(Square.prototype.__proto__ === Rectangle.prototype); // true
arr.__proto__ ---> Array.prototyp
e.__proto__ ---> Object.prototype
arr.__proto__ ---> Array.prototype.__proto__ ---> Object.prototy