JavaScript是prototype-based的语言,而标准的面向对象语言大多数是class-based的
然而其实对于面向对象来说,prototype-based的思想和class-based的思想一样是完备的
事实上prototype-based的思想是人类更直接地描绘自然世界的方法,它直接利用相似性来“认知世界”
这和人类的思维模式是非常的接近的
新生的儿童是通过相似类比(prototype)来学习和巩固接触到的新知识的,而只有在更高级别上才会对知识进行整理和归类(class)
所以说对prototype-based来说:
A.prototype = new B(); 的现实语言就是“A很像B”,或者“像B那样对待A就行了”
Tiger.prototype = new Cat(); //照猫画虎
对class-based来说,就不一样:
A extends B; 的现实语言是“A是B的一种”
abstract Felidae extends Animal //猫科动物是一种动物
Tiger extends Felidae //老虎是一种猫科动物
Cat extends Felidae //猫是一种猫科动物
区别就在上面,对class-based来说,猫和老虎的关系是(必须)通过抽象的“猫科动物”来建立联系的,猫和老虎重用的是猫科动物的通用行为
而对于prototype-based来说,因为猫本身像老虎,所以这个相似本身就能够让猫建立对老虎的行为重用的可能,至于哪些行为能够重用,交由使用者去处理。
我们认知世界也是同样,既有非常严谨的对世界的归类,也有比较宽松的“相似性”描述,而后者,可能出现得更加频繁。
人脑的“联想”通常是偏prototype-based的,而逻辑思维同时具有class-based(分析)、prototype-based(推理)两种特质。
本质上说,编程是一种把现实世界的模型抽象化后再利用计算机具现化的行为,所以无论是prototype-based还是class-based,都是思维抽象化的手段,在有prototype的情况下没必要为了继承而继承……
月影 前端技术 class, javascript, oop, prototype
范式:new C <=> TC = function(){}, TC.prototype = C.prototype, o= new TC, C.apply(o, arguments);
用文字和伪代码解释就是
与构造器C构造过程等价的函数调用序列为
1) 建立一个空的function模板TC var TC = function(){}
2) 设这个模板TC的原型设为构造器C的原型 TC.prototype = C.prototype
3) 无参数构造TC的对象o var o = new TC();
4) 以o为this执行C的构造器 C.apply(o, arguments);
5) 得到的o和直接构造C的过程完全等价 o <=> new C;
这个范式有非常大的作用
第一,用作继承时延迟基类构造函数的调用
- Function.prototype.$extends = function(p){
- var me = this;
- var T = function(){
- this.$super = p;
- me.apply(this, arguments);
- this.$super = null;
- };
-
- var fn = function(){};
- fn.prototype = p.prototype;
- T.prototype = new fn();
- T.constructor = me;
-
- return T;
- };
- function Vector(){
- this.axis = Array.prototype.slice.call(arguments,0);
- };
- Vector.prototype.dimension = function(){
- return this.axis.length;
- };
- Vector.prototype.length = function(){
- var len = this.axis.length;
- var ret = 0;
- for(var i = 0; i < len; i++){
- ret += this.axis[i] * this.axis[i];
- }
- return Math.sqrt(ret);
- };
- Vector.prototype.toString = function(){
- return "[" + this.axis + "]";
- };
-
- var Vector2D = function(x,y){
- this.x = x;
- this.y = y;
- this.$super(x,y);
- }.$extends(Vector);
- Vector2D.prototype.m = function(vector){
- return this.x * vector.y - vector.x * this.y;
- };
-
- var Vector3D = function(x,y,z){
- this.x = x;
- this.y = y;
- this.z = z;
- this.$super(x,y,z);
- }.$extends(Vector);
-
- var v1 = new Vector2D(1,2);
- alert([v1,v1.dimension()]);
- alert(v1.m(new Vector2D(3,4)));
-
- var v2 = new Vector3D(1,2,3);
- alert([v2,v2.dimension()]);
- alert(v2.length());
第二,实现构造器和函数调用的统一,让对象构造支持apply和call
- Function.prototype.createInstance = function(){
- var T = function(){};
- T.prototype = this.prototype;
- var o = new T();
- this.apply(o, arguments);
- return o;
- }
-
- function Foo(x,y,z){
- this.x = x;
- this.y = y;
- this.z = z;
- };
-
- var o = Foo.createInstance();
- alert(o);
- alert(o.constructor);
- alert(o instanceof Foo); //连instanceof都完全正确
-
- function test(){
- return Foo.createInstance.apply(Foo, arguments); //轻松使用apply
- }
-
- var o2 = test(1,2,3);
- alert([o2.x,o2.y,o2.z]);
月影 前端技术 javascript, oop, 继承
Recent Comments