1. Object 类型
创建一个对象有两种方式:
1 | # 构造函数 |
这两种方式创建对象区别不大,后者更常被使用在参数中,它能够更清晰的表达函数接收了什么,如:
1 | new Vue({ |
获取对象的属性有两种方式:
1 | const obj = { |
两种方式都可以获取到 name 属性,但对于 test attr 属性而言,打点的方式将不可用,只能使用 [] 获取。
值得一提的是,[] 方式可以使用变量来动态获取属性,但除非必须使用变量来访问属性,否则我们建议使用点表示法。
2. Array 类型
Array 用很多种创建方式:
1 | const colors = new Array(); |
上述写法都是合理的,但需要注意如下写法可能会带来问题,在部分浏览器中,会因为最后一个逗号解析为具有4个元素的数组。
1 | const colors = [ 'あか', 'あお', 'しろ', ] |
同样的,如下代码也可能带来问题,强烈建议不要使用这种语法。
1 | const colors = [ , , , ,]; |
2.1 Array 的长度
使用 length 可以获取数组的长度:
1 | const colors = [ 1, 2, 3, 4]; |
如上代码会输出 4。
有一点很有趣,修改一个 Array 的长度是允许的:
1 | const colors = [ 1, 2, 3, 4]; |
如上代码首先将 colors 数组的长度修改为 10,colors 数组的后面被填充了 6 个 undefined ,而后我们又修改其长度为 3,则 colors 数组从第 3 位(下标为 2)开始都被截掉了。
2.2 类型检测
前面我提到过,使用 typeof 关键字测试数组类型会返回 object。
1 | console.log(typeof []); |
我们也提到,对于这种情况我们可以使用 instanceof 操作符:
1 | console.log([] instanceof Array); |
这将返回 true。但这并不代表着问题解决了,事实上 instanceof 操作符在执行时会假设只有一个全局执行环境,如果页面中有两个以上的执行环境(如使用了 iframe 等场景),则会存在两个不同的 Array 构造函数,因而 instanceof 可能会返回一个错误的结论。为了解决这一问题,ES5 新增的 isArray() 方法彻底解决了这个问题。
1 | console.log(Array.isArray([])); |
2.3 类型转换
所有对象都具有 toLocaleString(),toString(),valueOf() 方法,当数组调用 toString() 方法的时候,会将所有元素组合在一起,并使用逗号分隔行成字符串。
1 | console.log([ 1, 2, 3].toString()); |
上述语句输出 '1,2,3'。toLocaleString() 与 toString() 方法相同,两者在调用时都会使用数组的每个元素来分别调用 toString() 与 toLocaleString() 方法。
另外我们也可以使用 join() 方法使用指定的分隔符将数组转换为字符串,如下代码输出 '1|2|3|4'。
1 | [ 1, 2, 3, 4 ].join('|'); |
值得说明的是,如果某个元素是 null ,undefined ,那么该值在调用 toLocaleString(),toString(), join 时都会以空字符串表示。
2.4 使数组具备栈的特性
栈是一种先进后出的数据结构,虽然数组并不是栈,但我们依然可以使用指定的方法使数组具备栈的特性。使用 push() 方法可以向数组中添加一个元素,该方法的返回值是数组的长度,对应的,我们可以使用 pop() 方法从数组中取出最后一个元素。
1 | const arr = [ 1, 2, 3 ]; |
如上代码分别打印 4 [ 1, 2, 3, 5 ] [ 1, 2, 3 ] 。
2.5 时数组具备队列的特性
既然提到了栈,难免要提到队列,和栈不同,队列是一种先进先出的数据结构。当我们使用 shift() 方法时,可以去掉数组第一项元素,也就是先进先出的实现了。
1 | const arr = [ 1, 2, 3 ]; |
如上代码分别打印 4 [ 1, 2, 3, 4 ] [ 2, 3, 4 ] 。
2.6 数组重排
能够实现数组重排的方法有两个:reverse() 和 sort() ,但需要说明的是,这两个方法在比较元素大小的时候均使用 ASCII 码值,也就是说,元素 10 会小于元素 2。
1 | const arr = [1, 2, 10, 4, 6]; |
该代码进行排序后会返回序列 1, 10, 2, 4, 6 ,同样的,当使用 reverse() 时,会返回序列 6, 4, 2, 10, 1 。
这样的序列是不符合我们对数字排序的要求的,因此我们可以为 sort() 方法传递一个方法协助它完成排序:
1 | const arr = [1, 2, 10, 4, 6]; |
使用如上代码将得到序列 1, 2, 4, 6, 10 。
2.7 操作方法
2.7.1 concat
当需要将两个数组连接在一起的时候,我们可以使用 concat() 方法,这对增量更新非常有用。
1 | console.log([1,2,3].concat([5,6,7])); |
上述代码输出 1, 2, 3, 5, 6, 7 。
2.7.2 slice
slice 方法用于截取数组中的指定片段,它接收两个参数,第一个参数为起始位置,当不传递第二个参数时,返回参数 1 至结尾的数组片段:
1 | [1, 2, 3, 4, 5, 6].slice(2); |
上述代码返回下标 2 开始到结尾的所有元素组成的新数组。
当传递第二个参数时,则返回第一个参数到第二个参数范围内的元素组成的新数组:
1 | [1, 2, 3, 4, 5, 6].slice(2, 5); |
另外该方法的参数允许为负数,当参数为负数时,实际使用该负数于数组长度相加得到的结果作为下标使用。
2.7.3 splice
splice() 方法用来向数组插入项目,但根据其参数的传递方式,我们可以使用这个方法实现删除,插入,替换等操作:
1 | let arr = [1, 2, 3, 4, 5, 6]; |
2.7.4 位置方法
查找数组中元素的位置可以使用 indexOf() 和 lastIndexOf() 方法,这个两个方法都接收两个参数,参数 1 是要查找的元素,参数二为开始查找的起始位置,区别在于 indexOf() 从前往后查找,而 lastIndexOf() 从后往前查找。当两个方法找到指定的元素时,它们会返回元素的下标,反之返回-1.
1 | const arr = [ 1, 2, 3, 4, 5]; |
2.8 迭代方法
迭代数组可以使用如下五种方式:
every():该函数接受回调函数并使用每一个元素执行,当所有元素的执行结果都是true时,则该函数返回true。fileter():该函数接受回调函数并使用每一个元素执行,返回所有能够返回true的项目组成的数组。forEach():使每一个元素执行回调函数,无返回值。map():使每一个元素执行回调函数,返回执行回调函数后的元素组成的数组。some():该函数接受回调函数并使用每一个元素执行,其中有一个元素执行结果为true时则该函数返回true。
2.9 归并方法
归并方法主要是将上一次执行的结果做为下一次执行函数的参数,可以使用 reduce() 方法和 reduceRight() 方法。其中 reduce() 方法从项目的第一项开始而 reduceRight() 从项目的最后一项开始。
3. Date 类型
就像它的名字一样,Date 类型用于创建日期数据,Date 类型的 valueOf() 方法会返回该时间对应的毫秒数。
4. Function 类型
声明一个函数可以使用如下方式:
1 | function fun1 () { |
三种方式都是合法的,但第三种语法会导致代码别解析两次,第一次解析赋值表达式,第二次解析构造函数,同时这种语法也不便于理解,因此不推荐使用。
4.1 无重载
JavaScript 函数没有重载的特性,当重复定义函数时,函数会被覆盖。
4.2 函数申明与函数表达式
上面提到这两种方法都是合法的,但解析器会先读取函数申明,也就是说声明式函数存在变量提升,而函数表达式不会,因而声明式的函数可以先使用后申明,而函数表达式不可以。
4.3 函数内部属性
函数内部有两个特殊的对象它们分别是 arguments 和 this 。arguments 是一个类数组对象,它有一个 callee 属性保存着拥有这个 arguments 对象的函数指针。
1 | function fun1 () { |
上述函数返回 true 。
函数还有另外一个属性 caller ,该属性返回调用当前函数的函数应用,如果在全局环境调用,则返回 null 。
4.4 函数属性与方法
函数的 length 属性返回参数的个数:
1 | function fun1 (num1, num2, num3) { |
每个函数都有两个方法 apply 和 call ,它们都可以为函数绑定 this,不过 call 的参数需要一一列举,而 apply 可以直接传递参数表。
至于 bind ,它会创建一个函数实例,同时将 this 绑定到函数内部。
5. 基本包装类型
关于本章节,没有太多可以讲的内容,一些常见的方法此处不再赘述。
5.1 Boolean
没卵用系列,看如下代码:
1 | const booleanObj = new Boolean(false); |
如上代码返回 true,因为 new Boolean(false) 实际返回了一个对象而非 Boolean 值,这会给人带来误解。
1 | console.log(typeof (new Boolean(true))); |
就像上面说的,此处返回 object 。
5.2 Number
Number.toFixed() 方法具有四舍五入的功能。
5.3 String
str.charAt(1) 基本等同于 str[1]。
除此之外还可以使用 str.charCodeAt() 来获取指定字符的字符编码。
6. 单体内置对象
6.1 Global
Global 对象提供了两个 URI 编码方法:encodeURI() 和 encodeURIComponent() ,前者可以编码整个 URI 中的空格,而后者会编码所有非字母数字字符。因而我们通常用 encodeURIComponent() 来编码 URI 中的参数部分。
对应的,我们也可以使用 decodeURI() 和 decodeURIComponent() 方法进行 URI 解码。
eval() 运行执行 JavaScript 代码,但该方法也会带来注入风险,在不了解的情况下不应该轻易使用。
最后,Global 对象是无法直接访问的,但浏览器中的 window 对象包含了 Global 的一部分作为实现,也正因为如此,全局变量和函数最终都成了 window 对象的变量或函数。