在JS中创建对象往往使用new xxx()的方法,其中xxx被称为构造函数,实际过程是由new操作符创建一个空对象,然后由后面的xxx方法对该对象进行初始化。在xxx方法中,可以使用this关键字引用到。通过定义构造方法,就定义了一个类。在这种语境下,构造方法的命名通常不同于一般的方法命名(动宾)而用类命名的方式。构造函数通常没有返回值,如果有返回值,返回值将会代替之前用new生成的对象。
?
如果构造函数返回元数据,对前面初始化的对象没有影响,被赋值的变量还是可以引用到新生成的对象。只有在返回对象时,才会代替返回对象。
?
function Shape(){ this.x = 100; this.y = 100; return new String("this is not the object you are expecting"); } function Shape1(){ this.x = 100; this.y = 100; return 3; } function test(){ var temp = new Shape(); alert(temp.x);//return undefined. var temp1 = new Shape1(); alert(temp1.x);//return 100 }
?
当函数被当作方法使用时,函数内的this关键字引用的是作为方法所有者的对象。
?
?
function Rectangle(w, h){ this.width = w; this.height = h; this.area = function(){ return this.width * this.height; } }
?
?使用普通属性作为对象方法的效率是很低的。
?
每一个JS对象都包括一个内部引用指向另一个对象,成为prototype对象。
如果一个对象是某个对象的PROTOTYPE,那么所有这个对象的属性都将会被把它作为prototype的对象继承
?
被构造方法初始化的对象的prototype就是构造方法的prototype对象
?
初始的prototype对象只有一个属性--constructor,指回这个prototype关联的构造器方法
任何prototype对象的属性将被作为该构造器生成的对象的属性(这就是为什么所有对象都有一个constructor属性的原因)
?
prototype的这种特性使得它成为设置方法,和共有常数的理想位置
?
另外一个用途是,可以通过prototype生成一个子类:
?
function heir(p){ function f(){}; f.prototype = p; return new f(); }?
这种继承关系是在查找一个属性时自动发生的,这些被继承的属性并不是在创建新对象时复制到新对象中的。这种设计节约了很多内存空间,另一个特性是,即使在一个继承对象创建之后,对原prototype对象新增的方法见依然可以在被创建对象中得到体现。
?
继承的属性和普通属性一样,都可以用for/in语句遍历到,只有通过hasOwnProperty()方法才能够识别是不是prototype的属性。
?
?
function Rectangle(w,h){ this.width = w; this.height = h; } Rectangle.prototype.area = function(){return this.width*this.height;}; .... var temp = new Rectangle(100,100); alert(temp.hasOwnProperty("area"));//false; alert("area" in temp);//true;?
当读取某个对象的某个属性时,JS先检查该对象是否有该属性,再检查该对象的prototype对象是否有该属性。
当写入某个对象的某个属性时,JS将不使用prototype属性。
这就是说,继承只有在读取对象属性时才发生
如果一个对象o的Prototype有一个属性k,那么o.k =4;将会先在o中寻找是否有一个属性叫k,如果没有就创建一个,并不会到prototype中去寻找。
?
一般的built-in对象比如String,Date,都可以修改其prototype,但是有些对象,比如浏览器相关的对象,就不具备这种能力。
?
?
修改built-in对象的一大作用就是,对某些浏览器没有实现的方法和功能,可以通过修改prototype对象来自己实现。
?
在JS中模拟类
每一个在constructor中创建并初始化的属性都是instance property.
创建一个instance method,就是通过设置constructor的prototype实现的。
和JAVA重要的不同是,在JAVA类中,this关键字是可以隐藏的,而JS中,必须显式的使用this关键字
定义一个属于constructor的属性来模拟class property.
function Shape(){ this.x = 100; this.y = 100; } Shape.UNIT = 200; .... var temp = new Shape(); alert(temp.UNIT);//returns undefined. alert(Shape.UNIT);//returns 200;
?同样也可以定义一个属于constructor的方法来模拟class method.
?
?
以下是完整的定义了一个类Circle
function Circle(radius){ this.r= radius;//instance property; } Circle.PI = 3.14;//class property; Circle.prototype.area = function() { return Circle.PI * this.r * this.r;} //instance method; //class method Circle.max = function(a,b){ if ( a.r > b.r ) return a; else return b; }?
private member
要实现封装,就需要用到闭包,但要这样做,访问方法只能存在每个对象实例中,不能从Prototype对象继承
function ImmutableRectangle(w,h){ this.getWidth = function() {return w;} this.getHeight = function() {return h;} } ImmutableRectangle.prototype.area = function(){ return this.getWidth() * this.getHeight(); };?
通用对象方法:
- toString()
Circle.prototype.toString = function(){.....} - valueOf()
在需要将该对象转换成元数据类型时调用。 - 比较方法(== < >。。。)
JS中的比较符比较的是引用而非内容,所以有必要实现自己的equals()方法。如果试图使用<.>这种符号,js将试图调用该对象的valueOf()方法,将对象转换成元对象再比较。
?
父类和子类:
JS中Object是所有类的父类
对一个对象属性的搜索路径是,先搜索该对象本身,再搜索该对象构造器的prototype,再搜索object的prototype。
?
继承Rectangle类:
- 定义一个子类构造器PositionedRectangle
function PositionedRectangle(w,h,x,y){ Rectangle.call(this,w,h);//调用父类构造器 this.x = x; this.y = y; }
? - 继承父类prototype
function heir(p){ function f(){}' f.prototype = p; return new f(); } PositionedRectangle.prototype = heir(Rectangle.prototype);
?
调用父类被覆盖的方法:
Rectangle.prototype.toString.call(this);
之所以用call,是因为无法确定toString指向的对象。
?
?
JS扩展的另一种方式(不使用继承)
直接把属性和方法拷贝到新的类
可以直接通过拷贝/borrow的方式实现多重继承:
function Colored(c){ this.color = c;} Colored.prototype.getColor = function(){ return this.color;} function ColoredRectangle(x,y,w,h,c){ Rectangle.call(this,x,y,w,h); Colored.call(this,c); } ColoredRectangle.prototype = heir(Rectangle.prototype); ColoredRectangle.prototype.constructor = ColoredRectangle;
borrowMethods(Colored, ColoredRectangle);
?注意这里prototype.constructor需要重新设置,否则将是父类的构造器.
?
?
?
typeof null是object
typeof undefined是undefined.
typeof function是function
用instanceof来判断到底是哪种对象
?
如果需要测试某个对象属于具体哪个类,可以使用if( d.constructor == xxxx)
?
对于built-in对象,toString()方法可以反映对象的类型信息
?
DUCK Typing
if it walks like a duck and quacks like a duck, it's a duck!
如果一个对象拥有一个类的所有方法/属性,那么就说它是那个类的一个实例
?
?
?
?
?
?
?
?
?
?
?
?