String
字符的Unicode 表示法
// JavaScript允许采用\uxxxx形式表示一个字符,其中“xxxx”表示字符的码点。
"\u0061"
// "a"
// 但是,这种表示法只限于\u0000——\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表达。
"\uD842\uDFB7"
// "𠮷"
"\u20BB7"
// " 7"
// es6
"\u{20BB7}"
// "𠮷"
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true
- codePointAt
处理返回占用资格字节存储的字符 - fromCodePoint
处理32位UTF-16 的字符 - 字符串可迭代
- at
可以用来识别Unicode编号大于 0xFFFF
的字符,返回正确的字符 - normalize
用来将字符的不同表示方法统一为同样的形式,称之为Unicode正规化
以下玩个方法都可以输入第二个参数,表示起始位置
- includes
返回一个bool, 表示是否找到了参数字符串 - startsWith
返回一个bool, 表示参数字符串是否正在源字符串的头部 - endsWith
返回一个bool, 表示参数字符串是否存在源字符串的尾部 ```javascript var s = ‘Hello world!’;
s.startsWith(‘Hello’) // true s.endsWith(‘!’) // true s.includes(‘o’) // true
s.startsWith(‘world’, 6) // true s.endsWith(‘Hello’, 5) // true s.includes(‘Hello’, 6) // false
- repeat <func> 返回一个新字符串, 表示将源字符串重复n次
es7 推出了字符串的补全方法。
- padStart <func> 从源字符串的头部填充
- padEnd <func> 从源字符串的尾部填充
```javascript
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
Number
es6 提供了二进制(0b)和八进制(0B)数值的新的写法,
0b111110111 === 503 // true
0o767 === 503 // true
对number 新增的方法
// 用来检查一个数值是否有限
.isFinite(true) // true
.isFinite(Infinity) // false
// 用来检查一个值是否为NaN. 是原来全局isNaN的更稳妥的版本
.isNaN(NaN) // true
.isNaN(1212) // false
// 转换为number, 与全局的方法没有区别
.parseInt(`12.32`) // 12
.parseFloat(`12.23`) // 12.23
// 判断一个值是否为整数,整数和浮点数在这是一致的
.isInteger(23) // true
.isInteger(25.1) || .isInteger(`foo`) // false
// 一个极小的常量
Number.EPSILON
// 一个数值是否为安全整数
.isSafeInteger()
Array
from
该 转换为数组,只要部署了Iterator接口的数据结构都可被转换
扩展运算符背后调用的是遍历器接口(Symbol.iterator), 如果一个对象没有部署这个接口,就无法转换。 .from 方法只要lenth属性就可以被转为数组
第二个参数类似于数组的map方法
// 转换为数组,只要部署了Iterator接口的数据结构都可被转换
Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
// 扩展运算符背后调用的是遍历器接口(Symbol.iterator), 如果一个对象没有部署这个接口,就无法转换
// .from 方法只要lenth属性就可以被转为数组,
[...arguments]
// 第二个参数类似于数组的map方法
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
of
将一组值,转换为数组,(主要弥补的Array的不足)
// Array()
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
// of
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
copyWithin
用于对一个数组的赋值操作
它接受三个参数。
- target(必需):从该位置开始替换数据。
- start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
find & findIndex
```javascript [1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) // 10
[1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2
<a name="riVSM"></a>
#### fill
该方法使用给定的值,填充一个数组
<a name="Rk8X3"></a>
#### entries & keys & values & includes
```javascript
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, NaN].includes(NaN); // true
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
数组的空位
forEach()
,filter()
,every()
和some()
都会跳过空位。map()
会跳过空位,但会保留这个值join()
和toString()
会将空位视为undefined
,而undefined
和null
会被处理成空字符串 ```javascript // forEach方法 [,’a’].forEach((x,i) => console.log(i)); // 1
// filter方法 [‘a’,,’b’].filter(x => true) // [‘a’,’b’]
// every方法 [,’a’].every(x => x===’a’) // true
// some方法 [,’a’].some(x => x !== ‘a’) // false
// map方法 [,’a’].map(x => 1) // [,1]
// join方法 [,’a’,undefined,null].join(‘#’) // “#a##”
// toString方法 [,’a’,undefined,null].toString() // “,a,,”
// 在es6 Array.from([‘a’,,’b’]) // [ “a”, undefined, “b” ]
[…[‘a’,,’b’]] // [ “a”, undefined, “b” ]
[,’a’,’b’,,].copyWithin(2,0) // [,”a”,,”a”]
new Array(3).fill(‘a’) // [“a”,”a”,”a”]
let arr = [, ,]; for (let i of arr) { console.log(1); } // 1 // 1
entries()、keys()、values()、find()和findIndex()会将空位处理成undefined
```javascript
// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]
// keys()
[...[,'a'].keys()] // [0,1]
// values()
[...[,'a'].values()] // [undefined,"a"]
// find()
[,'a'].find(x => true) // undefined
// findIndex()
[,'a'].findIndex(x => true) // 0
Object
- 对象简介表示法,
{a,b}}
- getter 和setter
{get [] (){}, set [] (){}}
- 属性表达式
{ ["name"]:"张大炮"}
- .is 比较两个值是否相等
- assign 合并一个或多个对象到源对象,返回新的对象,浅拷贝
- 扩展运算符
{...}
- 方法的name 属性
- bind方法创造的函数,name属性会返回bound加上原函数的名字
- function 构造函数创造的函数, name属性返回
anonymouns
```javascript var person = { sayName() { console.log(this.name); }, get firstName() { return “Nicholas”; } };
person.sayName.name // “sayName” person.firstName.name // “get firstName”
(new Function()).name // “anonymous”
var doSomething = function() { // … }; doSomething.bind().name // “bound doSomething”
const key1 = Symbol(‘description’); const key2 = Symbol(); let obj = { key1 {}, key2 {}, }; obj[key1].name // “[description]” obj[key2].name // “”
<a name="W1gW3"></a>
## function
<a name="xWzt9"></a>
#### 默认参数
**只有undefined有默认参数的效果**
```javascript
// 之前的写法
function log(x, y) {
y = y || 'World';
console.log(x, y);
}
function log(x, y = "world") {
console.log(x, y);
}
结构赋值
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
foo() // TypeError: Cannot read property 'x' of undefined
参数默认值的位置
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]
函数的length属性
在之前函数的length会返回该函数的参数个数
指定了默认值的参数后,该参数不会被length属性计算,length将失真
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
rest参数
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
严格模式
在es5开始,函数内部可以设定为严格模式
在es6,函数参数只要使用了默认值,结构赋值,扩展运算符,函数内部不能显式的指定为严格模式。
因为,函数内部的严格模式,同时适用于函数体代码和函数参数代码,函数执行的时候,先执行函数参数代码,然后再执行函数体代码。这样就有一个不合理的地方,只有从函数体代码之中,才能知道参数代码是否应该以严格模式执行,但是参数代码却应该先于函数体代码执行,虽然可以先解析函数体代码,再执行参数代码,但是这样无疑就增加了复杂性。因此,标准索性禁止了这种用法.
箭头函数
const fn = v => v;
// 需要返回对象时,用括号包括,数组也是
var getTempItem = id => ({ id: id, name: "Temp" });
- 函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。 - 不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。 - 不可以使用
yield
命令,因此箭头函数不能用作Generator函数绑定this
箭头函数可以绑定this
对象,大大减少了显式绑定this
对象的写法
ES7提出了“函数绑定”(function bind)运算符,用来取代call
、apply
、bind
调用
由于双冒号运算符返回的还是原对象,因此可以采用链式写法 ```javascript // rust? foo::bar; // 等同于 bar.bind(foo);
foo::bar(…arguments); // 等同于 bar.apply(foo, arguments);
const hasOwnProperty = Object.prototype.hasOwnProperty; function hasOwn(obj, key) { return obj::hasOwnProperty(key); }
// 默认绑定对象 var method = obj::obj.foo; // 等同于 var method = ::obj.foo;
let log = ::console.log; // 等同于 var log = console.log.bind(console);
<a name="Li518"></a>
#### 尾调用
一个函数式编程的一个重要概念,指的是某个函数的最后一步是调用另一个函数(不是指在函数体的最后一行,是最后一步)
<a name="Ch1TO"></a>
#### 尾递归
函数调用自身,称为递归,如果在尾调用自身,就称为尾递归
<a name="XlYfd"></a>
#### 函数参数的尾逗号
没啥用,给版本管理系统看的
<a name="g16OP"></a>
## Symbol
一个新的原始数据类型,表示独一无二的指。
<a name="Qv3UB"></a>
#### 迭代
symblo 作为属性名,该属性不会出现在 `for...in` 、 `for...of` 、 `Object.keys` 、 `Object.getOwnPropertyNames` 、 `JSON.stringify` 返回,但是不是私有属性,和neumble无关,可以被 `Objct.getOwnPropertySymblos` 方法获取指定对象所有Symbol属性名。可以被 `Reflect.ownKeys` 方法返回所有类型的键名,常规的和Symbol键名
<a name="HDWQw"></a>
#### for
使用.for生成的symbol值,会被登记在全局环境中供搜索<br />for不会每次调用返回一个新的symbol值,会先检查key是否存在,如果不存在才会新建一个值。
```javascript
Symbol.for("bar") === Symbol.for("bar")
// true
Symbol("bar") === Symbol("bar")
// false
keyFor
返回一个已登记的Symbol类型的值
不会被登记,不会被搜索
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let foo = Symbol.for("foo1");
let f1 = Symbol.keyFor(foo);
console.log(f1 === "foo1");
内置的属性
- hasInstance 指定一个方法。在使用instanceof 运算符时会被调用
- isConcatSpeaedable 指定一个bool, 表示该对象使用
.concat
时,是否可以展开 - species 指定一个方法,该对象所为构造函数创造实例,会被调用
- match 指定一个函数,当执行
str.match(obj)
时,如果该属性存在,会被调用,返回该方法的的返回值 - replace 指定一个方法, 当
string.replace
对调用时,会返回该方法的返回值 - search 指定一个方法,当该对象被
string.search
调用时,会返回该方法的返回值 - split 指定一个方法, 当
string.split
被调用时,返回该方法的返回值 - iterator 一个对象的属性,指定该对象的默认遍历器方法
- toStringTag 指定一个方法,在该对象调用
toString
如果这个属性存在,会出现在tostring的返回值中表示对象的类型。 ```javascript ({[Symbol.toStringTag]: ‘Foo’}.toString()) // “[object Foo]”
class Collection { get Symbol.toStringTag { return ‘你好’; } } var x = new Collection(); Object.prototype.toString.call(x) // “[object 你好]”
- toPrmitive 指定一个方法,该对象被转为原始类型的值时,被调用,返回该对象对应的原始类型值
```javascript
// Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。
Number // 该场合需要转成数值
String // 该场合需要转成字符串
Default// 该场合可以转成数值,也可以转成字符串
- unscopables 指定一个对象,该对象指定了使用with关键字时,那些属性会被with环境排除
Set & Map
Set
es6 提供新的数据结构Set,类似于数组,但是成员的值都是唯一的,所以具有唯一性
在Set加入值的时候,set不会发生类型转换。判断两个值是否相同使用的算法叫做 Same-value-equality
,类似于精确相等运算符
const seto = new Set([
{ a: 10 },
{ a: 10 }
]);
console.log(seto);
const setal = new Set([
[1, 2],
[1, 2]
])
console.log(setal);
let f1 = Symbol("foo"), f2 = Symbol("foo"), f3 = Symbol("foo");
const sym = new Set([
f1, f2, f3
])
sym.forEach((a, b) => {
console.log(a)
})
Set(2) {{…}, {…}}
Set(2) {Array(2), Array(2)}
3~ Symbol(foo)
属性、方法、可迭代
Set.prototype.constructor // 构造函数,默认就是Set函数。
Set.prototype.size // 返回Set实例的成员总数
add(value)// 添加某个值,返回Set结构本身。
delete(value)// 删除某个值,返回一个布尔值,表示删除是否成功。
has(value)// 返回一个布尔值,表示该值是否为Set的成员。
clear() // 清除所有成员,没有返回值
keys() // 返回键名的遍历器
values() // 返回键值的遍历器
entries() // 返回键值对的遍历器
forEach() // 使用回调函数遍历每个成员
// 扩展运算符也可以用在这
let set = new Set(['red', 'green', 'blue']);
let arr = [...set]; // ['red', 'green', 'blue']
weakSet
与set结构类似, 也是不重复值的集合
weakset的成员只能时对象,不能是其他类型的值,只能是数组类数组,对象
weakset中的对象都是弱引用,既垃圾回收机制不考虑weakset对该对象的引用,
所以,无法引用weakSet成员, 不可被遍历
方法
WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。
WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中
Map
由于object本质上是键值对的集合,一般都是字符串当作键,所以map出现了🎈🎈🎈
map的键不在局限与字符串,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
let items = [
['name', '张三'],
['title', 'Author']
];
let map = new Map();
items.forEach(([key, value]) => map.set(key, value)); // 执行
var map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
如果对一个键多次赋值,后面的值可以覆盖前面的值
let map = new Map();
map.set("a", "abc");
map.set("a", "cba");
map.get("a") // cba
只有对于同一个对象的引用,map结构才将其视为同一个键, map的键实际上是跟内存地址绑定的,只要内存地址不一样时,就为两个键,解决了同名属性碰撞(clash)的问题。
let map = new Map();
map.set(['a'], 666);
map.get(['a']) // undefined
let k1 = ['a'];
let k2 = ['a'];
map
.set(k1, 111)
.set(k2, 222);
map.get(k2) // 222
map.get(k1) // 111
如果Map的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map将其视为一个键,包括
0
和-0
。另外,虽然NaN
不严格相等于自身,但Map将其视为同一个键
方法、属性
.size // 当前键值对的数量
// set方法设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键
// 由于返回的是Map本身,所以可以采用链式写法
.set (key,val).set("edition", 6).set(262, "standard")
// 读取一个key对应的兼职,找不到就返回undefined
.get(key)
// 返回一个bool, 表示某个键是否存在
.has(key)
// 删除一个一个键, 成功->true;失败->false
.delete(key)
// 清除所有成员,没有返回值
.clear()
//迭代. Map的遍历顺序就是插入顺序
keys() // 返回键名的遍历器。
values() // 返回键值的遍历器。
entries() // 返回所有成员的遍历器。
forEach() // 遍历Map的所有成员。
各种转换
map转为数组
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
// 或者使用Array.from
数组转Map
new Map([[true, 7], [{foo: 3}, ['abc']]])
// Map {true => 7, Object {foo: 3} => ['abc']}
Map o object
const obj = { foo: 3 };
const map = new Map(Object.entries({ foo: 3 })) // 转为Map
const obj1 = Object.fromEntries(map) // 转为object
console.log(obj1); // {foo: 3}
obj.foo = 100;
console.log(obj, map); // {foo: 100} Map(1) {"foo" => 3}
map.set("foo", 9090)
console.log(obj, map); // {foo: 100} Map(1) {"foo" => 9090}
console.log(obj1); // {foo: 3}
const set = new Set([ obj, obj1 ])
console.log(set); // size -> 2
const set = new WeakMap([
[obj, "obj"],
[obj1, "obj1"]
])
console.log(set); // WeakMap {{…} => "obj1", {…} => "obj"}
// 深拷贝
WeakMap
区别就是只接收对象作为键名。(null)除外。
弱引用,不会计入垃圾回收机制。场景就是,键对应的对象,在后面可能会消失,有助于防止内存泄漏
区别
没有遍历操作 key(), values(), entries()
没有 size
属性
没有 clear()
方法,无法被清空
Iterator
遍历器(Iterator),就是一种机制,一种接口,为各种不同的数据结构提供统一的访问机制。任何数据机构只要实现, Iterator接口,就可以完成遍历操作
本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换。
不可直接遍历对象,因为对象没有实现Inerator接口。因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定
es6规定,默认的Iterator接口部署在数据结构的 Symbol.iterator
属性,一个数据结构只要Symbol.iterator
属性,就可以认为是可遍历的。
一个数据结构只要实现了 Iterator
接口,就称这种数据结构式可遍历的。
在es6中,三类数据结构原生的实现了该接口,
数组、某些类数组的对象、Set、Map、String
作用
- 为各种数据结构,提供一个统一的,简便的访问接口
- 使得数据几口的成员能够按照某种次序排列,
-
过程
创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的
next
方法,可以将指针指向数据结构的第一个成员。 - 第二次调用指针对象的
next
方法,指针就指向数据结构的第二个成员。 - 不断调用指针对象的
next
方法,直到它指向数据结构的结束位置 ```javascript let it = makeIterator([‘a’, ‘b’]);
it.next() // { value: “a”, done: false } it.next() // { value: “b”, done: false } it.next() // { value: undefined, done: true }
function makeIterator(array) { let nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; }
由于Iterator只是把接口的规格加到数据结构上,所以遍历器于所遍历对象是分开的。<br />可以模拟出对象的遍历器迭代的数据结构,比如下面的无限循环
```javascript
let it = idMaker();
it.next().value // '0'
it.next().value // '1'
it.next().value // '2'
// ...
function idMaker() {
let index = 0;
return {
next: function() {
return {value: index++, done: false};
}
};
}
以下场景会默认调用 Iterator
接口
// 解构赋值
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
// 扩展运算符
let str = 'hello';
[...str] // ['h','e','l','l','o']
let arr = ['b', 'c'];
['a', ...arr, 'd'] // ['a', 'b', 'c', 'd']
// yieId*
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
// orther
for...of
Array.from()
Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))
Promise.all()
Promise.race()
for…in
缺点:
- 数组的键名是数字,但是for…in循环是以字符串作为键名“0”、“1”、“2”等等。
- for…in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
-
for…of
一个数据结构只要部署了
Symbol.iterator
属性,就被视为具有iterator接口,就可以用for...of
循环遍历它的成员。也就是说,for...of
循环内部调用的是数据结构的Symbol.iterator
方法
优点: 有着同for…in一样的简洁语法,但是没有for…in那些缺点。
- 不同用于forEach方法,它可以与break、continue和return配合使用。
- 提供了遍历所有数据结构的统一操作接口。