JS高程Chapter-5 引用类型

对JS高级程序设计第五章引用类型的内容做一个梳理~

Object类型

创建Object实例的方式:

  • 使用new操作符后跟object构造函数
  • 使用对象字面量表示法

Object类型数据变化侦测原理

Object可以通过Object.defineProperty将属性转换成getter/setter的形式来追踪变化,读取数据时会触发getter,修改数据时会触发setter.
我们需要在getter中收集有哪些依赖使用了数据。当setter被触发时,去通知getter中收集的依赖数据发生了变化。


Array类型

创建数组的基本方式:

  • 使用Array构造函数
  • 使用数组字面量表示法

检测数组的方法

  • instanceof操作符
  • Array.isArray()方法

操作方法
操作方法包括concat(),slice(),splice()方法

用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// concat()
var colors = ['red', 'blue', 'green']
var colors2 = colors.concat('yellow', ['black', 'brown'])
// ['red', 'blue', 'green', 'yellow','black', 'brown']

// slice() 基于当前数组创建新数组,接受两个参数,返回项的起始位置和结束位置,该方法不会影响原始数组
var colors3 = colors2.slice(1) // ['blue', 'green', 'yellow','black', 'brown']
var colors4 = colors2.slice(1,4) // ['blue', 'green', 'yellow']

// splice() 最强大的数组操作,可实现删除、插入和替换操作
var colors = ['red', 'green', 'blue']
var removed = colors.splice(0, 1) // 删除第一项
console.log(colors) // ['green', 'blue']
console.log(removed) // ['red']

removed = colors.splice(1, 0 , 'yellow', 'orange') // 从位置一开始插入两项
console.log(colors) // ['green', 'blue' ,'yellow' ,'orange']
console.log(removed) // []

removed = colors.splice(1,1,'red') // 从位置1删除一项,插入一项
console.log(colors) // ['green', 'red', 'yellow', 'orange']
console.log(removed) // ['blue']

位置方法

  • indexOf() 从数组开头开始向后查找
  • lastIndexOf() 从数组末尾开始向前查找
    返回查找项在数据中 的位置,没找到的情况下返回-1

迭代方法
接受两个参数,要在每一项上运行的函数和运行该函数的作用域对象(可选)。运行函数接受三个参数,数组项的值、该项在数组中的位置和数组对象本身。

  • every() :对数组中每一项运行给定函数,如果每一项都返回true,则返回true
  • filter() :返回该函数会返回true的项组成的数组。
  • forEach() :无返回值。
  • map() :返回函数每次调用的结果组成的数组。
  • some() :如果函数有一项返回true,则返回true

归并方法
迭代数组的所有项,构建一个最终返回的值。接收两个参数:一个在数组每一项上调用的函数和作为归并基础的初始值(可选)。
调用的函数可接受四个参数:前一个值、当前值、项的索引和数组对象。

  • reduce() 从数组第一项开始,逐个遍历到最后。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 使用reduce模拟map
Array.prototype._map = function(fn, callbackThis) {
// 最终返回的新数组
let res = [];
// 定义回调函数的执行环境
// call第一个参数传入null,则 this指向全局对象,同 map的规则
let CBThis = callbackThis || null;
this.reduce((brfore, after, idx, arr) => {
// 传入map回调函数拥有的参数
// 把每一项的执行结果push进res中
res.push(fn.call(CBThis, after, idx, arr));
}, null);
return res;
};
  • reduceRight() 从数组最后一项开始,向前遍历到第一项。

一些常用方法

  • join() 把数组中的所有元素拼凑成一个字符串的形式,返回字符串
  • toString() 把数组转换为字符串,返回数组的字符串形式。

  • pop() 移除数组最后一个元素,返回被删除的元素,如果数组为空,返回undefined

  • push() 向数组末尾添加一个或多个元素,返回新数组的长度。
  • shift() 移除数组第一个元素,返回第一个元素的值,如果数组为空,返回undefined
  • unshift() 向数组开头添加一个或多个元素,返回新数组的长度。

  • reverse() 颠倒数组中元素的顺序,返回该数组。

  • sort() 对数组元素进行排序,默认按照元素的ascii码排序,返回该数组。

注意
pop()push()shift()unshift()reverse()sort()splice()方法都会改变原数组

其在Vue.js Array的变化侦测中通过创建拦截器去覆盖数组原型的方式去追踪变化。


Date类型

创建一个日期对象 var now = new Date()


RegExp类型

正则表达式,类似于perl的语法

1
var expression = / pattern / flags;

其中,pattern模式部分可以是任何简单的正则表达式。
flags标志,表明正则表达式的行为,支持下列三种标志。

  • g 表示全局(global)模式,而非在发现第一个匹配项时立即停止。
  • i 表示不区分大小写(case-insensitive)模式
  • m 表示多行(multiline)模式

正则表达式 匹配出生日期(简单匹配)

1
2
3
4
5
6
var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
r.exec('1985-10-15');
s1=RegExp.$1;
s2=RegExp.$2;
s3=RegExp.$3;
alert(s1+" "+s2+" "+s3)//结果为1985 10 15


Function类型

定义函数的基本方式:

  • 函数声明式

    1
    2
    3
    function sum(num1, num2) {
    return num1 + num2;
    }
  • 函数表达式

    1
    2
    3
    var sum = function(num1, num2) {
    return num1 + num2;
    }

解析器会率先读取函数声明,并使其在执行任何代码前可用,函数表达式必须等到函数执行到他所在的代码行,才会真正被执行。

函数内部属性

函数内部有两个特殊对象:argumentsthis

argumentscallee属性:指向拥有这个arguments对象的函数。在递归函数中,可以消除函数的耦合现象,严格模式会导致错误。
如下使用callee实现的递归阶乘函数:

1
2
3
4
5
6
7
function factorial(num) {
if(num <= 1) {
return 1
} else {
return num * arguments.callee(num-1)
}
}

函数的属性和方法

每个函数都包含两个非继承而来的方法:apply()call()。其用途都是在特定的作用域中调用函数,等于设置函数体内this对象的值,扩充函数赖以运行的作用域。他们的区别仅在于接收参数的方式不同。

  • apply()接收两个参数,其一是运行函数的作用域,其二是一个参数数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Function.prototype.myApply = function(context) {
var context = context || window
context.fn = this

var result
// 判断是否存在第二个参数
// 如果存在,则将第二个参数展开
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}

delete context.fn
return result
}
  • call() 第一个参数是this值,其余传递给函数的参数须逐个列举出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function.prototype.myCall = function(context) {
var context = context || window
context.fn = this

var result

// 将arguments后面的参数提取出来
var args = [...arguments].slice(1)
result = context.fn(...args)

// 删除fn
delete context.fn()
return result
}
  • bind()该方法创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function.prototype.myBind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
var _this = this
var args = [...arguments].slice(1)
// 返回一个函数
return function F() {
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}