前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【云+社区年度征文】再看JavaScript,那些遗漏或易混淆的知识点(2)

【云+社区年度征文】再看JavaScript,那些遗漏或易混淆的知识点(2)

原创
作者头像
踏浪
修改2020-11-26 10:14:39
7810
修改2020-11-26 10:14:39
举报
文章被收录于专栏:踏浪的文章踏浪的文章

数字类型

JavaScript 中数字有两种类型

  1. 双精度浮点数,也就是我们常用的数字
  2. BigInt 数字。因为常规数字不能超过 2^53 或者小于 -2^53 。所以退出了 BigInt 的类型。

使用 Obejct.is 判断 NaN

代码语言:javascript
复制
Object.is(NaN, NaN); // true

// 如果只是判断是否是NaN
isNaN(NaN); // true

Object.is 类似于执行 === 的相等判断。但是对于两种边缘情况更可靠

代码语言:javascript
复制
Object.is(0, -0); // false

字符串

https://pic-go-1253455210.cos.ap-chengdu.myqcloud.com/blog/20201106183011.png
https://pic-go-1253455210.cos.ap-chengdu.myqcloud.com/blog/20201106183011.png

push、pop、shift、unshift

push/pop 方法运行的比较快,而 shift/unshift 比较慢。

这个有点像是堆栈,push和pop都是操作栈顶的元素,所以快。

数组的方法

  • push、pop、shift、unshift
  • splice
  • slice
  • concat
  • forEach、map
  • indexOf、lastIndexOf、includes
  • find、findIndex
  • filter
  • sort、reverse
  • split、join
  • reduce、reduceRight
  • Array.isArray

迭代

使用 for...of 进行迭代

Symbol.iterator

使用 Symbol.iterator 给对象添加可迭代功能

代码语言:javascript
复制
let range = {
  from: 1,
  to: 5
};

// 我们希望 for..of 这样运行:
// for(let num of range) ... num=1,2,3,4,5
  1. 当 for..of 循环启动时,它会调用这个方法(如果没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next 方法的对象。
  2. 从此开始,for..of 仅适用于这个被返回的对象
  3. 当 for..of 循环希望取得下一个数值,它就调用这个对象的 next() 方法。
  4. next() 方法返回的结果的格式必须是 {done: Boolean, value: any},当 done=true 时,表示迭代结束,否则 value 是下一个值。

完整实现:

代码语言:javascript
复制
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 会为迭代生成值。

字符串的迭代

代码语言:javascript
复制
for (let char of "test") {
  // 触发 4 次,每个字符一次
  alert( char ); // t, then e, then s, then t
}

显示的调用迭代器

也是直接获取了 Symbol.iterator

代码语言:javascript
复制
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
  • 字符串迭代器能够识别代理对(surrogate pair)。(译注:代理对也就是 UTF-16 扩展字符。)

有索引属性和 length 属性的对象被称为 类数组对象。这种对象可能还具有其他属性和方法,但是没有数组的内建方法。如下

代码语言:javascript
复制
let arrayLike = {
  0: "Hello",
  1: "World",
  length: 2
};

如果我们仔细研究一下规范 —— 就会发现大多数内建方法都假设它们需要处理的是可迭代对象或者类数组对象,而不是“真正的”数组,因为这样抽象度更高。

Array.from(obj[, mapFn, thisArg]) 将可迭代对象或类数组对象 obj 转化为真正的数组 Array,然后我们就可以对它应用数组的方法。可选参数 mapFn 和 thisArg 允许我们将函数应用到每个元素。

Map 和 Set (映射和集合)

Map

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 —— 返回当前元素个数。

举个🌰

代码语言:javascript
复制
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 的键,可以是任何类型。

和可以是对象

代码语言:javascript
复制
let john = { name: "John" };

// 存储每个用户的来访次数
let visitsCountMap = new Map();

// john 是 Map 中的键
visitsCountMap.set(john, 123);

alert( visitsCountMap.get(john) ); // 123

map.set 调用返回map自身,可以“链式”调用

代码语言:javascript
复制
map.set('1', 'str1')
  .set(1, 'num1')
  .set(true, 'bool1');

Map 迭代

如果要在 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 在默认情况下使用的就是这个。

这个有点像是对象中的那三个方法。

Map 与 Object 的转换

Object to Map

Object.entries

代码语言:javascript
复制
let obj = {
  name: "John",
  age: 30
};

let map = new Map(Object.entries(obj));

alert( map.get('name') ); // John

Map to Object

Object.fromEntries

代码语言:javascript
复制
let prices = Object.fromEntries([
  ['banana', 1],
  ['orange', 2],
  ['meat', 4]
]);

// 现在 prices = { banana: 1, orange: 2, meat: 4 }

alert(prices.orange); // 2

Set

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..offorEach 来遍历 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

WeakMap and WeakSet(弱映射和弱集合)

Map使用对象作为键,不会被垃圾回收机制回收

代码语言:javascript
复制
let john = { name: "John" };

let map = new Map();
map.set(john, "...");

john = null; // 覆盖引用

// john 被存储在 map 中,
// 我们可以使用 map.keys() 来获取它

WeakMap

WeakMap 和 Map 的第一个不同点就是,WeakMap 的键必须是对象,不能是原始值,而且可以被垃圾回收机制回收。

代码语言:javascript
复制
let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok"); // 正常工作(以对象作为键)

// 不能使用字符串作为键
weakMap.set("test", "Whoops"); // Error,因为 "test" 不是一个对象

现在,如果我们在 weakMap 中使用一个对象作为键,并且没有其他对这个对象的引用 —— 该对象将会被从内存(和map)中自动清除。

代码语言:javascript
复制
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 可以用来管理缓存

代码语言:javascript
复制
// 📁 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

WeakSet 的表现类似:

  • 与 Set 类似,但是我们只能向 WeakSet 添加对象(而不能是原始值)。
  • 对象只有在其它某个(些)地方能被访问的时候,才能留在 set 中。
  • 跟 Set 一样,WeakSet 支持 addhas 和 delete 方法,但不支持 size 和 keys(),并且不可迭代。

结构复制

数组中不想要的元素也可以通过添加额外的逗号来把它丢弃:

代码语言:javascript
复制
// 不需要第二个元素
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];

alert( title ); // Consul

我们可以将其与任何可迭代对象一起使用,而不仅限于数组:

代码语言:javascript
复制
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);

时间日期

new Date() 创建时间日期。多种参数类型:

  • new Date(时间戳) ⇒ new Date(24 * 3600 * 1000)
  • new Date(字符串) ⇒ new Date('2020-11-11")
  • new Date(年月日时分秒) ⇒ new Date(year, month, date, hours, minutes, seconds, ms)。其中:
    • 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

JSON.stringify 还有其他两个参数

代码语言:javascript
复制
let json = JSON.stringify(value[, replacer, space])
  • **value:**要编码的值。
  • **replacer:**要编码的属性数组或映射函数 function(key, value)。返回处理后的值
  • **space:**用于格式化的空格数量,意思就是缩进的数量。

JOSN.parse 也有第二个参数

代码语言:javascript
复制
let value = JSON.parse(str, [reviver]);
  • **str:**要解析的 JSON 字符串。
  • **reviver:**可选的函数 function(key,value),该函数将为每个 (key, value) 对调用,并可以对值进行转换。

reviver 的使用

代码语言:javascript
复制
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

代码语言:javascript
复制
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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数字类型
  • 使用 Obejct.is 判断 NaN
  • 字符串
    • push、pop、shift、unshift
      • 数组的方法
      • 迭代
        • Symbol.iterator
          • 字符串的迭代
            • 显示的调用迭代器
            • Map 和 Set (映射和集合)
              • Map
                • Map 迭代
                  • Map 与 Object 的转换
                    • Set
                      • WeakMap and WeakSet(弱映射和弱集合)
                        • WeakMap
                          • WeakSet
                          • 结构复制
                          • 时间日期
                            • 设置日期组件
                            • JSON
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档