重温JS基础--引用类型(二)

咱们接着上面一篇继续~

1. Date类型

JavaScript中的Date类型使用自UTC时间,1970年1月1日零时开始的毫秒数来保存日期。
创建一个日期对象:

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.

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返回的是时间对象的毫秒数。

  • 日期格式化方法
    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"

以上的这些方法都会根据系统环境而异。

  • 日期/时间组件方法
    下面介绍一下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构造函数可以接受任意数量的参数,但最后一个参数始终都是被看成函数体。前面的额参数则枚举新函数的参数。

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的指向,其余的参数都是直接传递给函数。

--本篇记录不是一次性写完,中间有很多事情耽搁了,零零散散的感觉没有什么逻辑,随便看看了各位~

你可能感兴趣的:(webjavascript前端)