JavaScript高级程序设计笔记06 集合引用类型

集合引用类型

1. Object(详见c08 p205)

适合存储,在应用程序间交换数据

创建实例:

  1. 显式构造函数
  2. 字面量——>不会调用构造函数(代码更少、更有封装感)

函数:大量参数的情况下,适合用:命名参数(必选)+对象字面量封装多个(可选)参数的形式

2. Array

有序,动态大小

2.1 创建实例:

  1. 构造函数
  2. 字面量——>不会调用构造函数
  3. 两个方法

    from(类数组, (可选)映射函数, (可选)映射函数中this指定的对象)

    of() 参数->数组

2.2 empty元素:

  1. forEach(忽略),for(当成undefined处理),map(会跳过不处理),join(视为空串)
  2. ES6新增方法视其为undefined
  3. 行为不一致,性能隐患

2.3 索引相关:

  1. index 超过最大索引的处理
  2. length 不只读(可变大或变小)

2.4 检测是否数组:

Array.isArray(obj) 兼容框架间不同版本的构造函数

2.5 迭代器方法:

keys()、values() (默认)、entries()。

2.6 填充:

  1. fill(arg1, arg2, arg3) arg1:填充值
  2. copyWithin(arg1, arg2, arg3) arg1:填充的索引

arg2 \ arg3 : 开始、结束索引

2.7 转换

  1. toString() 各个元素转换后拼接
  2. toLocaleString()
  3. valueOf() 数组本身
  4. join(分隔符)

2.8 模拟数据结构

  1. 栈LIFO: push(接收任意数量的参数,返回数组的最新长度)、pop(返回出栈元素)
  2. 队FIFO: push、shift(返回出队元素)
  3. 反队:unshift(接收任意数量的参数,返回数组的最新长度)、pop

2.9 排序

  1. sort((a,b)=> {...}) 参数函数返回值1:ab需要调换,否则不需要。会改变数组本身
  2. reverse() 将数组元素反向排序。 改变数组本身。不够灵活

都返回调用它们的数组的引用。

2.10 在旧数组上建新数组

  1. concat(),可传多个参数
  2. slice(开始索引, 结束索引(不包含,可选))
  3. splice(开始索引, 长度(>=0,可选), N个插入的元素(可选)):改变原数组,返回被删除元素的数组

2.11 搜索

按严格相等(===)(要查找的元素、可选的起始搜索位置)、按断言函数

  • 严格相等:indexOf、lastIndexOf。返回要查找的元素在数组中的位置,或者-1
  • includes:返回布尔值。ES7新增。
  • 断言函数:find、findIndex。都从数组的最小索引开始。可选第二个参数为指定断言函数内部this的指向。返回第一个匹配元素的元素/索引

    断言函数接收3个参数:元素、索引和数组本身。返回的值决定了相应索引的元素是否被认为匹配。

2.12迭代

  • every((item, index, array)=>...)、some((item, index, array)=>...):全部符合函数/部分符合函数
  • filter(产生新数组):过滤。某一些是否应该包含在它返回的数组中。
  • 逐个迭代

    • forEach。相当于使用for循环遍历数组
    • map(新数组):映射。适合用于创建一个与原始数组元素一一对应的新数组。

2.13 归并

  • reduce(fn(pre, cur, index, array),[prev])
  • reduceRight

返回运行到最后归并函数的返回值

const a = ["foo", "bar", "baz", "qux"];

const aKeys = a.keys(),
aValues = a.values(),
aEntries = a.entries();
console.log( a.values === a[Symbol.iterator] ); // true

console.log( Array.from(aKeys) ); // [ 0, 1, 2, 3 ]
console.log( Array.from(aValues) ); // [ 'foo', 'bar', 'baz', 'qux' ]
console.log( Array.from(aEntries) ); // [ [ 0, 'foo' ], [ 1, 'bar' ], [ 2, 'baz' ], [ 3, 'qux' ] ]

for(const [idx, element] of a.entries()) {
   console.log( idx, element );
}
// 0 foo
// 1 bar
// 2 baz
// 3 qux
for(const e of a) {
   console.log( e );
}

// Array 
// copyWithin
let ints,
   reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
reset();

ints.copyWithin( 5 );
console.log( ints );
// [
//   0, 1, 2, 3, 4,
//   0, 1, 2, 3, 4
// ]
reset();

ints.copyWithin( 0, 5 );
console.log( ints );
// [
//   5, 6, 7, 8, 9,
//   5, 6, 7, 8, 9
// ]
reset();

ints.copyWithin( 4, 0, 3 );
console.log( ints );
// [
//   0, 1, 2, 3, 0,
//   1, 2, 7, 8, 9
// ]
reset();

ints.copyWithin( 2, 0, 6 );
console.log( ints );
// [
//   0, 1, 0, 1, 2,
//   3, 4, 5, 8, 9
// ]
reset();

ints.copyWithin( -4, -7, -5 );
console.log( ints );
// [
//   0, 1, 2, 3, 4,
//   5, 3, 4, 8, 9
// ]
reset();

// Array 
// empty
let a2 = [1, 2, undefined];
a2.length = 4;
a2[4] = null;
a2.forEach(item => console.log(item));
// 1
// 2
// undefined
// null
for(let i =0 ;i

3. 定型数组 TypedArray

一种特殊的包含数值类型的数组

目的:提升向原生库传输数据的效率。

使用场景:WebGL。可以直接传给底层图形驱动程序API。

3.1 ArrayBuffer

ArrayBuffer(字节数):分配的内存(供定型数组及视图引用的基本单位)

c27 p793

3.2 定型数组和视图

  • 视图:DataView(buf)
  • 定型数组:无法调整大小

    • .set(数组, 开始索引(可选))
    • .subarray(开始索引, 结束索引(可选))
function typedArrayConcat(typedArrayConstructor, ...typedArray) {
   const numElements = typedArray.reduce((x,y) => (x.length || x) + y.length);

   const resultArray = new typedArrayConstructor(numElements);

   let currentOffset = 0;
   typedArray.forEach(x => {
      resultArray.set(x, currentOffset);
      currentOffset += x.length;
   });

   return resultArray;
}
const concatArray = typedArrayConcat(Int32Array,
                        Int8Array.of(1, 2, 3),
                        Int16Array.of(4, 5, 6),
                        Float32Array.of(7, 8, 9));
console.log( concatArray );
// Int32Array(9) [
//   1, 2, 3, 4, 5,
//   6, 7, 8, 9
// ]
console.log( concatArray instanceof Int32Array ); // true

4. Map

Map(可迭代结构)

key可以是任意类型,(function也可)

  • 基本操作

    • .set(key, value)
    • .get(key), .has(key)
    • .delete(key)(返回是否有对应键的布尔值)、.clear()(清除所有键值对)
  • size、有序
  • key对比的SameValueZero的问题:NaN与NaN、+0与-0
  • 迭代器方法:keys() 、values()、entries()(默认)
  • 与Object对比

    • Map内存利用率高、插入更快、删除更快
    • Object 查找更快(有优化)
const m1 = new Map([
      ["key1", "value1"],
      ["key2", "value2"],
      ["key3", "value3"]
   ]);
console.log( m1 ); // Map(3) { 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3' }
console.log( m1.size ); // 3

const m2 = new Map({
   [Symbol.iterator]: function *() {
      yield ["key1", "value1"];
      yield ["key2", "value2"];
      yield ["key3", "value3"];
   }
});
console.log( m2 ); // Map(3) { 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3' }
console.log( m2.size ); // 3

const m = new Map();
console.log( m.has("firstName") ); // false
console.log( m.get("firstName") ); // undefined
console.log( m.size ); // 0

m.set( "firstName", "Matt" )
 .set( "lastName", "Frisble" );
console.log( m.has("firstName") ); // true
console.log( m.get("firstName") ); // Matt
console.log( m.size ); // 2

m.delete( "firstName" );
console.log( m.has("firstName") ); // false
console.log( m.get("firstName") ); // undefined
console.log( m.size ); // 1

m.clear();
console.log( m.has("firstName") ); // false
console.log( m.has("lastName") ); // false
console.log( m.size ); // 0

console.log( 'order=========' );
console.log( m.entries === m[Symbol.iterator] ); // true
for (let pair of m1.entries()) {
   console.log( pair );
}
// [ 'key1', 'value1' ]
// [ 'key2', 'value2' ]
// [ 'key3', 'value3' ]

for (let pair of m1) {
   console.log( pair );
}
// [ 'key1', 'value1' ]
// [ 'key2', 'value2' ]
// [ 'key3', 'value3' ]
console.log( ...m1 ); // [ 'key1', 'value1' ] [ 'key2', 'value2' ] [ 'key3', 'value3' ]
m1.forEach((value, key) => console.log( `${key}->${value}` ));
// key1->value1
// key2->value2
// key3->value3

5. WeakMap

键只能为对象类型或子类型;

无迭代(键不可迭代);

利于垃圾回收(键在其他地方无引用就回收);

使用场景:

1)(伪)私有变量

2)DOM元素映射(不影响回收垃圾)

const wm = new WeakMap();
class User {
   constructor(id) {
      this.idProperty = Symbol('id');
      this.setId(id);
      console.log( 'constructor' )
   }
   setId(id) {
      this.setPrivateProperty(this.idProperty, id);
   }
   setPrivateProperty(property, value) {
      const privateMembers = wm.get(this) || {};
      privateMembers[property] = value;
      if(!wm.get(this)) wm.set(this, privateMembers);
   }
   getId() {
      return this.getPrivateProperty(this.idProperty);
   }
   getPrivateProperty(property) {
      return wm.get(this)[property];
   }
}
const user = new User(123);
console.log( user.getId() ); // 123
user.setId(456);
console.log( user.getId() ); // 456
console.log( wm.get(user)[user.idProperty] ); // 456

const PackedUser = (()=> {
   const wm = new WeakMap();
   class PackedUser {
      constructor(id) {
         this.idProperty = Symbol('id');
         this.setId(id);
      }
      setId(id) {
         this.setPrivateProperty(this.idProperty, id);
      }
      setPrivateProperty(property, value) {
         const privateMembers = wm.get(this) || {};
         privateMembers[property] = value;
         if(!wm.get(this)) wm.set(this, privateMembers);
      }
      getId() {
         return this.getPrivateProperty(this.idProperty);
      }
      getPrivateProperty(property) {
         return wm.get(this)[property];
      }
   }
   return PackedUser;
})();
const packedUser = new PackedUser(123);
console.log( packedUser.getId() ); // 123

6. Set

Set(可迭代对象)

  • 不重复值
  • 基本操作

    • add(value)
    • has(value)
    • delete(value)(返回是否有对应值的布尔值)、clear()清空集合
  • size
  • 迭代器方法:keys() 、values()(默认)、entries()
  • 扩展Set实现

    交集、并集、差集、对称差集、笛卡尔积、幂集

class XSet extends Set {
   union(...sets) {
      return XSet.union(this, ...sets);
   }

   intersection(...sets) {
      return XSet.intersection(this, ...sets);
   }

   difference(set) {
      return XSet.difference(this, set);
   }

   symmetricDifference(set) {
      return XSet.symmetricDifference(this, set);
   }

   cartesianProduct(set) {
      return XSet.cartesianProduct(this, set);
   }

   powerSet() {
      return XSet.powerSet(this);
   }

   // 返回两个或多个集合的并集
   static union(a, ...bSets) {
      const unionSet = new XSet(a);
      for (const b of bSets) {
         for (const bValue of b) {
            unionSet.add(bValue);
         }
      }
      return unionSet;
   }

   // 返回两个或多个集合的交集
   static intersection(a, ...bSets) {
      const intersectionSet = new XSet(a);
      for (const aValue of intersectionSet) {
         for (const b of bSets) {
            if(!b.has(aValue)) {
               intersectionSet.delete(aValue);
            }
         }
      } 
      return intersectionSet;
   }

   // 返回两个集合的差集 a-b
   static difference(a, b) {
      const differenceSet = new XSet(a);
      for (const bValue of b) {
         if(a.has(bValue)) {
            differenceSet.delete(bValue);
         }
      }
      return differenceSet;
   }

   // 返回两个集合的对称差集 (a-b)+(b-a) | a和b的并集-a和b的交集
   static symmetricDifference(a, b) {
      return a.union(b).difference(a.intersection(b));
   }

   // 返回两个集合(数组对形式)的笛卡尔积
   // 必须返回数组集合,因为笛卡尔积可能包含相同值的对
   static cartesianProduct(a, b) {
      const cartesianProductSet = new XSet();
      for (const aValue of a) {
         for (const bValue of b) {
            cartesianProductSet.add([aValue, bValue]);
         }
      }
      return cartesianProductSet;
   }

   // 返回一个集合的幂集
   static powerSet(a) {
      const powerSet = new XSet().add(new XSet());
      for (const aValue of a) {
         for (const set of new XSet(powerSet)) {
            powerSet.add(new XSet(set).add(aValue));
         }
      }
      return powerSet;
   }
}
let xSet = new XSet().add(1);
console.log( xSet.powerSet() ); // XSet(2) [Set] { XSet(0) [Set] {}, XSet(1) [Set] { 1 } }
xSet.add(2);
console.log( xSet.powerSet() );
// XSet(4) [Set] {
//   XSet(0) [Set] {},
//   XSet(1) [Set] { 1 },
//   XSet(1) [Set] { 2 },
//   XSet(2) [Set] { 1, 2 }
// }

7. WeakSet

值只能为对象类型或子类型

无迭代(值不可迭代)

利用垃圾回收

使用场景:

1)DOM元素集合:DOM元素被从页面上删除(且无其他引用)即可回收

8. 迭代与扩展

有默认迭代器的类型:

values():Array、定型数组、Set

entries()——Map

自动调用的地方:for-of循环、扩展操作符

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