资讯详情

ES6(ES进阶之路一)

简介

JavaScript它是世界上发展最快的编程语言之一,不仅可以用来编写在浏览器中运行的客户端程序,还可以用来编写在浏览器中运行的客户端程序Node.js的发展,JavaScript它也广泛应用于编写服务端程序。JavaScript这种语言的不断发展和完善正在进行中2015年正式发布ECMAScript6已经成为了JavaScript这门语言的下一代标准使JavaScript用于编写复杂的大型应用程序更方便。近年来,几乎所有的应用都被使用JavaScript语言开发项目正在使用中ES开发新特性。

随着ES2015标准委员会决定每年发布一份ES新版本。但是很多开发者并没有真正理解ES2015 每个版本的新特征是什么,这些新特征和ES5语法差异,更不用说这些新特性在实际项目中的应用场景了。

由于篇幅原因,笔者将ES6~ES12分成了ES进阶之路一ES进阶之路二如果是的话,两篇文章ES6很清楚你可以直接看ES7、ES8、ES9、ES10、ES11、ES12(ES高级之路二)

我相信只要你仔细阅读作者,ES你一定会成为一系列文章ES大神。

先来看看ES6吧,篇幅有点长,建议收藏后再看,后期也可以当做字典查阅。

IMG_0387.jpeg

块级作用域

我们知道在js有全局作用域和函数作用域ES6又增加了一个块级作用域。块级作用域是什么?

关于什么是块,只要认识 {} 例如if后面的{}for循环后面的{}等等。

if (true) { 
           var a = 5;   console.log(a); // 5 } console.log(a); // 5 
if (true) { 
           let a = 5;   console.log(a); // 5 } console.log(a);// Uncaught ReferenceError: a is not defined 

在上面的例子中,我们可以看到它在使用var在块{}中定义的变量是全局变量,里外都能访问。但是在使用let在块{}定义的变量是块级作用域变量,只能在块中访问,外部不能访问。

const定义的变量也是如此,只能在块中访问,外部不能访问。

if (true) { 
           const a = 5;   console.log(a); // 5 } console.log(a);// Uncaught ReferenceError: a is not defined 

所以ES6事实上,块级作用域的概念仍然需要和谐let、const配合使用。什么是?let、const各有什么特点?

let

ES6 新增了let命令,用来声明变量。

1. let 声明的全局变化不是全局对象window的属性

这就意味着,你不可以通过 window.变量名 的方式访问这些变量,而 var 声明的全局变量是 window 的属性,是可以通过 window.变量名 的方式访问的。

var a = 5
console.log(window.a) // 5
let a = 5
console.log(window.a) // undefined

2. 用let定义变量不允许重复声明

这个很容易理解,使用 var 可以重复定义,使用 let 却不可以。

var a = 5
var a = 6

console.log(a) // 6

如果是 let ,则会报错

let a = 5
let a = 6
// Uncaught SyntaxError: Identifier 'a' has already been declared
// at <anonymous>:1:1

3. let声明的变量不存在变量提升

function foo() { 
        
    console.log(a)
    var a = 5
}

foo() //undefined

上述代码中, a 的调用在声明之前,所以它的值是 undefined,而不是 Uncaught ReferenceError。实际上因为 var 会导致变量提升,上述代码和下面的代码等同:

function foo() { 
        
    var a
    console.log(a)
    a = 5
}

foo() //undefined

而对于 let 而言,变量的调用是不能先于声明的,看如下代码:

function foo() { 
        
    console.log(a)
    let a = 5
}

foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization

在这个代码中, a 的调用是在声明之前,因为 let 没有发生变量提升,所有读取 a 的时候,并没有找到,而在调用之后才找到 leta 的定义,所以会报错。

4. let声明的变量具有暂时性死区

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

var a = 5
if (true) { 
        
    a = 6
    let a
}
// Uncaught ReferenceError: Cannot access 'a' before initialization

上面代码中,存在全局变量 a ,但是块级作用域内 let 又声明了一个局部变量 a ,导致后者绑定这个块级作用域,所以在let声明变量前,对 a 赋值会报错。

ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”

有时“暂时性死区”比较隐蔽,比如:

function foo(b = a, a = 2) { 
        
    console.log(a, b)
}
foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization

5. let 声明的变量拥有块级作用域

let实际上为 JavaScript 新增了块级作用域

{ 
        
    let a = 5
}
console.log(a) // undefined

a 变量是在代码块 {} 中使用 let 定义的,它的作用域是这个代码块内部,外部无法访问。

我们再看一个项目中很常见的 for 循环:

for (var i = 0; i < 3; i++) { 
        
    console.log('循环内:' + i) // 0、1、2
}
console.log('循环外:' + i) // 3

如果改为 let 会怎么样呢?

for (let i = 0; i < 3; i++) { 
        
    console.log('循环内:' + i) // 0、1、2
}
console.log('循环外:' + i) // ReferenceError: i is not defined

继续看下面两个例子的对比,这时 a 的值又是多少呢?

if (true) { 
        
    var a = 5
}
console.log(a) // 5
if (true) { 
        
    let a = 5
}
console.log(a)// Uncaught ReferenceError: a is not defined

const

constlet类似,但是使用const定义的变量是常量。如果变量是基本类型就不能改变值,如果是引用类型就不能改变引用地址。

1. const定义的变量是常量

基本数据类型

const a = 1

console.log(a) // 1

a = 2

console.log(a)// Uncaught TypeError: Assignment to constant variable.

引用数据类型

const user = { 
         name: "randy" };
user.name = "demi"; // 不改变引用地址的修改是可以的
console.log(user); //{ name: "demi" }

user = { 
         name: "jack" };
console.log(user); // Uncaught TypeError: Assignment to constant variable.

2. const 声明的全局变量不是全局对象window的属性

这就意味着,你不可以通过 window.变量名 的方式访问这些变量,而 var 声明的全局变量是 window 的属性,是可以通过 window.变量名 的方式访问的。

var a = 5
console.log(window.a) // 5
const a = 5
console.log(window.a) // undefined

3. 用const定义变量不允许重复声明

这个很容易理解,使用 var 可以重复定义,使用 const 却不可以。

var a = 5
var a = 6

console.log(a) // 6

如果是 const ,则会报错

const a = 5
const a = 6
// Uncaught SyntaxError: Identifier 'a' has already been declared
// at <anonymous>:1:1

4. const声明的变量不存在变量提升

function foo() { 
        
    console.log(a)
    var a = 5
}

foo() //undefined

上述代码中, a 的调用在声明之前,所以它的值是 undefined,而不是 Uncaught ReferenceError。实际上因为 var 会导致变量提升,上述代码和下面的代码等同:

function foo() { 
        
    var a
    console.log(a)
    a = 5
}

foo() //undefined

而对于 const 而言,变量的调用是不能先于声明的,看如下代码:

function foo() { 
        
    console.log(a)
    const a = 5
}

foo()
// Uncaught ReferenceError: Cannot access 'a' before initialization

在这个代码中, a 的调用是在声明之前,因为 const 没有发生变量提升,所有读取 a 的时候,并没有找到,而在调用之后才找到 consta 的定义,所以会报错。

5. const声明的变量具有暂时性死区

只要块级作用域内存在 const 命令,它所声明的变量就绑定在了这个区域,不再受外部的影响。

var a = 5
if (true) { 
        
    a = 6
    const a
}
// Uncaught ReferenceError: Cannot access 'a' before initialization

上面代码中,存在全局变量 a ,但是块级作用域内 const 又声明了一个局部变量 a ,导致后者绑定这个块级作用域,所以在const声明变量前,对 a 赋值会报错。

ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用 const 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”

6. const 声明的变量拥有块级作用域

const实际上为 JavaScript 新增了块级作用域

{ 
        
    const a = 5
}
console.log(a) // undefined

a 变量是在代码块 {} 中使用 const 定义的,它的作用域是这个代码块内部,外部无法访问。

解构赋值

ES6 中新增了变量赋值的方式:解构赋值。允许按照一定模式,从数组、对象、字符串中提取值,对变量进行赋值。

数组解构赋值

数组的解构是严格按照顺序来的,一一对应。

let [a, b, c] = ["a", "b", "c"]
console.log(a, b, c) // a b c
let [one, two, three] = new Set([1, 2, 3])
console.log(one, two, three) // 1 2 3

// 被赋值的变量还可以是对象的属性,不局限于单纯的变量。
let user = { 
        }
[user.firstName, user.secondName] = 'Kobe Bryant'.split(' ')
console.log(user.firstName, user.secondName) // Kobe Bryant

// 可以跳过赋值元素
let [name, , title] = ['John', 'Jim', 'Sun', 'Moon']
console.log( title ) // Sun

// rest 参数,相当于把剩下的放在一个数组里
// 我们可以使用 rest 来接受赋值数组的剩余元素,不过要确保这个 rest 参数是放在被赋值变量的最后一个位置上。
let [name1, ...rest] = ["jack", "randy", "demi"];
console.log(name1); // jack
console.log(rest[0]); // randy
console.log(rest[1]); // demi
console.log(rest.length); // 2

// 默认值,取不到值得时候就会使用默认值
let [name = "randy", surname = "demi"] = ["jack"]
console.log(name)    // jack
console.log(surname) // demi

对象解构赋值

对象的解构是按照属性名来的,跟顺序无关。

const user = { 
         name: "randy", age: 24 };
const { 
         age, name } = user;
console.log(name, age); // randy 24

// 取别名
const { 
         name: n, age: a } = user;
console.log(n, a); // randy 24

// 默认值
const { 
         name, age, sex = "male" } = user;
console.log(name, age, sex); // randy 24 male

// rest参数,相当于把剩下的放在一个对象里
const { 
         name, ...rest } = user;
console.log(name); // randy
console.log(rest); // {age: 24}

// 嵌套对象,对于嵌套我们保证层级一样即可
const user2 = { 
        
  name: "demi",
  age: 24,
  address: { 
         province: "湖南", city: "岳阳", area: "汨罗" },
  likes: ["orange", "apple"],
};
const { 
        
  name,
  age,
  address: { 
         province, city, area },
  likes: [fruits1, fruits2],
} = user2;

console.log(name, age, province, city, area, fruits1, fruits2); // demi 24 湖南 岳阳 汨罗 orange apple

字符串解构赋值

字符串的解构跟数组有点类似,也是可以设置默认值、rest参数等这里笔者就不再细说了。

let str = 'randy'

let [a, b, c, d, e] = str

console.log(a, b, c, d, e) // r a n d y

String扩展

Unicode表示法

ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。

"\u0061"
// "a"

但是,这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。

"\uD842\uDFB7"
// "𠮷"

"\u20BB7"
// " 7"

上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript 会理解成\u20BB+7。由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7。

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

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

有了这种表示法之后,JavaScript 共有 6 种方法可以表示一个字符。

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

遍历器接口

ES6 为字符串添加了遍历器接口,详见Iterator一节,使得字符串可以被for...of循环遍历。

for (let item of 'randy') { 
        
    console.log(item) // r a n d y
}

模板字符串

ES6 之前对字符串的处理是相当的麻烦,看如下场景:

字符串很长包括几种情形一个是开发时输入的文本内容,一个是接口数据返回的文本内容。如果对换行符处理不当,就会带来异常。

如果字符串不是静态内容,往往是需要加载变量或者表达式,这个也是很常见的需求。之前的做法是字符串拼接:

var a = 20
var b = 10
var c = 'JavaScript'
var str = 'My age is ' + (a + b) + ' and I love ' + c
console.log(str)

如果字符串有大量的变量和表达式,这个拼接简直是噩梦。

我们通常写代码都是有逻辑运算的,对于字符串也是一样,它包含的内容不是静态的,通常是根据一定的规则在动态变化。

var retailPrice = 20
var wholesalePrice = 16
var type = 'retail'

var showTxt = ''

if (type === 'retail') { 
        
  showTxt += '您此次的购买单价是:' + retailPrice
} else { 
        
  showTxt += '您此次的批发价是:' + wholesalePrice
}

看到这样的代码一定会感到很熟悉,通常大家的做法是使用上述的字符串拼接+逻辑判断,或者采用字符串模板类库来操作。

看了上述的应用场景,就要引入 String Literals 话题,这个是用来解决字符串拼接问题,从 ES6 开始可以这样定义字符串了。

`string text` 

`string text line 1 string text line 2`

`string text ${ 
          expression} string text` 

在这里你可以任意插入变量或者表达式,只要用 ${}包起来就好。

注意

这里的符号是反引号,也就是数字键 1 左边的键,不是单引号或者双引号

这样就可以轻松解决字符串包含变量或者表达式的问题了,对于多行的字符串,之前是这样处理

console.log('string text line 1\n' +
    'string text line 2')

// "string text line 1
// string text line 2"

现在可以这样做了

console.log(`string text line 1 string text line 2`)

// "string text line 1
// string text line 2"

完全不需要 \n 来参与。

前面的字符串字面量解决了字符串拼接的问题,对于包含复杂逻辑的字符串并不是简单的表达式能搞定的。所以需要另一种解决方案:Tag Literals,还是看上述那个例子:

var retailPrice = 20
var wholesalePrice = 16
var type = 'retail'

var showTxt = ''

if (type === 'retail') { 
        
    showTxt += '您此次的购买单价是:' + retailPrice
} else { 
        
    showTxt += '您此次的批发价是:' + wholesalePrice
}

现在可以定义一个 Tag 函数,然后用这个 Tag 函数来充当一个模板引擎:

function Price(strings, type) { 
        
    let s1 = strings[0]
    const retailPrice = 20
    const wholesalePrice = 16
    let txt = ''
    if (type === 'retail') { 
        
        txt = `购买单价是:${ 
          retailPrice}` 
    } else { 
        
        txt = `批发价是:${ 
          wholesalePrice}` 
    }
    return `${ 
          s1}${ 
          txt}` 
}

let showTxt = Price `您此次的${ 
          'retail'}` 

console.log(showTxt) //您此次的购买单价是:20

strings 参数指的是 Tag 函数后面被变量分割开的字符串集合,type 参数是对应第一个变量,Tag 函数可以有多个 type 类似的参数。

新增方法

String.prototype.fromCodePoint()

用于从 Unicode 码点返回对应字符,并且可以识别大于0xFFFF的字符。

// ES5
console.log(String.fromCharCode(65)) // A

// ES6
console.log(String.fromCodePoint(65)) // A

String.prototype.includes()

ES5中可以使用indexOf方法来判断一个字符串是否包含在另一个字符串中,indexOf返回出现的下标位置,如果不存在则返回-1。

const str = 'randy'

console.log(str.indexOf('dy'))

ES6提供了includes方法来判断一个字符串是否包含在另一个字符串中,返回boolean类型的值。

const str = 'randy'

console.log(str.includes('dy'))

String.prototype.startsWith()

判断参数字符串是否在原字符串的头部, 返回boolean类型的值。

const str = 'randy'

console.log(str.startsWith('ra'))

String.prototype.endsWith()

判断参数字符串是否在原字符串的尾部, 返回boolean类型的值。

const str = 'randy'

console.log(str.endsWith('dy' 

标签: 40针前置连接器6es7

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台