<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ES6提供的 Set 【WeakSet】 和 Map 【WeakMap】 数据结构</title>
</head>
<body>
<script type="text/javascript">
/*
基本类型: String、Number、Boolean、Null、Undefined、Symbol 【typeof 检测基本类型】
引用类型:对象(Object)、数组(Array)、函数(Function)
*/
// js基本数据类型
let a = undefined
console.log(typeof a) // undefined
let b = null
console.log(typeof b) // object
let c = 1
console.log(typeof c) // number
let d = true
console.log(typeof d) // boolean
let e = 'abc'
console.log(typeof e) // string
// 可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数BigInt()
// BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript中可以用 Number 表示的最大数字
// BigInt 可以表示任意大的整数
// BigInt 和 Number 不是严格相等的,但是宽松相等的
const f = 10n;
console.log(f, typeof f) // 10n "bigint"
const g = BigInt(10)
console.log(g, typeof g) // 10n "bigint"
console.log(0n === 0) // false
console.log(0n == 0) // true
// 每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的
const sy = Symbol();
const sy1 = Symbol(42);
console.log(typeof sy, sy1) // symbol Symbol(42)
console.log(Symbol(1) === Symbol(1)) // false
// 引用数据类型
let obj = new Object // 等价 new Object() 无参数()可省略
console.log(obj, obj instanceof Object) // {} true
// Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
console.log(Object.create({}))
let arr = new Array
console.log(arr, arr instanceof Object, typeof arr) // [] true object
// 用 Object.create实现类式继承
// ParentClass - 父类(superclass)
function ParentClass() {
this.x = 0;
this.y = 0;
}
// 父类的方法
ParentClass.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('ParentClass is change.');
};
// ChildClass - 子类(subclass)
function ChildClass() {
ParentClass.call(this); // call super constructor.
}
// 子类续承父类
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass;
let newObj = new ChildClass()
console.log(newObj, newObj instanceof Object) // ChildClass {x: 0, y: 0} true
console.log(newObj, newObj instanceof ParentClass) // ChildClass {x: 0, y: 0} true
newObj.move(2,2) // ParentClass is change.
let fn = function(){
console.log(this)
}
console.log(fn, fn instanceof Object, typeof fn) // f(){console.log(this)} true function
// constructor判断
console.log([] instanceof Array);//->true
console.log(/^$/ instanceof RegExp);//->true
console.log([] instanceof Object);//->true
console.log([].constructor === Array);//->true
console.log([].constructor === Object);//->false 我们的constructor可以避免instanceof检测的时候,用Object也是true的问题
console.log({}.constructor === Object); // true
/*
Array.isArray() ECMAScript5将Array.isArray()正式引入JavaScript,目的就是准确地检测一个值是否为数组 IE8不支持
两个或者多个typeof一起使用时,返回值一定是"string";
检测的不管是数组还是正则都返回的是"object",所以typeof不能判断一个值是否为数组
Object.prototype.toString.call(value) 判断某个对象值属于哪种内置类型
*/
// 接下来谈下这个 ES6中的Set 和 Map 数据结构
// Set 数据结构
let mySet = new Set()
console.log(mySet,typeof mySet) // Set(0){} "object"
mySet.add(1)
mySet.add(2)
mySet.add(2)
mySet.add(3)
console.log(mySet) // Set(3){1,2,3}
let setTest = new Set([1,2,3,4,5,5,6,6])
let setArr = [...setTest]
console.log(setTest) // Set(3){1,2,3,4,5,6}
console.log(setArr) // [1, 2, 3, 4, 5, 6]
// 结论
/*
Set 数据结构 类似于数组但是Set不会添加重复的值
Set 加入值的时候,不会发生类型转换
[...new Set(array)] 可以去除数组重复成员的方法
[...new Set('string')].join('') 可以去除字符串里面的重复字符
Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化
Array.from方法可以将 Set 结构转为数组 【Array.from是将类数组转为数组的一种方法】
将类数组转为数组的方法:
1、Array的slice方法 例如:let arr = Array.prototype.slice.call(arguments);
2、Array.from() 例如:let arr = Array.from(arguments); 只要有length属性的对象,都可以应用此方法转换成数组
3、扩展运算符... 例如:let arr = [...arguments]; 这种数据结构必须有遍历器接口
4、jquery的$.makeArray() 例如:let arr = $.makeArray(arguments);
使用Array的slice方法,此方法如果不传参数的话会返回原数组的一个拷贝,因此可以用此方法转换类数组到数组
let arr = Array.prototype.slice.call(arguments);
// 等同于
let arr = [].slice.call(arguments)
*/
// WeakSet 数据结构
const myWeakSet = new WeakSet();
// myWeakSet.add(1) // 报错 Invalid value used in weak set
console.log(myWeakSet,typeof myWeakSet) // WeakSet {} "object"
const arrs = [[1, 2], [3, 4]];
const ws = new WeakSet(arrs);
console.log(ws) // WeakSet {[1, 2], [3, 4]}
// 结论
/*
WeakSet 结构与 Set 类似,也是不重复的值的集合
WeakSet 的成员只能是对象,而不能是其他类型的值
WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,
如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存
WeakSet 没有size属性 ES6 规定 WeakSet 不可遍历
*/
// Map 数据结构
const mp = new Map();
console.log(mp,typeof mp) // Map(0) {} "object"
const items = [
['name', '小明'],
['age', 28]
]
items.forEach(
([key, value]) => mp.set(key, value)
)
console.log(mp) // Map(2) {"name" => "小明", "age" => 28}
const map = new Map();
map.set(1, 'aaa').set(1, 'bbb')
console.log(map,map.get(1)) // Map(1) {1 => "bbb"} 'bbb'
const mapTest = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
])
console.log([...mapTest.keys()]) // [1, 2, 3]
console.log([...mapTest.values()]) // ['one', 'two', 'three']
console.log([...mapTest.entries()]) // [[1,'one'], [2, 'two'], [3, 'three']]
console.log([...mapTest]) // [[1,'one'], [2, 'two'], [3, 'three']]
// 结论
/*
对同一个键多次赋值,后面的值将覆盖前面的值
读取【get方法】一个未知的键,则返回undefined
只有对同一个对象的引用,Map 结构才将其视为同一个键
同样的值的两个实例,在 Map 结构中被视为两个键
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键
Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
如果你需要“键值对”的数据结构,Map 比 Object 更合适
任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数, Set和Map都可以用来生成新的 Map
Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)
*/
// WeakMap 数据结构
const wmp = new WeakMap();
console.log(wmp, typeof wmp) // WeakMap {} "object"
let key = {age: 1}
console.log(wmp.set(key,20)) // WeakMap {{…} => 20}
console.log(wmp.get(key)) // 20
// 结论 【WeakMap与Map的区别有两点】
/*
WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
WeakMap的键名所指向的对象,不计入垃圾回收机制
如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap
WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。WeakMap结构有助于防止内存泄漏
WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用
WeakMap 的另一个用处是部署私有属性 class _xx开头的
*/
</script>
</body>
</html>