重重的壳裹着轻轻的仰望

I smile when I'm angry. I cheat and I lie. I do what I have to do ··· To get by.

导航

与其他高级语言不同,javascript的类和对象比较特殊,这里将详细阐述。

1.javascript没有真正的类。

2.因为不是强类型语言,所以javascript不支持早期绑定。

3.js中,所有的对象并非同等创建的,一般分为三类:

(1)本地对象:定义为“独立于宿主环境的js实现提供的对象”。包括Object,Function,Array,String,Boolean,Number,Date,RegExp,Error,EvalError,RangeError,ReferrenceError,SyntaxError,TypeError,URIError.
(详细介绍见另一篇文章(javascript常用本地对象的使用))

(2) 内置对象:定义为“独立于宿主环境的js实现提供的对象,在程序开始执行时出现”。从定义可以看出,每个内置对象都是本地对象。内置对象有两个:Global,Math.

(3) 宿主对象:定义为:“有js实现的宿主环境所提供的对象”。所有的DOM和BOM对象都是宿主对象。

4.作用域。

对js讲对象的作用域几乎毫无意义,因为js只存在一种作用域,公用作用域。因此,定义自己的类或对象时,必须格外小心,因为默认它们都是公用的。

5.this关键字

this总是指向调用该方法的对象。
var oCar = new Object;
oCar.color = "red";
oCar.showColor = function (){
 alert(this.color);   //outputs "red",this指向oCar
}

6.定义类:
(1).工厂方式
function createCar(sColor,iDoors,iMpg){
 var oCar = new Object;
 oCar.color = sColor;
 oCar.doors = iDoors;
 oCar.mpg = iMpg;
 oCar.showcolor = function(){
  alert(this.color);
 }
 
 return oCar;

}

var oCar1 = CreateCar("red",4,23);
var oCar2 = CreateCar("blue",2,20);
oCar1.showColor();//ouputs "red"
oCar2.showColor();//outputs "blue"

这种工厂方式的缺点是:每次调用craeteCar,都要创建新函数showcolor(),每一个对象都有自己的showcolor版本

(2).构造函数方式
function createCar(sColor,iDoors,iMpg){
 var oCar = new Object;
 this.color = sColor;
 this.doors = iDoors;
 this.mpg = iMpg;
 this.showcolor = function(){
  alert(this.color);
 }
}
var oCar1 = new createCar("red",4,23);
var oCar2 = new createCar("blue",2,20);

同工厂方法一样,构造函数方式同样会重复生成函数,为每个对象创建独立的函数版本

(3).原型方式
function Car(){
 Car.prototype.color = "red";
 Car.prototype.doors = 4;
 Car.prototype.mpg = 23;
 Car.prototype.showcolor = function(){
  alert(this.color) 
 }
}
var oCar1 = new Car();
var oCar2 = new Car();

该方法利用了对象的prototype属性,用空的构造函数来设置类名,然后所有的属性和方法都被直接赋予prototype属性。

问题:1.构造函数没有参数,使用原型方式时,不能通过给构造函数传递参数初始化属性;2.也是最致命的问题,当属性指向的是对象
,而不是函数时,对象是被多个实例共享的(函数共享不会造成任何问题):
function Car(){
 Car.prototype.color = "red";
 Car.prototype.doors = 4;
 Car.prototype.mpg = 23;
 Car.prototype.dirvers = new Array("Mike","Sue");
 Car.prototype.showcolor = function(){
  alert(this.showcolor);
 }
}
var oCar1 = new Car();
var oCar2 = new Car();

oCar1.dirvers.push("Matt");

alert(oCar1.dirvers)://outputs "Mike,Sue,Matt"
alert(oCar2.dirvers)://outputs "Mike,Sue,Matt"

改变oCar1.dirvers,同时也改变了oCar2.dirvers !!!

(4).混合的构造函数/原型方式
这种方式汲取了构造函数和原型方式的优点:
function Car(sColor,iDoors,iMpg){
 this.color = sColor;
 this.doors = iDoors;
 this.mpg = iMpg;
 this.dirvers = new Array("Mike","Sue");
}
Car.prototype.showcolor = function(){
 alert(this.color);
}

var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",2,23);

oCar1.drivers.push("Matt");

alert(oCar1.drivers);//outpust "Mike,Sue,Matt"
alert(oCar2.drivers);//outputs "Mike,Sue"

这种方式,所有的非函数属性都在构造函数里创建,而在原型里创建函数showcolor,避免了内存的浪费。除了视觉上的不习惯,这种解决方式堪称完美。

(5).动态原型方法

上面提到,混合的构造函数/原型方式,给人的视觉上不习惯。封装这一概念体现的很不明确。于是产生了动态原型方法,它与上面方法的
唯一区别是赋予对象方法的位置:
function Car(sColor,iDoors,iMpg){
 this.color = sColor;
 this.doors = iDoors;
 this.mpg = iMpg;
 this.drivers = new Array("Mike","Sue");
 if(typeof Car._initialized =="undefined"){
  Car.prototype.showcolor = function(){
   alert(this.color);
  }
 }
 car._initialized = true;

}

这样封装,传统的OOP开发者会高兴地发现,这样看起来舒服多了。

(6).混合工厂方式
function Car(){
 var oCar = new Object;
 oCar.color ="red";
 oCar.doors = 4;
 oCar.mpg =23;
 oCar.showcolor = function (){
  alert(this.color);
 }
 return oCar;
}

var car = new Car();
与工厂方式不同,仅仅是生成对象的方式,使用了new。其实因为构造函数内部调用了new,这个new将被忽略。

这种方式与经典工厂方式存在相同的问题。极不提倡使用这种方式。