javascript 的继承(一)

  21 May 2017


回顾历史

祖师爷Brendan Eich(布兰登.艾奇)发明js时,由于是一门脚本语言所以并没有引入(class)类的概念,但是由于js里都是对象(object),必须要一种机制将这些object关联起来。所以最后还是设计了继承的机制。 他考虑到,C++和Java语言都使用new命令,生成实例。C++的写法是:

ClassName *object = new ClassName(param);

Java的写法是:

Foo foo = new Foo();

因此,他就把new命令引入了Javascript,用来从原型对象生成一个实例对象。但是,Javascript没有”类”,怎么来表示原型对象呢? 这时,他想到C++和Java使用new命令时,都会调用”类”的构造函数(constructor)。他就做了一个简化的设计,在Javascript语言中,new命令后面跟的不是类,而是构造函数。 举例来说,现在有一个叫做DOG的构造函数,表示狗对象的原型。

function DOG(name){
        this.name = name;
}

对这个构造函数使用new,就会生成一个狗对象的实例。

var dogA = new DOG('大毛');
alert(dogA.name); // 大毛

注意构造函数中的this关键字,它就代表了新创建的实例对象。

new 运算符的缺点

用构造函数生成实例有个缺点,那就是无法共享属性和方法,例如:在构造函数DOG中设置一个共有属性type

function DOG(name){
   this.name=name;
   this.type="狗";
}

然后生成两个对象:

var dog1=new DOG("小黑");
var dog2=new DOG("小白");

这两个对象的type属性是独立的,修改其中一个不会影响另一个。

dog1.type="猫";
console.log(dog2.type);//狗

每个实例对象都有各自独立的属性和方法,这不仅无法做到数据共享,每次实例化对象时都重新写入共有属性,也是资源的浪费。


prototype的引入

考虑到上面的情况,祖师爷为每个构造函数引入了prototype属性。 这个属性包含一个prototype对象,所有实例化对象需要共享的属性和方法都放在这个里面。 不需要共享的全部放到构造函数里面。实例对象一旦创建,将会自动引用prototype里的属性和方法。实例化对象属性和方法分成本地的和引用prototype的。 以DOG构造函数为例子:

function DOG(name){
this.name=name;
}
DOG.prototype.type="狗";
var dog1=new DOG("小黑");
var dog2=new DOG("小白");
dog1.type="猫";
console.log(dog2.type);//猫

type属性放在prototype对象里,是共享属性,改变了一个所有的都受影响。 由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像”继承”了prototype对象一样。

21 May 2017