JavaScript 中数字有两种类型
2^53
或者小于 -2^53
。所以退出了 BigInt 的类型。Object.is(NaN, NaN); // true
// 如果只是判断是否是NaN
isNaN(NaN); // true
Object.is
类似于执行 ===
的相等判断。但是对于两种边缘情况更可靠
Object.is(0, -0); // false
push/pop
方法运行的比较快,而 shift/unshift
比较慢。
这个有点像是堆栈,push和pop都是操作栈顶的元素,所以快。
使用 for...of
进行迭代
使用 Symbol.iterator
给对象添加可迭代功能
let range = {
from: 1,
to: 5
};
// 我们希望 for..of 这样运行:
// for(let num of range) ... num=1,2,3,4,5
for..of
循环启动时,它会调用这个方法(如果没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next
方法的对象。for..of
仅适用于这个被返回的对象。for..of
循环希望取得下一个数值,它就调用这个对象的 next()
方法。next()
方法返回的结果的格式必须是 {done: Boolean, value: any}
,当 done=true
时,表示迭代结束,否则 value
是下一个值。完整实现:
let range = {
from: 1,
to: 5
};
// 1. for..of 调用首先会调用这个:
range[Symbol.iterator] = function() {
// ……它返回迭代器对象(iterator object):
// 2. 接下来,for..of 仅与此迭代器一起工作,要求它提供下一个值
return {
current: this.from,
last: this.to,
// 3. next() 在 for..of 的每一轮循环迭代中被调用
next() {
// 4. 它将会返回 {done:.., value :...} 格式的对象
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// 现在它可以运行了!
for (let num of range) {
alert(num); // 1, 然后是 2, 3, 4, 5
}
range
自身没有 next()
方法。range[Symbol.iterator]()
创建了另一个对象,即所谓的“迭代器”对象,并且它的 next
会为迭代生成值。for (let char of "test") {
// 触发 4 次,每个字符一次
alert( char ); // t, then e, then s, then t
}
也是直接获取了 Symbol.iterator
let str = "Hello";
// 和 for..of 做相同的事
// for (let char of str) alert(char);
let iterator = str[Symbol.iterator]();
while (true) {
let result = iterator.next();
if (result.done) break;
alert(result.value); // 一个接一个地输出字符
}
可以应用 for..of
的对象被称为 可迭代的。
Symbol.iterator
方法。 obj[Symbol.iterator]()
的结果被称为 迭代器(iterator)。由它处理进一步的迭代过程。next()
方法,它返回一个 {done: Boolean, value: any}
对象,这里 done:true
表明迭代结束,否则 value
就是下一个值。Symbol.iterator
方法会被 for..of
自动调用,但我们也可以直接调用它。Symbol.iterator
。有索引属性和 length
属性的对象被称为 类数组对象。这种对象可能还具有其他属性和方法,但是没有数组的内建方法。如下
let arrayLike = {
0: "Hello",
1: "World",
length: 2
};
如果我们仔细研究一下规范 —— 就会发现大多数内建方法都假设它们需要处理的是可迭代对象或者类数组对象,而不是“真正的”数组,因为这样抽象度更高。
Array.from(obj[, mapFn, thisArg])
将可迭代对象或类数组对象 obj
转化为真正的数组 Array
,然后我们就可以对它应用数组的方法。可选参数 mapFn
和 thisArg
允许我们将函数应用到每个元素。
Map 是一个带键的数据项的集合,就像一个 Object
一样。 但是它们最大的差别是 Map
允许任何类型的键(key)。
它的方法和属性如下:
new Map()
—— 创建 map。map.set(key, value)
—— 根据键存储值。map.get(key)
—— 根据键来返回值,如果 map
中不存在对应的 key
,则返回 undefined
。map.has(key)
—— 如果 key
存在则返回 true
,否则返回 false
。map.delete(key)
—— 删除指定键的值。map.clear()
—— 清空 map。map.size
—— 返回当前元素个数。举个🌰
let map = new Map();
map.set('1', 'str1'); // 字符串键
map.set(1, 'num1'); // 数字键
map.set(true, 'bool1'); // 布尔值键
// 还记得普通的 Object 吗? 它会将键转化为字符串
// Map 则会保留键的类型,所以下面这两个结果不同:
alert( map.get(1) ); // 'num1'
alert( map.get('1') ); // 'str1'
alert( map.size ); // 3
Map 的键,可以是任何类型。
和可以是对象
let john = { name: "John" };
// 存储每个用户的来访次数
let visitsCountMap = new Map();
// john 是 Map 中的键
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123
map.set
调用返回map自身,可以“链式”调用
map.set('1', 'str1')
.set(1, 'num1')
.set(true, 'bool1');
如果要在 map
里使用循环,可以使用以下三个方法:
map.keys()
—— 遍历并返回所有的键(returns an iterable for keys),map.values()
—— 遍历并返回所有的值(returns an iterable for values),map.entries()
—— 遍历并返回所有的实体(returns an iterable for entries)[key, value]
,for..of
在默认情况下使用的就是这个。这个有点像是对象中的那三个方法。
Object to Map
Object.entries
let obj = {
name: "John",
age: 30
};
let map = new Map(Object.entries(obj));
alert( map.get('name') ); // John
Map to Object
Object.fromEntries
let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['meat', 4]
]);
// 现在 prices = { banana: 1, orange: 2, meat: 4 }
alert(prices.orange); // 2
Set
是一个特殊的类型集合 —— “值的集合”(没有键),它的每一个值只能出现一次。
它的主要方法如下:
new Set(iterable)
—— 创建一个 set
,如果提供了一个 iterable
对象(通常是数组),将会从数组里面复制值到 set
中。set.add(value)
—— 添加一个值,返回 set 本身set.delete(value)
—— 删除值,如果 value
在这个方法调用的时候存在则返回 true
,否则返回 false
。set.has(value)
—— 如果 value
在 set 中,返回 true
,否则返回 false
。set.clear()
—— 清空 set。set.size
—— 返回元素个数。因为 Set
的每个值只能出现一次,所以,可以用来进行数组去重。
可以使用 for..of
或 forEach
来遍历 Set:
Map
中用于迭代的方法在 Set
中也同样支持:
set.keys()
—— 遍历并返回所有的值(returns an iterable object for values),set.values()
—— 与 set.keys()
作用相同,这是为了兼容 Map
,set.entries()
—— 遍历并返回所有的实体(returns an iterable object for entries)[value, value]
,它的存在也是为了兼容 Map
Map使用对象作为键,不会被垃圾回收机制回收
let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // 覆盖引用
// john 被存储在 map 中,
// 我们可以使用 map.keys() 来获取它
WeakMap
和 Map
的第一个不同点就是,WeakMap
的键必须是对象,不能是原始值,而且可以被垃圾回收机制回收。
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "ok"); // 正常工作(以对象作为键)
// 不能使用字符串作为键
weakMap.set("test", "Whoops"); // Error,因为 "test" 不是一个对象
现在,如果我们在 weakMap 中使用一个对象作为键,并且没有其他对这个对象的引用 —— 该对象将会被从内存(和map)中自动清除。
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // 覆盖引用
// john 被从内存中删除了!
WeakMap
不支持迭代以及 keys()
,values()
和 entries()
方法。所以没有办法获取 WeakMap
的所有键或值。
WeakMap
只有以下的方法:
weakMap.get(key)
weakMap.set(key, value)
weakMap.delete(key)
weakMap.has(key)
WeakMap
可以用来管理缓存
// 📁 cache.js
let cache = new WeakMap();
// 计算并记结果
function process(obj) {
if (!cache.has(obj)) {
let result = /* calculate the result for */ obj;
cache.set(obj, result);
}
return cache.get(obj);
}
// 📁 main.js
let obj = {/* some object */};
let result1 = process(obj);
let result2 = process(obj);
// ……稍后,我们不再需要这个对象时:
obj = null;
// 无法获取 cache.size,因为它是一个 WeakMap,
// 要么是 0,或即将变为 0
// 当 obj 被垃圾回收,缓存的数据也会被清除
WeakSet
的表现类似:
Set
类似,但是我们只能向 WeakSet
添加对象(而不能是原始值)。Set
一样,WeakSet
支持 add
,has
和 delete
方法,但不支持 size
和 keys()
,并且不可迭代。数组中不想要的元素也可以通过添加额外的逗号来把它丢弃:
// 不需要第二个元素
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert( title ); // Consul
我们可以将其与任何可迭代对象一起使用,而不仅限于数组:
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
new Date()
创建时间日期。多种参数类型:
year
必须是四位数:2013
是合法的,98
是不合法的。month
计数从 0
(一月)开始,到 11
(十二月)结束。date
是当月的具体某一天,如果缺失,则为默认值 1
。hours/minutes/seconds/ms
缺失,则均为默认值 0
。getMonth()
获取月份是 从 0 到 11
获取年份使用 getFullYear()
而不是 getYear()
。这才是官方的。
getDay()
是获取周几而不是获取几号,获取几号是 getDate()
下列方法可以设置日期/时间组件:
[setFullYear(year, [month], [date])](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setFullYear>)
[setMonth(month, [date])](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setMonth>)
[setDate(date)](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate>)
[setHours(hour, [min], [sec], [ms])](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setHours>)
[setMinutes(min, [sec], [ms])](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setMinutes>)
[setSeconds(sec, [ms])](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setSeconds>)
[setMilliseconds(ms)](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setMilliseconds>)
[setTime(milliseconds)](<https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Date/setTime>)
(使用自 1970-01-01 00:00:00 UTC+0 以来的毫秒数来设置整个日期)还有就是关于 UTC 的时间,可以上MDN看看。
Date.parse(str) 方法可以从一个字符串中读取日期。
字符串的格式应该为:YYYY-MM-DDTHH:mm:ss.sssZ
,其中:
YYYY-MM-DD
—— 日期:年-月-日。"T"
是一个分隔符。HH:mm:ss.sss
—— 时间:小时,分钟,秒,毫秒。'Z'
为 +-hh:mm
格式的时区。单个字符 Z
代表 UTC+0 时区。简短形式也是可以的,比如 YYYY-MM-DD
或 YYYY-MM
,甚至可以是 YYYY
。
这个用的不是很多。
JSON.stringify
还有其他两个参数
let json = JSON.stringify(value[, replacer, space])
function(key, value)
。返回处理后的值JOSN.parse
也有第二个参数
let value = JSON.parse(str, [reviver]);
(key, value)
对调用,并可以对值进行转换。reviver 的使用
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let meetup = JSON.parse(str);
alert( meetup.date.getDate() ); // TypeError! meetup.date.getDate is not a function
这样使用 reviver
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let meetup = JSON.parse(str, function(key, value) {
if (key == 'date') return new Date(value);
return value;
});
alert( meetup.date.getDate() ); // 现在正常运行了!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。