《JavaScript高級程序設計》回顧之引用類型(下)

這是我之前寫的文章,若有錯誤,請指正,謝謝!數組


Data

ES中的Date是從1970年1月1日午夜零點開始計算的,而且由毫秒數來保存。瀏覽器

建立日期

最簡單的建立日期的方法就是使用new關鍵字來調用Date構造函數:var date = new Date();在建立日期時,若是不傳入參數,則會建立表示當前時間的日期對象;若是想要建立特定的日期對象,必需要傳入表示這個日期的毫秒數。 爲了方便日期的建立,ES提供了2個方法:Date.parse 和 Date.UTC。 - Date.parse()方法接受一個表示日期的字符串參數,並試着根據這個參數返回表示日期的毫秒數。這個方法的實現方式因地區而異; - Date.UTC()方法一樣也返回一個表示日期的毫秒數,和Date.parse()方法不一樣的是,它規定了接收參數的格式。按照順序,這些參數分別表示:年份、從0開始計算的月份、月份中的日期、從0開始計算的小時數、分鐘、秒以及毫秒。在這七個參數中,只有第一個和第二個參數是必須的,若是第三個參數未傳入,則默認爲1,其餘參數爲傳入,都默認爲0.bash

console.log(new Date(Date.parse('Oct 7 1992'))); // Wed Oct 07 1992 00:00:00 GMT+0800 (CST) 
console.log(new Date(Date.UTC(2001, 11))); // Sat Dec 01 2001 08:00:00 GMT+0800 (CST)
複製代碼

示例中使用的 Date.UTC 方法獲得的時間因爲只傳入了2個參數,因此獲得的是2001年10月1日0點0分0秒0毫秒,通過是去轉換後輸出的時間是2001年10月1日8點。 在實際的實現過程當中,若是按照給 Date.parse 方法和 Date.UTC 方法傳遞參數的方式向new Date 傳遞參數的話,會在後臺自動調用 Date.parse 方法和 Date.UTC 方法:閉包

console.log(new Date('Oct 7 1992')); // Wed Oct 07 1992 00:00:00 GMT+0800 (CST)
console.log(new Date(2001, 11)); // Sat Dec 01 2001 00:00:00 GMT+0800 (CST)
複製代碼

使用直接向日期構造函數中傳遞 Date.UTC 方法的參數的形式建立日期和調用 Date.UTC 方法後建立日期有一點不一樣,日期和時間都會依據本地時間而不是GMT時間來建立:上述的例子中建立出來的時間是0點而不是8點。app

日期的方法

和其餘的引用類型相同,Date 也重寫了 valueOf、toString 和 toLocaleString 方法。 valueOf 方法返回日期的毫秒錶示,能夠用於日期大小的比對:較早的日期小於較晚的日期; toString 方法一般返回帶有時區信息的日期和時間,其中的小時通常用0-23表示; toLocaleString 方法會按照瀏覽器設置的地區返回時間和日期,通常會包含 AM 和 PM(上午和下午); 值得注意得失,不一樣瀏覽器對 toString 方法和 toLocaleString 方法的返回結果有所不一樣。 Date 類型有一些將日期格式化爲字符串的方法以及許多設定和獲取日期中部分信息的方法,因爲數量太多,這裏也不展開了,有興趣的能夠本身去查找相關文檔。函數

Function

ES中的函數其實是對象,全部函數都是 Function 的實例,也都擁有屬性和方法。 因爲函數是對象,因此函數名和對象名同樣,只是一個指向函數對象的指針。ui

建立函數

使用new關鍵字調用 Function 構造函數一樣也能建立函數,它接收任意多的參數,可是最後一個參數表示的是函數體,而前面的參數則是傳遞給函數的參數,舉個例子:this

var func = new Function('a', 'b', 'c', 'return a + b + c');
console.log(func(1, 2, 3)); // 6
複製代碼

除了使用構造函數建立函數,還可使用函數聲明和函數表達式的方法來建立函數: - 函數聲明:function func () {} - 函數表達式:var func = function () {} 在 JS 中,函數聲明和變量聲明同樣都會在解析的時候被提高,函數聲明的優先級甚至高於變量聲明。舉個例子:spa

let num = 1;
function func () {
    num = 2;
    function num () {}
}
func();
console.log(num); // 1
複製代碼

由於函數聲明的優先級高於變量聲明的緣故,這段代碼獲得的結果是1。 在這個例子中,執行函數 func 的時候,會在做用域鏈中尋找 num,若是在函數做用域中找到了,則會給它賦值爲2;若是沒有在函數做用域中找到,則會給全局做用域中的 num 賦值爲2。因爲函數聲明提高的優先級高於變量聲明,函數做用域中存在名爲 num 的函數名變量,它會被賦值爲2,而全局做用域中的變量 num 仍舊是1。 使用函數表達式另一個特色就是函數的調用可以寫在函數表達式以前,舉個例子:prototype

func(); // 1
function func () {
    return 1;
}
複製代碼

因爲聲明提高的緣由,函數聲明語句永遠在函數調用語句以前執行。 可是函數表達式就不能這麼使用了,舉個例子:

func(); // TypeError: func is not a function
var func = function () {
    return 1;
}
複製代碼

這段代碼等同於:

func(); // TypeError: func is not a function
var func;
func = function () {
    return 1;
}
複製代碼

var func;這句變量聲明語句會由於提高而被先執行,可是變量 func 卻沒有被賦值爲函數——只有執行到賦值語句的時候才它會被賦值,因此在執行func()的時候會報錯,提示 func 不是一個函數。

函數重載

ES 中的函數不存在重載。 函數名不是函數自己,只是一個函數對象的指針,因此再次給函數名變量賦值新的函數會覆蓋掉本來的函數對象指針。

一等公民函數

在 ES 中函數名是對函數對象的引用,它自己就是一個變量,因此可以像其餘的變量同樣做爲值來使用,也就是說函數可以做爲參數傳遞給另一個函數,也能做爲另一個函數的返回值來使用,這是 ES 中閉包實現的基礎。 可是須要注意的是,函數做爲參數傳遞到另一個函數中時,傳遞的是這個函數的引用而不是函數自己。 而函數做爲返回值來使用是一種極爲有用的技術,也是高階函數和函數柯里化的實現方式。

arguments

arguments 是一個相似數組的對象,保存着傳入函數的全部參數,即便在函數聲明的時候沒有聲明的參數也在其中,舉個例子:

function func (a, b) {
    console.log(...arguments);
}
console.log(func(1, 2, 3, 4)); // 1 2 3 4
複製代碼

這個例子中,咱們只聲明瞭2個參數,可是 arguments 中卻包含着傳入的4個參數。 arguments 有一個屬性 callee,指向擁有這個 arguments 的函數,修改下上面這個例子:

function func (a, b) {
    console.log(arguments.callee);
}
console.log(func(1, 2, 3, 4)); // f func (a, b) { console.log(arguments.callee); }
複製代碼

當咱們須要在函數內部調用函數自身的時候使用arguments.callee()可以將函數和函數名解藕,防止函數名變量被從新賦值而致使的錯誤,請看下面的例子:

function a (count) {
    if (count > 0) {
        a(count - 1);
    }
}
var b = a;
a = null;
b(3); // Uncaught TypeError: a is not a function
複製代碼
function a (count) {
    if (count > 0) {
        arguments.callee(count - 1);
    }
}
var b = a;
a = null;
a(3); 
複製代碼

第一個例子中,因爲 a 被賦值爲 null,切斷了它對函數的引用,因此在調用a的時候報錯了;而第二個例子因爲調用的是 arguments.callee,始終是函數的引用,因此代碼可以正常運行。 要注意的是,在嚴格模式下訪問 arguments.callee 會致使錯誤。

this

this 是函數中一個極爲常見同時也是很容易搞錯的關鍵字,一般狀況下,它表示的是函數被調用時候的執行上下文對象,請看例子:

function a () {
    console.log(this);
}
var obj = {};
obj.a = a;
a(); // Window {}
obj.a(); // { a: f }
複製代碼

在全局環境中調用函數,函數的 this 就是 Window 這個全局對象;而將函數 a 賦值給對象 obj 的屬性 a 後,在執行obj.a()的時候,this 就變成了 obj。 函數的 this 不可以在函數執行的時候修改,可是能夠在函數執行前或者執行後進行修改。每一個函數都擁有三個非繼承來的方法:call、apply 和 bind,它們可以修改函數執行時的做用域。 call 方法和apply 方法的做用相同,都是在函數執行的時候設置 this 的值,它們接受不了的第一個參數都是 this 的;而這兩個方法不一樣的地方在於,apply 方法只能接收兩個參數,第二個參數是一個數組,裏面存儲着須要依次傳遞給函數的參數,而 call 方法接收任意多的參數,除了第一個參數以外,其餘的參數就是須要依次傳遞給函數的參數。請看例子:

var obj = {
    a: 0,
    b: 0
};
function a (arg1, arg2) {
    this.a = arg1 + arg2;
}
function b (arg1, arg2) {
    this.b = arg1 + arg2;
}
a.apply(obj, [1, 2]);
b.call(obj, 3, 4);
console.log(obj); // { a: 3, b: 7 }
複製代碼

而函數的 bind 方法則是會建立一個新的函數,這個函數的函數體和調用 bind 方法的函數的函數體相同,可是它的 this 的值會被綁定爲 bind 方法傳入的第一個參數。 bind 方法接收任意多的參數,除了第一個參數外,其餘的參數是傳遞給被綁定函數的參數,它們會在被綁定函數調用的實參前傳入,看個例子:

var obj = {
    a: 0
};
function a (arg1, arg2) {
    console.log(...arguments);
    obj.a = arg1 + arg2;
}
var b = a.bind(obj, 1, 2);
b(3, 4); // 1 2 3 4
console.log(obj); // { a: 3 }
複製代碼

能夠看到,函數 b 的 this 被綁定到了 obj,而 bind 方法傳入的兩個參數1和2的傳入順序優先於函數b調用是傳入的參數3和4。 關於綁定函數的 this 還有許多的方法能夠作到,咱們在這裏就不往下討論了。

函數的屬性

函數是對象,因此它也擁有本身的屬性。

  1. length:函數的 length 屬性表示的是函數聲明的參數個數,這個屬性是沒法修改的;
  2. caller:函數的 caller 屬性保存着調用當前函數的函數的引用,若是當前函數在全局環境中被調用,則這個屬性爲 null。

函數的屬性

函數是對象,因此它也擁有本身的屬性。

  1. length:函數的length屬性表示的是函數聲明的參數個數,這個屬性是沒法修改的;
  2. caller:函數的caller屬性保存着調用當前函數的函數的引用,若是當前函數在全局環境中被調用,則這個屬性爲null。在嚴格模式下不能給caller屬性賦值,不然會致使錯誤發生。看個例子:
    function a () {
        b();
    }
    function b () {
        console.log(arguments.callee.caller);
    }
    a(); // function a () { b(); }
    複製代碼
  3. prototype:函數的prototype屬性是保存它的實例的全部方法和屬性的地方;在建立自定義實例和使用繼承的時候,這個屬性是極爲重要的。在ES5中,prototype是一個沒法被枚舉的屬性,不能使用for-in來訪問它。要的。在ES5中,prototype是一個沒法被枚舉的屬性,不能使用for-in來訪問它。

感謝閱讀,我的成果,請勿轉載:)

相關文章
相關標籤/搜索