javascript 权威指南(09)
9.3.5. js通过相关的prototype混合编程进行类的支持
function Circle(radius) { this.r = radius;//共有变量 this.getR=function(){return radius;}//私有变量的相关实现,是通过闭包实现的。 //私有函数是通过嵌套函数实现的,只能在函数体内通过this的方法定义,进行调用 } Circle.PI = 3.14159;//类共有静态的属性 Circle.max = function(a,b) { if (a.r > b.r) return a; else return b;};//类共有静态的方法 Circle.prototype.area = function( ) { return Circle.PI * this.r * this.r; }//每个实例共有的方法,这个比类函数中定义this方法减少该句的执行次数。
9.5. 类继承的相关代码,这相关的代码可见
该实现和一般的继承存在差异,父类对于子类的同名属性其实是不存在的,或者相关的值是undefine,因为原型链继承的时候是通过一个空实例的。
function Rectangle(w, h) { this.width = w; this.height = h; } Rectangle.prototype.area = function( ) { return this.width * this.height; } function PositionedRectangle(x, y, w, h) { Rectangle.call(this, w, h);//这个只是方法的调用,只是Rectangle函数里面涉及this的属性进行赋值 //相关的prototype创建操作其实是要通过new操作符实现的,new 是先执行函数,在对函数的prototype属性,对该实例的相关的原型链进行创建 this.x = x; this.y = y; } PositionedRectangle.prototype = new Rectangle( );//原型属性也是一个实例,继承则是使他成为父类的一个实例 //上句中PositionedRectangle.prototype为一个Rectangle对象,所以PositionedRectangle.prototype中的属性是多余的,我们一般是继承方法 delete PositionedRectangle.prototype.width; delete PositionedRectangle.prototype.height; //constructor属性指向的是创建函数,根据原型链现在指向额是Rectangle,所以需要重新定位 PositionedRectangle.prototype.constructor = PositionedRectangle; PositionedRectangle.prototype.contains = function(x,y) { return (x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height); }
个人总结,可能有误:
m.1. new操作符的作用,就是创建对象,没有new的是返回的是函数的返回值
function Circle(radius) { this.r = radius; } var a= Circle(12);//a访问不到area属性,a只是Circle函数的返回值,只是一个undefined; var b = new Circle(12);//b可访问area属性
m.2. new操作符的执行顺序 new 是先进行原型链的组成,再执行函数
function class1(){}; function class2(){}; function class3() { class3.prototype=new class2(); }; class3.prototype=new class1(); var obj=new class3(); alert(obj instanceof class3);//false alert(obj instanceof class2);//false alert(obj instanceof class1);//true var obj2=new class3(); alert(obj2 instanceof class3);//false alert(obj2 instanceof class2);//true alert(obj2 instanceof class1);//false var obj3=new class3(); alert(obj3 instanceof class3);//true alert(obj3 instanceof class2);//true alert(obj3 instanceof class1);//false
m.3. 原型链的相关的概念
原型链的建立其实是在对象创建的时候就建立的,在创建对象以后,修改原型链的方向,原来的对象是不受影响的,下面是引用博文
在javascript里,每个function都有一个prototype属性,这个属性的用途是实现继承机制。必如下面定义的function class1:
function class1(){} class1.prototype = {a:10,b:100};则class1的每个实例都会从prototype继承a和b这两个属性。
同时,每个对象都会有一个内部的属性_proto_(不同的javascript虚拟机实现用的名字可能不同),这个属性对js开发人员不可见,只在虚拟机内部使用。
每当创建一个对象的时候,这个对象的_proto_就会被赋值为这
个对象的构造函数的 prototype,这样对象的_proto_属性和构造函数的prototype引用相同的对象,并且一旦对象创建完成,_proto_属性就不会改变。
这样通过对象的_proto_属性,以及_proto_所引用的对象的_proto_属性,就构成了一个_proto_链。 当访问一个对象的属性和方法的时候,js虚拟机正是通过这个_proto_链来查找的。
关于instanceof:
假设有一条这样的语句:o instanceof c;
在上面的语句执行过程中,虚拟机会把c.prototype和o的_proto_链上的节点逐个进行比较,如果找到相等的节点,则返回true,否则返回 false。
function class1(){}; function class2(){}; class2.prototype=new class1(); function class3(){}; class3.prototype=new class2(); function class4(){}; var obj=new class3(); alert(obj instanceof class3);//true alert(obj instanceof class2);//true alert(obj instanceof class1);//true 但是有想过解释器是如何判断一个对象是否是一个类的实例吗?网上大多是说通过原型链来判断。上面可能看到有一个类class4没被用到过,那在后面添上这句 class2.prototype=new class4(); alert(obj instanceof class3);//true; alert(obj instanceof class2);//false;_proto_属性已经存在了,所以class2非原来的class2了 alert(obj instanceof class1);//true;
m.4. 一直有这个概念,原型链的查找,最后是有一个null值结束的。
原来我一直以为是Object.prototype.constructor.prototype指向了null,这是错的,Object.prototype.constructor是一个Prototype函数,它的prototype也是一个Object的实例,
根据Object.prototype.constructor.prototype===Object.prototype,我现在可以理解new操作的时候通过相应的判断,把最后的_proto_属性设置成了null
m.5.上文提到的一个在继承中实现的和其他语言的不同 (失败)
该实现和一般的继承存在差异,父类对于子类的同名属性其实是不存在的,或者相关的值是undefine,因为原型链继承的时候是通过一个空实例的。
function Rectangle(w, h) { this.width = w; this.height = h; } Rectangle.prototype.area = function( ) { return this.width * this.height; } PositionedRectangle.super=Rectangle; function PositionedRectangle(x, y, w, h) { this.x = x; this.y = y; PositionedRectangle.prototype= new PositionedRectangle.super(w,h);//拥有滞后性,因为先进行有原型链,在执行函数的,而且违背了原型链存在的初衷,方法的共享 PositionedRectangle.prototype.constructor = PositionedRectangle; } PositionedRectangle.prototype.contains = function(x,y) { return (x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height); }