1. 程式人生 > >JavaScript之原型和繼承

JavaScript之原型和繼承

1、實現示例:

function Person(name, sex) {
    this.name = name;
    this.sex = sex;
}

Person.prototype = {
    name:'無名氏',
    sex:'未知',
    nation:'火星',
    getName: function() {
        return this.name;
    },
    getSex: function() {
        return this.sex;
    },
    getNation: function() {
        return this.nation;
    }
}

var people = new Person("Tom", "man");
alert(people.getName());    //使用構造物件時的name值
alert(people.getNation());  //使用原型中的nation值

       我們把函式Person(也就是建立自定義物件的函式)稱為建構函式,Person.prototype稱之為Person的原型,可以看出JavaScript通過建構函式和原型的方式模擬實現了類的功能。prototype本質上是一個JavaScript物件,並且每個函式都有一個預設的prototype屬性。prototype原型中的屬性可以被原型所屬的類的自定義物件引用。

       如果將People理解為父類,要定義一個子類Employee繼承父類原型中的屬性。那麼:

function Employee(employeeID,name,sex){
    this.employeeID = employeeID;
    this.name = name;
    this.sex = sex;
}

Employee.prototype = new Person();   //將Employee的原型指向父類的物件
Employee.prototype.getEmployeeID = function() {
    return this.employeeID;
};

//此時Employee的物件就可以呼叫Person中的方法
var boss = new Employee("001", "Jim", "man");
alert(boss.getEmployeeID());   //使用構造物件時的employeeID值
alert(boss.getName());   //使用構造物件時的name值
alert(boss.getNation());   //使用原型中的nation值

2、變數this:表示當前物件。如果在全域性作用域內使用this,則返回當前頁面物件window。如果在函式(方法)中使用this,則返回呼叫該函式的物件。可以使用call或apply重新指定this所代表的物件。

        ①在全域性作用域內:

<script type="text/javascript">
    alert(this === window);   // true
</script>

        ②在函式內:

var fruit = "apple";   //定義一個全域性變數,等價於window.fruit = "apple";
function test() {
    alert(this.fruit);
}
test();  //apple

        ③在方法內:

var obj = {
    fruit: "orange",
    test: function(){alert(this.fruit);}
};
obj.test(); // "orange"

3、物件的constructor屬性:始終指向建立該物件的建構函式。

var a = new Array(1, 56, 34, 12);
alert(a.constructor===Array);  //true
var b = [1, 56, 34, 12];
alert(b.constructor===Array);  //true
var c = new Function();
alert(c.constructor===Function);  //true
var d = function(){};
alert(d.constructor===Function);  //true

var Foo = function(){};
var obj = new Foo();   
alert(obj.constructor.constructor === Function); //true

function Person(name) {
    this.name = name;
}
var p = new Person("Tom");
alert(p.constructor===Person);  //true

       如果修改Person的prototype,Person建立的物件的constructor依然為Person

function Person(name) {
    this.name = name;
}
//修改Person的原型,而不是全部覆蓋其原型
Person.prototype.getName = function() {
    return this.name;
};
var p = new Person("Tom");
alert(p.constructor===Person);  //true

       但如果覆蓋掉Person的prototype,Person建立的物件的constructor則變為Object

function Person(name) {
    this.name = name;
}
//覆蓋Person的原型
Person.prototype = {
    getName: function(){
        return this.name;
    }
};  
var p = new Person("Tom");
alert(p.constructor===Person);  //false
alert(p.constructor===Object);  //true

       這是因為覆蓋Person的prototype時實際做的操作是:

Person.prototype = new Object({
    getName: function(){
        return this.name;
    }
});

       所以物件的constructor指向的是Object而非Person,可以用以下方法修正這個錯誤:

Person.prototype.constructor=Person;

       特殊地:建構函式的原型的constructor也始終指向建構函式本身。

alert(String.prototype.constructor===String);   //true
alert(Array.prototype.constructor===Array);   //true
alert(Date.prototype.constructor===Date);   //true
alert(Number.prototype.constructor===Number);   //true
alert(Object.prototype.constructor===Object);   //true

function Person(name) {
    this.name = name;
}
alert(Person.prototype.constructor==Person);  //true

參考:Douglas Crockford《JavaScript語言精粹》

           http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html