JavaScript 学习笔记 03 (原型、继承)
一、构造函数与原型
JavaScript 中声明一个实例是这样写的
function Dog(name, color) { this.name = name this.color = color this.bark = () => { cosole.log("wangwangwang~") } } var dog1 = new Dog("dog1","black") var dog2 = new Dog("dog2","white")
通过构造函数创建了 dog1 和 dog2 两个实例,分别有自己的名字和颜色,和叫的方法。但是存在一个问题:叫的方法是一样的,但是因为通过构造函数创建实例的时候每一个实例中都重新创建了这个方法,造成了很大的浪费,为什么不把这个方法单独的放到一个地方,并且让所有的实例都可以访问到呢。
这时就需要用到原型(prototype):
- 每一个构造函数都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象。
- 原型对象默认拥有一个constructor属性,指向指向它的构造函数(也就是说构造函数和原型对象是互相指向的关系)。
- 每个实例都拥有一个隐藏的属性[[prototype]],指向它的原型对象,这个属性可以通过Object.getPrototypeOf(obj) 或者 obj.__proto__ 来访问。
- 构造函数的prototype属性指向的对象与实例的__proto__属性指向的对象是同一个。
因此可以用原型来存放公共的方法。
function Dog(name, color) { this.name = name this.color = color } Dog.prototype.bark = function(){ console.log("wangwangwang~") } var dog1 = new Dog("dog1","black") dog1.bark() // "wangwangwang~"
可以看到 dog1.bark() 方法能够被正常调用,这时候创建另一个实例并重写它的bark方法,然后再次调用。
const dog2 = new Dog('dog2', 'white') dog2.bark() = function () { console.log("miaomiaomiao") } dog1.bark() //"wangwangwang~" dog2.bark() //"miaomiaomiao"
dog2 重写 bark 方法并没有对 dog1 造成影响,因为它重写的 bark 方法只存在实例 dog2 中,而未对原型中的 bark 方法进行改动。
因此看到实例的一个重要特点:访问对象的属性时,JavaScript会首先在对象自身的属性内查找,若没有找到,则会跳转到该对象的原型对象中查找。
二、原型链与继承
JavaScript 中所有的对象都有自己的原型对象,而原型对象本身也是一个对象,它也有自己的原型对象,这样层层链接,就形成了一个类似链表的结构,这就是原型链(prototype chain)
所有原型链的终点都是 Object 函数的 prototype 属性,因此在 JavaScript 中对象都是默认由 Object() 构造。 Object.prototype 指向的原型对象同样拥有原型。
通过原型链就可以在 JavaScript 中实现继承。
function SuperType() { this.property = true } SuperType.protytype.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.getSuperValuer()) // true
上面的代码中,我们没有使用 SubType 默认提供的原型,而是给它换了一个新的原型。这个新原型就是 SuperType 的实例。于是,新原型不仅有作为一个 SuperType 的实例所拥有的全部属性和方法,而且内部还有一个指针指向了 SuperType 的原型。最终结果就是这样:instance 指向 SubType 的原型,SubType 的原型又指向了 SuperType 的原型。
如果加上最上层的 Object,关系图大致是这样的。