JavaScript物件導向精要(二)
建構函式和原型物件
建構函式也是函式,用new建立物件時呼叫的函式,與普通函式的一個區別是,其首字母應該大寫。但如果將建構函式當作普通函式呼叫(缺少new關鍵字),則應該注意this指向的問題。
var name = "Pomy"; function Per(){ console.log("Hello "+this.name); } var per1 = new Per(); //"Hello undefined" var per2 = Per(); //"Hello Pomy"
使用new時,會自動建立this物件,其型別為建構函式型別,指向物件例項;缺少new關鍵字,this指向全域性物件。
可以用instanceof來檢測物件型別,同時每個物件在建立時都自動擁有一個constructor屬性,指向其建構函式(字面量形式或Object建構函式建立的物件,指向Object,自定義建構函式建立的物件則指向它的建構函式)。
console.log(per1 instanceof Per); //true console.log(per1.constructor === Per); //true
每個物件例項都有一個內部屬性:[[Prototype]],其指向該物件的原型物件。建構函式本身也具有prototype 屬性指向原型物件。所有建立的物件都共享該原型物件的屬性和方法。
function Person(){} Person.prototype.name="dwqs"; Person.prototype.age=20; Person.prototype.sayName=function() { alert(this.name); }; var per1 = new Person(); per1.sayName(); //dwqs var per2 = new Person(); per2.sayName(); //dwqs alert(per1.sayName == per2.sayName); //true
所以,例項中的指標僅指向原型,而不指向建構函式。 ES5提供了hasOwnProperty()和isPropertyOf()方法來反應原型物件和例項之間的關係
alert(Person.prototype.isPrototypeOf(per2)); //true per1.blog = "www.ido321.com"; alert(per1.hasOwnProperty("blog")); //true alert(Person.prototype.hasOwnProperty("blog")); //false alert(per1.hasOwnProperty("name")); //false alert(Person.prototype.hasOwnProperty("name")); //true
因為原型物件的constructor屬性是指向建構函式本身,所以在重寫原型時,需要注意constructor屬性的指向問題。
function Hello(name){ this.name = name; } //重寫原型 Hello.prototype = { sayHi:function(){ console.log(this.name); } }; var hi = new Hello("Pomy"); console.log(hi instanceof Hello); //true console.log(hi.constructor === Hello); //false console.log(hi.constructor === Object); //true
使用物件字面量形式改寫原型物件改變了建構函式的屬性,因此constructor指向Object,而不是Hello。如果constructor指向很重要,則需要在改寫原型物件時手動重置其constructor屬性
Hello.prototype = { constructor:Hello, sayHi:function(){ console.log(this.name); } }; console.log(hi.constructor === Hello); //true console.log(hi.constructor === Object); //false
利用原型物件的特性,我們可以很方便的在JavaScript的內建原型物件上新增自定義方法:
Array.prototype.sum=function(){ return this.reduce(function(prev,cur){ return prev+cur; }); }; var num = [1,2,3,4,5,6]; var res = num.sum(); console.log(res); //21 String.prototype.capit = function(){ return this.charAt(0).toUpperCase()+this.substring(1); }; var msg = "hello world"; console.log(msg.capit()); //"Hello World"
繼承
利用[[Prototype]]特性,可以實現原型繼承;對於字面量形式的物件,會隱式指定Object.prototype為其[[Prototype]],也可以通過Object.create()顯示指定,其接受兩個引數:第一個是[[Prototype]]指向的物件(原型物件),第二個是可選的屬性描述符物件。
var book = { title:"這是書名"; }; //和下面的方式一樣 var book = Object.create(Object.prototype,{ title:{ configurable:true, enumerable:true, value:"這是書名", wratable:true } });
字面量物件會預設繼承自Object,更有趣的用法是,在自定義物件之間實現繼承。
var book1 = { title:"JS高階程式設計", getTitle:function(){ console.log(this.title); } }; var book2 = Object.create(book1,{ title:{ configurable:true, enumerable:true, value:"JS權威指南", wratable:true } }); book1.getTitle(); //"JS高階程式設計" book2.getTitle(); //"JS權威指南" console.log(book1.hasOwnProperty("getTitle")); //true console.log(book1.isPrototypeOf("book2")); //false console.log(book2.hasOwnProperty("getTitle")); //false
當訪問book2的getTitle屬性時,JavaScript引擎會執行一個搜尋過程:現在book2的自有屬性中尋找,找到則使用,若沒有找到,則搜尋[[Prototype]],若沒有找到,則繼續搜尋原型物件的[[Prototype]],直到繼承鏈末端。末端通常是Object.prototype,其[[Prototype]]被設定為null。
實現繼承的另外一種方式是利用建構函式。每個函式都具有可寫的prototype屬性,預設被自懂設定為繼承自Object.prototype,可以通過改寫它來改變原型鏈。
function Rect(length,width){ this.length = length; this.width = width; } Rect.prototype.getArea = function(){ return this.width * this.length; }; Rect.prototype.toString = function(){ return "[Rect"+this.length+"*"+this.width+"]"; }; function Square(size){ this.length = size; this.width = size; } //修改prototype屬性 Square.prototype = new Rect(); Square.prototype.constructor = Square; Square.prototype.toString = function(){ return "[Square"+this.length+"*"+this.width+"]"; }; var rect = new Rect(5,10); var square = new Square(6); console.log(rect.getArea()); //50 console.log(square.getArea()); //36
如果要訪問父類的toString(),可以這樣做:
Square.prototype.toString = function(){ var text = Rect.prototype.toString.call(this); return text.replace("Rect","Square"); }
相關文章
- 《JavaScript物件導向精要》之二:函式JavaScript物件函式
- 《JavaScript物件導向精要》系列文章JavaScript物件
- 《JavaScript物件導向精要》之六:物件模式JavaScript物件模式
- 《JavaScript物件導向精要》之三:理解物件JavaScript物件
- 《JavaScript物件導向精要》之五:繼承JavaScript物件繼承
- 《JavaScript 物件導向精要》 讀書筆記JavaScript物件筆記
- 《JavaScript物件導向精要》之四:建構函式和原型物件JavaScript物件函式原型
- 《JavaScript物件導向精要》之一:基本型別和引用型別JavaScript物件型別
- Javascript 物件導向程式設計(二)JavaScript物件程式設計
- JavaScript 物件導向JavaScript物件
- 更多物件導向的JavaScript物件JavaScript
- JavaScript7:物件導向JavaScript物件
- 【讀】JavaScript之物件導向JavaScript物件
- JavaScript 的物件導向(OO)JavaScript物件
- JavaScript 物件導向初步理解JavaScript物件
- JavaScript物件導向之二(建構函式繼承)JavaScript物件函式繼承
- JavaScript物件導向—物件的建立和操作JavaScript物件
- 二、Java之物件導向Java物件
- 1.16 JavaScript7:物件導向JavaScript物件
- JavaScript物件導向詳解(原理)JavaScript物件
- JavaScript 物件導向實戰思想JavaScript物件
- Javascript物件導向與繼承JavaScript物件繼承
- JavaScript高階:JavaScript物件導向,JavaScript內建物件,JavaScript BOM,JavaScript封裝JavaScript物件封裝
- 物件導向-物件導向思想物件
- JavaScript物件導向之一(封裝)JavaScript物件封裝
- javascript:物件導向的程式設計JavaScript物件程式設計
- Javascript 物件導向程式設計(一)JavaScript物件程式設計
- Javascript 物件導向程式設計(三)JavaScript物件程式設計
- JavaScript物件導向名詞詳解JavaScript物件
- JavaScript物件導向程式設計理解!JavaScript物件程式設計
- Javascript實現物件導向繼承JavaScript物件繼承
- java基礎二:物件導向Java物件
- Lua學習(二)物件導向物件
- 物件導向(理解物件)——JavaScript基礎總結(一)物件JavaScript
- 說清楚javascript物件導向、原型、繼承JavaScript物件原型繼承
- JavaScript物件導向 ~ 原型和繼承(1)JavaScript物件原型繼承
- JavaScript物件導向~ 作用域和閉包JavaScript物件
- JavaScript物件導向那些東西-繼承JavaScript物件繼承
- 前端_JavaScript_物件導向程式設計前端JavaScript物件程式設計