Js原型以及原型链继承详解
对象与数据类型
JS中共有七种数据类型,除了ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。其余六种是:undefined
、null
、Boolean
、String
、Number
、Object
。
undefined
, number
, string
, boolean
,null
属于简单的值类型,使用基本类型变量可以调用方法是因为产生了包装对象(临时的),其中函数、数组、对象、new Number(10)等等都是对象,他们都是引用类型。
其中有几个需要注意的点:
- 所有的对象都是由函数创建
- 函数也是一个对象,由Function函数创建
- Function也是一个对象,由它自己创建
- 对于字面量创建的对象,只是使用函数创建对象的一个语法糖,例如
var obj = { a: 1, b: 2};
//等同于
var obj = new Object();
obj.a=1;
obj.b=2;
prototype
与__proto__
- 可以通过
Object.getPrototypeOf()
和Object.setPrototypeOf()
访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性__proto__
。 - 所有函数对象具有
prototype
属性,普通对象没有,这个prototype
的属性值是一个对象,默认的只有一个叫做constructor
的属性,指向这个函数本身。 - 所有的对象都有
__proto__
,指向创建它的函数的prototype
(Object.prototype
的__proto__
除外,它指向null
),连同一个函数new出来的对象的__proto__
都统一指向了这个函数的prototype
,根据后面要讲述的原型链规则,也就是说通过这个函数new出来的所有对象都可以直接使用该函数原型上的任意属性和方法 - 所有的函数,比如
function fn(){}
,都是由Function函数创建,因此fn的__proto__
指向Function
的prototype
- Function也是函数,因此它也由Function创建的,也就是说它自己创建了自己!所有
Function
的__proto__
指向的就是Function
的prototype
- Object函数也是由Function创建,因此Object的
__proto__
同样指向Function
的prototype
- Object.prototype却是一个特例——它的
__proto__
指向的是null
- prototype也是一个对象,原始
prototype
只有一个叫做constructor
的属性,指向这个函数本身。因为prototype是一个对象,因此它也是由Object方法创建,因此它的__proto__
将指向Object.prototype
ES6语法糖Class
Es6新增的一个Class只是一个prototype的语法糖
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
原型链
javaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
继承
关于这部分可以参考我的这篇文章Js实现继承的几种方式
ES6语法糖Class的继承
Es6的class实现继承可以使用extends
class ColorPoint extends Point {
constructor() {
super(); // 调用父类的constructor()
}
}
super
关键字,它在这里表示父类的构造函数,用来新建父类的this对象。
子类必须在constructor
方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。