这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

最近每天学习的时候,发现了一道很有趣的面试题

1.const [a, b] = { a: 100, b: 200 }
2.console.log(a)
3.console.log(b)
如何在不改变1的情况下,让代码不报错

这个时候,我突然想起来,之前看红宝书的时候,有过这么一篇内容

最后我的解题代码为

Object.prototype[Symbol.iterator] = function(){
return Object.values(this)[Symbol.iterator]
}
const [a, b] = { a: 100, b: 200 }
console.log(a)
console.log(b)

试了下,果然ok

接下来给大家分享下我在红宝书的基础上,在网上找到的几个基础资料,方便大家理解代码

1.什么是symbol

首先symbol是es6新增的类型,它是一个基本类型,symbol英文翻译是符号的意思。

在叙述symbol之前,推出一个概念,“以操作目标为程序本身的行为特性的编程,我们称为元编程。”

我们已知symbol是es6新增类型,按照逻辑推演:作为新增的类型,symbol一定是为了弥补了之前的不足,所以才出现的,是这样的吗?

首先我们说说它的特别之处:

symbol属性值对应的值是唯一的,这解决了命名冲突的问题,类似于id的作用。
symbol值不能与其他数据进行计算,包括与字符串拼接。
for/in ,for/of遍历时不会遍布symbol属性
这样看是不是觉得没什么特别的?最多也就弥补了命名冲突的问题。

下面推出第二个问题:

2.Iterotor是什么?

Iterator是一个遍历器的接口,是部署在数据结构上的,很多数据结构原生具备Iterator接口,这就意味着,我们不需要任何处理就可以使用for/of了,拥有symbol.Iterator属性返回的对象,都会在使用for/of时被当作Iterator接口当这个对象符合Iterator接口的标准时,for/of就可以完成任务,不符合就会报错!

刨除这个问题,我们知道symbol可以作为属性值存在。并且它具有唯一的特性,举个栗子:

直接let s = Symbol();测试s就是Symbol类型了。怎么说他是唯一的呢?
let s = Symbol(); let ss = Symbol(); s == ss ; 结果是false;或者
let s = Symbol('a'); let ss = Symbol('a'); s == ss ; 结果是false 有人会好奇Symbol('a')里面的参数a又是怎么回事呢?字符串a表示一种修饰,对你当前创建的Symbol类型的一种修饰,作为区分使用,否则当你创建多个Symbol数据时,容易混淆。 现在我们回过头说Iterotor是symbol的内置符号,而字符串a是自定义的符号。

3.symbol的内置符号symbol.Iterator,有什么用?

这个符号可以是任意对象上的一个专门属性,语言机制会自动的在这个属性上寻找一个方法,这个方法会构造一个迭代器来迭代这个对象的值,这个方法就是next方法,...展开和for/of循环会自动使用它,我们可以自定义symbol.iterator属性为任意对象值定义自己的迭代器逻辑,他将覆盖默认的迭代器。相当于是定义了一种元编程行为,提供给Javascript其他部分(也就是运算符和循环结构)在处理定义的对象时使用。

在Js中迭代器对象实现了可迭代协议,迭代器对象由Symbol.iterator属性的值返回。
Symbol.iterator属性的值是一个函数,它返回一个迭代器对象。
迭代器指的是拥有next方法的对象。
该next方法必须返回一个带有value和done的对象。

4.为什么会出现for..of?

为了理解条件语句,我们曾想象JavaScript解释器在源代码中会经过不同路径。而循环语句则是把这些路径弯曲又折回起点,以重复执行代码中的某部分。

es6定义了一个新循环语句:for/of。这种新循环虽然使用for关键字,但它们是完全不一同的两种循环,你说和for/in像不像?为什么?

for/of循环是专门用于可迭代对象的,什么是可迭代对象呢?

我们前文提到具有symbol.iterator属性的对象就是可以迭代的。而这个对象就是可迭代对象。

对象本身默认是不可迭代的。运行时尝试对常规对象使用for/of会抛出TypeError:

let o={x:1,y:2,z:3};
for(let element of o){//抛出TypeError,因为o不是迭代的对象
console.log(element);
}

如果你想迭代对象,可以使用for/in循环,或者基于Object.keys()方法的结果使用for/of:

let o={x:1;y:2,z:3};
let keys="";
for(let k of Object .keys(o)){
keys+=k;
}
console.log(keys) //x y z
/*这是因为Object.keys()返回一个对象属性名的数组,而数组是通过for/of来迭代的。也要注意,这种对象的键的迭代并不是实时的,在循环体内修改o不会影响迭代。如果你不在乎对象的属性,也可以像下面这样迭代每个键对应的值:
*/
let o={x:1;y:2,z:3};
let sum=0;
for(let v of Object .values(0)){
sum+=v;
}
console.log(sum)
//6
如果你即想要对象的属性还想要属性的值,可以基于Object.entries()和解构赋值来使用for/of:
let pairs="";
for(let [k , v] of Object .entries(o)){
pairs+=k + v;
}
console.log(pairs)//x 1 y 2 z 3
Object .entries()返回一个数组的数组,其中每个内部数组表示对象的一个属性的键值对。这里使用解构赋值把这些内部数组分开并且分别把它们的元素赋值给两个变量。

不知道你懂了没有,如果没有,那么接下来一篇,会加深你的印象

es6中有三类结构生来就具有Iterator接口:数组、类数组对象、Map和Set结构。

var arr = [1,2,3,4];
let iterator = arr[Symbol.iterator](); console.log(iterator.next()); //{ value: 1, done: false }
console.log(iterator.next()); //{ value: 2, done: false }
console.log(iterator.next()); //{ value: 3, done: false }
console.log(iterator.next()); //{ value: 4, done: false }
console.log(iterator.next()); //{ value: undefined, done: true }

至于对象没有布置iterator接口的原因,不知道最近大家有没有看根据《你一生的故事》拍成的电影“降临",片中出现的外星语言是一门非线性的语言。而我们说的数组,Map等结构中的成员都是有顺序的,即都是线性的结构,而对象,各成员并没有一个确定的顺序,所以遍历时先遍历谁后遍历谁并不确定。所以,给一个对象部署iterator接口,其实就是对该对象做一种线性转换。如果你有这种需要,就需要手动给你的对象部署iterator接口咯~

  如:

let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};

可以看到,Symbol.iterator会返回一个对象,这就是一个遍历器对象,而作为遍历器对象,其必须具备的特征就是必须具备next()方法。

我们还可以据此实现指针结构的数据结构。具体略~

  至于可以使用Array.from转换成数组的类数组对象,部署iterator有一种很简单的方法,即直接使用数组的[Symbol.iterator]接口。 

fakeArray.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

当然,不知道你们看到next是否想到了es6的一个新玩意儿,即Generator函数。用Generator函数来实现Symbol.iterator接口,事半功倍。

var yieldIterator = {};
yieldIterator[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
}; [...yieldIterator] // [1, 2, 3]
  注意,yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

注意,yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
  其次,其它调用到遍历器的操作还有解构赋值、扩展操作符、其它任何接受数组作为参数的场合,如:

for...of
Array.from()
Map(), Set(), WeakMap(), WeakSet()(比如)
Promise.all()
Promise.race()

一旦当你给你的结构部署了iterator接口,那么恭喜你,你可以使用for...of来遍历你的结构了!

  遍历器对象除了必须布置next方法以外,还有2个可选方法。return()和throw()。当一个解构在遍历的时候异常提前退出(比如break,continue或者出错)的时候,就会调用return方法,其次,return方法必须返回一个对象。

至于throw方法,则是用于抛出错误,Generator.prototype.throw这里不展开讲了,感兴趣的可以搜索一下。

 for of循环有很多优点,比如不像for...in一样只遍历键名(甚至包括原型链上的键),而且不像foreach不能跳出循环。并且for...of为各种数据结构提供了一个统一的遍历方法。

foreach无法终止循环,当通过break来终止循环时会报错 Illegal break statement。

好了,相信到这里你应该对整个Symbol有一定的理解了,如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

一道题开始认识Symbol的更多相关文章

  1. 嵌入式系统Linux内核开发工程师必须掌握的三十道题(转)

    嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...

  2. [LeetCode] K-th Symbol in Grammar 语法中的第K个符号

    On the first row, we write a 0. Now in every subsequent row, we look at the previous row and replace ...

  3. iOS开发 引用第三方库出现duplicate symbol时的处理方法

      该篇文章是我自己从我的新浪博客上摘抄过来的, 原文链接为: http://blog.sina.com.cn/s/blog_dcc636350102wat5.html     在iOS开发中, 难免 ...

  4. OpenSceneGraph 编译 error LNK2019:unresolved external symbol 错误

    在编译 OpenSceneGraph 的一个简单示例时, #include <osgViewer/Viewer> #include <osgDB/ReadFile> void ...

  5. C语言调试过程中duplicate symbol错误分析

    说明:在我们调试C语言的过程中,经常会遇到duplicate symbol错误(在Mac平台下利用Xcode集成开发环境).如下图: 一.简单分析一下C语言程序的开发步骤. 由上图我们可以看出C语言由 ...

  6. 用vue.js学习es6(四):Symbol类型

    一.Symbol类型: 1.ES6引入了一种新的原始数据类型Symbol,表示独一无二的值.它是JavaScript语言的第七种数据类型,前六种是:Undefined.Null. 布尔值(Boolea ...

  7. 10 Symbol

    Symbol 书中讲了2部分. Symbol() Symbol 属性值. 完全两种画风的东西. 1. Symbol 首先他是一种全新的值. 不属于以前的任何一种 ES6引入了一种新的原始数据类型Sym ...

  8. Xcode同一个Workspace中两个工程依赖于Undefined Symbol Error

    Workspace中包含两个工程A和B: A是dylib工程,引用了另一个动态库C,B需要链接(依赖)A库.当编译B时,会先编译A,然后把A生成的dylib拷贝到B的生成目录中.如果要运行B的话需要把 ...

  9. 处理Assetbundle依赖关系时想到的一道题

    在处理unit3d的assetbundle依赖关系的时候,想到了一道有趣的题目: 给定一堆数据,例如{A = {1, 3, 4}, B = {3, 4}, C = {5, 6}, D = {6, 7, ...

  10. VC++ : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall std::basic_string<wchar_t,struct std::char_traits<wchar_t>

    最近学习Google Breakpad,将其用在了自己的项目中,编译的版本为VS2010,没有什么问题.但是为了和之前的程序兼容,需要使用VS2008版本的程序,于是又编译了VS2008版本的代码,但 ...

随机推荐

  1. C#后端接收前端的参数

    接收参数 1. 直接使用 [FromBody] 特性来告诉 ASP.NET Core 将请求的 JSON 数据反序列化为 实体类 对象 [FromBody] BlogNewsDTO实体类 点击查看代码 ...

  2. MySQL 幻象行

    当同一个查询在不同的时间产生不同的行集时,就会出现所谓的幻像问题.例如,如果执行了两次SELECT,但是第二次返回了第一次没有返回的行,那么该行就是一个"幻象"行. 假设在表chi ...

  3. 【Unity3D】点选物体、框选物体、绘制外边框

    1 需求描述 ​ 绘制物体外框线条盒子 中介绍了绘制物体外框长方体的方法,本文将介绍物体投影到屏幕上的二维外框绘制方法. 点选物体:点击物体,可以选中物体,按住 Ctrl 追加选中,选中的物体设置为红 ...

  4. 【Unity3D】人机交互Input

    1 前言 ​ Input 是 Unity3D 中用于人机交互的工具类,用户可以调用其 GetKey.GetMousePosition.GetMouseButton.GetAxis.GetButton ...

  5. 搭建Windows环境下的多功能免费SSH客户端

    关于Windows下的SSH客户端工具,可以有许多选择,从开源免费到商业收费的,零零总总. 免费版: Putty就是最简单的SSH客户端,非常轻量级. Electerm是一个开源可免费使用的跨平台SS ...

  6. 红胖子(红模仿)的博文大全:开发技术集合大版本更新v4.0.0

    <红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术.树莓派.三维.OpenCV.OpenGL.ffmpeg.OSG.单片机.软硬结合等等)持续更新中...>大版本更新,更新后版本 ...

  7. NSIS制作安装包笔记(二):NSIS使用NSIS+Qt界面制作安装包流程

    前言   Nsis可以使用duilib也可以使用qt界面,笔者主要qt,本文章梳理nsis+qt制作安装包的基本流程.   下载Nsis-Ui-Plugin插件   Github地址:https:// ...

  8. locals()用法

    views.py代码 def test(request): if request.method == 'GET': return render(request,'test.html') elif re ...

  9. 阿尔萨斯(Arthas)入门

    目录 简介 Arthas(阿尔萨斯) 能为你做什么 安装 快速安装 全量安装 卸载 使用 启动arthas 查看dashboard 通过thread命令来获取到arthas-demo进程的Main C ...

  10. 深入理解maven及应用

    在项目里用了快一年的maven了,最近突然发现maven项目在eclipse中build时非常慢,因为经常用clean install命令来build项目,也没有管那么多,但最近实在受不了乌龟一样的b ...