傳統的基於class的面嚮對象語言如Java中,都有兩個基本概念:編程
Student xiaoming = new Student()
而JS不區分類和實例的概念,它經過原型(prototype)實現面向對象。JS建立對象是用原型,實現繼承也是用原型。函數
建立對象:this
var Student = {name: 'abc', height: 1.7}; var xiaoming = {name: 'xiaoming'}; xiaoming._proto_ = Student;
JS對每一個建立的對象都會設置一個原型,指向它的原型對象。
當使用obj.***
訪問一個對象的屬性時,JS如今當前對象上查找該屬性;若是沒找到,就到其原型對象上找;若是還沒找到,就一直上溯到Object.prototype
這個原型對象;最後,若是還沒找到,就返回undefined
。這個過程能夠表示爲一個原型鏈。spa
// 構造函數對象 function Student(name) { this.name = name; //這裏設置了每一個對象的屬性 } // 原型對象 Student.prototype.hello = function() { alert('Hello, ' + this.name); //這裏設置了全部對象共享的hello函數,經過繼承得到 } // 實例對象 var xiaoming = new Student('小明'); var xiaohong = new Student('小紅');
原型鏈以下(圖中紅色箭頭是原型鏈):prototype
xiaoming \
xiaohong -- Student.prototype ----> Object.prototype ----> nullcode
補充:
見犀牛書對象
Java中,繼承的本質是:擴展一個已有的Class,生成一個新的Subclass。因爲Java嚴格區分類和實例,繼承其實是類型的擴展。blog
而JS沒法直接擴展一個Class,由於不存在Class這種類型,JS採用的是原型繼承。繼承
考慮基於Student
擴展出PrimaryStudent
,原型鏈必須修改成這樣:ip
new PrimaryStudent() ----> PrimaryStudent.prototype ----> Student.prototype ----> Object.prototype ----> null
實現方法:
// PrimaryStudent的構造函數 function PrimaryStudent(props) { Student.call(this, props); this.grade = props.grade || 1; } // 引入中間對象:空函數F function F() {} F.prototype = Student.prototype; // 修改兩個屬性,以實現上述原型鏈 PrimaryStudent.prototype = new F(); PrimaryStudent.prototype.constructor = PrimaryStudent; // 在PrimaryStudent的原型對象上定義方法 PrimaryStudent.prototype.getGrade = function() { return this.grade; } // 建立子類對象 var xiaoming = new PrimaryStudent({name: '小明', grade: 60}); // 驗證原型 xiaoming.__proto__ === PrimaryStudent.prototype; //true xiaoming.__proto__.__proto__ === Student.prototype; //true
原型鏈圖示: