原型
执行代码var o = new Object();
此时o对象内部会存储一个指针,这个指针指向了Object.prototype,当执行o.toString()
等方法(或访问其他属性)时,o会首先查看自身有没有该方法或属性,如果没有的话就沿着内部存储的指针找到Object.prototype
对象,然后查看Object.prototype
对象是否有对应名称的方法或属性,如果有就调用Object.prototype
的方法或属性。
我们把这个指针叫做o对象的原型。
ES3规范中定义了Object.prototype.isPrototypeOf()方法,该方法可以判断某个对象是不是另一个对象的原型。Object.prototype.isPrototypeOf(o)
返回true值可以确定Object.prototype就是o对象的原型。
在ES3规范中,不能直接读取o对象的原型,也就是o对象的原型看不见摸不着的。ES5.1规范定义了Object.getPrototypeOf()方法,通过该方法可以获取对象的原型。我们可以通过Object.getPrototypeOf(o) === Object.prototype
再次验证Object.prototype就是o对象的原型。
ES6规范更加直接,为对象添加了一个__proto__
属性,通过这个属性就可以获得对象的原型,所以在支持__proto__
的浏览器中,o.__proto__ === Object.prototype
也会返回true。
当我们执行var x = new X();
时,浏览器会执行x.__proto__ = X.prototype
,会将实例化对象的原型设置为对应的类的prototype对象,这一点很重要。
原型链
我们执行如下代码:
function Person(){}; var p = new Person();
p.__proto__指向了Person.prototype,Person.prototype的原型是Person.prototype.__proto__,其指向了Object.prototype,Object.prototype.__proto__为null。
通过__proto__向上追踪形成了如下的链式结构:
p -> Person.prototype -> Object.prototype -> null
这一原型的链式结构就叫做原型链。Object.prototype的原型是null,也就是说Object.prototype没有原型。
JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
JavaScript中的继承是通过原型实现的,虽然在ES6中引入了class
关键字,但是它只是原型的语法糖,JavaScript继承仍然是基于原型实现的。
ES5寄生组合继承 (业内比较提倡的方法)
function inserit(son, father) { var obj = Object.create(father.prototype); son.prototype = obj; obj.constructor = son } function SuperType(name, colors) { this.name = name; this.colors = colors; } SuperType.prototype.sayName = function () { return this.name; } function SubType(job, name, color) { SuperType.call(this, name, color); this.job = job; } //核心方法 inserit(SubType, SuperType); SubType.prototype.sayjob = function () { return this.job; } var instance = new SubType("doctor", "John", ["red", "green"]); console.log(instance.sayjob(), instance.sayName()) //doctor,John
ES6继承
ES6
支持通过类来实现继承,方法比较简单,代码如下
class Point { constructor(x, y) { this.x = x this.y = y } toString() { return this.x + '' + this.y } } class ColorPoint extends Point { constructor(x, y, color) { super(x, y) //调用父类的constructor(x, y) this.color = color } toString() { return this.color + ' ' + super.toString() // 调用父类的toString() } } var colorPoint = new ColorPoint('1', '2', 'red') console.log(colorPoint.toString()) // red 12