第6章,面向對象的程序設計
對象:
1、數據屬性
configurable,表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為訪問器屬性,默認為true
enumerbale,表示能否通過for-in訪問屬性,默認true
writable,表示能否修改屬性值,默認true
value,數據存儲位置,默認undefined
修改默認屬性特性:Object.defineProperty(),接收三個參數:屬性所在對象,屬性名,描述符對象,描述符對象屬性必須是:configurable、enumerable、writable、value
例:
var obj = {}; Object.defineProperty(obj,”name”,{ writable:true, value:”nihao” });
2、訪問器屬性
configurable,表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為訪問器屬性,默認為true
enumerbale,表示能否通過for-in訪問屬性,默認true
get,讀取屬性時調用,默認undefined
set,寫入屬性時調用,默認undefined
修改必須通過Object.defineProperty()
例:
var obj = { _year:2004, edition:1 } Object.defineProperty(book,”year”,{ get:function(){ return this._year; }, set:function(newValue){ if(newValue > 2004){ this._year = newValue; this.edition += newValue – 2004; } } }); book.year = 2005; alert(book.edition); //2
定義多個屬性:Object.defineProperties(),接收兩個對象,一是要修改和添加屬性的兌現,第二個對象屬性與第一個對象要修改或添加的屬性一一對應,支持的浏覽器:IE9+,FireFox4+,Safari5+,Opera12+,chrome
讀取屬性:Object.getOwnPropertyDescriptor(),接收兩個參數,屬性所在對象,要讀取描述符的屬性名稱,支持的浏覽器:IE9+,FireFox4+,Safari5+,Opera12+,chrome
創建對象:
工廠模式:
function createPerson(name,age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson(“g”,29);
構造函數模式:
function Person(name,age){ this.name = name; this.age = age; this.sayName() = function(){ alert(this.name); }; } var person = new Person(“g”,28);
兩種模式區別:
構造函數模式中不需要顯示創建對象,對this直接賦值,沒有返回語句
構造函數名首字母必須大寫,必須使用new操作符創建新實例
原型模式
創建的每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,換句話就是,prototype就是通過函數創建的對象的原型對象,好處在於可以是所有實例共享相同的屬性和方法。
isPrototypeOf(),個人理解就是可以用以判斷某個實例的原型是否與當前原型相同
例:
Person.prototype.isPrototypeOf(person1); //true
Object.getPrototypeOf(),可以返回某個實例的原型,支持的浏覽器IE9+,Firefox3.5+,Safari5+,Opera12+,chrome
注:訪問對象屬性名時會進行一次搜索,先在實例對象搜索,不存在則到當前對象的原型對象去搜索。
注:實例中的屬性若與原型對象中的屬性一樣,則會屏蔽原型對象的屬性,與上一條剛好可以對的上
hasOwnProperty()方法可以確定某個屬性是否來自實例,不是來自實例,則返回false,否則返回true
在實例上調用delete時,只會刪除實例上的屬性名,並不會刪除原型的屬性
例:
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.sayName = function(){ alert(this.name); } var per1 = new Person(); var per2 = new Person(); per1.name = "Greg"; alert(per1.name); //"Greg" 來自實例 alert(per2.name); //"Nicholas" delete per1.name; alert(per1.name); //"Nicholas" 來自原型 delete per1.name; alert(per1.name); //"Nicholas"
注:Object.getOwnPropertyDescriptor()方法只能用於實例屬性,要取得原型屬性描述符,必須直接在原型對象上調用本方法
in操作符:只有當屬性在實例對象中或者在原型對象中時,返回true
例:
alert(“name” in Person); //true alert(“name” in per1); //true
同時使用in和hasOwnProperty可以確定該屬性是存在原型中,還是實例中
Object.keys()方法:接收一個對象作為參數,返回所有可枚舉的屬性組成的字符串數組
Object.getOwnPropertyNames()方法:接收一個對象,返回所有屬性組成的字符串數組,無論是否可枚舉
更簡單的原型語法:
使用上述方法實在太麻煩了,更經常使用的是以下方法:使用對象字面量
Person.prototype = { name : “Nicholas”, age : 29 sayName = function(){ alert(this.name); } }
不過,此方法,相當於重寫了整個prototype對象,將導致constructor屬性不再指向Person而是指向Object,雖然instanceof還是會返回正確的結果,但通過constructor已經不能確定對象類型了。
var per = new Person(); alert(per instanceof Object); //true alert(per instanceof Person); //true alert(per constructor Object); //true alert(per constructor Person); //false
若constructor真的很重要,可以如下設置
Person.prototype = { constructor:Person, name : “Nicholas”, age : 29 sayName = function(){ alert(this.name); } }
以上寫法會使constructor的enumerable特性被設置為true,默認情況下原生的是false的,在兼容ECMAScript5的浏覽器可以使用Object.defineProperty()進行設置
Object.defineProperty(Person.prototype,”constructor”,{ enumerable:false, value:Person });
注:重寫原型對象,將會切斷現有原型與任何之前已經存在的對象實例之間的聯系
繼承(難度較大,需再仔細研究)
使用原型鏈來實現
子類型要覆蓋超類的方法,應該將給原型添加方法的代碼放在替換原型之後,
注:通過原型鏈實現繼承時,不能使用對象字面量創建原型方法,否則會重寫原型鏈
借用構造函數
組合繼承
原型式繼承,Object.creat();接收兩個參數:一是用作新對象原型的對象和(可選的)一個為新對象定義額外屬性的對象
例:Object.creat(person,{name:{value:”greg”}});
寄生式繼承
寄生組合式繼承
第7章,函數表達式
創建方式:
1、函數聲明,可以函數聲明提升,就是可以把使用函數的語句放在函數聲明之前
function funName(arg0,arg1){ //函數體 }
2、函數表達式,不能進行函數提升,也就是無法在函數創建前使用函數,在這種情況下創建的函數稱為匿名函數,有時也叫拉姆達函數
var funName = function(arg0,arg1){ //函數體 }
嚴格模式下無法使用arguments.callee來實現遞歸,可以使用如下方式實現遞歸:
var factorial = (function f(num){ if(num <= 1){ return 1; }else{ return num * f(num - 1); } });
閉包(難度也不小)
閉包指有權訪問另一個函數作用域中的變量的函數,閉包,也是一個函數
創建閉包的常見方式是在一個函數內部創建另一個函數
閉包只能取得包含函數即外部函數中任何變量的最後一個值。下例可以清晰說明問題
例:
function createFuncrions(){ var result = new Array(); for(var i = 0;i < 10;i++){ result[i] = function(){ return i; } } return result; } var re = createFuncrions(); alert(re[1](2));
每個函數返回的都將是10,而不是如預期般返回對應的索引值,因為createFuncrions函數最後返回時I = 10,此時每個函數都引用保存著變量i的同一個對象,所以在每個函數內部i都是10,可以使用如下方法強制閉包返回預期效果:
function createFuncrions(){ var result = new Array(); for(var i = 0;i < 10;i++){ result[i] = function(num){ return function(){ return num; }; }(i); } return result; } var re = createFuncrions(); alert(re[2]());
每一個都會返回各自的索引值
模仿塊級作用域
使用匿名函數可以模仿塊級作用域:
(function(){ alert("test"); //塊級作用域,沒有使用圓括號將function包起來將會出錯 })();
使用閉包和私有變量的明顯不足之處在於,會在作用域鏈中多查找一個層次,在一定程度上影響查找速度
函數中定義的變量可以在一定程度上稱為私有變量,通過函數可以模擬出私有變量,靜態私有變量
增強模塊模式:
var singleton = function(){ //private arg and private method var privateVariable = 10; function privateFunction(){ return false; } //create obj var obj = new Object(); obj.publicProperty = true; obj.publicFunction = function(){ privateVariable ++; return privateFunction(); }; return obj; }(); alert(typeof singleton); alert(singleton.publicProperty); alert(singleton.publicFunction());
以上內容是小編給大家介紹的JavaScript高級程序設計(第三版)學習筆記6、7章,希望對大家有所幫助!