ES6 语法糖

语法糖(Syntactic sugar)

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

Symbol

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

    let s = Symbol();
    typeof s
    // "symbol
    s;
    //Symbol();
复制代码

每个Symbol都是独一无二的

    let a = Symbol('bar');//Symbol(bar)
    let b = Symbol('bar');
    b.toString(); //"Symbol(bar)"
    a==b //false
    a.toString()==b.toString() //true
复制代码

!!Symbol不是对象,不能用new,也就不能添加属性。

Symbol的使用
  1. 作为属性名(注意,Symbol值作为对象属性名时,不能用点运算符。)
    var mySymbol = Symbol();
    // 第一种写法
    var a = {};
    a[mySymbol] = 'Hello!';
    // 第二种写法
    var a = {
      [mySymbol]: 'Hello!'
    };
    // 第三种写法
    var a = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });
    // 以上写法都得到同样结果
    a[mySymbol] // "Hello!"
复制代码
  1. 消除魔术字符串

魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,该由含义清晰的变量代替。

    <!--例如-->
    function getArea(shape, options) {
      var area = 0;
    
      switch (shape) {
        case 'Triangle': // 魔术字符串
          area = .5 * options.width * options.height;
          break;
        /* ... more code ... */
      }
    
      return area;
    }
    
    getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
复制代码

上面代码中,字符串“Triangle”就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。常用的消除魔术字符串的方法,就是把它写成一个变量。

    <!--例如-->
    var shapeType = {
      triangle: 'Triangle'
    };
    
    function getArea(shape, options) {
      var area = 0;
    
      switch (shape) {
        case shapeType.triangle: // 魔术字符串
          area = .5 * options.width * options.height;
          break;
        /* ... more code ... */
      }
    
      return area;
    }
    
    getArea(shapeType.triangle, { width: 100, height: 100 }); // 魔术字符串
复制代码

上面代码中,我们把“Triangle”写成shapeType对象的triangle属性,这样就消除了强耦合。

如果仔细分析,可以发现shapeType.triangle等于哪个值并不重要,只要确保不会跟其他shapeType属性的值冲突即可。因此,这里就很适合改用Symbol值。

    const shapeType = {
      triangle: Symbol()
    };
复制代码
  1. 特殊功能

由于以 Symbol 值作为名称的属性,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。

    let s = Symbol('my_key');
    let obj = {
      [s]: 1,
      enum: 2,
      nonEnum: 3
    };
    for(let item in obj){
        console.log(item);
    }
    // enum,nonEnum
    obj[s]; //1
    Reflect.ownKeys(obj)
    // [Symbol(my_key), 'enum', 'nonEnum']
复制代码
  1. Symbol.for(),Symbol.keyFor()
    var s1 = Symbol.for('foo');
    var s2 = Symbol.for('foo');
    s1 === s2 // true
    
    var s1 = Symbol.for("foo");
    Symbol.keyFor(s1) // "foo"
    var s2 = Symbol("foo");
    Symbol.keyFor(s2) // undefined
复制代码
  1. 模块的 Singleton 模式
    // mod.js
    const FOO_KEY = Symbol.for('foo');
    
    function A() {
      this.foo = 'hello';
    }
    
    if (!global[FOO_KEY]) {
      global[FOO_KEY] = new A();
    }
    
    module.exports = global[FOO_KEY];
    //上面代码中,可以保证global[FOO_KEY]不会被无意间覆盖,但还是可以被改写。
    var a = require('./mod.js'); 
    global[Symbol.for('foo')] = 123;
    //键名使用Symbol方法生成,那么外部将无法引用这个值,当然也就无法改写
    const FOO_KEY = Symbol('foo');
复制代码
  1. 内置的Symbol值

    Symbol.hasInstance。 对象的Symbol.hasInstance属性,指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。比如,foo instanceof Foo在语言内部,实际调用的是Foo[Symbol.hasInstance](f oo)。

    class MyClass {
      [Symbol.hasInstance](foo) {
        return foo instanceof Array;
      }
    }
    
    [1, 2, 3] instanceof new MyClass() // true
    
    class Even {
      static [Symbol.hasInstance](obj) {
        return Number(obj) % 2 === 0;
      }
    }
    
    1 instanceof Even // false
    2 instanceof Even // true
    12345 instanceof Even // false
复制代码
Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象使用Array.prototype.concat()时,是否可以展开。
复制代码
    let arr1 = ['c', 'd'];
    ['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
    arr1[Symbol.isConcatSpreadable] // undefined
    
    let arr2 = ['c', 'd'];
    arr2[Symbol.isConcatSpreadable] = false;
    ['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
复制代码
类似数组的对象也可以展开,但它的Symbol.isConcatSpreadable属性默认为false,必须手动打开。
复制代码

set和map数据结构

数据结构set
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成Set数据结构。
复制代码
    var s = new Set();
    
    [2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
    
    for (let i of s) {
      console.log(i);
    }
    // 2 3 5 4
    [...s]//[2,3,5,4]
    //
    s.size //4
复制代码
  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。
  • Array.from(new Set([1,2,3,4])):转成数组。
  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
    let set = new Set(['red', 'green', 'blue']);
    for (let item of set.keys()) {
      console.log(item);
    }
    // red
    // green
    // blue
    for (let item of set.values()) {
      console.log(item);
    }
    // red
    // green
    // blue
    for (let item of set.entries()) {
      console.log(item);
    }
    // ["red", "red"]
    // ["green", "green"]
    // ["blue", "blue"]
复制代码
WeakSet

WeakSet结构与Set类似,也是不重复的值的集合。但是,它与Set有两个区别。

首先,WeakSet的成员只能是对象,而不能是其他类型的值。

其次,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。

    var a = [[1,2], [3,4]];
    var ws = new WeakSet(a);
复制代码
Map

JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。

    var m = new Map([
      [true, 'foo'],
      ['true', 'bar']
    ]);
    
    m.get(true) // 'foo'
    m.get('true') // 'bar'
复制代码
  • size属性:m.size
  • set(key, value):m.set("hello","vv")
  • get(key)
  • has(key)
  • delete(key)
  • clear()
  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历Map的所有成员。

转载于:https://juejin.im/post/5cd50eff6fb9a032076c2341

### ES6 语法糖特性及其功能 ES6(ECMAScript 2015)引入了许多新的特性和语法糖,这些改进使得 JavaScript 的开发更加高效和简洁。以下是几个重要的语法糖特性以及它们的功能和用法。 #### 箭头函数 (Arrow Functions) 箭头函数提供了一种更短的函数书写方式,并且不会绑定自己的 `this` 值,而是继承自外层作用域[^1]。 ```javascript // 普通函数写法 function multiply(x, y) { return x * y; } // 使用箭头函数简化 const multiply = (x, y) => x * y; console.log(multiply(3, 4)); // 输出 12 ``` #### 默认参数值 (Default Parameters) 默认参数允许开发者在定义函数时指定参数的默认值,从而减少不必要的条件判断逻辑[^2]。 ```javascript // 定义带有默认值的参数 function greet(name = 'Guest') { console.log(`Hello, ${name}!`); } greet(); // Hello, Guest! greet('Alice'); // Hello, Alice! ``` #### 解构赋值 (Destructuring Assignment) 解构赋值可以从数组或对象中提取数据并将其分配给变量,极大地提高了代码可读性[^3]。 ```javascript // 数组解构 let [a, b, c] = [1, 2, 3]; console.log(a); // 输出 1 // 对象解构 let { name, age } = { name: 'John', age: 30 }; console.log(name); // 输出 John ``` #### 扩展运算符 (Spread Operator) 扩展运算符可以用于展开数组或者对象中的元素,在复制、合并操作中有广泛的应用场景[^4]。 ```javascript // 合并两个数组 let array1 = [1, 2, 3]; let array2 = [...array1, 4, 5]; console.log(array2); // 输出 [1, 2, 3, 4, 5] // 复制对象 let obj1 = { a: 1, b: 2 }; let obj2 = { ...obj1, c: 3 }; console.log(obj2); // 输出 { a: 1, b: 2, c: 3 } ``` #### 模板字符串 (Template Strings) 模板字符串通过反引号 `` 提供多行字符串支持以及嵌入表达式的便利方法[^5]。 ```javascript let firstName = 'Jane'; let lastName = 'Smith'; // 使用模板字符串构建完整姓名 let fullName = `${firstName} ${lastName}`; console.log(fullName); // 输出 Jane Smith ``` ### 总结 上述列举的是 ES6 中一些常见的语法糖特性,每一种都旨在提升编码效率清晰度。理解并熟练掌握这些新特性对于现代前端工程师来说至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值