前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS Advance --- ES6语法(二)

JS Advance --- ES6语法(二)

作者头像
玖柒的小窝
修改2021-10-09 14:17:53
1.2K0
修改2021-10-09 14:17:53
举报
文章被收录于专栏:各类技术文章~

在ES6之前,如果我们想要将字符串和一些动态的变量(标识符)拼接到一起,是非常麻烦和丑陋的

ES6允许我们使用字符串模板来嵌入JS的变量或者表达式来进行拼接:

  • 首先,我们会使用 `` 符号来编写字符串,称之为模板字符串
  • 其次,在模板字符串中,我们可以通过 ${expression} 来嵌入动态的内容
代码语言:javascript
复制
const age = 23

// 基本使用
console.log(`age is ${age}`) // => age is 23

// ${expression}中可以使用合法的js表达式
console.log(`age is ${age * 2}`) // => age is 46

function doubleAge() {
  return age * 2
}

// 函数调用也是一个合法的js表达式
console.log(`age is ${doubleAge()}`) // => age is 46
复制代码
标签模板字符串

模板字符串还有另外一种用法:标签模板字符串(Tagged Template Literals)

模板字符串可以认为是函数调用的一种特殊形式

代码语言:javascript
复制
function foo() {
  console.log('foo 被调用了')
}

// 传统的函数调用
foo()

// 标签模板字符串调用
foo``
复制代码

标签模板字符串在被调用的时候,会根据传任入的模板字符串自动进行字符串的分割和参数的传递

  • 第一个参数是数组,是被模块字符串拆分的字符串组合
  • 后边的参数是一个个模块字符串传入的内容
代码语言:javascript
复制
function foo(...args) {
  console.log(...args)
}

foo`` // 默认会接收一个参数,类型为数组 --> ['']
复制代码
代码语言:javascript
复制
function foo(...args) {
  console.log(...args)
}

const lang = 'JS'
const username = 'Kluas'

foo`Hello ${lang}, my name is ${username}`
/*
  =>
    [Hello, , my name is]
    JS,
    Klaus
*/
复制代码

函数参数

默认参数

ES5

代码语言:javascript
复制
function sum(m, n) {
  // ES5中设置默认值的方式,但是这么设置其实是有bug的
  // 如果m或n的值是0或者空字符串的时候
  // 他们转换为boolean类型的时候,也是false,会触发使用默认值
  // 但是很明显,他们之间是不应该使用默认值的
  m = m || 'm'
  n = n || 'n'
  console.log(m + n)
}
复制代码
代码语言:javascript
复制
function sum(m, n) {
  // 所以我们可能会这么书写函数的默认值
  m = m === undefined ? 'm' : m
  n = n === undefined ? 'n' : n
  console.log(m + n)
}
复制代码

但是这么书写函数的默认值是十分繁琐的,所以ES6为我们提供了一种新的函数默认值的书写方式

代码语言:javascript
复制
function sum(m = 'm', n = 'n') {
  console.log(m + n)
}

sum() // => mn
sum(0, 0) // => 0
复制代码

如果函数参数是一个对象的时候,函数参数的默认值和对象的解构结合在一起使用,会十分的方便

代码语言:javascript
复制
function print({ name, age } = { name: 'Klaus', age: 23 }) {
  console.log(name, age)
}

print()

print({
  name: 'Alex',
  age: 18
})
复制代码

上述的代码还有另外一种书写方式

代码语言:javascript
复制
function print({ name = 'Klaus', age = 23 } = {}) {
  console.log(name, age)
}

print()

print({
  name: 'Alex',
  age: 18
})
复制代码
注意事项
  1. 参数的默认值我们通常会将其放到最后
代码语言:javascript
复制
function print(m = 23, n) {
  console.log(m, n)
}

// 如果需要使用默认值
print(undefined, 23)
复制代码
  1. 默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了
代码语言:javascript
复制
function foo(m, n = 2) {
  console.log(arguments.length) // => 1
}

foo()

function baz(m, n = 2, x, y) {
  // 从默认值开始包括之后的参数都不再被计算到arguments中
  console.log(arguments.length) // => 1
}

baz()
复制代码
剩余参数

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

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

Tips:

  1. 剩余参数必须作为最后一个参数进行传递,否则会报错
  2. 剩余参数中的...是前缀,不是展开运算符
代码语言:javascript
复制
function foo(m, n, ...args) {
  console.log(args) // => [4, 5, 6]
}

foo(2, 3, 4, 5, 6)
复制代码
arguments vs 剩余参数
  • 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实
  • arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作

rest参数是ES6中提供的一种替代arguments的来获取函数参数的方式,所以在开发中推荐使用剩余参数来替换arguments

箭头函数

箭头函数内部没有this,如果需要使用,会沿着作用域链去使用上层作用域中的this

箭头函数内部是没有arguments的,如果需要使用,可以使用剩余参数进行替换

箭头函数内部是没有显示原型对象prototype,这也就意味着箭头函数只能作为普通函数被调用,是无法使用new关键字来进行调用的

代码语言:javascript
复制
const foo = () => {
  // 箭头函数内部没有this,所以去上层作用域查找
  // 在这里上层作用域就是全局作用域
  console.log(this) // => globalThis

  // 箭头函数内部没有arguments, 直接打印会报错
  // 在浏览器端,会直接报错
  // 但是在node端,因为模块化解析需要,会存在默认值,但是也并不是我们所需要的那个arguments
  console.log(arguments) // error
}

console.log(foo.prototype) // => undefined

foo()
复制代码

展开运算符

可以在函数调用/数组构造和创建对象字面量的时候,将数组表达式或者string在语法层面展开

展开运算符其实是一种浅拷贝

代码语言:javascript
复制
// 函数调用
function foo(...args) {
  console.log(...args)
}

foo(...['Alex', 'Klaus'])
foo(...'Steven')
// apply的第一个参数是null,表示的是不指定函数调用内部的this,依旧使用原本的那个this
// 第二个参数是一个数组,apply在实际调用的时候,会自动将第二个参数解构出来并依次作为函数的参数被传入
foo.apply(null, [1, 2])
复制代码
代码语言:javascript
复制
// 数组构造
const users = ['Klaus', 'Alex', 'Steven']
const name = 'coderwxf'

const newUsers = [...users]
const newName = [...name]

console.log(newUsers, newName)
复制代码
代码语言:javascript
复制
// 构建对象字面量 --- 数组
const users = ['Klaus', 'Alex', 'Steven']
const userObj = { ...users }
console.log(userObj) // => { '0': 'Klaus', '1': 'Alex', '2': 'Steven' }
复制代码
代码语言:javascript
复制
// 构建对象字面量 --- 对象
const info = {
  name: 'Klaus',
  age: 23
}

const newObj = {...info}
console.log(newObj) // => { name: 'Klaus', age: 23 }
复制代码

数值表示

代码语言:javascript
复制
// 十进制
let num = 100

// 二进制
num = ob100

// 八进制
num = 0o100

// 十六进制
num = 0x100
复制代码
代码语言:javascript
复制
// 对于一些大的数值,看起来不是很方便
// 在生活中,我们会使用逗号进行分割 100,000,000,000
// 在ES2021中可以使用下划线来模拟这里的逗号

const num = 100_000_000_000

// 注意:这仅仅只是一个方便阅读和标识的方式,并不影响数值的实际使用和表示
console.log(num) // => 100000000000
复制代码

Symbol

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

在ES6之前,对象的属性名都是字符串形式,那么很容易造成属性名的冲突

比如原来有一个对象,我们希望在其中添加一个新的属性和值,

但是我们在不确定它原来内部有什么内容的情况下, 很容易造成冲突,从而覆盖掉它内部的某个属性

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

Symbol值是通过Symbol函数来生成的,生成后可以作为属性名

在ES6中,对象的属性名可以使用字符串,也可以使用Symbol值

代码语言:javascript
复制
// Symbol即使多次创建值,它们也是不同的:Symbol函数执行后每次创建出来的值都是独一无二的
const s1 = Symbol()
const s2 = Symbol()
console.log(s1 === s2) // => false
复制代码
代码语言:javascript
复制
// 可以在创建Symbol值的时候传入一个描述description, 用以起到标记的功能
const s = Symbol('foo')
console.log(s) // => Symbol(foo)
// 获取到symbol的描述符
console.log(s.description) // => foo
复制代码
代码语言:javascript
复制
// 可以使用Symbol在对象中表示唯一的属性名
let s1 = Symbol()
let s2 = Symbol()
let s3 = Symbol()

// 设置方式1
const obj = {
  [s1]: 'Klaus'
}

// 设置方式2
obj[s2] = 'Alex'

// 设置方式3
Object.defineProperty(obj, s3, {
  value: 'Steven',
  enumerable: true,
  configurable: true,
  writable: true
})
复制代码
代码语言:javascript
复制
// 获取symbol属性值
// 获取Symbol值只能使用中括号语法,不可以使用点语法
// 如果使用点语法,例如obj.s1, 浏览器在解析的时候会将s1作为字符串类型的值去进行查找
console.log(obj[s1])
console.log(obj[s2])
console.log(obj[s3])

// 在普通的遍历中,无法遍历到以symbol值作为key的属性

// Object.keys获取属性名数组的时候,不包含以symbol值作为key的属性
console.log(Object.keys(obj)) // => []

// for ... of 循环中是无法打印出以symbol值作为key的属性
for (const k in obj) {
  // 没有任何的输出
  console.log(k)
}

// 无法使用Object.getOwnPropertyNames, 获取以symbol值作为key的属性
console.log(Object.getOwnPropertyNames(obj)) // => []
复制代码
代码语言:javascript
复制
// 可以使用Object.getOwnPropertySymbols方法获取以symbol值作为key的属性
// Object.getOwnPropertySymbols方法返回的数据类型是数组类型
// 可以通过遍历的方式去获取到每一个symbol类型的属性名及其对应的属性值
console.log(Object.getOwnPropertySymbols(obj)) // => [ Symbol(), Symbol(), Symbol() ]
复制代码

创建Symbol的目的是为了创建一个独一无二的值

但是在某些情况下,就是需要创建建相同的Symbol值

此时可以使用Symbol.for方法

代码语言:javascript
复制
const s1 = Symbol.for()
const s2 = Symbol.for()

console.log(s1 === s2) // => true

// ---------------------------------

// 使用Symbol.for来创建symbol类型的值的时候
// 可以传入一个参数作为标识符
// 在创建的时候,会优先去寻找之前是否存在相同标识符的symbol值
// 如果存在就返回之前所创建过的symbol值,如果没有,则新建一个symbol值并返回
const s3 = Symbol.for('Klaus')
const s4 = Symbol.for('Klaus')

console.log(s3 === s4) // => true

// ---------------------------------------

// 可以通过Symbol.keyFor方法来获取对应的key
// Symbol.keyFor方法去获取一个Symbol类型值的标识符的时候

// 如果创建的时候传入了标识符,则将标识符返回
const s1 = Symbol.for('foo')
console.log(Symbol.keyFor(s1)) // => foo


// 如果创建的时候没有传入标识符,则返回undefined
// 注意: 这里返回的undefined是字符串类型的值
const s2 = Symbol.for()
console.log(Symbol.keyFor(s2)) // => undefined
console.log(typeof Symbol.keyFor(s2)) // => string

// 如果symbol在创建的时候,不是使用Symbol.keyFor方法创建的
// 那么无论该symbol值在被创建的时候,有没有传入标识符
// 其返回的结果都是undefined,且值的类型也是undefined
const s3 = Symbol('baz')
console.log(Symbol.keyFor(s3)) // => undefined
console.log(typeof Symbol.keyFor(s3)) // => undefined

// 此时需要通过属性description来获取
console.log(s3.description) // => baz

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 标签模板字符串
  • 函数参数
    • 默认参数
      • 注意事项
    • 剩余参数
      • arguments vs 剩余参数
  • 箭头函数
  • 展开运算符
  • 数值表示
  • Symbol
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档