代码改变世界

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

2012-11-08 09:25  Justany_WhiteSnow  阅读(1746)  评论(2编辑  收藏  举报

 

Javascript继承(下)——干嘛要继承

 

Quiz1

 

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继承机制的设计思想 . 阮一峰 . 2011年6月5日

 

补充阅读

Javascript的声明

Javascript引用 

Javascript中this关键字详解