JavaScript學習——物件

weixin_33860722發表於2015-08-04
1. 本文是在學習廖雪峰先生的JavaScrip教程 後的歸納

一、標準物件

  1. typeof
    • JavaScript的世界,一切都是物件
    • typeof操作符獲取物件的型別,總是返回一個字串
    typeof 123; // 'number'
    typeof NaN; // 'number'
    typeof 'str'; // 'string'
    typeof true; // 'boolean'
    typeof undefined; // 'undefined'
    typeof Math.abs; // 'function'
    typeof null; // 'object'
    typeof []; // 'object'
    typeof {}; // 'object'
    
    • numberstringbooleanfunctionundefined有別於其他型別
    • nullArray{}的型別是object,故typeof無法區分三者
  2. 包裝物件
    • numberboolean、和string都有包裝型別,使用new建立
    var n = new Number(123); // 123,生成了新的包裝型別
    var b = new Boolean(true); // true,生成了新的包裝型別
    var s = new String('str'); // 'str',生成了新的包裝型別
    
    • 包裝物件雖和原來的值一樣,但型別已經發生變化,都變成object
    • 儘量不要使用包裝型別,尤其是string型別
    • NubmerBooleanString沒寫new時,可以被當成普通函式,把任何型別的資料轉換為numberbooleanstring型別(不是包裝型別)
    var n = Number('123'); // 123,相當於parseInt()或parseFloat()
    typeof n; // 'number'
    
    var b = Boolean('true'); // true
    typeof b; // 'boolean'
    
    var b2 = Boolean('false'); // true! 'false'字串轉換結果為true!因為它是非空字串!
    var b3 = Boolean(''); // false
    
    var s = String(123.45); // '123.45'
    typeof s; // 'string'
    
  3. 總結
    • 不要使用new Number()、new Boolean()、new String()建立包裝物件;
    • parseInt()parseFloat()來轉換任意型別到number
    • String()來轉換任意型別到string,或者直接呼叫某個物件的toString()方法;
    • 通常不必把任意型別轉換為boolean再判斷,因為可以直接寫if (myVar) {...}
    • typeof操作符可以判斷出number、boolean、string、function和undefined
    • 判斷Array要使用Array.isArray(arr)
    • 判斷null請使用myVar === null
    • 判斷某個全域性變數是否存在用typeof window.myVar === 'undefined'
    • 函式內部判斷某個變數是否存在用typeof myVar === 'undefined'
    • nullundefined 沒有toString()方法
    • 特殊情況:number使用toString()方法
    123..toString();//兩個點
    (123).toString();
    

二、Date

  1. Date表示日期和時間
    • 獲取系統時間如下:
    var now = new Date();
    now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
    now.getFullYear(); // 2015, 年份
    now.getMonth(); // 5, 月份,注意月份範圍是0~11,5表示六月
    now.getDate(); // 24, 表示24號
    now.getDay(); // 3, 表示星期三
    now.getHours(); // 19, 24小時制
    now.getMinutes(); // 49, 分鐘
    now.getSeconds(); // 22, 秒
    now.getMilliseconds(); // 875, 毫秒數
    now.getTime(); // 1435146562875, 以number形式表示的時間戳
    
    • 建立一個指定日期和時間的Date物件,可以用:
    var d = new Date(2015, 5, 19, 20, 15, 30, 123);
    d; // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)
    
    • JavaScript的月份範圍用整數表示是0-11
    • 建立一個指定日期和時間的方法是解析一個符合ISO 8601格式的字串
    • Data.parse('2015-06-24T19:49:22.875+08:00'); 返回一個時間戳;該時間戳很容易轉換成Date
  2. 時區
    • Date物件表示的時間總是按瀏覽器所在時區顯示的,不過,我們既可以顯示本地時間,也可以顯示調整後的UTC時間
    var d = new Date(1435146562875);
    d.toLocaleString(); // '2015/6/24 下午7:49:22',本地時間(北京時區+8:00),顯示的字串與作業系統設定的格式有關
    d.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC時間,與本地時間相差8小時
    
    • 時間戳: 是一個自增的整數,它表示從1970年1月1日零時整的GMT時區開始的那一刻,到現在的毫秒數。

三、RegExp

  1. 基本
    • \d可以匹配一個數字,\w可以匹配一個字母或數字
    • .可以匹配任意字元,*表示任意個字元,用+表示至少一個字元,?表示0個或1個字元,用{n}表示n個字元,用`{n,m}表示n-m個字元
    • \s可以匹配一個字元(也包括Tab等字元)
  2. 進階
    • []表示範圍,A|B可以匹配A或B
    • ^ 表示行的開頭,^\d表示必須以數字開頭
    • & 表示行的結束
  3. JavaScript中使用正規表示式
    • 寫法一: /正規表示式/
    • 寫法二: new RegExp('正規表示式)`建立一個RegExp物件
    • 示例:
      var re = /^\d{3}\=\d{3,8}$/;
      re.test('010-12345');//true
      
    • RegExp物件test()方法用於測試給定的字串是否符合規定
    • 切分字串:用正規表示式來把不規範的輸入轉化成正確的陣列
    • 分組:提取子串的功能,通過()表示的就是要提取的分組(Group)
      var re = /^(\d{3})-(\d{3,8})$/;
      re.exec('010-12345'); // ['010-12345', '010', '12345']
      re.exec('010 12345'); // null
      
      在正則表示式中定義了組,就可以在RegExp物件上用exec()方法提取出子串來
      exec()方法在匹配成功後,會返回一個Array,第一元素始終是原始字串本身,後面的字串表示匹配成功的子串
      exec()方法在匹配失敗後,返回null
    • 正規表示式預設的是貪婪匹配,也就是匹配儘可能多的字元
    • \d+加個?就可以採用貪婪匹配
  4. 全域性搜尋
    • g表示全域性匹配
    • var r1 = /test/g; 等價於 var r2=new RegExp('test','g');
    • 全域性匹配可以多次執行exec()方法來搜尋一個匹配的字串,當指定g標誌後,每次執行exec(),正規表示式本身會更新lastIndex屬性,表示上次匹配到的最後索引
    var s = 'JavaScript, VBScript, JScript and ECMAScript';
    var re=/[a-zA-Z]+Script/g;
    
    // 使用全域性匹配:
    re.exec(s); // ['JavaScript']
    re.lastIndex; // 10
    
    re.exec(s); // ['VBScript']
    re.lastIndex; // 20
    
    re.exec(s); // ['JScript']
    re.lastIndex; // 29
    
    re.exec(s); // ['ECMAScript']
    re.lastIndex; // 44
    
    re.exec(s); // null,直到結束仍沒有匹配到
    
    • 全域性匹配類似搜尋,因此,不能使用/^...$/,那樣只會最多匹配一次
    • 正規表示式還可以指定i標誌,表示忽略大小寫,m標誌,表示執行多行匹配

四、JSON

  1. 定義
    • JSON是JavaScript Object Notation的縮寫,是一種資料交換格式
    • 由道格拉斯·克羅克福特(Douglas Crockford)發明
    • JSON實際上是JavaScript的一個子集
    • JSON資料型別和JavaScript基本一樣: number,boolean,string,null,array,object以及前面的任意組合
    • JSON定死了字符集為UTF-8,對多語言沒有問題
    • 為了統一解析,JSON的字串規定必須用"",Object的鍵也必須用雙引號""
    • 把任何JavaScript物件變成JSON,就是把這個物件序列化成一個JSON格式的字串
    • 收到一個JSON格式的字串,只需要把它反序列化成一個JavaScript物件
  2. 序列化
    • 示例:
    var xiaoming = {
        name: '小明',
        age: 14,
        gender: true,
        height: 1.65,
        grade: null,
        'middle-school': '\"W3C\" Middle School',
        skills: ['JavaScript', 'Java', 'Python', 'Lisp']
    };
    
    JSON.stringify(xiaoming); // '{"name":"小明","age":14,"gender":true,"height":1.65,"grade":null,"middle-school":"\"W3C\" Middle School","skills":["JavaScript","Java","Python","Lisp"]}'
    
    • 輸出比較規範: JSON.stringify(xiaoming, null, ' ');
    • JSON.stringify(xiaoming,['name','skill'],' ');
      第二個引數用來篩選物件的鍵值,只輸出指定的屬性,則Array
    • JSON.stringify(xiaoming, convert, ' ');還可以傳入一個函式(function convert(key,value){})
    • 還可以為物件定義一toJSON()方法
    var xiaoming = {
        name: '小明',
        age: 14,
        gender: true,
        height: 1.65,
        grade: null,
        'middle-school': '\"W3C\" Middle School',
        skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
        toJSON: function () {
            return { // 只輸出name和age,並且改變了key:
                'Name': this.name,
                'Age': this.age
            };
        }
    };
    
    JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'
    
  3. 反序列化
    • 拿到一JSON格式的字串,我們直接用JSON.parse()把它變成一個JavaScript物件
    • 示例:
    JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
    JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
    JSON.parse('true'); // true
    JSON.parse('123.45'); // 123.45
    
    • JSON.parse()可以接收一個函式,用來轉換解析出來的屬性
    • 示例:
    JSON.parse('{"name":"小明","age":14}', function (key, value) {
         // 把number * 2:
         if (key === 'name') {
             return value + '同學';
         }
         return value;
    });// Object {name: '小明同學', age: 14}
    

五、物件導向程式設計

  1. 物件導向
    • 類和例項是大多數物件導向程式設計的基本概念
    • JavaScript中,JavaScript不區分類和例項的概念,而是通過原型(prototype)來實現物件導向程式設計
    • 示例:
    var Student = {
        name: 'Robot',
        height: 1.2,
        run: function () {
            console.log(this.name + ' is running...');
        }
    };
    
    var xiaoming = {
        name: '小明'
    };
    
    xiaoming.__proto__ = Student;
    
    • JavaScript的原型鏈和Java的Class的區別就是在於,JavaScript沒有"Class"概念,所有物件都是例項,所謂繼承關係不過是把一個物件的原型指向另一個物件而已
    • 編寫JavaScript程式碼時,不要直接用obj.__proto__去改變一個物件的原型,可以使用Object.create()方法可以傳入一個原型物件,並建立一個基於該原型的新物件,但新物件什麼屬性都沒有
    • 示例:
    function createStudent(name) {
        // 基於Student原型建立一個新物件:
        var s = Object.create(Student);
        // 初始化新物件:
        s.name = name;
        return s;
    }
    

六、建立物件

  1. 原型鏈
    • JavaScript對每個建立的物件都會設定一個原型,指向它的原型物件
    • 當使用obj.xxx訪問一個物件的屬性時,JavaScript引擎先在當前物件上查詢該屬性,如果沒有找到,就到其原型物件上找,如果還沒找到,就到Object.prototype物件,最後還沒找到,就只能返回undefined
      示例:
    var arr=[1,2,3];
    原型鏈是:
        arr---->Array.prototype-->Object.prototype--->null
    其中`Array.prototype`定義了`indexOf()`、`shift()`等方法,
     因此可以在所有`Array`物件上直接呼叫執行方法
    
    function foo(){
        return 0;
    }
    foo--->Function.prototype--->Object.prototype--->null
    其中Function.prototype定義了apply()方法
    
    • 如果原型鏈很長,那麼訪問一個物件的屬性會因為耗費更多時間查詢而變得更慢,因此,原型鏈不宜太長
  2. 建構函式
    • 除了{...}直接建立物件外,還可以通過建構函式的方法來建立物件
    • 示例:
    function Student(name) {
        this.name = name;
        this.hello = function () {
            alert('Hello, ' + this.name + '!');
        }
    }   
    
    var xiaoming=new Student('xiaoming');
    原型鏈如下:
    xiaoming---->Student.prototype--->Object.prototype--->null
    
    • 在JavaScript中,可以用關鍵字new來呼叫這個函式,並返回一個物件
    • 不寫new,是個普通函式,加上new就變成一個建構函式,它繫結this指向新建立的物件,並預設返回this,即不需要在最後加return this
    • new Student()建立的物件還從原型上獲得了一constructor屬性,其指向Student本身
    xiaoming.constructor === Student.prototype.constructor; // true
    Student.prototype.constructor === Student; // true
    Object.getPrototypeOf(xiaoming) === Student.prototype; // true
    xiaoming instanceof Student; // true
    
    • 讓建立物件共享一個函式時,根據物件的屬性查詢原則,可以把函式移到物件共同的原型上
    • 為了區分普通函式和建構函式,按照約定,建構函式首字母大寫,而普通函式首字母小寫
    • 一個常用的程式設計模式:
    function Student(props) {
        this.name = props.name || '匿名'; // 預設值為'匿名'
        this.grade = props.grade || 1; // 預設值為1
    }
    Student.prototype.hello = function () {
        alert('Hello, ' + this.name + '!');
    };
    function createStudent(props) {
        return new Student(props || {})
    }
    var xiaoming = createStudent({
        name: '小明'
    });
    
    xiaoming.grade; // 1
    優點: 這個`createStudent()`函式有幾個優點:
        a. 不需要new來呼叫
        b. 引數非常靈活,可以傳參,也可以不傳參
    

七、原型繼承

  1. 繼承
    • Java等傳統的基於Class語言,本質上是擴充套件一個已有的Class,並生成新的Subclass,由於這類語言嚴格區分類和例項,繼承實際上是型別的擴充套件
    • JavaScript 採用的原型繼承,無法直接擴充套件一個Class
    • JavaScript的原型繼承實現方式就是:
      • 定義新的建構函式,並在內部用call()呼叫希望"繼承"的建構函式,並繫結this
      • 藉助中間函式F實現原型鏈繼承,最好通過封裝的extendes函式完成
      • 繼續在新的建構函式的原型上定義新方法

相關文章