標籤:物件導向 賦值 種類型 階段 定位 函數 函數名 tde 外部
建立對象的幾種常用方式
1.使用Object或對象字面量建立對象
2.原廠模式建立對象
3.建構函式模式建立對象
4.原型模式建立對象
1.使用Object或對象字面量建立對象
JS中最基本建立對象的方式:
var student = new Object();student.name = "easy";student.age = "20";
這樣,一個student對象就建立完畢,擁有2個屬性name
以及age
,分別賦值為"easy"
和20
。
如果你嫌這種方法有一種封裝性不良的感覺。來一個對象字面量方式建立對象。
var sutdent = { name : "easy", age : 20};
這樣看起來似乎就完美了。但是馬上我們就會發現一個十分尖銳的問題:當我們要建立同類的student1,student2,…,studentn時,我們不得不將以上的代碼重複n次....
var sutdent1 = { name : "easy1", age : 20};var sutdent2 = { name : "easy2", age : 20};...var sutdentn = { name : "easyn", age : 20};
有個提問?能不能像工廠車間那樣,有一個車床就不斷生產出對象呢?我們看”原廠模式”。
2.原廠模式建立對象
JS中沒有類的概念,那麼我們不妨就使用一種函數將以上對象建立過程封裝起來以便於重複調用,同時可以給出特定介面來初始化對象
function createStudent(name, age) { var obj = new Object(); obj.name = name; obj.age = age; return obj;}var student1 = createStudent("easy1", 20);var student2 = createStudent("easy2", 20);...var studentn = createStudent("easyn", 20);
這樣一來我們就可以通過createStudent函數源源不斷地”生產”對象了。看起來已經高枕無憂了,但貪婪的人類總有不滿足於現狀的天性:我們不僅希望”產品”的生產可以像工廠車間一般源源不斷,我們還想知道生產的產品究竟是哪一種類型的。
比如說,我們同時又定義了”生產”水果對象的createFruit()函數:
function createFruit(name, color) { var obj = new Object(); obj.name = name; obj.color = color; return obj;}var v1 = createStudent("easy1", 20);var v2 = createFruit("apple", "green");
對於以上代碼建立的對象v1、v2,我們用instanceof操作符去檢測,他們統統都是Object類型。我們的當然不滿足於此,我們希望v1是Student類型的,而v2是Fruit類型的。為了實現這個目標,我們可以用自訂建構函式的方法來建立對象
3.建構函式模式建立對象
在上面建立Object這樣的原生對象的時候,我們就使用過其建構函式:
var obj = new Object();
在建立原生數組Array類型對象時也使用過其建構函式:
var arr = new Array(10); //構造一個初始長度為10的數組對象
在進行自訂建構函式建立對象之前,我們首先瞭解一下建構函式
和普通函數
有什麼區別。
1、實際上並不存在建立建構函式的特殊文法,其與普通函數唯一的區別在於調用方法。對於任意函數,使用new操作符調用,那麼它就是建構函式;不使用new操作符調用,那麼它就是普通函數。
2、按照慣例,我們約定建構函式名以大寫字母開頭,普通函數以小寫字母開頭,這樣有利於顯性區分二者。例如上面的new Array(),new Object()。
3、使用new操作符調用建構函式時,會經曆(1)建立一個新對象;(2)將建構函式範圍賦給新對象(使this指向該新對象);(3)執行建構函式代碼;(4)返回新對象;4個階段。
ok,瞭解了建構函式
和普通函數
的區別之後,我們使用建構函式將原廠模式
的函數重寫,並添加一個方法屬性:
function Student(name, age) { this.name = name; this.age = age; this.alertName = function(){ alert(this.name) };}function Fruit(name, color) { this.name = name; this.color = color; this.alertName = function(){ alert(this.name) };}
這樣我們再分別建立Student和Fruit的對象:
var v1 = new Student("easy", 20);var v2 = new Fruit("apple", "green");
這時我們再來用instanceof操作符來檢測以上物件類型就可以區分出Student以及Fruit了:
alert(v1 instanceof Student); //truealert(v2 instanceof Student); //falsealert(v1 instanceof Fruit); //falsealert(v2 instanceof Fruit); //truealert(v1 instanceof Object); //true 任何對象均繼承自Objectalert(v2 instanceof Object); //true 任何對象均繼承自Object
這樣我們就解決了原廠模式
無法區分物件類型的尷尬。那麼使用構造方法來建立對象是否已經完美了呢?使用構造器函數通常在js中我們來建立對象。
我們會發現Student和Fruit對象中共有同樣的方法,當我們進行調用的時候這無疑是記憶體的消耗。
我們完全可以在執行該函數的時候再這樣做,辦法是將對象方法移到建構函式外部:
function Student(name, age) { this.name = name; this.age = age; this.alertName = alertName;}function alertName() { alert(this.name);}var stu1 = new Student("easy1", 20);var stu2 = new Student("easy2", 20);
在調用stu1.alertName()時,this對象才被綁定到stu1上。
我們通過將alertName()函數定義為全域函數,這樣對象中的alertName屬性則被設定為指向該全域函數的指標。由此stu1和stu2共用了該全域函數,解決了記憶體浪費的問題
但是,通過全域函數的方式解決對象內部共用的問題,終究不像一個好的解決方案。如果這樣定義的全域函數多了,我們想要將自訂對象封裝的初衷便幾乎無法實現了。更好的方案是通過原型對象模式來解決。
4.原型的模式建立對象
原型鏈甚至原型繼承,是整個JS中最難的一部分也是最不好理解的一部分,在這裡由於我們課程定位的原因,如果對js有興趣的同學,可以去查閱一下相關JS原型的一些知識點。更加有助於你以後前端JS的面試。
function Student() { this.name = ‘easy‘; this.age = 20;}Student.prototype.alertName = function(){ alert(this.name);};var stu1 = new Student();var stu2 = new Student();stu1.alertName(); //easystu2.alertName(); //easyalert(stu1.alertName == stu2.alertName); //true 二者共用同一函數
13-JS中的物件導向