es6学习(1-7) ( 一 )

学习ES6 入门教程的总结学习:

1. 查看 Node.js 默认没有打开的 ES6 实验性语法

// Linux & Mac
$ node --v8-options | grep harmony

// Windows
$ node --v8-options | findstr harmony

2.Babel转码器 将 ES6 代码转为 ES5 代码,就能在不支持的 JavaScript 环境执行了;

Babel 的配置文件是.babelrc,存放在项目的根目录下

Babel 提供命令行工具@babel/cli,用于命令行转码。

$ npm install --save-dev @babel/core


  {
    "presets": [
      "@babel/env",
      "@babel/preset-react"
    ],
    "plugins": []
  }


$ npm install --save-dev @babel/cli

3. let命令所在的代码块内有效;

不存在变量提升:所声明的变量一定要在声明后使用,否则报错;

暂时性死区:在代码块内,使用let命令声明变量之前,该变量都是不可用的;

let不允许在相同作用域内,重复声明同一个变量,不能在函数内部重新声明参数;

ES5 只有全局作用域和函数作用域,没有块级作用域,let为 JavaScript 新增了块级作用域;

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1







// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;





if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}





// 不报错
var x = x;

// 报错
let x = x;
// ReferenceError: x is not defined






// 报错
function func() {
  let a = 10;
  var a = 1;
}

// 报错
function func() {
  let a = 10;
  let a = 1;
}






var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined

4.const声明一个只读的常量。一旦声明,常量的值就不能改变。其他用法和let一样;

const PI = 3.1415;
PI // 3.1415

PI = 3; // TypeError: Assignment to constant variable.

5.顶层对象,同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this关键字,但是有局限性。

  • 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window
  • 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self
  • Node 里面,顶层对象是global,但其他环境都不支持。

6. ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构

  1. 数组的解构赋值
  2. 对象的解构赋值
  3. 字符串的解构赋值
  4. 数值和布尔值的解构赋值
  5. 函数参数的解构赋值
  6. 圆括号问题
  7. 用途
    var a = 1;
	let b = 1;
	console.log(window.a,window.b)//1  undefined
	// 数组的结构赋值
	let [c, d, f] = [1,2,3];
	console.log(c,d,f)//1 2 3
	let [g, ...h] = [1,2,3,4];
	console.log(g,h)//1  [2, 3, 4]
	let [i, j, ...k] = ["a"];
	console.log(i,j,k)//a  undefined  []
	let [foo] = [];
	console.log(foo)//undefined
	// 如果等于右边等于undefined设置的默认值优先
	let [foo1 = true] = [];
	console.log(foo1)//true
	let [foo2 = 1] = [null]
	console.log(foo2)//null
	let [foo3 = 1] = [undefined]
	console.log(foo3)//1
	//部分解构不完全解构
	let [x,y] = [1,2,3];
	console.log(x,y)//1 2
	let [l, [m], n] = [1, [2, 3], 4];
	console.log(l,m,n)//1 2 4
	// 报错
	let [a1] = 1;
	let [a2] = false;
	let [a3] = NaN;
	let [a4] = undefined;
	let [a5] = null;
	let [a6] = {}
	console.log(a1,a2,a3,a4,a5,a6)//Uncaught TypeError: ... is not iterable



function* fibs() {
  let a = 0;
  let b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5

解构赋值允许指定默认值:ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'


let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null


let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined x用y做默认值时,y还没有声明


对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。 

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"



let {length : len} = 'hello';
len // 5

 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

数值和布尔值的包装对象都有toString属性,因此变量s都能取到值







let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。

 函数的参数也可以使用解构赋值。

function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]




function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。




[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ] 
undefined就会触发函数参数的默认值。

7. 变量的解构赋值用途很多。

(1)交换变量的值

let x = 1;
let y = 2;

[x, y] = [y, x];

上面代码交换变量xy的值,这样的写法不仅简洁,而且易读,语义非常清晰。

(2)从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

(3)函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。

// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

(4)提取 JSON 数据

解构赋值对提取 JSON 对象中的数据,尤其有用。

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

上面代码可以快速提取 JSON 数据的值。

(5)函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。

(6)遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

如果只想获取键名,或者只想获取键值,可以写成下面这样。

// 获取键名
for (let [key] of map) {
  // ...
}

// 获取键值
for (let [,value] of map) {
  // ...
}

(7)输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");

8.字符的 Unicode 表示法 

'\z' === 'z'  // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true

'中' === '\u4e2d' // true

字符串for...of循环遍历

let text = String.fromCodePoint(0x20BB7);

for (let i = 0; i < text.length; i++) {
  console.log(text[i]);
}
// " "
// " "

for (let i of text) {
  console.log(i);
}
// "𠮷"

可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""

模板字符串(template string)是增强版的字符串,用反引号(`)标识。模板字符串中嵌入变量,需要将变量名写在${}之中:

能运算,调用函数,嵌套

let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"


function fn() {
  return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar


let func = (name) => `Hello ${name}!`;
func('Jack') // "Hello Jack!"


alert`hello`
// 等同于
alert(['hello'])



let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
模板字符串前面有一个标识名tag,它是一个函数。整个表达式的返回值,就是tag函数处理模板字符串后的返回值。函数tag依次会接收到多个参数。
第一个参数:['Hello ', ' world ', '']
第二个参数: 15
第三个参数:50

function tag(s, v1, v2) {
  console.log(s[0]);
  console.log(s[1]);
  console.log(s[2]);
  console.log(v1);
  console.log(v2);

  return "OK";
}

tag`Hello ${ a + b } world ${ a * b}`;
// "Hello "
// " world "
// ""
// 15
// 50
// "OK"

字符串新增方法: 

  1. String.fromCodePoint()  兼容>码点
  2. String.raw()   转义
  3. 实例方法:codePointAt()  返回字符的码点
  4. 实例方法:normalize()  Unicode 正规化
  5. 实例方法:includes(), startsWith(), endsWith() 是否找到参数字符串 返回值true 
  6. 实例方法:repeat() 返回一个新字符串,表示将原字符串重复n
  7. 实例方法:padStart(),padEnd() 字符串补全长度
  8. 实例方法:trimStart(),trimEnd() 消除字符串空格
  9. 实例方法:matchAll() 返回一个正则表达式在当前字符串的所有匹配
  10. 实例方法:replaceAll() 替换所有匹配
  11. 实例方法:at() 接受一个整数作为参数,返回参数指定位置的字符,支持负索引

String.raw`Hi\\n`
// 返回 "Hi\\\\n"

String.raw`Hi\\n` === "Hi\\\\n" // true





String.raw = function (strings, ...values) {
  let output = '';
  let index;
  for (index = 0; index < values.length; index++) {
    output += strings.raw[index] + values[index];
  }
  output += strings.raw[index]
  return output;
}

// `foo${1 + 2}bar`
// 等同于
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"




let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
使用第二个参数n时(第二个参数可有可无),endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。




'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'



'aabbcc'.replace('b', '_')
// 'aa_bcc'
'aabbcc'.replace(/b/g, '_')
// 'aa__cc'
'aabbcc'.replaceAll('b', '_')
// 'aa__cc'
/ $& 表示匹配的字符串,即`b`本身
// 所以返回结果与原字符串一致
'abbc'.replaceAll('b', '$&')
// 'abbc'

// $` 表示匹配结果之前的字符串
// 对于第一个`b`,$` 指代`a`
// 对于第二个`b`,$` 指代`ab`
'abbc'.replaceAll('b', '$`')
// 'aaabc'

// $' 表示匹配结果之后的字符串
// 对于第一个`b`,$' 指代`bc`
// 对于第二个`b`,$' 指代`c`
'abbc'.replaceAll('b', `$'`)
// 'abccc'

// $1 表示正则表达式的第一个组匹配,指代`ab`
// $2 表示正则表达式的第二个组匹配,指代`bc`
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1')
// 'bcab'

// $$ 指代 $
'abc'.replaceAll('b', '$$')
// 'a$c'





const str = 'hello';
str.at(1) // "e"
str.at(-1) // "o"

8. 正则

'2015-01-02'.replace(re, (
   matched, // 整个匹配结果 2015-01-02
   capture1, // 第一个组匹配 2015
   capture2, // 第二个组匹配 01
   capture3, // 第三个组匹配 02
   position, // 匹配开始的位置 0
   S, // 原字符串 2015-01-02
   groups // 具名组构成的一个对象 {year, month, day}
 ) => {
 let {day, month, year} = groups;
 return `${day}/${month}/${year}`;
});





const string = 'test1test2test3';
const regex = /t(e)(st(\d?))/g;

for (const match of string.matchAll(regex)) {
  console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]

遍历器转为数组是非常简单的,使用...运算符和Array.from()方法就可以了。

// 转为数组的方法一
[...string.matchAll(regex)]

// 转为数组的方法二
Array.from(string.matchAll(regex))

9.数值

二进制和八进制数值的新的写法:分别用前缀0b(或0B)和0o(或0O)表示

0b111110111 === 503 // true
0o767 === 503 // true


将0b和0o前缀的字符串数值转为十进制,要使用Number方法。
Number('0b111')  // 7
Number('0o10')  // 8


数值分隔符 _ 有几个使用注意点:

  • 不能放在数值的最前面(leading)或最后面(trailing)。
  • 不能两个或两个以上的分隔符连在一起。
  • 小数点的前后不能有分隔符。
  • 科学计数法里面,表示指数的eE前后不能有分隔符。
  • Number()parseInt()parseFloat() 不支持分隔符
let num = 12_345;
num // 12345
num.toString() // 12345

Number('123_456') // NaN
parseInt('123_456') // 123

如果参数类型不是数值,Number.isFinite一律返回false

如果参数类型不是NaNNumber.isNaN一律返回false

ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,取整取字符串

Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true

Number.isInteger()用来判断一个数值是否为整数。

Number.EPSILON可以用来设置“能够接受的误差范围”。比如,误差范围设为 2 的-50 次方(即Number.EPSILON * Math.pow(2, 2)),即如果两个浮点数的差小于这个值,我们就认为这两个浮点数相等。

Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

Math 静态数学方法 Math 对象的扩展 :(共17个)

1.Math.trunc方法用于去除一个数的小数部分,返回整数部分。

对于非数值,Math.trunc内部使用Number方法将其先转为数值。

对于空值和无法截取整数的值,返回NaN

Math.trunc = Math.trunc || function(x) {
  return x < 0 ? Math.ceil(x) : Math.floor(x);
};

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

  • 参数为正数,返回+1
  • 参数为负数,返回-1
  • 参数为 0,返回0
  • 参数为-0,返回-0;
  • 其他值,返回NaN
Math.sign = Math.sign || function(x) {
  x = +x; // convert to a number
  if (x === 0 || isNaN(x)) {
    return x;
  }
  return x > 0 ? 1 : -1;
};

3.Math.cbrt()方法用于计算一个数的立方根

Math.cbrt = Math.cbrt || function(x) {
  var y = Math.pow(Math.abs(x), 1/3);
  return x < 0 ? -y : y;
};

4.Math.clz32()方法将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0。

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

6.Math.fround方法返回一个数的32位单精度浮点数形式。(2的24次方)

Math.fround = Math.fround || function (x) {
  return new Float32Array([x])[0];
};

7.Math.hypot方法返回所有参数的平方和的平方根

8. Math.expm1(x)返回 ex - 1,即Math.exp(x) - 1

Math.expm1 = Math.expm1 || function(x) {
  return Math.exp(x) - 1;
};

9.Math.log1p(x)方法返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN

Math.log1p = Math.log1p || function(x) {
  return Math.log(1 + x);
};

10.Math.log10(x)返回以 10 为底的x的对数。如果x小于 0,则返回 NaN。

Math.log10 = Math.log10 || function(x) {
  return Math.log(x) / Math.LN10;
};

11.Math.log2(x)返回以 2 为底的x的对数。如果x小于 0,则返回 NaN。

Math.log2 = Math.log2 || function(x) {
  return Math.log(x) / Math.LN2;
};

12.双曲线(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)

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值