Junwen's home
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • 怎么写出更好的css
  • BFC详解
  • box-shadow详解
  • CSS小技巧
  • Grid布局详解
HTML
  • IP十问
  • http笔试
  • http协议
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
  • 前端性能优化
  • 前端如何进行seo优化
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • leetcode题解

    • 两数之和
    • 判断整数是否为回文串
    • 无重复字符的最长子串
  • Js链表
  • JavaScript排序
  • React

    • 虚拟DOM原理理解
    • React Hook
    • 组件复用指南
  • Vue

    • Vue举一反三
面试题
读书笔记
GitHub (opens new window)

Syun0216

多读书多种树
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • 怎么写出更好的css
  • BFC详解
  • box-shadow详解
  • CSS小技巧
  • Grid布局详解
HTML
  • IP十问
  • http笔试
  • http协议
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
  • 前端性能优化
  • 前端如何进行seo优化
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • leetcode题解

    • 两数之和
    • 判断整数是否为回文串
    • 无重复字符的最长子串
  • Js链表
  • JavaScript排序
  • React

    • 虚拟DOM原理理解
    • React Hook
    • 组件复用指南
  • Vue

    • Vue举一反三
面试题
读书笔记
GitHub (opens new window)
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • Object.create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
      • chrome 之调试
      • 代码风格
      • 使用 mocha 进行自动化测试
      • 开发流程
      • Babel
      • Object 对象: 基础知识
      • 垃圾回收
      • Sysmbol 类型
      • 对象方法与 this
      • iterables(可迭代对象)
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • JavaScript
junwen
2020-02-01

基础知识2

# chrome 之调试

# 代码风格

总结:

  • 对于很短的代码,一行是可以接受的:例如 if (cond) return null .
  • 但是括号中的每个语句单独一行通常更好些。

# 使用 mocha 进行自动化测试

describe("title", function() { ... })

表示我们正在描述的功能是什么。用于组织 “工人(workers)” – 代码块。在我们的例子中我 们正在描述函数 。

it("title", function() { ... })

it 里面的 “title” 中我们以人类可读的方式描述特定的用例,第二个参数是一个测试它的函数。

assert.equal(value1, value2)

# 开发流程

  1. 编写初始规范,测试基本功能
  2. 创建一个最出实现
  3. 检查它是否工作
  4. 现在我们有一个基于测试的能工作的初步实现。
  5. 我们增加更多的用例到规范中,或许目前的程序实现还不支持。测试从失败开始。
  6. 进行第 3 步,更新程序直到测试不会抛出错误。
  7. 重复第 3 步到第 6 步,直到功能完善。

# Babel

当我们使用语言的一些现代特性时,一些引擎可能无法支持这样的代码。
Babel 包含两个部分:

  1. transpiler 程序,就是重写代码的那个。开发者在自己的电脑上运行。诸如 webpack 或者 brunch 这样的现代项目构建系统提供了每次代码改变都会自动运行 transpiler 方法
  2. polyfill:transpiler 会重写代码,但对于新特性我们需要写一个特殊的脚本来实现他们。js 是一个高度动态化的语言。脚本可能不仅是添加一些新特性,还会修改一些内置特性,以便于他们表现得符合现代标准。

# Object 对象: 基础知识

总结 对象是具有一些特殊特性的关联数组。 他们存储键值对,其中:

  • 属性的键必须是字符串或者 Symbol(通常是字符串)。
  • 值可以是任何类型。 我们可以用下面的方法获取属性:
  • 点符号: obj.property 。
  • 方括号 obj["property"] ,方括号中可以使用变量 obj[varWithKey] 。 其他操作:
  • 删除属性: delete obj.prop。
  • 检查属性是否存在: "key" in obj。
  • 遍历对象: for(let key in obj) 循环。

对象根据引用来赋值或者复制。换句话说,变量存的不是对象的"值",而是值的 “引用”(内存地 址)。 所以复制变量或者传递变量到方法中只是复制了对象的引用。 所有的引用操作(像增加, 删除属性)都作用于同一个对象。 深拷贝的话我们可以使用 Object.assign 或者 _.cloneDeep(obj)  。 我们在这一章学习的叫做“基本对象” — 对象。
JavaScript 中还有很多其他类型的对象:

  • Array 存储有序数据集合
  • Date 存储时间日期
  • Error 存储错误信息

他们有一些特别的特性,我们将在后面学习到。有时候大家说“数组类型”,“时间类型”,他们都属 于对象类型的一种,都以不同的方式对对象类型做了一些扩展。

# 垃圾回收

可达性 JavaScript 中主要的内存管理概念是可达性。 简而言之,『可达』值是那些以某种方式可访问或可用的值。它们保证存储在内存中。

  1. 这里列出固有的可达值基本集合,这些值明显不能被释放。 比方说:
  • 当前函数的局部变量和参数。
  • 嵌套调用时,当前调用链上所有函数的变量与参数。
  • 全局变量。
  • (还有一些内部的) 这些值被称作根。
  1. 如果一个值可以通过引用或引用链,从根值访问到,则认为这个值是可达的。 比方说,如果局部变量中有一个对象,并且该对象具有引用另一个对象的 property,则该对象被 认为是可达的。而且它引用的内容也是可达的。下面是详细的例子。

内部算法 垃圾回收的基本算法被称为 “mark-and-sweep”。 定期执行以下“垃圾回收”步骤:

  • 垃圾收集器找到所有的根,并“标记”(记住)它们。
  • 然后它遍历并"标记"来自它们的所有参考。
  • 然后它遍历到标记的对象并标记他们的引用。所有被遍历到的对象都会被记住,以免将来再次 遍历到同一个对象。
  • ...一直这样,直到有未访问的引用(从根访问到)。
  • 没有被标记的所有对象都被删除。

JavaScript 引擎做了很多优化,使其运行速度更快,并且不会影响代码运行

  • 分代收集 —— 对象被分成两组:『新的』和『旧的』。许多对象出现,完成他们的工作并快速 释放,他们可以很快被清理。那些长期存活下来的对象会变得『老旧』,而且检查的次数也会 减少。
  • 增量收集 —— 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时 间并在执行过程中带来明显的延迟。所以引擎试图将垃圾收集工作分成几部分来做,然后将这 几部分逐一处理。这需要他们之间额外的标记来追踪变化,但是会有许多微小的延迟而不是大 的延迟。
  • 闲时收集 —— 垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。

总结 主要需要掌握的东西:

  • 垃圾回收是自动完成的,我们不能强制执行或是阻止执行。
  • 当对象是可达状态时,它在内存中是可达的。
  • 被引用与可访问(从一个根)不同:一组相互连接的对象可能整体都无法访问。

# Sysmbol 类型

Symbol 保证是唯一的。即使我们创建了许多具有相同描述的 Symbol,它们的值也是不同。描述 只是一个不影响任何东西的标签。

全局 symbol
正如我们所看到的,通常所有的 Symbol 都是不同的,即使它们有相同的名字。但有时我们想要同
一个名字的 Symbol 是相同的实体。 比如,我们希望在应用程序的不同部分访问相同的 Symbol "id" 属性 。
为此,存在一个全局 symbol 注册表。我们可以在其中创建 Symbol 并在稍后访问它们,它可以确 保每次访问相同名称都会返回相同的 Symbol。
为了在注册表中创建或读取 Symbol,请使用 Symbol.for(key) 。 该调用会检查全局注册表,如果有一个描述为 的 Symbol,则返回该 Symbol,否则将创建一 个新 Symbol( Symbol(key) ),并通过给定的 将其存储在注册表中。 例如:

// 从全局注册表中读取
let id = Symbol.for('id') // 如果该 Symbol 不存在,则创建它
// 再次读取
let idAgain = Symbol.for('id')
// 相同的 Symbol
alert(id === idAgain) // true
1
2
3
4
5
6

Symbol.keyFor 对于全局 symbol, 不仅按名称返回一个 symbol,而且还有一个反向调用: Symbol.keyFor(sym),反过来:通过全局 symbol 返回一个名称。

系统 Symbol

  • Symbol.hasIntance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.toPromitive

# Symbol 总结

Symbol 是标识符的基本类型

Symbol 使用 Symbol 创建的,调用带有一个可选描述。 Symbol 总是不同的值,即使他们有相同的名称。我们希望同名的 Symbol 相等,那么我们使用全局注册表;Symbol.for(key)返回一个以 key 作为名称的全局 Symbol, 返回(如果需要的话创建)一个以 key 作为名称的全局 Symbol。 的多次调用完全返回相同的 Symbol。

Symbol 有两个主要的使用场景:

  • 隐藏对象属性。如果需要将属性添加到另一个脚本或库中的对象中,则可以创建 Symbol 并将其用作属性键。Symbol 属性不出现在 for...in 中,因此不会无心列出。另外它不会被直接访问,因为另一个脚本没有我们的符号,所以它不会不小心干预它的操作。
  • JavaScript 使用了许多系统 Symbol,这些 Symbol 可以作为 访问。我们可以使用 Symbol.for(key)Symbol.for 它们来改变一些内置行为。例如,在本教程的后面部分,我们将使用 Symbol.iterator 迭代,Symbol.toPrimitive 来设置对象原始值的转换等等。
  • Object.getOwnPropertySymbols(obj) 允许我们获取所有的 Symbol。
let obj = { name: 'Miro' }
obj[(Symbol('age') = 25)]
for (let key in obj) {
  console.log(key)
} // name undefined
console.log(obj[Symbol('age')]) // undefined
Object.getOwnPropertySymbols(obj) // [Symbol(age)]
1
2
3
4
5
6
7

# 对象方法与 this

总结

  • 存储在对象中函数称之为『方法』。
  • 对象执行方法进行『操作』,比如 object.doSomething() 。
  • 方法可以将该对象引用为 this 。 this 的值是在运行时求值的。
  • 函数声明使用的 this 只有等到调用时才会有值。
  • 函数可以在对象之间进行共用。
  • 当函数使用『方法』语法 object.method() 调用时,调用过程中的 this 总是指向 object 。 请注意箭头函数有些特别:它们没有 this 。在箭头函数内部访问的都是来自外部的 this 值。

# 对象原始值转换

Symbol.toPrimitive 我们从第一个方法开始。有一个名为 Symbol.toPrimitive 的内置符号应该用来命名转换方 法,像这样:

obj[Symbol.toPrimitive] = function(hint) {
  // 返回一个原始值
  // hint = "string","number" 和 "default" 中的一个
}
1
2
3
4
let user = {
  name: 'John',
  money: 1000,
  [Symbol.toPrimitive](hint) {
    alert(`hint: ${hint}`)
    return hint == 'string' ? `{name: "${this.name}"}` : this.money
  }
}

// 转换演示:
alert(user) // hint: string -> {name: "John"}
alert(+user) // hint: number -> 1000
alert(user + 500) // hint: default -> 1500
1
2
3
4
5
6
7
8
9
10
11
12
13

对象到原始值的转换,是由许多内置函数和操作符自动调用的,这些函数使用一个原始值作为返回 值的。 它有三种类型(暗示):

  • "string"(对于 alert 和其他字符转换)
  • "number"(对于 maths)
  • "default"(少数操作) 规范明确描述了哪个操作符使用哪个暗示。极少数操作者“不知道期望什么”并使用 "default" 暗示。通常对于内置对象,"default" 暗示的处理方式与 "number" 相同,因此在实践中最后 两个通常合并在一起。 转换算法是:
  1. 调用 objSymbol.toPrimitive如果这个方法存在的话,
  2. 否则如果暗示是"string"
    2-1. 尝试 obj.toString() 和 obj.valueOf(),无论哪个存在
  3. 否则,如果暗示"number"或者"default"
    3-1. 尝试 obj.valueOf() 和 obj.toString() 无论哪个存在。

在实践中,为了记录或调试目的,仅实现 obj.toString() 作为“全捕获"方法通常就够了,这样所有转换都能返回一种“人类可读”的对象表达形式。

# 构造函数和操作符 new

一个函数作为 new User(...)执行时,它执行以下步骤:

  • 一个新的空对象被创建并分配给 this
  • 函数体执行。通常它会修改 this,并为其添加新的属性。
  • 返回 this 的值

使用 new.target 来检查它是否被调用

function User(name) {
  if (!new.target) {
    return new User(name)
  }
  this.name = name
}
1
2
3
4
5
6

# 数字类型

在 JavaScript 中,我们通过在数字后附加字母 “e” 来缩短数字,并指定零的数量来计数
换句话说, "e" 把数字乘以 1 后面跟着指定数量的 0。 换句话说, e 后面的负数表示除以 1 后面跟着给定数量的 0:

1e3 = 1 * 1000
1.23e6 = 1.23 * 1000000
1e-3 = 1 / 1000 (=0.001)
1.23e-6 = 1.23 / 1000000 (=0.00000123)
1
2
3
4

parseInt 和 parseFloat 会忽略数字后的字符,而 Number 和“+”并不会, 例:

;+'1000px' // NaN
Number('1000px') // NaN
Number('12.3.4') // NaN
parseInt('1000px') // 1000
parseFloat('12.3.4') // 12.3 the second point stops the reading
1
2
3
4
5

parseInt(str, radix) 第二个参数指定了数字系统的基础,例:

parseInt('0xff', 16) // 255
parseInt('n9c', 36) // 123456
1
2

总结: 写入非常大的数字,使用 e 来代替 0
对于不同进制:

  • 可以在十六进制 0x,八进制 0o 和二进制 0b 系统中直接写入数字
  • parseInt(str, base) 解析来自任何数字系统的整数,
  • num.toString(base)将数字转换为数字系统中具有给定 base 的字符串
  • 使用 parseInt / parseFloat 进行 软 转换,它从字符串中读取一个数字,然后返回错误发生前可以读取的值。
    分数:
  • 使用 Math.floor,Math.ceil,Math.trunc,Math.round 或 num.toFixed(precision)循环。
  • 请记住,使用分数时会损失精度。

用于替代 indexof(x) !== -1 可以用~运算符既~n 的意思跟-(n+1)完全一样,既:

if ([1,2,3].indexOf(4) !== -1)  可以写成
if (~[1,2,3].indexOf(4))
1
2

es6 更推荐使用 includes 方法

# 获取子字符串

有三种方法 substring, substr, slice

方法 选择方式...... 负号参数
slice(start, end) 从 start 到 end(不含 end) 允许
substring(start, end) start 和 end 之间 负值代表 0
substr(start, length) 从 start 开始获取长为 length 的字符串 允许 start 为负数

总结:

  • 有 3 种类型的引号。反引号允许字符串跨越多行并可以在 ${...} 中嵌入表达式。
  • js 中的字符串使用 UTF-16 进行编码
  • 我们可以使用想\n 这样的特殊字符或者通过使用\u...佬操作他们的 unicode 进行字符插入
  • 获取字符时使用[]
  • 获取子字符串,使用 slice 或 substring 。
  • 字符串的大/小写转换,使用: toLowerCase 或 toUpperCase
  • 查找子字符串时,使用 indexOf 或 includes、startsWith、endsWith 进行简单的检查
  • 根据语言比较字符串时使用 localeCompare,否则将按字符代码进行比较

# 数组

避免用 for...in 循环数组的原因:

  • for..in 循环会迭代所有属性,不仅仅是这些数字属性。 在浏览器和其它环境中有一种“类数组”的对象,它们看似是数组,也就是说,它们有 length 和索引属性,但是也可能有其它的非数字的属性和方法,这通常是我们不需要的。for...in 循环会把它们都列出来。所以如果我们需要处理类数组对象,这些“额外”的属性就会存在问题。
  • for..in 循环适用于普通对象,不适用于数组,而且会慢 10-100 倍。当然即使是这样也依然 非常快。只有在遇到瓶颈或者一些不相关的场景增速可能会有问题。但是我们仍然应该了解这其中的不同

通常来说我们不应该用 for...in 来处理数组

# concat

通常 concat 只复制数组中的元素,比如类数组,即使他们看起来像数组,但仍作为一个整体添加:

let arr = [1, 2]
let arrayLike = {
  0: 'something',
  length: 1
}

console.log(arr.concat(arrayLike)) // [1,2,[object Object]]
1
2
3
4
5
6
7

但是如果类似数组的对象具有 Symbol.isdConcatSpreadable 属性,将替换其元素:

let arrLike = {
  0: 'something',
  1: 'else',
  [Symbol.isConcatSpreadable]: true,
  length: 2
}

console.log(arr.concat(arrayLike)) // 1,2,something,else
1
2
3
4
5
6
7
8

# indexOf 和 includes 的差别

includes 能正常的处理 NaN,例如:

const arr = [NaN]
console.log(arr.indexOf(NaN)) // -1 should be 0,but === equality doesn't work for NaN
console.log(arr.includes(NaN)) // true (correct)
1
2
3

# sort 函数

sort 函数会对数组的元素转换为字符串进行排序, 所以进行数字排序的话,它会先把数字转化为字符串然后按照词典顺序进行比较

# 总结

数组方法备忘录:

添加删除元素:

  • push --- 从结尾添加元素
  • pop --- 从结尾提取元素
  • shift --- 从开头提取元素
  • unshift --- 从开头添加元素
  • splice(pos, deleteCount, ...items) — 从 index 开始:删除 deleteCount 元素并在当前位置插入元素。
  • slice(start, end) — 它从所有元素的开始索引 "start" 复制到 "end" (不包括 ) 返回一个新的数组。
  • concat --- 返回一个新的数组,复制当前数组的所有成员向其中添加 items

查询元素

  • indexOf/lastIndexOf(item, pos) --- 从 pos 找到 item,则返回索引否则返回-1
  • includes -- 如果数组中有 value,则返回 true,否则返回 false
  • find/filter -- 返回符合条件的第一个值 / 符合条件的所有值
  • findIndex -- 返回符合条件的索引

转换函数

  • map -- 从每个元素调用 func 的结果创建一个新数组。

  • sort(func) — 将数组倒序排列,然后返回。

  • reverse() — 在原地颠倒数组,然后返回它。

  • split/join -- 将字符串转换为数组并返回

  • reduce -- 累加

  • forEach -- 为每个元素调用 func,不返回任何东西

  • arr.some(fn)  /arr.every(fn)  检查数组。 在类似于 map 的数组的每个元素上调用函数 fn 。如果任何/所有结果为 true ,则返回 true ,否则返回 false 。

  • arr.fill(value, start, end)  — 从 start 到 end 用 value 重复填充数组。

  • arr.copyWithin(target, start, end)  — copies its elements from position into itself, at position target (overwrites existing).将其元素从 位置复制到 本身(覆盖现有)

# iterables(可迭代对象)

Symbol.iterator(一个特殊的内置标记)

  • 当 for..of 循环开始,它将会调用这个方法(如果没找到,就会报错)。
  • 这个方法必须返回一个迭代器 —— 一个有 next 方法的对象。
  • 返回结果的格式必须是{done: Boolean, value: any}, 当done为true时,表示迭代结束,否则value必须是一个未被迭代的新值。
    
let range = {
  from: 1,
  to: 5
}
// 1. 使用for..of会首先调用它
range[Symbol.iterator] = function() {
// 2. ...它返回一个迭代器:
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 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

这段代码中有几点需要着重关注:

  • range 自身没有 next 方法
  • 相反,是调用 rangeSymbol.iterator将会被创建的另外一个所谓的迭代器对象

所以,迭代器对象和迭代的对象其实是分离的。技术上说,我们可以将它们合并,用 range 自身作为迭代器来简化代码。

let range = {
  from: 1,
  to: 5,
  [Symbol.iterator]() {
    this.current = this.from
    return this
  },
  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ }
    } else {
      return { done: true }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 可迭代对象和类数组对象

这两个正式术语很相似, 但是却非常不同。

  • Iterables 是应用于 Symbol.iterator 方法的对象
  • Array-likes 是有索引和 length 属性的对象,所以它们很像数组

# 总结

可以应用 for...of 的对象被称为可迭代的。

  • 技术上来说,可迭代对象必须实现方法 Symbol.iterator。
    • obj[Symbol.iterator]的结果被称为迭代器。由它处理更深入的迭代过程。
    • 一个迭代器必须有 next()方法,它返回一个{done: Boolean, value: any},这里的 done: true 表明迭代结束,否则 value 就是下一个值
    • Symbol.iterator 方法会被 for...of 自动调用,但我们也可以直接调用。
    • 内置的可迭代对象例如字符串和数组,都实现了 Symbol.iterator。
    • 字符串迭代器能够识别 UTF-16 扩展字符。

有索引属性和 length 属性的对象称为类数组对象。这种对象也许也有其他属性和方法,但是没有数组内建方法。
Array.from(obj[, mapFn, thisArg])将可迭代对象或类数组对象 obj 转化为真正的 Array 数组,然后我们就可以对它应用数组的方法。可选参数 mapFn 和 thisArg 允许我们队每个元素都应用一个函数。

# Map、Set、WeakMap 和 WeakSet

Map 是一个键值对的集合,很像 Object 。但主要的区别是, Map 允许所有数据类型作为键。
Map 可以使用对象作为键。

链式调用 map:

map
  .set(1, 'str1')
  .set(2, 'str2')
  .set(3, 'str3')
1
2
3
4

set 是一个值的集合,这个集合中所有的值仅出现一次。

# WeakMap 和 WeakSet

WeakSet 是一种特殊的 Set,他不会阻止 js 将它的元素从内存中移除。WeakMap 也一样
WeakMap/WeakSet 不会阻止内存移除对象。
WeakMap 和 Map 的第一个区别是他的键必须是对象,不能为基础类型的值
WeakMap 和 WeakSet 最显著的限制就是没有迭代器,也不能获取当前所有内容。这可能会有 点不方便,但是实际上并不妨碍 WeakMap/WeakSet 的主要任务 —— 作为对象的附加存储,该 对象在其他位置被保存或管理。

总结 Map —— 是一个键值对集合 和普通 Object 的区别:

  • 对象可以作为键。
  • 迭代顺序是插入顺序。
  • 附加方便的方法,有 size 属性。 Set —— 是一个包含不重复值的集合。
  • 和 array 不同,set 不允许元素重新排序。
  • 保持插入的顺序。 WeakMap —— Map 的一个变体,仅允许对象作为键,并且当对象由于其他原因不可引用的时 候将其删除。
  • 它不支持整体的操作:没有 size 属性,没有 clear() 方法,没有迭代器。 WeakSet —— 是 Set 的一个变体,仅存储对象,并且当对象由于其他原因不可引用的时候 将其删除。
  • 同样不支持 size/clear() 和迭代器。

WeakMap 和 WeakSet 被用作主要对象存储的次要数据结构补充。一旦对象从存储移除,那么 存在于 WeakMap/WeakSet 的数据将会被自动清除。

# 结构赋值

  • 解构赋值允许将对象或数组立即映射到多个变量上。
//结构对象
let {prop: varName = default, ...} = object
// 这个属性prop会被赋值给变量varName, 如果没有这个属性的话,就会使用default的值。
//结构数组
let [item1 = default, item2, ...rest] = array
// 数组的第一个元素赋值给item1,第二个元素赋值给item2,剩下的所有组成另一个数组rest
1
2
3
4
5
6

# Date 对象

  • 在 js 中,日期和时间使用 Date 对象来表示。不能只创建时间,Date 对象总是两个都创建。
  • 月份从 0 开始计算
  • 一周的某一天使用 getDay, 0 代表星期天
  • 当超出范围的信息被设置,Date 会做自动校准。这一点对于日/月/小时 的加减很有效。
  • 日期可以相减,得到的是两者的差值,用毫秒表示。因为当转化为数字时, Date 对象变为时间戳。
  • 使用 Date.now()可以更快地获得当前时间戳

和其他语言不同,JavaScript 中时间戳是用毫秒表示,而不是秒。

在Github上编辑此页 (opens new window)
#JavaScript
上次更新: 3/22/2021, 3:47:15 AM
JavaScript基础知识
基础知识3

← JavaScript基础知识 基础知识3→

最近更新
01
如何打造全链路项目生命周期的统一交付平台
04-10
02
如何建立前端标准化研发流程
04-10
03
如何从0到1一步步成体系地搭建CI
04-10
更多文章>
Theme by Vdoing | Copyright © 2019-2021 Syun
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式