ES6学习摘要

ES6学习摘要

let,const

for循环,函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

for (let i = 0; i < 3; i++) {
   
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

不存在变量提升

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

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

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响

var tmp = 123;

if (true) {
   
  tmp = 'abc'; // ReferenceError
  let tmp;  //有let命令,所以tmp的作用域就只有在块作用里
}

有些“死区”比较隐蔽,不太容易发现。

function bar(x = y, y = 2) {
     //x=y,y没有声明
  return [x, y];
}

bar(); // 报错

不允许重复声明

影响

块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。

// IIFE 写法
(function () {
   
  var tmp = ...;
  ...
}());

// 块级作用域写法
{
   
  let tmp = ...;
  ...
}

*块级作用域与函数声明

ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。,但实际上浏览器可以运行

ES5 会替升声明的函数到函数头部

function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f();
}());

相当于

function f() { console.log('I am outside!'); }

(function () {
	function f() { console.log('I am inside!');
  if (false) {
     }
  }

  f();
}());

ES6

相当于

function f() { console.log('I am outside!'); }

(function () {
  var f = undefine //***
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f(); //f is not a function
}());
  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。

注意

应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句

function f() { console.log('I am outside!'); }

(function () {
      if (false) {
        // 重复声明一次函数f
        let f = function() { console.log('I am inside!'); 
        }
  }
  f(); //
}());

const

变量指向的那个内存地址所保存的数据不得改动

要是保存的是对象,只能保证对象指针不变,而原对象还是可以操作

如果真的想将对象冻结,应该使用Object.freeze方法。

const foo = Object.freeze({
   });

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

上面代码中,常量foo指向一个冻结的对象,所以添加新属性不起作用,严格模式时还会报错。

除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

var constantize = (obj) => {
   
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, i) => {
   
    if ( typeof obj[key] === 'object' ) {
   
      constantize( obj[key] );
    }
  });
};

ES6 声明变量的六种

var function let const import class

顶层对象的属性

全局变量将逐步与顶层对象的属性脱钩。

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1

let b = 1;
window.b // undefined

globalThis 对象

变量的解构赋值

数组的解构赋值

let [a, b, c] = [1, 2, 3];
let [foo, [[bar], baz]] = [1, [[2], 3]];
let [head, ...tail] = [1, 2, 3, 4];//tail  [2, 3, 4]
let [a, [b], d] = [1, [2, 3], 4];//不完全解构
let [x, y, z] = new Set(['a', 'b', 'c']);

如果等号的右边不是数组(或者严格地说,不是可遍历的结构,),那么将会报错

默认值

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效

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

let [x = 1] = [null];
x // null
function f() {
   
  console.log('aaa');
}

let [x = f()] = [1];//具有惰性,若是能取到值就不运行
let [x = 1, y = x] = [];     // x=1; y=1

对象的解构赋值

数组的元素是按次序排列的,变量的取值由它的位置决定;

而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

let {
    foo, bar } = {
    foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

// 例一
let {
    log, sin, cos } = Math;

// 例二
const {
    log } = console;
log('hello') // hello

如果变量名与属性名不一致,必须写成下面这样。

let {
    foo: baz } = {
    foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = {
    first: 'hello', last: 'world' };
let {
    first: f, last: l } = obj;
f // 'hello'
l // 'world'

与数组一样,解构也可以用于嵌套结构的对象。

let obj = {
   
  p: [
    'Hello',
    {
    y: 'World' }
  ]
};

let {
    p: [x, {
    y }] } = obj;
x // "Hello"
y // "World"
({
    foo: obj.prop, bar: arr[0] } = {
    foo: 123, bar: true });

obj // {prop:123}
arr // [true]

对象的解构赋值可以取到继承的属性

也有默认值

1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法
let x;
{
   x} = {
   x: 1};
// SyntaxError: syntax error
// 正确的写法
let x;
({
   x} = {
   x: 1});

字符串的解构赋值

数值和布尔值的解构赋值

1

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefinednull无法转为对象,所以对它们进行解构赋值,都会报错

函数参数的解构赋值

function add([x, y]){
   
  return x + y;
}

add([1, 2]); // 3

圆括号问题

尽量不用

可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。

[(b)] = [3]; // 正确
({
    p: (d) } = {
   }); // 正确
[(parseInt.prop)] = [3]; // 正确

用途

7

字符串扩展

字符的 Unicode 表示法

\uxxxx这种表示法只限于码点在\u0000~\uFFFF之间的字符

ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。

"\u{20BB7}"
// "?"

"\u{41}\u{42}\u{43}"
// "ABC"

let hello = 123;
hell\u{
   6F} // 123

'\u{1F680}' === '\uD83D\uDE80'
// true

字符串的遍历器接口

字符串可以被for...of循环遍历。

可以识别大于0xFFFF的码点

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);
}
// "?"

5个字符不能在字符串里面直接使用

  • U+005C:反斜杠(reverse solidus)
  • U+000D:回车(carriage return)
  • U+2028:行分隔符(line separator)
  • U+2029:段分隔符(paragraph separator)
  • U+000A:换行符(line feed)

ES2019 允许 JavaScript 字符串直接输入 U+2028(行分隔符)和 U+2029(段分隔符)。

JSON.stringify() 的改造

模板字符串甚至还能嵌套

${ }

如果使用模板字符串表示多行字符串,则所有的空格、缩进和换行都会被保留在输出中。

大括号内可以放入任意的JavaScript表达式,可以进行运算,以及引入对象属性。

模板字符串之中还可以调用函数

实例:模板编译

标签模板

alert`123`
// 等同于
alert(123)
let a = 5;
let b = 10;

tag`Hello ${
      a + b } world ${
      a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);

“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。

字符串新增方法

String.fromCodePoint()

主要原因js以utf-16编码,字符占2个字节,需要4个字节表示的字符,js会认为使两个字符

charAt(),charCodeAt()都不能正确处理4个字节表示的字符

codePointAt()可以返回正确的码点,以十进制编码,但是index要跳着

比如:下列取a码点要从2开始取

let s = '?a';
s.codePointAt(0).toString(16) // "20bb7"
s.codePointAt(2).toString(16) // "61"

改良:for of可以遍历字符串

let s = '?a';
for (let ch of s) {
console.log(ch.codePointAt(0).toString(16));
}

codePointAt(),charAt(),charCodeAt()都运用在实例上,都是通过index来获取内容

String.fromCharCode(),String.fromCodePoint() 运用在string类上,输入编码输出字符

String.fromCharCode()不能识别码点大于0xFFFF的字符

String.fromCodePoint()

//可以输入多位
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true 
String.raw()
String.raw`Hi\n${
     2+3}!`
// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"

String.raw`Hi\\n`
// 返回 "Hi\\\\n"
// `foo${1 + 2}bar`
// 等同于
String.raw({
    raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
实例方法:codePointAt()
实例方法:normalize()

欧洲语言有语调符号和重音符号。为了表示它们,

一种是直接提供带重音符号的字符,比如Ǒ(\u01D1)。

另一种是提供合成符号,两个字符合成一个字符,比如O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C)。

js不能识别

'\u01D1'==='\u004F\u030C' //false

'\u01D1'.length // 1
'\u004F\u030C'.length // 2
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
// true
[实例方法:includes(), startsWith(), endsWith()](http://es6.ruanyifeng.com/#docs/string-methods#实例方法:includes(), startsWith(), endsWith())
  • includes():返回布尔值,表示是否找到了参数字符串。

  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

  • let s = 'Hello world!';
    s.startsWith('world', 6) // true 表示从index=6开始检索
    s.endsWith('Hello', 5) // 表示前5个字符
    s.includes('Hello', 6) // false
    
实例方法:repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次。

参数是负数或者Infinity

参数如果是小数,会被取整。

参数是 0 到-1 之间的小数,则等同于 0

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
实例方法:padStart(),padEnd()

补全字符串长度

padStart()padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串

'abc'.padStart(10, '0123456789')
实例方法:trimStart(),trimEnd()
const s = '  abc  ';

s.trim() // "abc"
s.trimStart() // "abc  "
s.trimEnd() // "  abc"
实例方法:matchAll()

正则扩展

RegExp 构造函数

返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符

new RegExp(/abc/ig, 'i').flags

ES5

var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;

var regex = new RegExp(/xyz/i);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值