Array.prototype.keys()
:返回以索引值为遍历器的对象
1.Let 和 Const
在ES6以前,JS
只有var
一种声明方式,但是在ES6之后,就多了let
跟const
这两种方式。用var
定义的变量没有块级作用域的概念,而let
跟const
则会有,因为这三个关键字创建是不一样的
var | let | const | |
变量提升 | + | - | - |
全局变量 | + | - | - |
重复赋值 | + | + | - |
重复声明 | + | - | - |
暂时死区 | - | + | + |
块作用域 | - | + | + |
只声明不赋值 | + | + | - |
2.类(Class)
/* 匿名类 */ let Rectangle = class { constructor(height, width) { this.height = height; this.width = width; } }; /* 命名的类 */ let Rectangle = class Rectangle { constructor(height, width) { this.height = height; this.width = width; } };
在ES6之前,如果我们要生成一个实例对象,传统的方法就是写一个构造函数,例子如下
function Person(name, age) { this.name = name this.age = age } Person.prototype.information = function () { return 'My name is ' + this.name + ', I am ' + this.age }
Person.distance(a,b){
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
但是在ES6之后,我们只需要写成以下形式:
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
// Getter
get area() {
return this.calcArea()
}
// 静态方法
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
// 原型方法
information() {
return 'My name is ' + this.name + ', I am ' + this.age
}
}
3.箭头函数(Arrow function)
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this
,arguments
,super
或 new.target
。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。
4.函数参数默认值(Function parameter defaults)
在ES6之前,如果我们写函数需要定义初始值的时候,需要这么写:
function config (data) { var data = data || 'default' }
这样看起来也没有问题,但是如果参数的布尔值为falsy时就会出问题,结果就永远是后面的值
const config = (data = 'data is empty') => {}
5.模板字符串(Template string)
6.解构赋值(Destructuring assignment)
我们通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
let a = 10 let b = 20 [a, b] = [b, a]
7.模块化(Module)
8.扩展操作符(Spread operator)
扩展操作符可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。
const sum = (x, y, z) => x + y + z const list = [5, 6, 7] const total = sum(...list)
但是要注意的是扩展操作符只能用于可迭代对象
9.对象属性简写(Object attribute shorthand)
let cat = 'Miaow' let dog = 'Woof' let bird = 'Peet peet' let someObject = { cat, dog, bird }
10.Promise
11.Symbol
数据类型 “symbol” 是一种原始数据类型,该类型的性质在于这个类型的值可以用来创建匿名的对象属性。该数据类型通常被用作一个对象属性的键值——当你想让它是私有的时候
Symbol()
函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()
"。
当一个 symbol 类型的值在属性赋值语句中被用作标识符,该属性(像这个 symbol 一样)是匿名的;并且是不可枚举的。
每个从Symbol()
返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。
const symbol1 = Symbol(); const symbol2 = Symbol(42); const symbol3 = Symbol('foo'); console.log(typeof symbol1); // "symbol" console.log(symbol3.toString()); // "Symbol(foo)" console.log(Symbol('foo') === Symbol('foo')); // false
12.迭代器(Iterator)/ 生成器(Generator)
在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。 更具体地说,迭代器是通过使用 next()
方法实现 Iterator protocol 的任何一个对象,该方法返回具有两个属性的对象: value
,这是序列中的 next 值;和 done
,如果已经迭代到序列中的最后一个值,则它为 true
。如果 value
和 done
一起存在,则它是迭代器的返回值。
一旦创建,迭代器对象可以通过重复调用next()显式地迭代。 迭代一个迭代器被称为消耗了这个迭代器,因为它通常只能执行一次。 在产生终止值之后,对next()的额外调用应该继续返回{done:true}。
自定义迭代器
function makeRangeIterator(start = 0, end = Infinity, step = 1) { let nextIndex = start; let iterationCount = 0; const rangeIterator = { next: function() { let result; if (nextIndex < end) { result = { value: nextIndex, done: false } nextIndex += step; iterationCount++; return result; } return { value: iterationCount, done: true } } }; return rangeIterator; }
let it = makeRangeIterator(1, 10, 2);
let result = it.next();
while (!result.done) {
console.log(result.value); // 1 3 5 7 9
result = it.next();
}
console.log("Iterated over sequence of size: ", result.value); // 5
虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 生成器函数使用 function*
语法编写。 最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。 通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。
function* makeRangeIterator(start = 0, end = Infinity, step = 1) { for (let i = start; i < end; i += step) { yield i; } } var a = makeRangeIterator(1,10,2) a.next() // {value: 1, done: false} a.next() // {value: 3, done: false} a.next() // {value: 5, done: false} a.next() // {value: 7, done: false} a.next() // {value: 9, done: false} a.next() // {value: undefined, done: true}
13.for...of
for...of
语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments
对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
const array1 = ['a', 'b', 'c']; for (const element of array1) { console.log(element) } // "a" // "b" // "c"
14.Set/WeakSet
Set
对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
如果传递一个可迭代对象,它的所有元素将不重复地被添加到新的 Set中。如果不指定此参数或其值为null
,则新的 Set为空。
另外,NaN
和undefined
都可以被存储在Set 中, NaN
之间被视为相同的值(NaN被认为是相同的,尽管 NaN !== NaN)
const set1 = new Set([1, 2, 3, 4, 5]); console.log(set1.has(1)); // expected output: true console.log(set1.has(5)); // expected output: true console.log(set1.has(6)); // expected output: false
Set.prototype.size
返回Set
对象的值的个数。
Set.prototype.add(value)
在Set对象尾部添加一个元素。返回该
Set对象。
Set.prototype.clear()
移除Set
对象内的所有元素。
Set.prototype.delete(value)
移除Set的中与这个值相等的元素,返回Set.prototype.has(value)在这个操作前会返回的值(即如果该元素存在,返回true,否则返回false)。
Set.prototype.has(value)在此后会返回false。
Set.prototype.entries()
返回一个新的迭代器对象,该对象包含Set对象中的
按插入顺序排列的所有元素的值的[value, value]数组。为了使这个方法
和Map对象保持相似,
每个值的键和值相等。
Set.prototype.forEach(callbackFn[, thisArg])
按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。
Set.prototype.has(value)
返回一个布尔值,表示该值在Set中存在与否。
Set.prototype.keys()
与values()
方法相同,返回一个新的迭代器对象,该对象包含Set对象中的
按插入顺序排列的所有元素的值。
Set.prototype.values()
返回一个新的迭代器对象,该对象包含Set对象中的
按插入顺序排列的所有元素的值。
WeakSet
对象是一些对象值的集合, 并且其中的每个对象值都只能出现一次。在WeakSet
的集合中是唯一的
它和 Set
对象的区别有两点:
- 与
Set
相比,WeakSet
只能是对象的集合,而不能是任何类型的任意值。 WeakSet
持弱引用:集合中对象的引用为弱引用。 如果没有其他的对WeakSet
中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 正因为这样,WeakSet
是不可枚举的。
15.Map/WeakMap
Map
对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。
WeakMap
对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
16.Proxy/Reflect
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。
let p = new Proxy(target, handler);
target
用Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。handler
一个对象,其属性是当执行一个操作时定义代理的行为的函数。
let handler = { get: function(target, name){ return name in target ? target[name] : 37; } }; let p = new Proxy({}, handler); p.a = 1; p.b = undefined; console.log(p.a, p.b); // 1, undefined console.log('c' in p, p.c); // false, 37
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。Reflect
不是一个函数对象,因此它是不可构造的。
与大多数全局对象不同,Reflect
不是一个构造函数。你不能将其与一个new运算符一起使用,或者将Reflect
对象作为一个函数来调用。Reflect
的所有属性和方法都是静态的(就像Math
对象)。
17.Array对象的扩展
Array.prototype.from()
:转换具有Iterator接口
的数据结构为真正数组,返回新数组。
console.log(Array.from('foo')) // ["f", "o", "o"] console.log(Array.from([1, 2, 3], x => x + x)) // [2, 4, 6]
Array.prototype.of()
:转换一组值为真正数组,返回新数组。
Array.of(7) // [7] Array.of(1, 2, 3) // [1, 2, 3] Array(7) // [empty, empty, empty, empty, empty, empty] Array(1, 2, 3) // [1, 2, 3]
Array.prototype.copyWithin()
方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
arr.copyWithin(target[, start[, end]])
const array1 = ['a', 'b', 'c', 'd', 'e'] console.log(array1.copyWithin(0, 3, 4)) // ["d", "b", "c", "d", "e"] console.log(array1.copyWithin(1, 3)) // ["d", "d", "e", "d", "e"]
target
0 为基底的索引,复制序列到该位置。如果是负数,target
将从末尾开始计算。如果 target
大于等于 arr.length
,将会不发生拷贝。
如果 target
在 start
之后,复制的序列将被修改以符合 arr.length
。
start
0 为基底的索引,开始复制元素的起始位置。如果是负数,start
将从末尾开始计算。如果 start
被忽略,copyWithin
将会从0开始复制。
end
0 为基底的索引,开始复制元素的结束位置。
copyWithin
将会拷贝到该位置,但不包括 end
这个位置的元素。如果是负数, end
将从末尾开始计算。
如果 end
被忽略,copyWithin
方法将会一直复制至数组结尾(默认为 arr.length
)
Array.prototype.find()
:返回第一个符合条件的成员
Array.prototype.findIndex()
:返回第一个符合条件的成员索引值
Array.prototype.fill()
:根据指定值填充整个数组,返回原数组
Array.prototype.keys()
:返回以索引值为遍历器的对象
Array.prototype.values()
:返回以属性值为遍历器的对象
Array.prototype.entries()
:返回以索引值和属性值为遍历器的对象数组空位
:ES6明确将数组空位转为undefined
或者empty
Array.from(['a',,'b']) // [ "a", undefined, "b" ] [...['a',,'b']] // [ "a", undefined, "b" ] Array(3) // [empty × 3] [,'a'] // [empty, "a"]