/ES6-Note

Primary LanguageJavaScript

ES6笔记

字符串的扩展

  1. 字符串的Unicode表示法

    "\u0061"
      // "a"

    但是,这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。 有了这种表示法之后,JavaScript 共有6种方法可以表示一个字符。

    '\z' === 'z'  // true
    '\172' === 'z' // true
    '\x7A' === 'z' // true
    '\u007A' === 'z' // true
    '\u{7A}' === 'z' // true
  2. codePointAt()

    codePointAt方法是测试一个字符由两个字节还是由四个字节组成的最简单方法

    function is32Bit(c) {
      return c.codePointAt(0) > 0xFFFF;
    }
    
    is32Bit("𠮷") // true
    is32Bit("a") // false
  3. String.fromCodePoint()

    ES5提供String.fromCharCode方法,用于从码点返回对应字符,但是这个方法不能识别32位的UTF-16字符(Unicode编号大于0xFFFF)。

    String.fromCharCode(0x20BB7)
    // "ஷ"

    ES6提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反。

    String.fromCodePoint(0x20BB7)
    // "𠮷"

    注意,fromCodePoint方法定义在String对象上,而codePointAt方法定义在字符串的实例对象上。

  4. 字符串的遍历接口

    ES6为字符串提供了遍历器接口,使得字符串可以被for...of循环遍历

    for (let codePoint of 'foo') {
      console.log(codePoint)
    }
    var text = String.fromCodePoint(0x20BB7);
    for (let i = 0; i < text.length; i++) {
      console.log(text[i]);
    }
    // " "
    // " "
    
    for (let i of text) {
      console.log(i);
    }
    // "𠮷"

    上面代码中,字符串text只有一个字符,但是for循环会认为它包含两个字符(都不可打印),而for...of循环会正确识别出这一个字符。

  5. at()

    提出字符串实例的at方法,可以识别Unicode编号大于0xFFFF的字符,返回正确的字符

    'abc'.at(0) // "a"
    '𠮷'.at(0) // "𠮷"
  6. includes(), startsWith(), endsWith()

    • includes():返回布尔值,表示是否找到了参数字符串。
    • startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
    • endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。

    这三个方法都支持第二个参数,表示开始搜索的位置。

    var s = 'Hello world!';
    
    s.startsWith('world', 6) // true
    s.endsWith('Hello', 5) // true
    s.includes('Hello', 6) // false

    上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。

  7. repeat()

    repeat方法返回一个新字符串,表示将元字符歘重复n次,参数如果是小数,回去取整,如果是负数或者Infinity会报错。如果repeat的参数是字符串,则会先转换成数字。

    'na'.repeat(2.9) // "nana"
    
  8. padStart(),padEnd()

    ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。

    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'
  9. 模板字符串

    模板字符串(template string)是增强版的字符串,用反引号\(`\)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。模板字符串中嵌入变量,需要将变量名写在${}之中。大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。模板字符串甚至还能嵌套。

数值的扩展

  1. 二进制和八进制的表示法

ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法

Number('0b111')  // 7
Number('0o10')  // 8
  1. Number.isFinite(), Number.isNaN()

它们与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。

  1. Number.parseInt(), Number.parseFloat()

ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变

这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。

  1. Number.isInteger()

Number.isInteger()用来判断一个值是否为整数。需要注意的是,在 JavaScript 内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值

  1. Number.EPSILON

在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的。但是如果这个误差能够小于Number.EPSILON,我们就可以认为得到了正确结果。

  1. 安全整数和Number.isSafeInteger()

JavaScript能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。

ES6引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。

  1. Math对象的扩展

ES6在Math对象上新增了17个与数学相关的方法。所有这些方法都是静态的,只能在Math对象上调用。对于非数值,这些方法都会先使用Number方法将其转为数值

  1. Math.trunc Math.trunc方法用于去除一个数的小数部分,返回整数部分。对于非数值,Math.trunc内部使用Number方法将其先转为数值。 对于空值和无法截取整数的值,返回NaN。

  2. Math.sign() Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。它会返回五种值。

    • 参数为正数,返回+1;
    • 参数为负数,返回-1;
    • 参数为0,返回0;
    • 参数为-0,返回-0;
    • 其他值,返回NaN。
  3. Math.cbrt() Math.cbrt方法用于计算一个数的立方根。

  4. Math.clz32() JavaScript的整数使用32位二进制形式表示,Math.clz32方法返回一个数的32位无符号整数形式有多少个前导0

    Math.clz32(0) // 32
    Math.clz32(1) // 31
    Math.clz32(1000) // 22
    Math.clz32(0b01000000000000000000000000000000) // 1
    Math.clz32(0b00100000000000000000000000000000) // 2
    

    clz32这个函数名就来自”count leading zero bits in 32-bit binary representations of a number“(计算32位整数的前导0)的缩写。

  5. Math.imul() Math.imul方法返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数。

  6. Math.fround() Math.fround()方法返回一个数的单精度浮点数形式

    Math.fround(0)     // 0
    Math.fround(1)     // 1
    Math.fround(1.337) // 1.3370000123977661
    Math.fround(1.5)   // 1.5
    Math.fround(NaN)   // NaN
    
  7. Math.hypot() Math.hypot方法返回所有参数的平方和的平方根。

  8. 对数方法 ES6新增了4个对数相关方法

    • Math.expm1()
    • Math.log1p()
    • Math.log10()
    • Math.lgo2()
  9. 双曲函数方法 ES6新增了6个双曲函数方法 Math.sinh(x) 返回x的双曲正弦(hyperbolic sine) Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine) Math.tanh(x) 返回x的双曲正切(hyperbolic tangent) Math.asinh(x) 返回x的反双曲正弦(inverse hyperbolic sine) Math.acosh(x) 返回x的反双曲余弦(inverse hyperbolic cosine) Math.atanh(x) 返回x的反双曲正切(inverse hyperbolic tangent)

  10. 指数运算符 ES2016 新增了一个指数运算符(**)。

2 ** 2 // 4
2 ** 3 // 8
  1. Integer 数据类型

根据国际标准IEEE 754,64位浮点数格式的64个二进制位中,第0位到第51位储存有效数字部分,第52到第62位储存指数部分,第63位是符号位,0表示正数,1表示负数

JavaScript 所有数字都保存成64位浮点数,这决定了整数的精确程度只能到53个二进制位。大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。

为了与 Number 类型区别,Integer 类型的数据必须使用后缀n表示。 1n + 2n //3n 二进制、八进制、十六进制的表示法,都要加上后缀n。

typeof运算符对于 Integer 类型的数据返回integer。

运算

- 相等运算符(==)会改变数据类型,是不允许混合使用。
```
0n == 0
// 报错 TypeError

0n == false
// 报错 TypeError
```
- Interger 类型不能与 Number 类型进行混合运算。

函数的扩展

1. ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

2. 默认值可以与解构复制的默认值结合起来使用

```
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
```

3. 函数的 length 属性

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。同理,rest 参数也不会计入length属性。

对象的扩展

  1. ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值
function f(x, y) {
  return {x, y};
}

// 等同于

function f(x, y) {
  return {x: x, y: y};
}

f(1, 2) // Object {x: 1, y: 2}

除了属性简写,方法也可以简写。

var o = {
  method() {
    return "Hello!";
  }
};

// 等同于

var o = {
  method: function() {
    return "Hello!";
  }
};

这种写法用于函数的返回值,将会非常方便。

function getPoint() {
  var x = 1;
  var y = 10;
  return {x, y};
}

getPoint()
// {x:1, y:10}

如果某个方法的值是一个Generator函数,前面需要加上星号。

var obj = {
  * m(){
    yield 'hello world';
  }
};
  1. 属性名表达式

用表达式作为属性名,这时要将表达式放在方括号之内。

obj['a' + 'bc'] = 123;

  1. Object.is()

ES6提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
  1. Object.assign()

用于对象的合并,将源对象的所有可枚举属性,复制到目标对象 Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。 Object.assign(target, source1, source2);

Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

常见用途

a. 为对象添加属性

b. 为对象添加方法

c. 克隆对象

d. 合并多个对象

e. 为属性制定默认值

Object.assign方法将DEFAULTS和options合并成一个新对象,如果两者有同名属性,则option的属性值会覆盖DEFAULTS的属性值。

const DEFAULTS = {
  logLevel: 0,
  outputFormat: 'html'
};

function processContent(options) {
  options = Object.assign({}, DEFAULTS, options);
  console.log(options);
  // ...
}
  1. 属性的遍历

a. for...in

for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

b. Object.keys(obj)

Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)。

c. Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)。

d. Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性。

e. Reflect.ownKeys(obj)

Reflect.ownKeys返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举。

以上的5种方法遍历对象的属性,都遵守同样的属性遍历的次序规则。

  • 首先遍历所有属性名为数值的属性,按照数字排序。
  • 其次遍历所有属性名为字符串的属性,按照生成时间排序。
  • 最后遍历所有属性名为 Symbol 值的属性,按照生成时间排序。

Symbol

  1. 概述 ES5的对象属性名都是字符串,存在冲突的可能性。如果有一种机制能保证每个属性的名字都是第一无二的就好了,这就是ES6引入Symbol的原因 ES6引入了一种新的原始数据类型Symbol,表示第一无二的至,它就是JavaScript语言的第七种数据类型。前六种是undefined、null、Boolean、String、Number、Object。

    let s = Symbol();
    
    typeof s
    // "symbol"
    

Set和Map数据结构

  1. Set

    通过add方法向 Set 结构加入成员,不会存在相同的值 Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

    const set = new Set([1, 2, 3, 4, 4]);
    [...set]
    // [1, 2, 3, 4]
    

    向Set加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。 另外,两个对象总是不相等的。

  2. Set实例的属性和方法

    • add(value):添加某个值,返回Set结构本身。
    • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    • has(value):返回一个布尔值,表示该值是否为Set的成员。
    • clear():清除所有成员,没有返回值。

    Array.from方法可以将 Set 结构转为数组。

    遍历操作

    • keys():返回键名的遍历器
    • values():返回键值的遍历器
    • entries():返回键值对的遍历器
    • forEach():使用回调函数遍历每个成员
  3. WeakSet

    • 首先,WeakSet 的成员只能是对象,而不能是其他类型的值。

    • 其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

    • WeakSet没有size属性,没有办法遍历它的成员。

    • WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。

Map

JavaScript对象,传统上只能用字符串当作键,这给它的使用带来了很大的限制,为了解决这个问题,ES提供了Map数据结构。键的范围不限于字符串

```
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false
```

js原型和原型链

1. 静态变量和静态函数

当定义一个函数后通过点号 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数

```
function Obj(){};

Obj.num = 72;//静态变量
Obj.fn = function()  //静态函数
{} 
```

2. 实例变量和实例函数

```
function Box(){
	this.a=[]; //实例变量
	this.fn=function(){ //实例方法
	}
}
```

3. 基本概念

在js中,一共有两种类型的值,原始值和对象值,每个对象都有一个内部属性prototype,我们称之为原型。原型的值尅是对象也可以是null,如果是对象的话,那么这个对象也一定有自己的原型,这样就形成了一条线性的链,我们称之为原型链

只有函数有prototype属性,并且可以被访问到,而对象没有。对象只有一个内部的不可访问的__proto__属性。按照标准__proto__是不对外公开的,但是Firefox引擎将它暴露出来成了一个公共属性。我们可以对外访问和设置。

当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(__proto__)指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。

4. 构造函数、实例和原型对象的区别

实例创建出来就有constructor属性(指向构造函数)和__proto__属性(指向原型对象)

```
var a = [];
a.constructor  // function Array() { [native code] }
```

5. 原型链

当访问一个对象的属性或方法时,如果该对象不存在该属性就从对象的原型中找,如果原型中也不存在就从原型的原型中找,直到原型为undefined,(Object的prototypei是undefined),从而额形成了所谓的原型链

6 原型继承 通过原型链实现集成

7. 原型链问题

包含引用类型的原型属性会被所有实例共享,这也是为什么要在构造函数中定义属性,而不是原型中定义属性的原因。

8. __ptoto__属性
指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor,通过这两个属性,就可以访问原型里的属性和方法了

9. __proto__属性和prototype属性的区别
prototype是function对象中专有的属性。 

__proto__是普通对象的隐式属性,在new的时候,会指向prototype所指的对象; __ptoto__实际上是某个实体对象的属性,而prototype则是属于构造函数的属性。__ptoto__只能在学习或调试的环境下使用