Javascript继承(上)——对象构建介绍

  Javascript中存在“类”么?

  万物皆对象

  Javascript中除了基本数据(Undefined、Null、Boolean、Number、String),其他都是对象(Object)。

  实际上,Javascript中的对象是数据与功能的集合。例如我们知道:

  

复制代码 代码如下:

  var foo = new Function("alert('hello world!')");

  foo();

  可见foo是一个函数,也是一种对象。再比如说:

  

复制代码 代码如下:

  function foo(){

  //do something

  }

  foo.data = 123;

  foo["data2"] = "hello";

  alert(foo.data);

  alert(foo.data2);

  函数也可以像对象一样添加属性。

  对象的构建

  一般我们用构造函数来构建对象,但如果没有构造函数,我们也有办法构建我们想要的对象:

  

复制代码 代码如下:

  function creatPerson(__name, __sex, __age){

  return {

  name: __name,

  sex: __sex,

  age: __age,

  get: function(__key){

  alert(this[__key]);

  }

  };

  }

  var Bob = creatPerson("Bob", "male", 18);

  Bob.get("name"); //Bob

  Bob.get("sex"); //male

  Bob.get("age"); //18

  但是这不够,我希望方法是可以共享的。比如我再用该函数创建一个Tom对象,get函数就又被创建了一次,这明显地浪费了我的内存。

  导入共享资源

  因为我们知道函数也是对象,所以我们可以把需要共享的方法或属性放在放在他“身上”:

  

复制代码 代码如下:

  function creatPerson(__name, __sex, __age){

  var common = arguments.callee.common;

  return {

  //自身的属性

  name: __name,

  sex: __sex,

  age: __age,

  //自身的方法

  sayhi: function(){alert("hi");},

  //共享的方法

  get: common.get,

  getType: common.getType,

  //共享的属性

  type: common.type

  };

  }

  creatPerson.common = {

  get:function(__key){

  alert(this[__key]);

  },

  getType: function(){

  alert(this.type);

  },

  type: "Person"

  };

  var Bob = creatPerson("Bob", "male", 18);

  Bob.get("name"); //Bob

  Bob.get("sex"); //male

  Bob.getType(); //Person

  于是我们就用蹩脚的方法,成功的创建了一个拥有自有属性方法和共享属性方法的对象。但实际上,Javascript就是这么蹩脚地创建对象的。

  其实共享属性没有真正实现,因为这个共享属性,依然只是一个副本。这并不是我们真正希望的共享属性。

  new关键字

  和上面的“对象的构建”相同,new的目的是创建对象的自有属性和方法。例如:

  

复制代码 代码如下:

  function Person(__name, __sex, __age){

  this.name = __name;

  this.sex = __sex;

  this.age = __age;

  this.get = function(__key){

  alert(this[__key]);

  };

  }

  var Bob = new Person("Bob", "male", 18);

  Bob.get("name"); //Bob

  Bob.get("sex"); //male

  Bob.get("age"); //18

  原型(Prototype)

  Javascript的作者用了和上面“导入共享资源”的方法差不多。既然函数也是对象,那么把需要共享的“东东”放在他“身上”吧:

  

复制代码 代码如下:

  function Person(__name, __sex, __age){

  this.name = __name;

  this.sex = __sex;

  this.age = __age;

  this.sayhi = function(__key){

  alert("hi");

  };

  }

  Person.prototype = {

  constructor: Person,

  get: function(__key){

  alert(this[__key]);

  }

  };

  var Bob = new Person("Bob", "male", 18);

  Bob.get("name"); //Bob

  Bob.get("sex"); //male

  alert(Bob.constructor); //function Person

  Javascript创建对象的模型是简洁的,new来处理自身问题,prototype来处理共享问题。

  如果说Java的对象(实例)产生方式是将原材料丢到模子里(类)熔炼而成;那么Javascript的对象产生方式就是给材料给建筑工(构造函数)让他按图纸搭建而成。

  实际流程

  当然实际流程并不是这样的,新建一个对象先做的是处理共享资源,例如:

  

复制代码 代码如下:

  function A(){

  console.dir(this);

  alert(this.type); //A

  }

  A.prototype.type = "A";

  var a = new A();

  通过console.dir将a打印出来我们可以看到:

  

type "A"
__proto__ A {type = "A"}
  type "A"
  constructor A()

  构造函数新建一个对象以后,立刻将其prototype的引用赋给新建对象的内部属性__proto__,然后再运行构造函数里面的构造语句。

  并没有覆盖

  

复制代码 代码如下:

  function A(){

  this.type = "B"

  }

  A.prototype.type = "A";

  var a = new A();

  alert(a.type); //B

  当我们想得到a.type时,引擎会先去在a对象中查看是否有属性type,如果有则返回该属性,没有则试图在__proto__中查找是否有type属性,如果有则返回该属性。

  __proto__并不是标准的,比如IE上没有,但IE上也有类似的内部属性,但我们也无法使用它。

  基于这个原因,我们删掉a.type时依然可以返回a.type:

  

复制代码 代码如下:

  function A(){

  this.type = "B"

  }

  A.prototype.type = "A";

  var a = new A();

  alert(a.type); //B

  delete a.type;

  alert(a.type); //A

  到底有没有类?

  严格地讲,Javascript并没有类(class)这种东西。

  但有时候我们会用构造函数的名字作为利用该构造函数创建的对象们的“类型(type not class)名”,以方便我们用Javascript进行面向对象编程时的交流。

  名字只是一个代号,一个方便理解的工具罢了。

  参考文献

  Javascript继承机制的设计思想