当前位置: 代码迷 >> 综合 >> 犀牛书笔记:(11)Classes, Constructors and Prototypes
  详细解决方案

犀牛书笔记:(11)Classes, Constructors and Prototypes

热度:36   发布时间:2023-12-06 16:43:49.0

在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();
};
 

通用对象方法:

  1. toString()
    Circle.prototype.toString = function(){.....}
  2. valueOf()
    在需要将该对象转换成元数据类型时调用。
  3. 比较方法(== < >。。。)
    JS中的比较符比较的是引用而非内容,所以有必要实现自己的equals()方法。如果试图使用<.>这种符号,js将试图调用该对象的valueOf()方法,将对象转换成元对象再比较。

 

父类和子类:

JS中Object是所有类的父类

对一个对象属性的搜索路径是,先搜索该对象本身,再搜索该对象构造器的prototype,再搜索object的prototype

 

继承Rectangle类:

  1. 定义一个子类构造器PositionedRectangle
    function PositionedRectangle(w,h,x,y){Rectangle.call(this,w,h);//调用父类构造器this.x = x;this.y = y;
    }
     
  2. 继承父类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!

如果一个对象拥有一个类的所有方法/属性,那么就说它是那个类的一个实例

 

 

 

 

 

 

 

 

 

 

 

 

  相关解决方案