JavaScript 物件導向精要(一)
資料型別
在JavaScript中,資料型別分為兩類:
原始型別
儲存一些簡單資料,如true,5等。JavaScript共有5中原始型別:
- boolean:布林,值為true或false
- number:數字,值為任何整型會浮點數值
- string:字串,值為由單引號或雙引號括出的單個字元或連續字元(JavaScript不區分字元型別)
- null:空型別,其僅有一個值:nulll
- undefined:未定義,其僅有一個值:undefined
var name = "Pomy"; var blog = "http://www.ido321.com"; var age = 22; alert(typeof blog); //"string" alert(typeof age); //"number"
原始型別的值是直接儲存在變數中,並可以用 typeof 進行檢測。但是typeof對null的檢測是返回object,而不是返回null:
//彈出Not null if(typeof null){ alert("Not null"); }else{ alert("null"); }
所以檢測null時,最好用全等於(===),其還能避免強制型別轉換:
console.log("21" === 21); //false console.log("21" == 21); //true console.log(undefined == null); //true console.log(undefined === null); //false
對於字串、數字或者布林值,其都有對應的方法,這些方法來自於對應的原始封裝型別:String、Number和Boolean。原始封裝型別將被自動建立。
var name = "Pomy"; var char = name.charAt(0); console.log(char); //"P"
在JavaScript引擎中發生的事情:
var name = "Pomy"; var temp = new String(name); var char = temp.charAt(0); temp = null; console.log(char); //"P"
字串物件的引用在用完之後立即被銷燬,所以不能給字串新增屬性,並且instanceof檢測對應型別時均返回false:
var name = "Pomy"; name.age = 21; console.log(name.age); //undefined console.log(name instanceof String); //false
引用型別
儲存為物件,實質是指向記憶體位置的引用,所以不在變數中儲存物件。除了自定義的物件,JavaScript提供了6中內建型別:
- Array:陣列型別,以數字為索引的一組值的有序列表
- Date:日期和時間型別
- Error:執行期錯誤型別
- Function:函式型別
- Object:通用物件型別
- RegExp:正規表示式型別
可以用new來例項化每一個物件,或者用字面量形式來建立物件:
var obj = new Object; var own = { name:"Pomy", blog:"http://www.ido321.com", "my age":22 }; console.log(own.blog); //訪問屬性 console.log(own["my age"]); obj = null; //解除引用
obj 並不包含物件例項,而是一個指向記憶體中實際物件所在位置的指標(或者說引用)。因為typeof對所有非函式的引用型別均返回object,所以需要用instanceof來檢測引用型別。
函式
在JavaScript中,函式就是物件。使函式不同於其他物件的決定性特性是函式存在一個被稱為[[Call]]的內部屬性。內部屬性無法通過程式碼訪問而是定義了程式碼執行時的行為。
建立形式
1、函式宣告:用function關鍵字,會被提升至上下文
2、函式表示式:不能被提升
3、例項化Function內建型別
sayHi(); //函式提升 function sayHi(){ console.log("Hello"); } //其他等效等效方式 /* var sayHi = function(){ console.log("Hello"); } var sayHi = new Function(" console.log(\"Hello\");"); */
引數
JavaScript函式的另外一個獨特之處在於可以給函式傳遞任意數量的引數。函式引數被儲存在arguments類陣列物件中,其自動存在函式中,能通過數字索引來引用引數,但它不是陣列例項:
alert(Array.isArray(arguments)); //false
類陣列物件arguments 儲存的是函式的實參,但並不會忽略形參。因而,arguments.length返回實參列表的長度,arguments.callee.length返回形參列表的長度。
function ref(value){ return value; } console.log(ref("Hi")); console.log(ref("Hi",22)); console.log(ref.length); //1
函式中的this
關於this的問題,可參考此文:JavaScript中的this。
JavaScript提供了三個方法用於改變this的指向:call、apply和bind。三個函式的第一個引數都是指定this的值,其他引數均作為引數傳遞給函式。
物件
物件是一種引用型別,建立物件常見的兩種方式:Object建構函式和物件字面量形式:
var per1 = { name:"Pomy", blog:"http://www.ido321.com" }; var per2 = new Object; per2.name = "不寫程式碼的碼農";
屬性操作
在JavaScript中,可以隨時為物件新增屬性:
per1.age = 0; per1.sayName = function(){ alert(this.name); //"Pomy" }
因而,在檢測物件屬性是否存在時,常犯的一個錯誤是:
//結果是false if(per1.age){ alert(true) }else{ alert(false); }
per1.age 是存在的,但是其值是0,所以不能滿足if條件。if判斷中的值是一個物件、非空字串、非零數字或true時,判斷會評估為真;而當值是一個null、undefined、0、false、NaN或空字串時評估為假。
因而,檢測屬性是否存在時,有另外的兩種方式:in和hasOwnProperty(),前者會檢測原型屬性和自有(例項)屬性,後者只檢測自有(例項)屬性。
console.log("age" in per1); //true console.log(per1.hasOwnProperty("age")); //true console.log("toString" in per1); //true console.log(per1.hasOwnProperty("toString")); //false
物件per1並沒有定義toString,該屬性繼承於Object.prototype,所以in和hasOwnProperty()檢測該屬性時出現差異。如果只想判斷一個物件屬性是不是原型,可以利用如下方法:
function isPrototypeProperty(obj,name){ return name in obj && !obj.hasOwnProperty(name); }
若要刪除一個屬性,用delete操作符,用於刪除自有屬性,不能刪除原型屬性。
per1.toString = function(){ console.log("per1物件"); }; console.log(per1.hasOwnProperty("toString")); //true per1.toString(); //"per1物件" delete per1.toString; console.log(per1.hasOwnProperty("toString")); //false console.log(per1.toString()); //[object Object]
有時需要列舉物件的可列舉屬性,也有兩種方式:for-in迴圈和Object.keys(),前者依舊會遍歷出原型屬性,後者只返回自有屬性。所有可列舉屬性的內部屬性[[Enumerable]]的值均為true。
var per3 = { name:"Pomy", blog:"http://www.ido321.com", age:22, getAge:function(){ return this.age; } };
實際上,大部分原生屬性的[[Enumerable]]的值均為false,即該屬性不能列舉。可以通過propertyIsEnumerable()檢測屬性是否可以列舉:
console.log(per3.propertyIsEnumerable("name")); //true var pros = Object.keys(per3); //返回可列舉屬性的名字陣列 console.log("length" in pros); //true console.log(pros.propertyIsEnumerable("length")); //false
屬性name是自定義的,可列舉;屬性length是Array.prototype的內建屬性,不可列舉。
屬性型別
屬性有兩種型別:資料屬性和訪問器屬性。二者均具有四個屬性特徵:
- 資料屬性:[[Enumerable]]、[[Configurable]]、[[Value]]和[[Writable]]
- 訪問器屬性:[[Enumerable]]、[[Configurable]]、[[Get]]和[[Set]]
[[Enumerable]] :布林值,屬性是否可列舉,自定義屬性預設是true。
[[Configurable]] :布林值,屬性是否可配置(可修改或可刪除),自定義屬性預設是true。它是不可逆的,即設定成false後,再設定成true會報錯。
[[Value]]:儲存屬性的值。
[[Writable]]:布林值,屬性是否可寫,所有屬性預設可寫。
[[Get]]:獲取屬性值。
[[Set]]:設定屬性值。
ES 5提供了兩個方法用於設定這些內部屬性:
Object.defineProperty(obj,pro,desc_map) 和 Object.defineProperties(obj,pro_map)。利用這兩個方法為per3新增一個屬性和建立一個新物件per4:
Object.defineProperty(per3,"sex",{ value:"male", enumerable:false, configurable:false, //屬性不能刪除和修改,該值也不能被設定成true }); console.log(per3.sex); //'male' console.log(per3.propertyIsEnumerable("sex")); //false delete per3.sex; //不能刪除 per3.sex = "female"; //不能修改 console.log(per3.sex); //'male' Object.defineProperty(per3,"sex",{ configurable:true, //報錯 }); per4 = {}; Object.defineProperties(per4,{ name:{ value:"dwqs", writable:true }, blog:{ value:"http://blog.92fenxiang.com" }, Name:{ get:function(){ return this.name; }, set:function(value){ this.name = value; }, enumerable:true, configurable:true } }); console.log(per4.name); //dwqs per4.Name = "Pomy"; console.log(per4.Name); //Pomy
需要注意的是,通過這兩種方式來定義新屬性時,如果不指定特徵值,則預設是false,也不能建立同時具有資料特徵和訪問器特徵的屬性。可以通過Object.getOwnPropertyDescriptor()方法來獲取屬性特徵的描述,接受兩個引數:物件和屬性名。若屬性存在,則返回屬性描述物件。
var desc = Object.getOwnPropertyDescriptor(per4,"name"); console.log(desc.enumerable); //false console.log(desc.configurable); //false console.log(desc.writable); //true
根據屬性的屬性型別,返回的屬性描述物件包含其對應的四個屬性特徵。
禁止修改物件
物件和屬性一樣具有指導其行為的內部特徵。其中,[[Extensible]]是一個布林值,指明改物件本身是否可以被修改([[Extensible]]值為true)。建立的物件預設都是可以擴充套件的,可以隨時新增新的屬性。
ES5提供了三種方式:
- Object.preventExtensions(obj):建立不可擴充套件的obj物件,可以利用Object.isExtensible(obj)來檢測obj是否可以擴充套件。嚴格模式下給不擴充套件物件新增屬性會報錯,非嚴格模式下則新增失敗。
- Object.seal(obj):封印物件,此時obj的屬性變成只讀,不能新增、改變或刪除屬性(所有屬性都不可配置),其[[Extensible]]值為false,[[Configurable]]值為false。可以利用Object.isSealed(obj)來檢測obj是否被封印。
- Object.freeze(obj):凍結物件,不能在凍結物件上新增或刪除屬性,不能改變屬性型別,也不能寫入任何資料型別。可以利用Object.isFrozen(obj)來檢測obj是否被凍結。 注意:凍結物件和封印物件均要在嚴格模式下使用。
"use strict"; var per5 = { name:"Pomy" }; console.log(Object.isExtensible(per5)); //true console.log(Object.isSealed(per5)); //false console.log(Object.isFrozen(per5)); //false Object.freeze(per5); console.log(Object.isExtensible(per5)); //false console.log(Object.isSealed(per5)); //true console.log(Object.isFrozen(per5)); //true per5.name="dwqs"; console.log(per5.name); //"Pomy" per5.Hi = function(){ console.log("Hi"); }; console.log("Hi" in per5); //false delete per5.name; console.log(per5.name); //"Pomy" var desc = Object.getOwnPropertyDescriptor(per5,"name"); console.log(desc.configurable); //false console.log(desc.writable); //false
注意,禁止修改物件的三個方法只對物件的自有屬性有效,對原型物件的屬性無效,仍然可以在原型上新增或修改屬性。
function Person(name){ this.name = name; } var person1 = new Person("Pomy"); var person2 = new Person("dwqs"); Object.freeze(person1); Person.prototype.Hi = function(){ console.log("Hi"); }; person1.Hi(); //"Hi"; person2.Hi(); //"Hi";
相關文章
- JavaScript物件導向精要(二)JavaScript物件
- 《JavaScript物件導向精要》之六:物件模式JavaScript物件模式
- 《JavaScript物件導向精要》之三:理解物件JavaScript物件
- 《JavaScript物件導向精要》系列文章JavaScript物件
- 《JavaScript 物件導向精要》 讀書筆記JavaScript物件筆記
- 《JavaScript物件導向精要》之五:繼承JavaScript物件繼承
- 《JavaScript物件導向精要》之二:函式JavaScript物件函式
- 《JavaScript物件導向精要》之一:基本型別和引用型別JavaScript物件型別
- 《JavaScript物件導向精要》之四:建構函式和原型物件JavaScript物件函式原型
- JavaScript 物件導向JavaScript物件
- Javascript 物件導向程式設計(一)JavaScript物件程式設計
- JavaScript物件導向之一(封裝)JavaScript物件封裝
- JavaScript的物件導向JavaScript物件
- 初探 JavaScript 物件導向JavaScript物件
- 物件導向(理解物件)——JavaScript基礎總結(一)物件JavaScript
- 【讀】JavaScript之物件導向JavaScript物件
- JavaScript 的物件導向(OO)JavaScript物件
- JavaScript7:物件導向JavaScript物件
- 更多物件導向的JavaScript物件JavaScript
- JavaScript物件導向入門JavaScript物件
- JavaScript 物件導向初步理解JavaScript物件
- JavaScript模擬物件導向JavaScript物件
- 第一章:物件導向的 JavaScript物件JavaScript
- Javascript 物件導向程式設計(一):封裝JavaScript物件程式設計封裝
- JavaScript物件導向—物件的建立和操作JavaScript物件
- JavaScript 物件導向實戰思想JavaScript物件
- JavaScript物件導向詳解(原理)JavaScript物件
- Javascript物件導向與繼承JavaScript物件繼承
- JavaScript學習2:物件導向JavaScript物件
- JavaScript中的物件導向----類JavaScript物件
- 全面理解物件導向的 JavaScript物件JavaScript
- Javascript 物件導向程式設計JavaScript物件程式設計
- DEJAVU庫:讓JavaScript物件導向JavaScript物件
- 物件導向-物件導向思想物件
- javascript物件導向和回撥的一個示例JavaScript物件
- Java物件導向(一)Java物件
- JavaScript高階:JavaScript物件導向,JavaScript內建物件,JavaScript BOM,JavaScript封裝JavaScript物件封裝
- JavaScript物件導向名詞詳解JavaScript物件