首先,你應該知道javascript是一門面向對象語言。javascript
是對象,就具備繼承性。java
繼承性,就是子類自動共享父類的數據結構和方法機制。git
而prototype 和 __proto__ 的存在就是爲了創建這種子類與父類間的聯繫。github
咱們將prototype稱做原型,將經過__proto__來創建起來的對象與對象的關係稱做原型鏈。數據結構
下面,經過建立一個簡單對象,來探索原型和原型鏈究竟是什麼。ide
首先,建立一個最簡單的對象函數
function Foo(){} var o = new Foo();
ps:這是剛從java轉入JavaScript時,最令我費解的一段代碼,憑什麼一個function就能夠用來建立一個對象。下面就是new 關鍵字的分解動做。。。這個關鍵字究竟作了什麼,能建立一個對象。。this
這個建立的過程,能夠分解成下面代碼spa
function Foo(){} // 建立一個基本對象 var o = new Object(); // 建立對象和父類原型之間的連接 o.__proto__ = Foo.prototype; // 執行構造函數 Foo.call(o);
爲了更好的理解這段代碼,咱們先理解這幾個概念prototype
構造函數就是對象建立時,自動調用的方法
prototype,長這樣
{ constructor: f foo() __proto__: Object }
它是一個對象,存儲着一類事物的基本信息,因此能夠將它稱做類。
__proto__,這個屬性用來創建對象和類之間的關係。
有了這些概念,咱們來分析建立對象的過程當中,究竟作了些什麼.
建立一個對象,會作以下三件事。
new Object()
小結:prototype能夠理解爲類,也就是存儲一類事物的基本信息。__proto__能夠理解爲一條線索,用來創建原型(類)和對象之間的關係。
繼承,須要知足以下三個要求。
咱們該如何實現繼承呢?
// 建立一個構造函數,我認爲 a.prototype就是父類對象。 function a(x,y) { a.prototype.x = x; a.prototype.y = y } // 爲父類對象添加一個method a.prototype.console = function() { console.log(this.x); console.log(this.y); } //建立子類構造函數 function b(x,y) { // 子類顯示的調用父類構造方法 a.call(this,x,y); } // 子類繼承父類的成員變量以及父類的方法 b.prototype = Object.create(a.prototype); = b.prototype.constructor = b; // 建立對象 var c = new b(1,2);
// 這裏Object.create 是用來建立一個新的prototype,用來記錄新類的信息,並與父類創建聯繫 Object.create = function() { //建立一個基本對象 var temp = new Object(); //與父類的的原型創建聯繫 temp.__proto__ = proto; //返回新類的原型 return temp; }
小結:繼承關係的實現,作了以下兩件事情
原型就是類,原型鏈就是來創建子類和父類之間的聯繫。
先建立一個類
function people() {} // 爲父類對象添加一個method people.prototype.run = function() { console.log("I am running"); }
經過類來建立一個對象
var p = new people(); p.run(); // i am running
這裏p對象長這樣
{ __proto__: Object }
很顯然,這個對象之中並無run方法。
可是它卻能調用run,由於它會經過__proto__(原型鏈)來尋找類中的方法。
我想看到這裏,你應該很明白了。
那麼又有人會問function中__proto__又是什麼關係呢?
function 自己是對象,因此固然也有本身原型。function繼承於Function.(看下圖藍線)。
下面介紹一下原型繼承和類繼承的關係。
ES5
'use strict'; /** * Shape class. * * @constructor * @param {String} id - The id. * @param {Number} x - The x coordinate. * @param {Number} y - The y coordinate. */ function Shape(id, x, y) { this.id = id; this.setLocation(x, y); } /** * Set shape location. * * @param {Number} - The x coordinate. * @param {Number} - The y coordinate. */ Shape.prototype.setLocation = function(x, y) { this.x = x; this.y = y; }; /** * Get shape location. * * @return {Object} */ Shape.prototype.getLocation = function() { return { x: this.x, y: this.y }; }; /** * Get shape description. * * @return {String} */ Shape.prototype.toString = function() { return 'Shape("' + this.id + '")'; }; /** * Circle class. * * @constructor * @param {String} id - The id. * @param {Number} x - The x coordinate. * @param {Number} y - The y coordinate. * @param {Number} radius - The radius. */ function Circle(id, x, y, radius) { Shape.call(this, id, x, y); this.radius = radius; } Circle.prototype = Object.create(Shape.prototype); Circle.prototype.constructor = Circle; /** * Get circle description. * * @return {String} */ Circle.prototype.toString = function() { return 'Circle > ' + Shape.prototype.toString.call(this); }; // test the classes var myCircle = new Circle('mycircleid', 100, 200, 50); // create new instance console.log(myCircle.toString()); // Circle > Shape("mycircleid") console.log(myCircle.getLocation()); // { x: 100, y: 200 }
ES6
'use strict'; /** * Shape class. * * @constructor * @param {String} id - The id. * @param {Number} x - The x coordinate. * @param {Number} y - The y coordinate. */ class Shape(id, x, y) { constructor(id, x, y) { // constructor syntactic sugar this.id = id; this.setLocation(x, y); } /** * Set shape location. * * @param {Number} - The x coordinate. * @param {Number} - The y coordinate. */ setLocation(x, y) { // prototype function this.x = x; this.y = y; } /** * Get shape location. * * @return {Object} */ getLocation() { return { x: this.x, y: this.y }; } /** * Get shape description. * * @return {String} */ toString() { return `Shape("${this.id}")`; } } /** * Circle class. * * @constructor * @param {String} id - The id. * @param {Number} x - The x coordinate. * @param {Number} y - The y coordinate. * @param {Number} radius - The radius. */ function Circle extends Shape { constructor(id, x, y, radius) { super(id, x, y); // call Shape's constructor via super this.radius = radius; } /** * Get circle description. * * @return {String} */ toString() { // override Shape's toString return `Circle > ${super.toString()}`; // call `super` instead of `this` to access parent } } // test the classes var myCircle = new Circle('mycircleid', 100, 200, 50); // create new instance console.log(myCircle.toString()); // Circle > Shape("mycircleid") console.log(myCircle.getLocation()); // { x: 100, y: 200 }
這段代碼,本身體會。。。。