ES6其他知识点

2022/2/11 JavaScript模板字符串解构剩余参数Symbol

# 模板字符串

const myName = 'okarin'
const myAge = 18
const myHeight = 1.73

const message = `my name is ${myName},my age is ${myAge}, my height is ${myHeight}`

console.log(message)
1
2
3
4
5
6
7

同时,模板字符串里面可以使用JS表达式

const info = `age double is ${myAge * 2}`
1
const info = `age double is ${doubleAge()}`

function doubleAge(){
    return myAge * 2
}
1
2
3
4
5

# 标签模板字符串

function foo(m,n){
    console.log(m,n)
}

const name = "okarin"

foo`he${name}llo`

//[ 'he', 'llo' ] okarin
1
2
3
4
5
6
7
8
9
  • 第一个参数是模板字符串的整个字符串,只是被切成了块,放在了一个数组中。
  • 第二个参数是模板字符串中的${ },以此类推。

# 函数的默认参数

function foo(m = 'aaa',n = 'bbb'){
    console.log(m,n)
}

foo()
1
2
3
4
5

ES6可以给函数参数提供默认值

# 对象参数默认值以及解构

function printInfo({name,age} = {name:"okarin",age:18})
{
    console.log(info.name,info.age)
}

printInfo({name:"retr0",age:19})
1
2
3
4
5
6
function printInfo({name = "oakrin",age = 18} = {})
{
    console.log(info.name,info.age)
}

printInfo({name:"retr0",age:19})
1
2
3
4
5
6

# 默认值的补充

function bar (x , y , z = 30){
    console.log(x,y,z)
}
1
2
3

另外参数的默认值我们通常会将其放到最后(在很多语言中,如果不放到最后其实会报错的):但是JavaScript允许不将其放到最后,但是意味着还是会按照顺序来匹配; 另外默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了。

# 函数的剩余参数

ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中:

如果最后一个参数是...为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组;

function foo(m,n,...args){
    console.log(m,n)// 1 2
    console.log(args)//[3,4,5]
    console.log(arguments)//[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
}

foo(1,2,3,4,5)
1
2
3
4
5
6
7

剩余参数和 arguments 的区别:

  • 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参
  • arguments 对象不是一个真正的数组,而 rest 参数是一个真正的数组,可以进行数组的所有操作;
  • arguments是早期的 ECMAScript 中为了方便去获取所有的参数提供的一个数据结构,而 rest 参数是 ES6 中提供并且希望以此来替代 arguments 的;

剩余参数必须放到最后!

# ES6箭头函数的补充

var foo = () => {
    console.log("foo")
}
console.log(fo.prototype) //undefind

var f = new foo()//TypeError: foo is not a constructor

1
2
3
4
5
6
7
  • 箭头函数是没有显式原型的,所以不能作为构造函数,使用new来创建对象;

# 展开语法(Spread syntax)

  • 可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;

  • 还可以在构造字面量对象时,将对象表达式按key—value的方式展开;

  • 展开语法的场景:

    • 在函数调用时使用;
    • 在数组构造时使用;
    • 在构建对象字面量使用(ES9新增)
const names = ["abc", "cba", "nba"]
const name = "abc"
const info = {
  name: "okarin",
  age: "18",
}

function foo(x, y, z) {
  console.log(x, y, z) 
}

foo.apply(null, names)//abc cba nba
foo(...names)//abc cba nba
foo(...name)//a b c

const newNames = [...names, ...name]
console.log(newNames)//[ 'abc', 'cba', 'nba', 'a', 'b', 'c' ]

const obj = { ...info, city: "chengdu" }
console.log(obj)//{ name: 'okarin', age: '18', city: 'chengdu' }   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

注意:展开运算符其实进行的是一个浅拷贝

# ES6表示数值的方式

# 进制

可以使用进制表示

const num1 = 100 //十进制
const num2 = 0b100 //二进制
const num3 = 0o100 //八进制
const num4 = 0x100 //十六进制

1
2
3
4
5

# 大的数值(ES12新增)

大的数值的连接符

const num = 10_000_000_000
1

# Symbol的基本使用

Symbol是ES6中新增的一个基本数据类型,翻译为符号。

那么为什么需要Symbol呢?

  • 在ES6之前,对象的属性名都是字符串形式,那么很容易造成属性名的冲突
  • 比如原来有一个对象,希望在其中添加一个新的属性和值,但是在不确定它原来内部有什么内容的情况下,很容易造成冲突,从而覆盖掉它内部的某个属性;
  • 比如在apply、call、bind实现时,给其中添加一个fn属性,那么如果它内部原来已经有了fn属性了呢?
  • 比如开发中使用混入,那么混入中出现了同名的属性,必然有一个会被覆盖掉;

ES6之前,对象的属性名(key)是字符串的形式。

var obj = {
    name:"okarin",
    friend:{name:"mayuri"},
    "age":18
}
1
2
3
4
5

而Symbol就是为了解决上面的问题,用来生成一个独一无二的值

  • Symbol值是通过Symbol函数来生成的,生成后可以作为属性名
  • 也就是在ES6中,对象的属性名可以使用字符串,也可以使用Symbol值
const s1 = Symbol()
const s2 = Symbol()

console.log(s1,s2,s1 === s2)//Symbol() Symbol() false
1
2
3
4

# Symbol的描述(description)(ES10)

const s3 = Symbol("aaa")
console.log(s3.description)//aaa
1
2

# Symbol的值作为key

  • 在定义对象字面量时使用
const s1 = Symbol()
const s2 = Symbol()

const obj = {
    [s1]:"abc",
    [s2]:"cba"
}

console.log(obj)
//{ [Symbol()]: 'abc', [Symbol()]: 'cba' }

1
2
3
4
5
6
7
8
9
10
11
  • 新增属性
obj[s3] = "nba"
1
  • 通过Object.defineProperty
const s4 = Symbol()

Object.defineProperty(obj,s4,{
    enumerable:true,
    configurable:true,
    writable:true,
    value:"bbc"
    
})
1
2
3
4
5
6
7
8
9

注意:不能通过obj.属性名的方式来获取

console.log(obj,obj[s1],obj[s2],obj[s3],obj[s4])
//{
//  [Symbol()]: 'abc',
//  [Symbol()]: 'cba',
//  [Symbol(aaa)]: 'nba',
//  [Symbol()]: 'bbc'
//} abc cba nba bbc

console.log(obj.s1,obj.s2,obj.s3,obj.s4)
//undefined

1
2
3
4
5
6
7
8
9
10
11

# 获取Symbol的值

注意:使用 Symbol 作为 key 的属性名,在遍历 Object.keys 等中是获取不到这些 Symbol 值的。

  • 使用Object.getOwnPropertySymbols()获取 Symbol 的 key。
console.log(Object.keys(obj))//[]
console.log(Object.getOwnPropertyNames(obj))//[]
console.log(Object.getOwnPropertySymbols(obj))//[ Symbol(), Symbol(), Symbol(aaa), Symbol() ]
1
2
3

# 遍历使用Symbol的对象

const sKeys = Object.getOwnPropertySymbols(obj)
for(const s of sKeys){
    console.log(obj[s])
}
1
2
3
4

# Symbol.for(key)

  • 当需要创建两个一样的Symbol时,使用Symbol.for()来创建。
  • 当需要获取一个 Symbol 值的 key 时,使用Symbol.keyFor()来获取

const aa = Symbol.for("aaa")
const bb = Symbol.for("aaa")
console.log(aa === bb)//true

const key = Symbol.keyFor(aa)
console.log(key)//aaa
1
2
3
4
5
6
7
Last Updated: 2022/2/14下午9:33:34