Javascript继承
Javascript对象继承有很多种方法,但各有缺陷,这里只介绍一种经典的没有缺陷(不会引起被继承对象改变)的方法。
在three.js源码中摘出的几行代码如下:
THREE.InstancedBufferAttribute = function ( array, itemSize, meshPerAttribute ) { THREE.BufferAttribute.call( this, array, itemSize ); // 继承1 this.meshPerAttribute = meshPerAttribute || 1; }; THREE.InstancedBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); // 继承2 THREE.InstancedBufferAttribute.prototype.constructor = THREE.InstancedBufferAttribute; // 继承3
js继承最重要的就是如上3步操作。
我们使用一个简单的例子来说明:
function Animal(name, age) { // 构造函数 this.name = name; this.age = age; this.showName = function () { console.log('in Animal:' + this.name); } } Animal.prototype.showAge = function() { console.log('in Animal:'+ this.age); } function Cat(name, age) { // 构造函数 Animal.call(this, name, age); // 继承1 } Cat.prototype = Object.create(Animal.prototype); // 继承2 Cat.prototype.constructor = Cat; // 继承3 var cat = new Cat('Black Cat', 2); cat.showName(); cat.showAge(); console.log(cat.constructor); var animal = new Animal('animal', '15'); animal.showAge();
上面的代码放到一个html页面中的<script></script>标签内,在控制台输出:
in Animal:Black Cat
in Animal:2
Cat(name, age) {
Animal.call(this, name, age);
}
in Animal:15
这里解释一下这三步操作。
继承1:
调用了js的call方法,call([thisObj[,arg1[, arg2[, [,.argN]]]]]),用法是父类.call(this,参数1,参数2,...)。作用是更改子类内部指针this指向父类,这样一来,子类就拥有了父类的所有方法,但只包括父类构造函数function 父类名(){}中的方法,不包含父类.prototype.xxx(){}方法。比如上面例子中:showName 方法被继承。而prototype.showAge 方法并没有,所以需要继承2.
继承2:
继承2则使得prototype.showAge 方法被继承。但由于使用了继承2,Cat类的prototype.constructor也就被改变了,所以需要继承3.
继承3:
还原Cat类的constructor。这个步骤省略了不会有任何不良影响,因为Cat的prototype是利用Object.create创建的,这是对Animal.prototype的一份拷贝。唯一不同的只是Cat的所有实例的constructor都指向了Animal而已,而对象实例化的时候,无论是Cat的构造函数还是Animal的构造函数,都会得到执行。