向ES6看齐,用更好的JavaScript(三)

本文是ES6系列的第三篇,主要介绍ES6新增的数据类型、数据结构,先上传送门:

1 第七种数据类型Symbol

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

    let s = Symbol();
    console.log(typeof s); //"symbol"

Symbol类型变量通过Symbol()方法来构建(不能使用new),另外该方法可以接受一个字符串类型的参数作为该Symbol的描述

    let s1 = Symbol(‘tag‘);
    let s2 = Symbol(‘tag‘);

    s1 == s2; //false,参数仅仅作为描述,就算相同描述的两个Symbol也是不同的

Symbol类型使用注意:

    let s = Symbol();

    "symbol:" + s; //报错,无法和字符串运算

    s + 2;  //报错,无法和字符串运算

    s1.toString(); //"Symbol(tag)",Symbol显示转换为字符串类型是可以的

    if(s){
        ...         //可以转换为bool
    }
    

说了这么多,ES6中引入Symbol到底是用来干嘛呢?

由于任意两个Symbol都是不相等的,这就意味着我们可以将其作为对象的属性名,而不担心属性名重复覆盖原有属性,这在团队开发中是很有用的,举个栗子:

    let attr = Symbol();

    //方法1
    let obj = {};
    obj[attr] = ‘hello‘;  

    //方法2
    let obj = {
        [attr]: ‘hello‘
    }

    //方法3
    let obj = {};
    Object.defineProperty(a, mySymbol, { value: ‘Hello!‘ });

    //上面三种定义属性的方式效果是一样的
    obj[attr]; //"hello"

    //方法4
    let obj = {};
    obj.attr = ‘hello‘;
    obj[attr];  //undefined,注意不能使用“.”运算符

另外通过Symbol定义的函数是不会被for...in等遍历出来的,如果要遍历Symbol属性要使用Object.getOwnPropertySymbols来遍历Symbol属性,或使用另一个新的APIReflect.ownKeys遍历所有属性(包括Symbol和其它属性),看例子:


    var attr1 = Symbol(‘a1‘);
    var attr2 = Symbol(‘a2‘);

    var obj = {
        [attr1]:‘hello‘,
        [attr2]:‘world‘,
        name:‘vicfeel‘
    };

    for(let attr in obj){
        console.log(attr); //name,仅遍历到name属性
    }

    Object.getOwnPropertySymbols(obj);//[Symbol(a1),Symbol(a2)]仅遍历Symbol属性

    Reflect.ownKeys(obj);  //[Symbol(a1),Symbol(a2),name],遍历所有属性

2 新的数据结构Set

Set数据结构和数组类似,区别在于Set内元素是唯一不重复的,Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化,可以通过add方法添加元素,看栗子:

   //ES6环境下

   //Set的方法
   //Set - 构造函数,参数为一个数组
   let arr = [1,2,3,3,4,4];
   let s = new Set(arr);//Set{1,2,3,4}

   //add - 添加一个值,返回结构本身
   s.add(5); //Set{1,2,3,4,5}
   s.add(2); //Set{1,2,3,4,5}
   s.add(6).add(7);//Set{1,2,3,4,5,6,7}

   //delete - 删除一个值,返回一个布尔值表明删除是否成功
   s.delete(6); //true,Set{1,2,3,4,5,7}

   //has - 判断是否包含该值,返回一个布尔值
   let ok = s.has(6);//false,Set{1,2,3,4,5,7}

   //clear - 清空Set
   s.clear();//Set{}

   //Set的属性
   s.size; //0,与数组不同set通过size获取大小
   s.add(5);
   s.size; //1
   

Set内元素具有唯一性,因此最直观的用途便是数组去重,现在我们可以这样实现数组去重:

    function unique(arr){
        return [...new Set(arr)]; //...运算符参看ES6系列(二)

        //或者 return Array.from(new Set(arr));
    }

Set是如何界定两元素是否相同呢,我们来测试一下:

    let s = new Set();
    s.add(5);  //Set{5}
    s.add(‘5‘);  //Set{5,‘5‘},不会进行类型转换,是通过"==="而不是“==”

    let [n1,n2] = [NaN,NaN];
    s.add(n1);  //Set{5,‘5‘,NaN}
    s.add(n2);  //Set{5,‘5‘,NaN},只有一个NaN表明在Set内NaN是相等的

    s.add({});  //Set{5,‘5‘,NaN,{}}
    s.add({});  //Set{5,‘5‘,NaN,{},{}},任意两个对象是不相等的
  • 我们来简单看一下另一个和Set类似的数据结构WeakSet

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

(1)WeakSet的成员只能是对象,而不能是其他类型的值。

    var ws = new WeakSet();
    ws.add(1)
    // TypeError: Invalid value used in weak set
    ws.add(Symbol())
    // TypeError: invalid value used in weak set

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

3 新数据结构Map

map一词本身就有映射的意思,Map数据结构提供了一种完善的键值对结构,之所以称之为完善是相对于之前而言,我们知道JS中的对象Object本身就是一种键值对hash结构,然而这种键值对确是不完善的。

Object中只能将字符串作为键,无法使用对象作为键,Map数据结构的提出就是为了解决这个问题,来看个栗子:

    var a = {};
    var p = {name:‘vicfeel‘};
    a[p] = ‘val‘;
    a;//Object {[object Object]: "val"},p对象被转换成了字符串“[Object Object]”

来看一下Map数据结构的基础用法:

    //构造函数
    var m = new Map();
    var p = {name:‘vicfeel‘};
    //添加键值对
    m.set(p,‘val‘);
    //获取键值对
    m.get(p); //"val"
    m.get(‘name‘); //undefined
    //返回大小
    m.size; //1
    //重复添加相同键会覆盖先前的
    m.set(p,‘newVal‘);
    m.get(p); //"newVal"

    //利用包含键值对的数组初始化Map,相同键后面也会覆盖前面
    var arr = [{‘name‘:‘vicfeel‘},{‘age‘:23},{‘age‘:25}];
    var m2 = new Map(arr);
    m2.get(‘age‘); //25

    //判断是否含有某个键
    m2.has(‘name‘);  //true
    //删除某个键
    m2.delete(‘name‘);
    m2.has(‘name‘); //false

    //清空
    m2.clear();
    m2.size; //0

另外,另外Map数据结构也有一个forEach方法用于遍历:

    let m = new Map();
    m.set(‘name‘,‘vicfeel‘).set(‘age‘,25);
    m.forEach(function(val,key,map){
        console.log("Key: %s, Value: %s", key, value);
        //Key: name, Value: vicfeel
        //Key: age, Value: 25
    });

4 Iterator(遍历器)

虽然本篇博客写的是新的数据类型和数据结构,遍历器并不在此列,将Iterator放在这里是因为其与上面提到的Set、Map联系比较紧,趁热打铁,便在此一起说了。

首先要说明遍历器(Iterator)是一种机制、一种接口,它为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口(ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性),就可以完成遍历操作(即依次处理该数据结构的所有成员)。

ES新提供的遍历方法for...of的遍历方式便是自动寻找该对象的Iterator接口,一些数据结构是默认部署Iterator接口的,包括数组、Set和Map结构、伪数组(比如arguments对象、DOM NodeList对象)、后文的Generator对象,以及字符串,因此这些数据结构是可以直接使用for...of进行遍历的,看栗子:

    let arr = [1,2,3];
    for(let item of arr){
        item;
        //1
        //2
        //3
    }

    let s = new Set(arr);
    for(let item of s){
        item;
        //1
        //2
        //3
    }

    let m = new Map();
    m.set(‘name‘,‘vicfeel‘);
    m.set(‘age‘,23);
    let p = {‘width‘:100,‘height‘:200};
    m.set(p,‘val‘);
    for(let item of m){
        item;
        //["name", "vicfeel"]
        //["age", 23]
        //[{‘width‘:100,‘height‘:200},‘val‘]
    }

    let str = ‘hello‘;
    for(let item of str){
        item;
        //‘h‘
        //‘e‘
        //...
    }
    

对于未部署Iterator接口的结构想要对其使用for...of遍历可自己部署Iterator接口,比如对象Object默认是不部署Iterator接口的,因为系统不知道从哪个属性开始遍历以及按照什么样的次序进行遍历,我们一个对象来看一下如何部署Iterator接口:

    let obj = {
      data: [ ‘hello‘, ‘world‘ ],
      [Symbol.iterator]() {
        const self = this;
        let index = 0;
        return {
          //Iterator通过next()函数进行遍历,直至next函数返回的done值为true
          next() {
            if (index < self.data.length) {
              return {
                value: self.data[index++],
                done: false
              };
            } else {
              return { value: undefined, done: true };
            }
          }
        };
      }
    };

    for(let item of obj){
        item;
        //‘hello‘
        //‘world‘
    }
时间: 2024-08-18 14:10:25

向ES6看齐,用更好的JavaScript(三)的相关文章

向ES6看齐,用更好的JavaScript(二)

向ES6看齐,用更好的JavaScript(二) 上一篇 中介绍了关于变量部分的新特性,本篇将从现有对象的拓展来展开介绍 1 增加了模板字符串 先看一下,ES6之前我们是如何实现输出模板的: document.getElementById('root').innerHTML = "the user name is " + username + "\nthe user age is " + age; 这样通过字符串相加拼接确实挺繁琐的,很容易出错,ES6引入了模板字符

使用 Promises 编写更优雅的 JavaScript 代码

你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它们写出更优雅的 JavaScript 代码. 您可能感兴趣的相关文章 开发中可能会用到的几个 jQuery 提示和技巧 精心挑选的优秀jQuery Ajax分页插件和教程 推荐几款很好用的 JavaScript 文件上传插件 精心挑选的优秀 jQuery 文本特效插件和教程 精心挑选12款优秀 jQ

【摘】50个jQuery代码段帮助你成为一个更好的JavaScript开发者

今 天的帖子会给你们展示50个jQuery代码片段,这些代码能够给你的JavaScript项目提供帮助.其中的一些代码段是从jQuery1.4.2才 开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助你又快又好地把事情完成.这些都是我尽量记住的有着最佳性能的代码段,因此如果你发现你任 何可以做得更好的地方的话,欢迎把你的版本粘贴在评论中!我希望你在这一文章中能找到有帮助的东西. 1.     如何创建嵌套的过滤器: //允许你减少集合中的匹配元素的过滤器, //只剩下那些与给定的选择器

更快学习 JavaScript 的 6 个思维技巧---分享

更快学习 JavaScript 的 6 个思维技巧 2015-10-10 全栈开发者中心 我们在学习JavaScript,或其他任何编码技能的时候,往往是因为这些拦路虎而裹足不前: 有些概念可能会造成混淆,尤其当你是从其他语言转过来的时候. 找不到时间(有时是动力)学习. 很容易忘记已经理解了的东西. 工具多又在不断变化,所以不知道从哪里开始. 幸运的是,这些拦路虎是可以被识别,并消灭的.在这篇文章中,我将介绍六个思维技巧来帮助你更快地学习JavaScript,并成为一个更快乐.更富有成效的程序

帮助你更快学习JavaScript的六个思维技巧

? ? ? ? ? ? ? ? 当人们试图学习JavaScript或其他编程语言的时候,他们通常会遇到如下挑战. 一些概念让他们感到困惑,特别是如果之前学过其他类型的语言. 很难找到学习的时间(或者动力)去学习. 你很容易忘掉之前学到的东西. JavaScript工具太多并且经常更新,以至于很难找到学习的切入点. 幸运的是,这些难题最终能够被克服.在这篇文章,我将展示六个能够帮助你更快.更开心.更高效地学习JavaScript的六个思维技巧. 1   不要让未来的忧虑干扰你现在的学习 有些Jav

[label][翻译][JavaScript-Translation]七个步骤让你写出更好的JavaScript代码

7 steps to better JavaScript 原文:http://www.creativebloq.com/netmag/7-steps-better-javascript-51411781七个步骤让你写出更好的JavaScript代码 随着浏览器的性能提升,新的HTML5 APIS也在不断地被应用,JavaScript在web使用中不断增长.然而,一行糟糕的代码就有可能会影响到整个网站,产生糟糕的用户体验和造成潜在客户的流失. 开发者必须使用他所能使用的工具和技巧来提高代码的质量,

数据结构与算法JavaScript (三) 链表

数据结构与算法JavaScript (三) 链表 我们可以看到在javascript概念中的队列与栈都是一种特殊的线性表的结构,也是一种比较简单的基于数组的顺序存储结构.由于 javascript的解释器针对数组都做了直接的优化,不会存在在很多编程语言中数组固定长度的问题(当数组填满后再添加就比较困难了,包括添加删除, 都是需要把数组中所有的元素全部都变换位置的,javascript的的数组确实直接给优化好了,如 push,pop,shift,unshift,split方法等等…) 线性表的顺序

javascript 三种数组复制方法的性能对比

javascript 三种数组复制方法的性能对比,对于webkit, 使用concat; 其他浏览器, 使用slice. 一. 三种数组复制方法 1. by slice var arr = [1, 2, 3], copyArr; copyArr = arr.slice(); 2. by concat var arr = [1, 2, 3], copyArr; copyArr = arr.concat(); 3. by loop var arr = [1, 2, 3], copyArr = [];

更快学习 JavaScript 的 6 个思维技巧

我们在学习JavaScript,或其他任何编码技能的时候,往往是因为这些拦路虎而裹足不前: 有些概念可能会造成混淆,尤其当你是从其他语言转过来的时候. 找不到时间(有时是动力)学习. 很容易忘记已经理解了的东西. 工具多又在不断变化,所以不知道从哪里开始. 幸运的是,这些拦路虎是可以被识别,并消灭的.在这篇文章中,我将介绍六个思维技巧来帮助你更快地学习JavaScript,并成为一个更快乐.更富有成效的程序员. 1.不要让未来的决策阻止你现在前进的方向 很多人学习JavaScript,问的第一个