构造函数、实例原型、实例之间的关系
构造函数创建对象
实例 = new 构造函数
| 【☆示例】用构造函数创建一个对象:```javascript function Person() {
} var person = new Person(); person.name = ‘Kevin’; console.log(person.name) // Kevin
1、Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person。 |
| --- |
<a name="yiPl8"></a>
## prototype,构造函数->原型
**构造函数.prototype = 原型**<br />一、每个函数都有一个 prototype 属性
| 【示例】```javascript
function doSomething () {}
console.log(doSomething.prototype)
console.log(doSomething)
// 和声明函数的方式无关
// JavaScript中的函数永远有一个默认原型属性
// var doSomething = function () {}
// console.log(doSomething.prototype)
1、在控制台中,可以看到doSomething函数的一个默认属性prototype。```javascript { constructor: ƒ doSomething(), proto: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }
2、给doSomething函数的原型对象添加新属性```javascript
function doSomething () {}
doSomething.prototype.foo = 'bar'
console.log(doSomething.prototype)
(1)运行结果如下```javascript { foo: “bar”, constructor: ƒ doSomething(), proto: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }
|
| --- |
| 【☆示例】构造函数.prototype = 原型,即Person.prototype = Person.prototype```javascript
function Person() {
}
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin
1、函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 person1 和 person2 的原型。
2、那什么是原型呢?你可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型”继承”属性。
3、让我们用一张图表示构造函数和实例原型之间的关系:
(1)在这张图中我们用 Object.prototype 表示实例原型。 |
| —- |
proto,实例->原型
实例.proto = 原型 = 构造函数.prototype
一、每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型。
| 【☆示例】实例.proto = 原型 = 构造函数.prototype,即person.proto = Person.prototype = Person.prototype```javascript function Person() {
}
var person = new Person();
console.log(person.proto === Person.prototype); // true
1、我们更新下关系图:<br /><br />(1)实例对象和构造函数都可以指向原型 |
| --- |
<a name="yuWls"></a>
## constructor,原型->构造函数,也是实例 -> 构造函数
**构造函数 = 原型.constructor** = 实例.__proto__.constructor = 构造函数.prototype.constructor<br />一、原型没有指向实例的属性,因为一个构造函数可以生成多个实例,<br />二、原型有指向构造函数的属性constructor,每个原型都有一个 constructor 属性指向关联的构造函数。
| 【☆示例】构造函数 = 原型.constructor = 实例.__proto__.constructor = 构造函数.prototype.constructor,即Person = Person.prototype.constructor = person.__proto__.constructor = Person.prototype.constructor```javascript
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
1、更新下关系图:
2、综上我们已经得出:```javascript
function Person() {
}
var person = new Person();
console.log(person.proto == Person.prototype) // true console.log(Person.prototype.constructor == Person) // true // 顺便学习一个ES5的方法,可以获得对象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) // true
|
| --- |
<a name="QcA4U"></a>
# 确定原型和实例的基本关系
一、可以通过两种方式确定原型和实例(实现机制)的关系
- instanceof操作符:instanceof运算符用于检测函数的prototype属性是否出现在某个实例对象的原型链上
- 实例对象的__proto__属性和构造函数的prototype属性,判断是不是同一个引用
- isPrototypeOf():isPrototypeOf()方法用于测试一个对象是否存在于另一个对象的原型链上
| 【示例】```javascript
function SuperType() {
this.prototy = true;
}
// 在SuperType函数的原型链上创建实例共享方法
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();
alert(instance.getSuperValue()); // true
| | —- |
| 【示例】instanceOf```javascript alert(instance instanceof Object); // true alert(instance instanceof SuperType); // true alert(instance instanceof SubType); // true
|
| --- |
| 【示例】```javascript
alert(Object.prototype.isPrototypeOf(instance)); // true
alert(SuperType.prototype.isPrototypeOf(instance)); // true
alert(SubType.prototype.isPrototypeOf(instance)); // true
| | —- |
区别
- B instanceof A:A构造函数的prototype对象是否在B的原型链上
- isPrototypeOf(B): A对象是否在B的原型链上 | 【示例】```javascript class A {} class B extends A {} let b = new B();
A.isPrototypeOf(B); // true A.inPrototypeOf(b); // false
b instanceof B; // true b instanceof A; // true B instanceof A; // false
1、这是一个很简单的继承,两个类之间的关系```javascript
B.__proto__ === A; // true
B.prototpye.__proto__ === A.prototype; // true
b.__proto__ === B.prototype; // true
(1) 类的继承是按下面的方式实现的```javascript class A {} class B {}
// B的实例继承A的实例 Object.setPrototypeOf(B.prototype, A.prototype); const b = new B();
// B的实例继承A的静态属性 Object.setPrototypeOf(B, A); const b = new B();
setPrototypeOf方法是```javascript
Object.setPrototypeOf = function(obj, proto) {
obj.__proto__ = proto;
return obj;
}
所以得出```javascript B.proto = A; B.proto.prototype = A.prototype;
(2)new操作符实现方式```javascript
var b = new Object();
b.__proto__ = B.prototype;
B.call(b);
所以得出```javascript b.proto = B.prototype;
2、由上述关系```javascript
B.__proto__ === A; // true
B.prototpye.__proto__ === A.prototype; // true
b.__proto__ === B.prototype; // true
可知:
(1)A对象在B的原型链上,不在b的原型链上。所以```javascript
A.isPrototypeOf(B);//true
A.isPrototypeOf(b);//false
(2)A, B的prototype在b的原型链上而不在B的原型链上,所以```javascript
b instanceof B;//true
b instanceof A;//true
B instanceof A;//false
|
| —- |