构造函数、原型和实例之间的关系
关系图:
原型链的基本概念
基于上述关系图的理解,让原型对象等于另一个类型的实例,假如这个类型的原型又等于另一个类型的实例,这样层层递进,构成了实例和原型的链条。
关系图:
原型链的代码实现的基本模式
//组合构造函数模式和原型模式
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue()); //true
console.log(instance.constructor === SuperType); //true
console.log(SubType.prototype.constructor === SuperType); //true
SubType继承了SuperType。继承是通过创建SuperType实例,然后赋值给SubType.prototype实现的。实现的本质是重写原型对象,代之以一个新类型的实例。
代码关系图:
关系结果:instance指向SubType的原型,Sub-Type的原型又指向SuperType的原型。
注意两点:
- getSuperValue()方法仍然还在SuperType.prototype中,但property则位于Sub-Type.prototype中。这是因为property是一个实例属性,而get-SuperValue()则是一个原型方法。既然SubType.prototype现在是SuperType的实例,那么property当然就位于该实例中了。
- instance.constructor现在指向的是SuperType。原因:SubType 的原型指向了另一个对象——SuperType 的原型,而这个原型对象的constructor 属性指向的是SuperType。
通过实现原型链,本质上扩展了原型搜索机制。调用instance.getSu-perValue()会经历三个搜索步骤:
- 搜索实例;
- 搜索Sub-Type.prototype;
- 搜索SuperType.prototype,最后一步才会找到该方法。
原型链的最顶层
所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。
继承关系图(完整版):
SubType继承了SuperType,而SuperType了继承Object。当调用instance.toString()时,实际上调用的是保存在Object.prototype中的那个方法。
确定原型和实例的关系
instanceof操作符和isPrototypeOf()方法
//instanceof操作符
console.log(instance instanceof Object); //true
console.log(instance instanceof SuperType); //true
consolo.log(instance instanceof SubType); //true
//isPrototypeOf()方法
console.log(Object.prototype.isPrototypeOf(instance)); //true
console.log(SuperType.prototype.isPrototypeOf(instance)); //true
console.log(SubType.prototype.isPrototypeOf(instance)); //true
子类型定义方法注意
- 重写父类方法或定义新方法注意:给原型添加方法的代码一定要放在替换原型的语句之后。为什么?因为,继承的本质就是重写子类的prototype,如果写在继承前面,那么后面创建实例的时候就访问不到新添加或修改的方法了。
- 在通过原型链实现继承时,不能使用对象字面量创建原型方法。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承SuperType,这个在前
SubType.prototype = new SuperType();
//子类添加父类没有的方法,在后
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
//重写父类方法,在后
SubType.prototype.getSuperValue = function() {
return false;
};
var instance = new SubType();
console.log(instance.getSuperValue()); //false
var instanceSuper = new SuperType();
console.log(instanceSuper.getSuperValue()); //true
由上述结果可以看出:子类重写父类方法,只是屏蔽,原方法不变。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承
SubType.prototype = new SuperType();
//字面量定义方法会使上一句代码无效
SubType.prototype = {
getSubValue: function() {
return this.subproperty;
},
someOtherMethod: function() {
return false;
}
};
var instance = new SubType();
console.log(instance.getSuperValue()); //error
上述继承后字面量写原型对象的方法会导致下面的错误是因为:现在的原型包含的是一个Object的实例,而非SuperType的实例,因此我们设想中的原型链已经被切断,现在的SubType和SuperType没关系了。
原型链问题
- 包含引用类型值的原型;
- 在创建子类型的实例时,不能向超类型的构造函数中传递参数。
//第一个问题
function SuperType() {
this.colors = ["blue", "red", "yellow"];
}
function SubType() {
}
//继承
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"blue,red,yellow,black"
var instance2 = new SubType();
console.log(instance2.colors); //"blue,red,yellow,black"
instance2的colors输出和instance1的colors一样,是因为这属性不是他们自己的,是SuperType实例的,不是他们本身的。
相关推荐
JavaScript中的继承和原型链是其核心特性之一,尤其对于从基于类的语言背景转到JavaScript的开发者来说,理解这一概念至关重要。在JavaScript中,没有传统的类,而是基于对象和原型进行继承。每个对象都有一个指向其...
2. **对象与原型链**:ECMAScript是基于对象的语言,这意味着它的核心概念是对象。每个对象都有属性和方法,属性是无序的键值对集合。对象可以通过原型链(Prototype Chain)相互关联,使得一个对象可以继承另一个...
在JavaScript中,每个对象都拥有一个原型(prototype),这个原型自身也是拥有原型的,从而形成了一个原型链(prototype chain)。在原型链上,对象能够继承其原型对象的属性和方法。这个机制是理解JavaScript继承和...
7. **原型与继承**:JavaScript使用原型链实现继承,每个对象都有一个`__proto__`属性指向其构造函数的原型。ES5中的`Object.create()`和ES6的类继承都是基于原型链的。 8. **闭包**:闭包是一种函数特性,它可以...
- 对象方法和原型链,实现继承和多态。 5. **数组** - 数组是一种特殊的对象,其属性名是整数。 - `length`属性返回数组元素的数量。 - `push()`, `pop()`, `shift()`, `unshift()`等方法用于操作数组元素。 -...
根据ECMAScript标准,null没有原型,并作为这个原型链的最后一个环节。这种原型对象的链接结构称为“原型链”。使用原型链,一个对象可以继承其原型对象的属性和方法。 **原型链的几个关键点如下:** 1. `Object....
在深入理解JavaScript的原型和原型链之前,首先我们需要知道原型是什么。在JavaScript中,原型是一个特殊的对象,它为对象实例提供共享的属性和方法。每个对象都拥有一个原型,并且原型自身也可能拥有一个原型,这种...
在JavaScript中,原型(Prototype)和原型链(Prototype Chain)是核心概念之一,它们是实现继承的关键,对于理解JavaScript的面向对象编程至关重要。 一、原型对象的理解 当我们用JavaScript创建一个函数时,这个...
在ES2015之前,JavaScript中的对象是通过构造函数和原型链来创建的,这种方式对于新手来说比较难以理解。而类提供了一种更接近于其他编程语言的方式来创建和管理对象。 模块是ES2015中的另一个重要特性。模块可以将...
当我们访问一个对象的属性或方法时,如果在对象本身上没有找到,JavaScript 引擎会继续在该对象的原型链上查找,直到找到该属性或方法或者查找到原型链的末端。 原型链是多个对象通过原型连接起来的链条。对象的...
这对于理解 JavaScript 原型链机制非常有帮助。 - **`Object.defineProperty()`**:该方法可以用来直接修改对象上的某个特定属性或添加新属性,同时还可以设置属性的各种特征,比如可写性、枚举性和配置性等。 - **`...
对于对象,它需要处理原型链和原型继承等特性。 此外,ECMAScript引入了模块系统(ES6的import/export),使得JavaScript代码可以被组织和隔离。JavaScript解释器需要能够正确处理模块导入和导出,确保模块间的依赖...
在深入理解JavaScript面向对象编程时,了解其原型和原型链的概念至关重要。本文将详细解释这些概念以及它们如何工作,帮助初学者构建扎实的基础。 首先,原型链是JavaScript中实现继承的一种机制。在JavaScript中,...
在ECMAScript中,面向对象是一种重要的编程范式,允许开发者通过创建和操作对象来组织代码。本文主要围绕标题...此外,ECMAScript还提供了类、原型链、继承等概念,这些将在后续的面向对象学习中逐步深入探讨。
在JavaScript中,原型链是一种机制,它允许对象之间共享属性和方法。这主要涉及到`prototype`、`__proto__`以及`new`操作符的工作原理。让我们深入理解这些概念。 首先,`new`操作符在创建新对象时起着至关重要的...
在ECMAscript中描述了原型链的概念,并将原型链作为实现继承的主要方法,其基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。 构造函数和原型还有实例之间的关系: 每个构造函数都有一个原型...
要实现ECMAScript的原型链,可以使用Delphi的类(class)和接口(interface)来模拟。类可以作为实例的模板,而接口可以用于实现多继承。 对于严格模式,虽然Pascal语言本身没有直接对应的概念,但可以通过在编译...