JavaScript面向對象精要

數據類型

在JavaScript中,數據類型分爲兩類:

  • 原始類型:保存一些簡單數據,如true5等。JavaScript共有5中原始類型: 
    • boolean:布爾,值爲truefalse
    • number:數字,值爲任何整型會浮點數值
    • string:字符串,值爲由單引號或雙引號括出的單個字符或連續字符(JavaScript不區分字符類型)
    • null:空類型,其僅有一個值:nulll
    • undefined:未定義,其僅有一個值:undefined
    1. var name = "Pomy";
    2. var blog = "http://www.ido321.com";
    3. var age = 22;
    4. alert(typeof blog); //"string"
    5. alert(typeof age); //"number"

原始類型的值是直接保存在變量中,並可以用typeof進行檢測。但是typeofnull的檢測是返回object,而不是返回null

    1. //彈出Not null
    2. if(typeof null){
    3. alert("Not null");
    4. }else{
    5. alert("null");
    6. }

所以檢測null時,最好用全等於(===),其還能避免強制類型轉換:

    1. console.log("21" === 21); //false
    2. console.log("21" == 21); //true
    3. console.log(undefined == null); //true
    4. console.log(undefined === null); //false

對於字符串、數字或者布爾值,其都有對應的方法,這些方法來自於對應的原始封裝類型:StringNumberBoolean。原始封裝類型將被自動創建。

    1. var name = "Pomy";
    2. var char = name.charAt(0);
    3. console.log(char); //"P"

在JavaScript引擎中發生的事情:

    1. var name = "Pomy";
    2. var temp = new String(name);
    3. var char = temp.charAt(0);
    4. temp = null;
    5. console.log(char); //"P"

字符串對象的引用在用完之後立即被銷燬,所以不能給字符串添加屬性,並且instanceof檢測對應類型時均返回false

    1. var name = "Pomy";
    2. name.age = 21;
    3. console.log(name.age); //undefined
    4. console.log(name instanceof String); //false
  • 引用類型:保存爲對象,實質是指向內存位置的引用,所以不在變量中保存對象。除了自定義的對象,JavaScript提供了6中內建類型:
    • Array:數組類型,以數字爲索引的一組值的有序列表
    • Date:日期和時間類型
    • Error:運行期錯誤類型
    • Function:函數類型
    • Object:通用對象類型
    • RegExp:正則表達式類型 
      可以用new來實例化每一個對象,或者用字面量形式來創建對象:
    1. var obj = new Object;
    2. var own = {
    3. name:"Pomy",
    4. blog:"http://www.ido321.com",
    5. "my age":22
    6. };
    7. console.log(own.blog); //訪問屬性
    8. console.log(own["my age"]);
    9. obj = null; //解除引用

obj 並不包含對象實例,而是一個指向內存中實際對象所在位置的指針(或者說引用)。因爲typeof對所有非函數的引用類型均返回object,所以需要用instanceof來檢測引用類型。

函數

在JavaScript中,函數就是對象。使函數不同於其他對象的決定性特性是函數存在一個被稱爲[[Call]]的內部屬性。內部屬性無法通過代碼訪問而是定義了代碼執行時的行爲。

創建形式

1、函數聲明:用function關鍵字,會被提升至上下文 
2、函數表達式:不能被提升 
3、實例化Function內建類型

    1. sayHi(); //函數提升
    2. function sayHi(){
    3. console.log("Hello");
    4. }
    5. //其他等效等效方式
    6. /*
    7. var sayHi = function(){
    8. console.log("Hello");
    9. }
    10. var sayHi = new Function(" console.log(\"Hello\");");
    11. */

參數

JavaScript函數的另外一個獨特之處在於可以給函數傳遞任意數量的參數。函數參數被保存在arguments類數組對象中,其自動存在函數中,能通過數字索引來引用參數,但它不是數組實例:

    1. alert(Array.isArray(arguments)); //false

類數組對象arguments 保存的是函數的實參,但並不會忽略形參。因而,arguments.length返回實參列表的長度,arguments.callee.length返回形參列表的長度。

    1. function ref(value){
    2. return value;
    3. }
    4. console.log(ref("Hi"));
    5. console.log(ref("Hi",22));
    6. console.log(ref.length); //1

函數中的this

關於this的問題,可參考此文:JavaScript中的this。 
JavaScript提供了三個方法用於改變this的指向:callapplybind。三個函數的第一個參數都是指定this的值,其他參數均作爲參數傳遞給函數。

對象

對象是一種引用類型,創建對象常見的兩種方式:Object構造函數和對象字面量形式:

    1. var per1 = {
    2. name:"Pomy",
    3. blog:"http://www.ido321.com"
    4. };
    5. var per2 = new Object;
    6. per2.name = "不寫代碼的碼農";

屬性操作

在JavaScript中,可以隨時爲對象添加屬性:

    1. per1.age = 0;
    2. per1.sayName = function(){
    3. alert(this.name); //"Pomy"
    4. }

因而,在檢測對象屬性是否存在時,常犯的一個錯誤是:

    1. //結果是false
    2. if(per1.age){
    3. alert(true)
    4. }else{
    5. alert(false);
    6. }

per1.age 是存在的,但是其值是0,所以不能滿足if條件。if判斷中的值是一個對象、非空字符串、非零數字或true時,判斷會評估爲真;而當值是一個nullundefined0falseNaN或空字符串時評估爲假。 
因而,檢測屬性是否存在時,有另外的兩種方式:inhasOwnProperty(),前者會檢測原型屬性和自有(實例)屬性,後者只檢測自有(實例)屬性。

    1. console.log("age" in per1); //true
    2. console.log(per1.hasOwnProperty("age")); //true
    3. console.log("toString" in per1); //true
    4. console.log(per1.hasOwnProperty("toString")); //false

對象per1並沒有定義toString,該屬性繼承於Object.prototype,所以inhasOwnProperty()檢測該屬性時出現差異。如果只想判斷一個對象屬性是不是原型,可以利用如下方法:

    1. function isPrototypeProperty(obj,name){
    2. return name in obj && !obj.hasOwnProperty(name);
    3. }

若要刪除一個屬性,用delete操作符,用於刪除自有屬性,不能刪除原型屬性。

    1. per1.toString = function(){
    2. console.log("per1對象");
    3. };
    4. console.log(per1.hasOwnProperty("toString")); //true
    5. per1.toString(); //"per1對象"
    6. delete per1.toString;
    7. console.log(per1.hasOwnProperty("toString")); //false
    8. console.log(per1.toString()); //[object Object]

有時需要枚舉對象的可枚舉屬性,也有兩種方式:for-in循環和Object.keys(),前者依舊會遍歷出原型屬性,後者只返回自有屬性。所有可枚舉屬性的內部屬性[[Enumerable]]的值均爲true

    1. var per3 = {
    2. name:"Pomy",
    3. blog:"http://www.ido321.com",
    4. age:22,
    5. getAge:function(){
    6. return this.age;
    7. }
    8. };

實際上,大部分原生屬性的[[Enumerable]]的值均爲false,即該屬性不能枚舉。可以通過propertyIsEnumerable()檢測屬性是否可以枚舉:

    1. console.log(per3.propertyIsEnumerable("name")); //true
    2. var pros = Object.keys(per3); //返回可枚舉屬性的名字數組
    3. console.log("length" in pros); //true
    4. console.log(pros.propertyIsEnumerable("length")); //false

屬性name是自定義的,可枚舉;屬性lengthArray.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:

    1. Object.defineProperty(per3,"sex",{
    2. value:"male",
    3. enumerable:false,
    4. configurable:false, //屬性不能刪除和修改,該值也不能被設置成true
    5. });
    6. console.log(per3.sex); //'male'
    7. console.log(per3.propertyIsEnumerable("sex")); //false
    8. delete per3.sex; //不能刪除
    9. per3.sex = "female"; //不能修改
    10. console.log(per3.sex); //'male'
    11. Object.defineProperty(per3,"sex",{
    12. configurable:true, //報錯
    13. });
    14. per4 = {};
    15. Object.defineProperties(per4,{
    16. name:{
    17. value:"dwqs",
    18. writable:true
    19. },
    20. blog:{
    21. value:"http://blog.92fenxiang.com"
    22. },
    23. Name:{
    24. get:function(){
    25. return this.name;
    26. },
    27. set:function(value){
    28. this.name = value;
    29. },
    30. enumerable:true,
    31. configurable:true
    32. }
    33. });
    34. console.log(per4.name); //dwqs
    35. per4.Name = "Pomy";
    36. console.log(per4.Name); //Pomy

需要注意的是,通過這兩種方式來定義新屬性時,如果不指定特徵值,則默認是false,也不能創建同時具有數據特徵和訪問器特徵的屬性。可以通過Object.getOwnPropertyDescriptor()方法來獲取屬性特徵的描述,接受兩個參數:對象和屬性名。若屬性存在,則返回屬性描述對象。

    1. var desc = Object.getOwnPropertyDescriptor(per4,"name");
    2. console.log(desc.enumerable); //false
    3. console.log(desc.configurable); //false
    4. 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是否被凍結。

注意:凍結對象和封印對象均要在嚴格模式下使用。

    1. "use strict";
    2. var per5 = {
    3. name:"Pomy"
    4. };
    5. console.log(Object.isExtensible(per5)); //true
    6. console.log(Object.isSealed(per5)); //false
    7. console.log(Object.isFrozen(per5)); //false
    8. Object.freeze(per5);
    9. console.log(Object.isExtensible(per5)); //false
    10. console.log(Object.isSealed(per5)); //true
    11. console.log(Object.isFrozen(per5)); //true
    12. per5.name="dwqs";
    13. console.log(per5.name); //"Pomy"
    14. per5.Hi = function(){
    15. console.log("Hi");
    16. };
    17. console.log("Hi" in per5); //false
    18. delete per5.name;
    19. console.log(per5.name); //"Pomy"
    20. var desc = Object.getOwnPropertyDescriptor(per5,"name");
    21. console.log(desc.configurable); //false
    22. console.log(desc.writable); //false

注意,禁止修改對象的三個方法只對對象的自有屬性有效,對原型對象的屬性無效,仍然可以在原型上添加或修改屬性

    1. function Person(name){
    2. this.name = name;
    3. }
    4. var person1 = new Person("Pomy");
    5. var person2 = new Person("dwqs");
    6. Object.freeze(person1);
    7. Person.prototype.Hi = function(){
    8. console.log("Hi");
    9. };
    10. person1.Hi(); //"Hi";
    11. person2.Hi(); //"Hi";

來自:淡忘~淺思.

鏈接:http://www.ido321.com/1585.html 和 http://www.ido321.com/1586.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章