重学js(字符串模板,默认参数,剩余参数,展开运算符,symbol)

94 阅读5分钟

字符串模板基本使用

在ES6之前,如果我们想要将字符串和一些动态的变量(标识符)拼接到一起,是非常麻烦和丑陋的(ugly)。 ES6允许我们使用字符串模板来嵌入JS的变量或者表达式来进行拼接: 首先,我们会使用 `` 符号来编写字符串,称之为模板字符串; 其次,在模板字符串中,我们可以通过 ${expression} 来嵌入动态的内容;

    const name = "zhangsan";
    const age = 18;
    const height = 1.88;
    
    console.log(`my name is ${name} ,age is ${age}`);
    console.log(`我是成年人吗? ${ age > 18 ? '是' : '否'}`)
    
    function foo() {
        return "function is foo";
    }
    
    console.log(`mu function ${foo()}`);

标签模板字符串(Tagged Template Literals)。

     function foo(...args) {
      console.log(args);
    }

     foo''=>foo()
   
    const name = "why";
    const age = 18;
    
    foo`Hello${name}Wor${age}ld`; =>foo() //[hello,wor,ld]
 
    -   如果我们使用标签模板字符串,并且在调用的时候插入其他的变量:
    -   模板字符串被拆分了;
    -   第一个元素是数组,是被模块字符串拆分的字符串组合;
    -   后面的元素是一个个模块字符串传入的内容;

image.png

函数的默认参数

  • 在ES6之前,我们编写的函数参数是没有默认值的,所以我们在编写函数时,如果有下面的需求:
  • 传入了参数,那么使用传入的参数;没有传入参数,那么使用一个默认值;
  • 在ES6中,我们允许给函数一个默认值
    // ES5 写法
    function foo( x , y) {
        x = 20 || x;
        y = 30 || y;
        console.log(x, y);
    } 
    
    
    // ES6 写法
    function foo( x = 20 , y = 30) {
        console.log(x , y)
    }
    
    foo(10,20); // 10 20
    foo(); // 20 30
    
    foo(0,"") // es5 有bug  es6没有bug
    //默认值和结构一起用
    //写法一
    function prantInfo({name,age}={name:'why',age:18}){
    console.log(name,age)
    }
     //写法二
     function prantInfo({name='why',age=18}={}){
    console.log(name,age)
    }
    
    另外参数的默认值我们通常会将其放到最后(在很多语言中,如果不放到最后其实会报错的): 
    但是JavaScript允许不将其放到最后,但是意味着还是会按照顺序来匹配; 
    另外默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了。

函数的剩余参数

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

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

    // 剩余参数只能放到最后面
    function foo( m, n, ...args) {
      console.log(m, n)
      console.log(args)

      console.log(arguments)
    }
    // args 是一个数组 (ES6新增想要替代arguments)
    // arguments 是伪数组
    // args只包含那些没有对应形参的实参,arguments 对象包含了传给函数的所有实参
    foo(20, 30, 40, 50, 60)
    
那么剩余参数和arguments有什么区别呢? 
剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参;
parguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;
parguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,
rest参数是ES6中提供 并且希望以此来替代arguments的; 剩余参数必须放到最后一个位置,否则会报错。

箭头函数

箭头函数是没有显式原型的,所以不能作为构造函数,使用new来创建对象

    var foo = () => {
        console.log("foo");
    }
    
    console.log(foo.prototype); //undefined
    var f = new foo(); //TypeError: foo is not constructor
    箭头函数是没有显式原型的,所以不能作为构造函数,使用new来创建对象

展开运算符(Spread syntax)

可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开; 还可以在构造字面量对象时, 将对象表达式按key-value的方式展开; 展开语法的场景: 在函数调用时使用;在数组构造时使用; 在构建对象字面量时,也可以使用展开运算符,这个是在ES2018(ES9)中添加的新特性;

注意:展开运算符其实是一种浅拷贝;

const names = ["abc", "cba", "nba"]
const name = "why"
const info = {name: "why", age: 18}

// 1.函数调用时
function foo(x, y, z) {
  console.log(x, y, z)
}

// foo.apply(null, names)
foo(...names)
foo(...name)

// 2.构造数组时
const newNames = [...names, ...name]
console.log(newNames)

// 3.构建对象字面量时ES2018(ES9)
const obj = { ...info, address: "广州市", ...names }
console.log(obj)
  • 展开运算符浅拷贝
  const info = {
  name: "why",
  friend: { name: "kobe" }
}

const obj = { ...info, name: "coderwhy" }
// console.log(obj)
obj.friend.name = "james"

console.log(info.friend.name) // 会被改变成james

数值表示方式

const num1 = 100 // 十进制

// b -> binary
const num2 = 0b100 // 二进制
// o -> octonary
const num3 = 0o100 // 八进制
// x -> hexadecimal
const num4 = 0x100 // 十六进制

console.log(num1, num2, num3, num4)

// 大的数值的连接符(ES2021 ES12)
const num = 10_000_000_000_000_000
console.log(num)

Symbol

  • Symbol在通常在对象中表示唯一的属性名
    // 在对象中,属性名key是唯一的,相同的会覆盖,但是Symbol就是用来创建一个独一无二的值
    // 可以让其不被覆盖
    
   const s1 = Symbol("abc");
   const s2 = Symbol("bcd");
   
   console.log(s1.description)//abc
   
   const obj = {};
   
   // 1.写法1:属性名赋值 , 不能使用.的语法
   obj[s1] = "abc";
   obj[s2] = "bcd";
   //obj.s1 = "abc" 错误
   
   // 2.写法2 Object.defineProperty
   Object.defineProperty(obj,s1,{
        configurable: true,
        writable: true,
        enumerable: true,
        value: "abc"
   })
   
   
   // 3.写法3 字面量
   const info = {
       [s1]: "abc",
       [s2]: "bcd"
   };
   
   //使用Symbol作为key的属性名,在遍历/Object.keys等中是获取不到这些Symbol值
   const symbolKyes = Object.getOwnPropertySymbols(info);

    // symbol 的key
    console.log(symbolKyes)

    // 遍历info for of遍历的是value   ---- for in 遍历的是key
    for (const item of symbolKyes) {
      console.log(info[item])
    }
  • 相同值的Symbol
    // 使用for  让描述相同 就可以了
    Symbol.for(key)/Symbol.keyFor(symbol)
    const s1 = Symbol.for("aaa");
    const s2 = Symbol.for("aaa");
    console.log(s1 === s2); // true
    
    // keyFor 也可以 key要是 Symbol创建出来的
    const s3 = Symbol.keyFor(s1);
    const s4 = Symbol.keyFor(s2);
    console.log(s3 === s4); //true
    
    const s5 = Symbol("aaa");
    const s6 = Symbol("aaa");
    console.log(s5 === s6); // false