重溫JS基礎--引用類型(二)

我們接着上面一篇繼續~javascript

1. Date類型

JavaScript中的Date類型使用自UTC時間,1970年1月1日零時開始的毫秒數來保存日期。
建立一個日期對象:java

var now = new Date()
console.log(now) //Fri Sep 22 2017 15:42:29 GMT+0800 (中國標準時間)

在調用Date構造函數而不傳參數的狀況下,新建立的對象自動得到當前日期和時間數組

若是想根據特定的日期和時間建立日期對象,必須傳入表示日期的毫秒數(即從UTC時間開始截止到當前的毫秒數)。瀏覽器

var d = new Date(2165461213546)
console.log(d) //Sun Aug 15 2038 13:00:13 GMT+0800 (中國標準時間)
  • Date.parse() 、 Date.UTC()
    還有一些簡化的方法:Date.parse() 和 Date.UTC()。其中Date.parse()方法接受一個表示日期的字符串參數,而後嘗試根據這個字符串返回相應日期的毫秒數(可是在JavaScript中並無規定傳入改方法的參數的格式):
Date.parse()一般有如下幾種格式的參數:
1."月/年/日", 如:6/12/2017
2."英文月名 日,年",如:January 12,2004
3."英文星期幾 英文月名 日 年 時:分:秒 時區",如Tue May 25 2004 00:00:00 GMT-0700

var some = new Date(Date.parse("May 25, 2004"))
console.log(some) //Tue May 25 2004 00:00:00 GMT+0800 (中國標準時間)

//其實這樣寫也是能夠的,它在內部會先調用Date.parse()方法
var someDate = new Date("May 25, 2004");

Date.UTC()方法一樣也是返回表示日期的毫秒數,它和Date.parse()在構建值時使用不一樣的信息。Date.UTC()接受的參數分別是年份,基於0的月份,月中的哪一天,小時數,分鐘,秒,毫秒。在這些參數中,前兩個參數是必填的。若是沒有提供月中的日期數,則會默認爲1,若是省略其餘數,則都假設爲0.app

var y2k = new Date(Date.UTC(2000, 0))
console.log(y2k) //Sat Jan 01 2000 08:00:00 GMT+0800 (中國標準時間)

//其實這樣寫也是能夠的.
var d = new Date(2000, 0)
var d1 = new Date(2005,4,5,17,55,55)
以上代碼建立的日期對象,只不過此次的日期對象是基於系統設置的be
  • Date.now()
    該方法能夠獲取當前日期和時間的毫秒數:
var start = Date.now() //獲取開始時間

do() //作些啥

var stop = Date.now() //獲取結束時間

若是某些瀏覽器不支持的話,咱們能夠經過如下技巧得到當前時間的毫秒數,就是在前面加一個‘+’函數

var s = +new Date()
console.log(s) //1506069877901
  • 繼承的方法
    這裏說下繼承自Object的三個方法,toLocalString, toString, valueOf
var d = new Date()
d.toLocaleString() //"2017/9/22 下午4:49:43"
d.toString() //"Fri Sep 22 2017 16:49:43 GMT+0800 (中國標準時間)"
d.valueOf() //1506070183078

稍微下他們之間的區別,主要valueOf返回的是時間對象的毫秒數。this

  • 日期格式化方法
    Date類型還有一些專門用於將日期格式化爲字符串的方法:
var d = new Date()
d.toDateString()  //"Fri Sep 22 2017"
d.toTimeString() //"17:02:27 GMT+0800 (中國標準時間)"
d.toLocaleDateString() //"2017/9/22"
d.toLocaleTimeString() //"下午5:02:27"
d.toUTCString() //"Fri, 22 Sep 2017 09:02:27 GMT"

以上的這些方法都會根據系統環境而異。prototype

  • 日期/時間組件方法
    下面介紹一下Date對象提供的一些方法,能夠取得和設置日期值中特定部分的方法。
var d = new Date()

1. 獲取日期的毫秒數,和valueOf方法返回的值相同。
d.getTime() //1506071307006

2. 經過毫秒設置日期,會改變當前的日期對象。
d.setTime(1213123)
console.log(d) //Thu Jan 01 1970 08:20:13 GMT+0800 (中國標準時間)

3. 獲取4位數的年份
d.getFullYear() // 1970

4. 返回UTC日期的4位數年份
d.getUTCFullYear() //1970

5. 返回日期中的月份,從0開始算起
d.getMonth() // 8

6. 返回UTC日期中的月份,從0開始算起
d.getUTCMonth() //8

7. 返回日期月份中的天數, 若是傳入的值超過了該月應有的天數,則增長月份
d.getDate() // 22

8. 返回UTC日期月份中的天數, 若是傳入的值超過了該月應有的天數,則增長月份
d.getUTCDate() // 22

9. 返回日期中星期的星期幾(0表示星期天,6表示星期6)
d.getDay() //6

10. 返回UTC中的日期中的星期幾(0表示星期天,6表示星期6)
d.getUTCDay() //1

11.返回日期中的小時數(0~23),傳入的值超過23則增長月份中的天數
d.getHours() // 9

12. 返回UTC日期中的小時數(0~23),傳入的值超過23則增長月份中的天數
d.getUTCHours()

13. 返回日期中的分鐘數(0~59),也能夠進行設置。
d.getMinutes()

14. 返回UTC中日期的分鐘數,也能夠進行設置。
d.getUTCMinutes()

15. 返回日期中的秒數0~59,也能夠進行設置。
d.getSeconds()

16. 返回日期對象中UTC的秒數
d.getUTCSeconds()

17. 返回日期中的毫秒數,也能夠進行設置
d.getMilliseconds()

二. Function類型

在JavaScript中,函數其實就是一個對象,每一個函數都是Function類型的實例,並且和其餘引用類型同樣具備屬性和方法。
由於函數是一個對象,因此函數名實際上是一個指向函數對象的指針,不會與某個函數綁定
定義函數有兩種方法:函數聲明和函數表達式。指針

function fn(){ ... }

var fn = function() { ... };

還有一種方法就是經過Function構造函數。Function構造函數能夠接受任意數量的參數,但最後一個參數始終都是被當作函數體。前面的額參數則枚舉新函數的參數。code

var fn = new Function("num1", "num2", "return num1+num2")

從技術的角度來講,這是一個函數表達式。可是最佳實踐中並不推薦使用這種方法,由於這種方法會致使解析兩次代碼。第一次是正常的解析,第二次是解析傳入構造函數中的字符串。
因爲函數名是一個指針,因此函數可能會具備多個函數名:

function fn() {console.log(123)}
var fn1 = fn

若是如下操做還能夠繼續訪問:
fn = null
fn1() // 123
  • 沒有重載
    先看一個例子:
fucntion add (num){
    return num + 100
}

function add (num) {
    return num + 200
}
console.log(add(100)) // 300

而後改寫下上面的例子:

var add = function(num) {
    return num + 100
}

add = function (num) {
    return num + 200
}
add(100) //300
  • 函數表達式和函數聲明
    以前說過建立函數的方法有兩種,函數聲明和函數表達式,咱們來看下他們之間的區別。

js引擎在解析的時候會先讀取函數聲明,並使其在執行任何代碼以前能夠訪問。由於在代碼執行以前,解析器就已經經過一個函數聲明提高的過程,讀取並將函數聲明添加到執行環境中。對代碼求值時,JavaScript引擎會在第一遍聲明函數,並將它們放到源代碼樹的頂部。

函數表達式,必須等解析器執行到它所在的代碼行,纔會真正的被解釋執行:

console.log(fn(10, 10)) // error 'fn is not a function'

var fn = function(a, b) {
    return a + b
}

以上代碼會報錯,由於在函數位於一個初始化語句中。而不是一個函數聲明。換句話說,在執行到函數所在的語句以前,變量fn是不會保存對函數的引用。並且因爲第一行已經報錯了,代碼也不會繼續向下執行。

  • 做爲值的函數
    JavaScript中,函數名自己也是一個變量,因此函數能夠做爲值來使用。因此函數能夠做爲另一個函數的參數,並且能夠將一個函數做爲另一個函數的結果進行返回。
function callSomeFn(fn, arg) {
    return fn(arg)
}

如上,這個函數接受兩個參數,第一個參數應該是一個函數,第二個參數是要傳遞給函數的一個值。而後,就能夠以下:

function add(num) {
    return num+10
}
var res = callSomeFn(fn, 10)
console.log(res) //20

function greet (name) {
    return 'hello' + name
}
var res = callSomeFn(greet, 'world')
console.log(res) //'hello world'

並且,咱們能夠在一個函數中返回另一個函數,以下咱們經過函數建立另一個函數而後返回:

function create(proName) {
    return function (obj1, obj2) {
        var val1 = obj1[proName]
        var val2 = obj[proName]
        
        if(val1 < val2) {
            return -1
        }else if(val1 > val2) {
            return 1
        }else {
            return 0
        }
    }
}
  • 函數內部屬性

    • callee
      在函數內部,有兩個特殊的對象:arguments和this。arguments是一個類數組的對象,它包含傳入函數中的全部參數。該對象還有一個callee的屬性,該屬性是一個指針,指向的是擁有這個arguments對象的函數。
function factor(num) {
    if(num <= 1) {
        return 1
    }else{
        return num * factor(num - 1)
    }
}

如上是一個遞歸函數,經過callee能夠改寫成下面這樣:

function factor(num) {
    if(num < 1) {
        return 1
    }else{
        return num * argument.callee(num - 1)
    }
}
  • this
    函數內部的另外一個特殊對象是thisthis引用的是函數當前執行的環境對象。this是在函數調用的時候進行綁定的。徹底取決於函數的調用位置。

當某個函數在全局做用域中定義的,當在全局做用域中調用改函數時,this引用的是全局對象window.

var a = 12
function b() {
    console.log(this.a)
}
b() //12

在理解this的綁定過程以前,咱們瞭解一下調用位置,調用位置表示的是函數所被調用的位置,而不是其聲明的位置。

如何知道函數的調用位置,最重要的是分析函數的調用棧(即爲了到達當前執行位置所調用的全部函數)。那麼調用位置就是當前正在執行函數的前一個調用中。

function baz() {
  //當前的調用棧是baz
  //當前的調用位置是全局做用域,即當前調用棧的前一個調用
  console.log('baz');
  bar();
}

function bar() {
  //當前調用棧是 baz-->bar
  //當前的調用位置是:baz
  console.log('bar');
  foo();
}

function foo() {
  //當前的調用棧是baz --> bar --> foo
  //當前調用位置是bar
}

baz(); //<-- baz的調用位置就是全局做用域
  • caller
    另一個函數對象的屬性是:caller.該屬性保存着調用當前函數的函數引用。若是在全局做用域中調用當前函數,它的值爲null。
function outer() {
    inner()
}
function inner() {
    console.log(inner.caller)
}
outer()
  • 函數屬性和方法
    前面說過函數也是一個對象,因此函數也是有屬性和方法的。每一個函數都包含兩個屬性:length和prototype.其中length屬性表示函數接受命名參數的個數。
funtion setName(name) {
    console.log(name)
}
function sun(s1, s2){
    //...
}
console.log(setName.length) // 1
console.log(sun.length) //2

再說下prototype屬性,它是保存全部實例方法的真正所在。

再說下apply()和call()。這兩個方法的用途都是在特定的做用域中調用函數,實際上等於設置函數體內this對象的值。它們是每一個函數都具備的非繼承而來的方法。
apply()接受兩個參數,一個是在其中運行函數的做用域,另外一個是參數數組。其中第二個參數能夠是Array實例,也能夠是arguments對象。
call()和apply()相同,它們的區別僅在於接受參數的方式不一樣。call()第一個參數是this的指向,其他的參數都是直接傳遞給函數。

--本篇記錄不是一次性寫完,中間有不少事情耽擱了,零零散散的感受沒有什麼邏輯,隨便看看了各位~

相關文章
相關標籤/搜索