探究 JavaScript 中的 Array

203 阅读3分钟

前言

本文探究一下 Array ,并实现 Vue 中对数组下标操作进行响应式化, Vue 中的数组操作可看这篇文章 Vue 数组操作及源码分析

什么是 Array

JavaScript的 Array 对象是用于构造数组的全局对象,数组是类似于列表的高阶对象。

数组是引用数据类型,可通过字面量和 Array() 构造函数来创建,其中使用 Array() 构造函数时,若值传入一个实参,且为数字时,则生成一个 length 为该实参的空数组。

数组1.png

Array 下标操作

数组2.png

备注: 这里我在写示例时有一个小插曲,我是在 chrome 的 console 中,将代码全部执行完之后然后再打开折叠的输出内容,所以 chrome 应该是在我点击哪个三角形之后去读取变量 a 的内容,所以导致打印出来的内容一样,与 Array 无关,也没什么用,只是记录一下

Array 的方法

Array 的方法在 MDN 中已经讲的非常清楚了,这里我作一些理解和总结

  1. 数组也是对象,数组的原型对象为 Array.prototype ,拥有 length 属性。

数组3.png

  1. 数组的下标其实是字符串,这个知识点从上面的例子可以看出,所以我们定义一个拥有 length 的对象,然后将原型改为 Array.prototype 也可以获得一个数组对象,但是其与使用字面量或构造函数定义的数组还是不同的,可以通过一些例子来证明

数组4.png

从图中可以看出,我们通过字面量定义数组 a ,我们按照 1 中的说法将 a 变成数组,但是我们操作 length 时,下标为 10 的属性并没有因为 length 的改变而被截掉,而是作为对象的属性 (这是 chrome 浏览器中的表现,其他引擎没有试,因为这个区别反正也是无用的知识,突发奇想测试出来的)

  1. 数组的长度是 length ,而不是里面存了多少元素,当然,数组中的元素数小于 length ,使用一些涉及到数组长度的方法是根据 length 来操作的,比如 pop 弹出的是 [length -1] 元素,如果该下标元素为空,则返回 undefined

Vue2 中响应式化下标操作的简单实现

根据前面的学习,数组中的元素其实也可以类比键值对形式,而 Vue 中的响应式化就是通过 Object.defineProperties() 来将属性描述符设置为访问器描述符,即重写属性的 get()set() ,而我们通过对下标进行响应式化即可监听对数组的下标操作,即重写下标的 get()set() 即可

var Observer = function Observer (value) {
  this.value = value;
  this.dep = new Dep();
  this.vmCount = 0;
  def(value, '__ob__', this);
  if (Array.isArray(value)) {
    if (hasProto) {
      protoAugment(value, arrayMethods);
    } else {
      copyAugment(value, arrayMethods, arrayKeys);
    }
    // this.observeArray(value);
    this.walkArray(value)
  } else {
    this.walk(value);
  }
};

Observer.prototype.walkArray = function walkArray (obj) {
  obj.forEach((item, index) => {
    defineReactive$$1(obj, index) // 在这里对其下标进行响应式化
  });
}

数组6.png

但是 length 无法进行响应式化,因为 length 的属性描述符不允许被修改

数组5.png