内容简介:JavaScript 内建的继承方法被称为 原型对象链(又叫原型对象继承)。原型对象的属性可经由对象实例访问,这就是继承的一种形式。对象实例继承了原型对象的属性,而原型对象也是一个对象,它也有自己的原型对象并继承其属性,以此类推。这就是原型对象链。
JavaScript 内建的继承方法被称为 原型对象链(又叫原型对象继承)。
原型对象的属性可经由对象实例访问,这就是继承的一种形式。
对象实例继承了原型对象的属性,而原型对象也是一个对象,它也有自己的原型对象并继承其属性,以此类推。这就是原型对象链。
所有对象(包括自义定的)都自动继承自 Object
,除非你另有指定。更确切地说,所有对象都继承自 Object.prototype
。任何以对象字面量形式定义的对象,其 [[Prototype]]
的值都被设为 Object.prototype
,这意味着它继承 Object.prototype
的属性。
5.1.1 继承自 Object.prototype 的方法
Object.prototype 一般有以下几个方法:
- hasOwnProperty() 检测是否存在一个给定名字的自有属性
- propertyIsemumerable() 检查一个自有属性是否可枚举
- isPrototypeOf 检查一个对象是否是另一个对象的原型对象
- valueOf() 返回一个对象的值表达
- toString() 返回一个对象的字符串表达
这 5 种方法经由继承出现在所有对象中。
因为所有对象都默认继承自 Object.prototype
,所以改变它就会影响所有的对象。所以不建议。
5.2 继承
对象继承是最简单的继承类型。你唯需要做的是指定哪个对象是新对象的 [[Prototype]]
。对象字面量形式会隐式指定 Object.prototype
为其 [[Protoype]]
。当然我们可以用 ES5 的 Object.create()
方法显式指定。该方法接受两个参数,第一个是新对象的 [[Prototype]]
所指向的对象。第二个参数是可选的一个属性描述对象,其格式与 Object.definePrototies()
一样。
var obj = {
name: "Ljc"
};
// 等同于
var obj = Object.create(Object.prototype, {
name: {
value: "Ljc",
configurable: true,
enumberable: true,
writable: true
}
});
复制代码
下面是继承其它对象:
var person = {
name: "Jack",
sayName: function(){
console.log(this.name);
}
}
var student = Object.create(person, {
name:{
value: "Ljc"
},
grade: {
value: "fourth year of university",
enumerable: true,
configurable: true,
writable: true
}
});
person.sayName(); // "Jack"
student.sayName(); // "Ljc"
console.log(person.hasOwnProperty("sayName")); // true
console.log(person.isPrototypeOf(student)); // true
console.log(student.hasOwnProperty("sayName")); // false
console.log("sayName" in student); // true
复制代码
当访问一个对象属性时,JavaScript 引擎会执行一个搜索过程。如果在对象实例存在该自有属性,则返回,否则,根据其私有属性 [[Protoype]]
所指向的原型对象进行搜索,找到返回,否则继承上述操作,知道继承链末端。末端通常是 Object.prototype
,其 [[Prototype]]
是 null
。
当然,也可以用 Object.create()
常见一个 [[Prototype]]
为 null
的对象。
var obj = Object.create(null);
console.log("toString" in obj); // false
复制代码
该对象是一个没有原型对象链的对象,即是一个没有预定义属性的白板。
5.3 构造函数继承
JavaScript 中的对象继承也是构造函数继承的基础。
第四章提到,几乎所有函数都有 prototype
属性,它可被修改或替换。该 prototype
属性被自动设置为一个新的继承自 Object.prototype
的泛用对象,该对象(原型对象)有一个自有属性 constructor
。
实际上,JavaScript 引擎为你做了下面的事情。
// 你写成这样
function YourConstructor(){
// initialization
}
// JavaScript引擎在背后为你做了这些处理
YourConstructor.prototype = Object.create(Object.prototype, {
constructor: {
configurable: true,
enumerable: true,
value: YourConstructor,
writable: true
}
})
复制代码
你不需要做额外的工作,这段代码帮你把构造函数的 prototype
属性设置为一个继承自 Object.prototype
的对象。这意味着 YourConstructor
创建出来的任何对象都继承自 Object.prototype
。
由于 prototype 可写,你可以通过改变它来改变原型对象链。
instanceof 运算符可以用来判断某个构造函数的 prototype 属性是否存在另外一个要检测对象的原型链上。
function Rectangle(length, width){
this.length = length;
this.width = width
}
Rectangle.prototype.getArea = function(){
return this.length * this.width
}
Rectangle.prototype.toString = function(){
return "[Rectangle " + this.length + "x" + this.width + "]";
}
// inherits from Rectangle
function Square(size){
this.length = size;
this.width = size;
}
Square.prototype = new Rectangle(); // 尽管是 Square.prototype是指向了 Rectangle的对象实例,即Square的实例对象也能访问该实例的属性(如果你提前声明了该对象,且给该对象新增属性)。
// Square.prototype = Rectangle.prototype; // 这种实现没有上面这种好,因为Square.prototype 指向了 Rectangle.prototype,导致修改Square.prototype时,实际就是修改Rectangle.prototype。
console.log(Square.prototype.constructor); // 输出 Rectangle 构造函数
Square.prototype.constructor = Square; // 重置回 Square 构造函数
console.log(Square.prototype.constructor); // 输出 Square 构造函数
Square.prototype.toString = function(){
return "[Square " + this.length + "x" + this.width + "]";
}
var rect = new Rectangle(5, 10);
var square = new Square(6);
console.log(rect.getArea()); // 50
console.log(square.getArea()); // 36
console.log(rect.toString()); // "[Rectangle 5 * 10]", 但如果是Square.prototype = Rectangle.prototype,则这里会"[Square 5 * 10]"
console.log(square.toString()); // "[Square 6 * 6]"
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
console.log(square instanceof Object); // true
复制代码
Square.prototype
并不真的需要被改成为一个 Rectangle
对象。事实上,是 Square.prototype
需要指向 Rectangle.prototype
使得继承得以实现。这意味着可以用 Object.create()
简化例子。
// inherits from Rectangle
function Square(size){
this.length = size;
this.width = size;
}
Square.prototype= Object.create(Rectangle.prototype, {
constructor: {
configurable: true,
enumerable: true,
value: Square,
writable: true
}
})
复制代码
在对原型对象添加属性前要确保你已经改成了原型对象,否则在改写时会丢失之前添加的方法(因为继承是将被继承对象赋值给需要继承的原型对象,相当于重写了需要继承的原型对象)。
5.4 构造函数窃取
由于 JavaScript 中的继承是通过原型对象链来实现的,因此不需要调用对象的父类的构造函数。如果确实需要在子类构造函数中调用父类构造函数,那就可以在子类的构造函数中利用 call
、 apply
方法调用父类的构造函数。
// 在上面的代码基础上作出修改
// inherits from Rectangle
function Square(size){
Rectangle.call(this, size, size);
// optional: add new properties or override existing ones here
}
复制代码
一般来说,需要修改 prototype
来继承方法并用构造函数窃取来设置属性,由于这种做法模仿了那些基于类的语言的类继承,所以这通常被称为伪类继承。
5.5 访问父类方法
其实也是通过指定 call
或 apply
的子对象调用父类方法。
以上所述就是小编给大家介绍的《《JavaScript面向对象精要》之五:继承》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 内存管理设计精要
- 网络爬虫精要
- 调度系统设计精要
- 《JavaScript面向对象精要》之二:函数
- 《JavaScript面向对象精要》之六:对象模式
- 《JavaScript面向对象精要》之三:理解对象
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Introduction to Computation and Programming Using Python
John V. Guttag / The MIT Press / 2013-7 / USD 25.00
This book introduces students with little or no prior programming experience to the art of computational problem solving using Python and various Python libraries, including PyLab. It provides student......一起来看看 《Introduction to Computation and Programming Using Python》 这本书的介绍吧!