定义二个全局变量,并赋值定义顺序对程序的影响,玄学!

&figure&&img src=&https://pic3.zhimg.com/v2-377a5cd607e3b485fe7ec95fae60be97_b.jpg& data-rawwidth=&906& data-rawheight=&418& class=&origin_image zh-lightbox-thumb& width=&906& data-original=&https://pic3.zhimg.com/v2-377a5cd607e3b485fe7ec95fae60be97_r.jpg&&&/figure&&p&很高兴通知大家,Python 3.7 的&a href=&http://link.zhihu.com/?target=https%3A//pythoncaff.com/docs/tutorial/3.7.0& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《入门教程》&/a& 已经翻译完毕。&/p&&p&号召翻译的帖子请见这里:&a href=&http://link.zhihu.com/?target=https%3A//pythoncaff.com/topics/375/python-document-translation& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&翻译召集 -- 《Python 3.7 中文官方文档:入门教程》&/a& &/p&&p&从号召到完成,花费不到一周的时间。&/p&&p&共有 42 位译者参与翻译,完整的列表请见:&a href=&http://link.zhihu.com/?target=https%3A//pythoncaff.com/docs/tutorial/3.7.0%3Fmode%3Dtranslators& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&参与译者列表&/a& &/p&&figure&&img src=&https://pic4.zhimg.com/v2-660a04ca8b37992cae6b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1958& data-rawheight=&482& class=&origin_image zh-lightbox-thumb& width=&1958& data-original=&https://pic4.zhimg.com/v2-660a04ca8b37992cae6b_r.jpg&&&/figure&&p& 下一步的计划是翻译标准库,这是将会是一项巨大的工程,请大家保持关注,很快我们就会开始行动的。&/p&
很高兴通知大家,Python 3.7 的 已经翻译完毕。号召翻译的帖子请见这里: 从号召到完成,花费不到一周的时间。共有 42 位译者参与翻译,完整的列表请见: 下一步的计划是翻译标…
&figure&&img src=&https://pic4.zhimg.com/v2-7fbf12c8f3d177ce3b693aa886ea5e87_b.jpg& data-rawwidth=&1458& data-rawheight=&603& class=&origin_image zh-lightbox-thumb& width=&1458& data-original=&https://pic4.zhimg.com/v2-7fbf12c8f3d177ce3b693aa886ea5e87_r.jpg&&&/figure&&h2&前言&/h2&&p&《你不知道的 javascript》是一个前端学习必读的系列,让不求甚解的JavaScript开发者迎难而上,深入语言内部,弄清楚JavaScript每一个零部件的用途。本书介绍了该系列的两个主题:“作用域和闭包”以及“this和对象原型”。这两块也是值得我们反复去学习琢磨的两块只是内容,今天我们用思维导图的方式来精读一遍。(思维导图图片可能有点小,记得点开看,你会有所收获)&/p&&h2&第一部分 作用域和闭包&/h2&&h2&作用域是什么&/h2&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-5e7d1dad2d2d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1377& data-rawheight=&872& class=&origin_image zh-lightbox-thumb& width=&1377& data-original=&https://pic2.zhimg.com/v2-5e7d1dad2d2d_r.jpg&&&/figure&&p&&br&&/p&&p&作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对 变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。赋值操作符会导致 LHS 查询。 的赋值操作。 =操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。 JavaScript 引擎首先会在代码执行前对其进行编译,在这个过程中,像 var a = 2 这样的声 明会被分解成两个独立的步骤:&/p&&ol&&li&首先, var a 在其作用域中声明新变量。这会在最开始的阶段,也就是代码执行前进行。&/li&&li&接下来, a = 2 会查询(LHS 查询)变量 a 并对其进行赋值。&/li&&/ol&&p&LHS 和 RHS 查询都会在当前执行作用域中开始,如果有需要(也就是说它们没有找到所 需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一级作用域(一层 楼),最后抵达全局作用域(顶层),无论找到或没找到都将停止。&/p&&p&不成功的RHS引用会导致抛出 ReferenceError 异常。不成功的 LHS 引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用 LHS 引用的目标作为标识符,或者抛 出 ReferenceError 异常(严格模式下)。&/p&&h2&词法作用域&/h2&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-febbb7de38e93c4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1105& data-rawheight=&471& class=&origin_image zh-lightbox-thumb& width=&1105& data-original=&https://pic1.zhimg.com/v2-febbb7de38e93c4_r.jpg&&&/figure&&p&&br&&/p&&p&词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。编译的词法分析阶段 基本能够知道全部标识符在哪里以及是如何声明的,从而能够预测在执行过程中如何对它 们进行查找。&/p&&p&JavaScript 中有两个机制可以“欺骗”词法作用域: eval(..) 和 with 。 前者可以对一段包 含一个或多个声明的“代码”字符串进行演算,并借此来修改已经存在的词法作用域(在 运行时)。后者本质上是通过将一个对象的引用 当作 作用域来处理,将对象的属性当作作 用域中的标识符来处理,从而创建了一个新的词法作用域(同样是在运行时)。&/p&&p&这两个机制的副作用是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎地认 为这样的优化是无效的。使用这其中任何一个机制都 将 导致代码运行变慢。 不要使用它们。&/p&&h2&函数作用域和块作用域&/h2&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-1d35d742e39dd546f3bbe3fafa32ab55_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1689& data-rawheight=&828& class=&origin_image zh-lightbox-thumb& width=&1689& data-original=&https://pic2.zhimg.com/v2-1d35d742e39dd546f3bbe3fafa32ab55_r.jpg&&&/figure&&p&&br&&/p&&p&函数是 JavaScript 中最常见的作用域单元。本质上,声明在一个函数内部的变量或函数会 在所处的作用域中“隐藏”起来,这是有意为之的良好软件的设计原则。&/p&&p&但函数不是唯一的作用域单元。块作用域指的是变量和函数不仅可以属于所处的作用域, 也可以属于某个代码块(通常指 { .. } 内部)。&/p&&p&从 ES3 开始, try/catch 结构在 catch 分句中具有块作用域。在 ES6 中引入了 let 关键字( var 关键字的表亲), 用来在任意代码块中声明变量。 if(..) { let a = 2; } 会声明一个劫持了 if 的 { .. } 块的变量,并且将变量添加到这个块 中。&/p&&p&有些人认为块作用域不应该完全作为函数作用域的替代方案。两种功能应该同时存在,开 发者可以并且也应该根据需要选择使用何种作用域,创造可读、可维护的优良代码。&/p&&h2&提升&/h2&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-8a2d52c55ca340cccb214_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1651& data-rawheight=&539& class=&origin_image zh-lightbox-thumb& width=&1651& data-original=&https://pic1.zhimg.com/v2-8a2d52c55ca340cccb214_r.jpg&&&/figure&&p&&br&&/p&&p&我们习惯将 var a = 2; 看作一个声明,而实际上 JavaScript 引擎并不这么认为。它将 var a 和 a = 2 当作两个单独的声明,第一个是编译阶段的任务,而第二个则是执行阶段的任务。&/p&&p&这意味着无论作用域中的声明出现在什么地方,都将在代码本身被执行前 首先 进行处理。 可以将这个过程形象地想象成所有的声明(变量和函数)都会被“移动”到各自作用域的最顶端,这个过程被称为提升。&/p&&p&声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。&/p&&p&要注意避免重复声明,特别是当普通的 var 声明和函数声明混合在一起的时候,否则会引 起很多危险的问题!&/p&&h2&作用域闭包&/h2&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-38ccff4b6b9_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1549& data-rawheight=&731& class=&origin_image zh-lightbox-thumb& width=&1549& data-original=&https://pic2.zhimg.com/v2-38ccff4b6b9_r.jpg&&&/figure&&p&&br&&/p&&p&闭包就好像从 JavaScript 中分离出来的一个充满神秘色彩的未开化世界,只有最勇敢的人 才能够到达那里。但实际上它只是一个标准,显然就是关于如何在函数作为值按需传递的 词法环境中书写代码的。&/p&&p&当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时 就产生了闭包。&/p&&p&如果没能认出闭包,也不了解它的工作原理,在使用它的过程中就很容易犯错,比如在循 环中。但同时闭包也是一个非常强大的工具,可以用多种形式来实现 模块 等模式。模块有两个主要特征:&/p&&p&(1)为创建内部作用域而调用了一个包装函数; (2)包装函数的返回 值必须至少包括一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的闭 包。&/p&&p&现在我们会发现代码中到处都有闭包存在,并且我们能够识别闭包然后用它来做一些有用 的事!&/p&&h2&第二部分 this 和对象原型&/h2&&h2&this 全面解析&/h2&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-17af028e2eb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1696& data-rawheight=&873& class=&origin_image zh-lightbox-thumb& width=&1696& data-original=&https://pic4.zhimg.com/v2-17af028e2eb_r.jpg&&&/figure&&p&&br&&/p&&p&如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后 就可以顺序应用下面这四条规则来判断 this 的绑定对象。&/p&&ol&&li&由 new 调用?绑定到新创建的对象。&/li&&li&由 call 或者 apply (或者 bind )调用?绑定到指定的对象。&/li&&li&由上下文对象调用?绑定到那个上下文对象。&/li&&li&默认:在严格模式下绑定到 undefined ,否则绑定到全局对象。&/li&&/ol&&p&一定要注意,有些调用可能在无意中使用默认绑定规则。如果想“更安全”地忽略 this 绑 定,你可以使用一个 DMZ 对象,比如 ? = Object.create(null) ,以保护全局对象。ES6中的箭头函数并不会使用四条标准的绑定规则, 而是根据当前的词法作用域来决定 this ,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这 其实和 ES6 之前代码中的 self = this 机制一样。&/p&&h2&对象&/h2&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-0babe06a0c65df9c27349_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1594& data-rawheight=&760& class=&origin_image zh-lightbox-thumb& width=&1594& data-original=&https://pic2.zhimg.com/v2-0babe06a0c65df9c27349_r.jpg&&&/figure&&p&&br&&/p&&p&JavaScript 中的对象有字面形式(比如 var a = { .. } )和构造形式(比如 var a = new Array(..) )。字面形式更常用,不过有时候构造形式可以提供更多选项。&/p&&p&许多人都以为“JavaScript 中万物都是对象”,这是错误的。对象是 6 个(或者是 7 个,取 决于你的观点)基础类型之一。对象有包括 function 在内的子类型,不同子类型具有不同 的行为,比如内部标签 [object Array] 表示这是对象的子类型数组。&/p&&p&对象就是键 / 值对的集合。可以通过 .propName 或者 [&propName&] 语法来获取属性值。访 问属性时, 引擎实际上会调用内部的默认 [[Get]] 操作(在设置属性值时是 [[Put]] ), [[Get]] 操作会检查对象本身是否包含这个属性,如果没找到的话还会查找 [[Prototype]] 链(参见第 5 章)。&/p&&p&属性的特性可以通过属性描述符来控制,比如 writable 和 configurable 。此外,可以使用 Object.preventExtensions(..) 、 Object.seal(..) 和 Object.freeze(..) 来设置对象(及其 属性)的不可变性级别。&/p&&p&属性不一定包含值——它们可能是具备 getter/setter 的“访问描述符”。此外,属性可以是 可枚举或者不可枚举的,这决定了它们是否会出现在 for..in 循环中。&/p&&p&你可以使用 ES6 的 for..of 语法来遍历数据结构(数组、对象, 等等)中的值, for..of 会寻找内置或者自定义的 @@iterator 对象并调用它的 next() 方法来遍历数据值。&/p&&h2&混合对象&类&&/h2&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-abde940edff88b1979da17_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1428& data-rawheight=&862& class=&origin_image zh-lightbox-thumb& width=&1428& data-original=&https://pic4.zhimg.com/v2-abde940edff88b1979da17_r.jpg&&&/figure&&p&&br&&/p&&p&类是一种设计模式。 许多语言提供了对于面向类软件设计的原生语法。 JavaScript 也有类 似的语法,但是和其他语言中的类完全不同。&/p&&p&类意味着复制。&/p&&p&传统的类被实例化时,它的行为会被复制到实例中。类被继承时,行为也会被复制到子类 中。&/p&&p&多态(在继承链的不同层次名称相同但是功能不同的函数)看起来似乎是从子类引用父 类,但是本质上引用的其实是复制的结果。&/p&&p&JavaScript 并不会(像类那样)自动创建对象的副本。&/p&&p&混入模式(无论显式还是隐式)可以用来模拟类的复制行为,但是通常会产生丑陋并且脆 弱的语法,比如显式伪多态( OtherObj.methodName.call(this, ...) ),这会让代码更加难 懂并且难以维护。&/p&&p&此外, 显式混入实际上无法完全模拟类的复制行为, 因为对象(和函数!别忘了函数也 是对象)只能复制引用, 无法复制被引用的对象或者函数本身。 忽视这一点会导致许多 问题。&/p&&p&总地来说,在 JavaScript 中模拟类是得不偿失的,虽然能解决当前的问题,但是可能会埋下更多的隐患。&/p&&h2&原型&/h2&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-654aa183cd82d7ae187768_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1458& data-rawheight=&603& class=&origin_image zh-lightbox-thumb& width=&1458& data-original=&https://pic1.zhimg.com/v2-654aa183cd82d7ae187768_r.jpg&&&/figure&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-9c1e3a7aa_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1458& data-rawheight=&781& class=&origin_image zh-lightbox-thumb& width=&1458& data-original=&https://pic3.zhimg.com/v2-9c1e3a7aa_r.jpg&&&/figure&&p&&br&&/p&&p&如果要访问对象中并不存在的一个属性, [[Get]] 操作(参见第 3 章)就会查找对象内部 [[Prototype]] 关联的对象。这个关联关系实际上定义了一条“原型链”(有点像嵌套的作用域链),在查找属性时会对它进行遍历。&/p&&p&所有普通对象都有内置的 Object.prototype ,指向原型链的顶端(比如说全局作用域),如 果在原型链中找不到指定的属性就会停止。 toString() 、 valueOf() 和其他一些通用的功能 都存在于 Object.prototype 对象上,因此语言中所有的对象都可以使用它们。&/p&&p&关联两个对象最常用的方法是使用 new 关键词进行函数调用, 在调用的 章)中会创建一个关联其他对象的新对象。4个步骤(第2章)中会创建一个关联其他对象的新对象。&/p&&p&使用 new 调用函数时会把新对象的 .prototype 属性关联到“其他对象”。带 new 的函数调用 通常被称为“构造函数调用”,尽管它们实际上和传统面向类语言中的 类构造函数 不一样。&/p&&p&JavaScript 是 中的机制有一个核心区别, 那就是不会进行复制, 对象之间是通过内部的&/p&&p&虽然这些 机制和传统面向类语言中的“类初始化”和“类继承”很相似, 但是 javascript 机制和传统面向对象类语言中的“类初始化”和“类继承”很相似但是 javascript 中的机制有一个核心区别,就是不会进行复制,对象之间是通过内部的 [[Prototype]] 链关联的。&/p&&p&出于各种原因,以“继承”结尾的术语(包括“原型继承”)和其他面向对象的术语都无 法帮助你理解 JavaScript 的 真实 机制(不仅仅是限制我们的思维模式)。&/p&&p&相比之下,“委托”是一个更合适的术语,因为对象之间的关系不是 复制 而是委托。&/p&&h2&行为委托&/h2&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-e2eb6bcd5c8eaa_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1754& data-rawheight=&763& class=&origin_image zh-lightbox-thumb& width=&1754& data-original=&https://pic3.zhimg.com/v2-e2eb6bcd5c8eaa_r.jpg&&&/figure&&p&&br&&/p&&p&在软件架构中你可以 选择是否 使用类和继承设计模式。大多数开发者理所当然地认为类是 唯一(合适)的代码组织方式,但是本章中我们看到了另一种更少见但是更强大的设计模式: 行为委托 。&/p&&p&行为委托认为对象之间是兄弟关系, 互相委托, 而不是父类和子类的关系。 JavaScript 的 [[Prototype]] 机制本质上就是行为委托机制。也就是说,我们可以选择在 JavaScript 中努 力实现类机制(参见第 4 和第 5 章),也可以拥抱更自然的 [[Prototype]] 委托机制。&/p&&p&当你只用对象来设计代码时,不仅可以让语法更加简洁,而且可以让代码结构更加清晰。&/p&&p&对象关联(对象之前互相关联)是一种编码风格,它倡导的是直接创建和关联对象,不把 它们抽象成类。对象关联可以用基于 [[Prototype]] 的行为委托非常自然地实现。&/p&&h2&扩展&/h2&&p&思维导图能比较清晰的还原整本书的知识结构体系,如果你还没用看过这本书,可以按照这个思维导图的思路快速预习一遍,提高学习效率。学习新事物总容易遗忘,我比较喜欢在看书的时候用思维导图做些记录,便于自己后期复习,如果你已经看过了这本书,也建议你收藏复习。如果你有神马建议或则想法,欢迎留言或加我微信交流:&/p&&p&&a href=&http://link.zhihu.com/?target=https%3A//www.kancloud.cn/kancloud/you-dont-know-js-this-object-prototypes/516674& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&你不知道的javascript上卷第二部分在线文档&/a&&/p&&p&&a href=&http://link.zhihu.com/?target=https%3A//github.com/threerocks/studyFiles/blob/master/js/%25E4%25BD%25A0%25E4%25B8%258D%25E7%259F%25A5%25E9%E7%259A%2584JavaScript%25EF%25BC%%25B8%258A%25E5%258D%25B7%25EF%25BC%2589.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&你不知道的 javascript(上卷)PDF 下载地址&/a&&/p&&p&&a href=&http://link.zhihu.com/?target=https%3A//link.juejin.im/%3Ftarget%3Dhttps%253A%252F%252Fgithub.com%252Fbailinlin%252FAwsome-Front-End-Xmind& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&思维导图下载地址&/a&&/p&
前言《你不知道的 javascript》是一个前端学习必读的系列,让不求甚解的JavaScript开发者迎难而上,深入语言内部,弄清楚JavaScript每一个零部件的用途。本书介绍了该系列的两个主题:“作用域和闭包”以及“this和对象原型”。这两块也是值得我们反复去学…
&figure&&img src=&https://pic3.zhimg.com/v2-80f03dfe036ad4ff0e34_b.jpg& data-rawwidth=&638& data-rawheight=&724& class=&origin_image zh-lightbox-thumb& width=&638& data-original=&https://pic3.zhimg.com/v2-80f03dfe036ad4ff0e34_r.jpg&&&/figure&&p&今天在空间timeline上看见一张图片,描述了JavaScript作为一门“神奇”的语言有着许许多多所谓的“特性“,下面让我们来一一探索一下。(参考书:犀牛书)&/p&&p&&br&&/p&&h2&1. 抽风的数字类型&/h2&&p&&br&&/p&&h2&1.1. NaN&/h2&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
typeof NaN
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&&code&NaN&/code&是js预定义的全局变量,用以表示0/0的结果。而其被定义为number类型。也可以通过&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&new Number(NaN)
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&这样的操作来构建NaN对象。&/p&&p&补充说明:经过评论区指出,NaN的定义是由IEEE754浮点数标准直接给出的,这个和js半毛钱关系都没有。&/p&&p&关于typeof,还有一个有趣的结论应该就是&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
typeof null
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&这是由于null的开头第一位的内部编码和object一样的原因,不然就会是&code&undefined&/code&。&/p&&p&&br&&/p&&h2&1.2. 迷之相等&/h2&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
0.5+0.1==0.6
0.1+0.2==0.3
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&首先,js真的不能进行精确的计算,如果涉及精确的计算,建议自行设计高精度算法。要问为什么,那就是因为js没有专门的整数类型,它的所有number类型(NaN等奇怪的东西)除外,都是浮点数。&/p&&p&js完全采用IEEE754标准的64位方案来表示其数字,从而,根据犀牛书所指出的(也可以根据IEEE754标准推算),其能够准确表示的整数范围只到74 0992 (这里正好16个数),而16个9,就有着被表示成1*10^16的危险。然而,在js它parseNumber的时候,在后面的幂大于20的时候才会显示成科学计数法。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&整数部分尚且可以在二进制下精确表达,但是小数部分,则是真的很容易产生误差。二进制下的小数部分,只能精确表示能被拆分成(1/2)^n的和的部分,剩下的部分,就或多或少有着偷工减料了。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&这同时也意味着在处理小数是否相等时,js中需要进行的是差值在多少范围内的比较,而不能用相等直接比较。&/p&&p&&br&&/p&&h2&1.3. 代劳了的初始化&/h2&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
Math.max()
Math.min()
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&这个还真的不能算bug,平时题目做多了的人可能就注意到了这个用意,一般而言,最大最小值还真就是这么初始化的。为了方便得进行后续取最大和最小值的比较和判断。&/p&&p&&br&&/p&&h2&2. 迷之类型转化&/h2&&p&&br&&/p&&p&后面一整串,其实在犀牛书关于js的类型自动转化之中都有详细解答。所以都列在这里了:&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
&[object Object]&
true+true+true===3
(!+[]+[]+![]).length
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&但是首先,我们要来讲讲运算符。&/p&&p&&code&+&/code& 加号在js中可以用作number类型的加法运算,也可以用来拼接string。所以参与加法运算的两个参数都需要将数据类型转化为对应的number或者是string。&/p&&p&而js中,只要参与运算的对象不全是number类型,就会发生各种迷之操作。&/p&&p&首先,对象会去调用各自的valueOf(),用valueOf的结果来继续运算(valueOf的结果各种各样,但是会是js的四种基本类型 string、bool、number、object之一),但是不幸的是,一般对象都不会有这个玩意儿,而可以进行valueOf()并且产生number返回值&code&(就是那个距离创世日的毫秒数)&/code&的日期对象,在这里会强制调用toString(),所以一般都会直接进入调用各自的toString()然后进行字符串拼接。(如果调用完valueOf()之后,加法两端可以进行数学意义上的加法,那么就会进行啦,不然还是字符串拼接)&/p&&p&js面对加法,没有不择手段的进行数学加法运算,而是不择手段的进行字符串拼接。&/p&&p&那么我们根据以上法则,一个个看过去。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[]+[]
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&&code&[]&/code&数组的valueOf()会直接返回&&空字符串,所以结果是空字符串,没有任何毛病。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[]+{}
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&[]的valueOf()依然会返回空字符串,这没有任何问题。&/p&&p&而&code&{}&/code&作为object其valueOf()的结果依然是object,因此就会调用toString(),产生返回值&[object Object]&。从而拼接字符串,产生结果。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&{}+[]
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&那么你来说说,这个反过来加怎么就可以得到数字了呢。这个我做了下实验,发现如果是对对象进行赋值的再做相加操作的话,正着和倒着的结果是一样的。但是直接输入以上的式子,结果确实是0。那么这里的&code&{}&/code&到底被当成什么了呢?&code&花括号&/code&,在这里的意思已经不是对象了,而是我们平时用来框语句块的花括号,代表的是一组空白&code&表达式&/code&。所以这里已经不是加法的世界了。相当于是在计算:&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&+[]
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&而+作为一元运算符的时候,右边的参数优先转化为数字,而[]会转化为0。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
true+true+true===3
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&这一串其实,这么看下来应该很好解释,true在做加法运算的时候能够转化成数字(能够成功的valueOf)从而得到数字1。那么1+1+1自然是严格等于3的(毕竟类型转化了,大家都是number)。&br&所以其实这组其实是非常正常的运算结果。&/p&&p&java的相等&code&==&/code&是会考虑valueOf的,而&code&===&/code&严格相等是不容含糊的(虽然也会出现各种神奇的结果)。&/p&&p&那么下面这个式子就自己品味了吧。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&而下面这组式子也很好解释:&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&加法优先考虑字符串连接,减法自然只存在强行计算。如果字符串转化成number失败,计算结果会是NaN。&/p&&p&那么最后来看看这个式子:&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&(!+[]+[]+![]).length
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&到底发生了什么&/p&&p&首先,逻辑非&code&!&/code&有着极高的优先级,所以首先计算的是!+[]和![]。&/p&&p&+[]的结果我们刚刚已经知道了是数字0,对其做逻辑非运算会将数字0直接转化为&code&false&/code&,然后再得到&code&true&/code&。&/p&&p&而对[]直接去逻辑非的结果呢?则是对[]直接转化为&code&true&/code&再求逻辑非,得到&code&false&/code&&br&那么式子就变成了&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&(true+[]+false).length
&/code&&/pre&&/div&&p&&br&&/p&&p&&br&&/p&&p&之后如何计算就无需多言了。&/p&&p&只是觉得其中有的内容确实不错,但是有的内容过于钓鱼,所以甘愿咬勾,写下这篇文字。&/p&&p&工作中摸鱼,但愿不会被炒。&/p&
今天在空间timeline上看见一张图片,描述了JavaScript作为一门“神奇”的语言有着许许多多所谓的“特性“,下面让我们来一一探索一下。(参考书:犀牛书) 1. 抽风的数字类型 1.1. NaN & typeof NaN
&· "number"
NaN是js预定义的全局变量,用以表示0/0的…
&p&这是一个之前面试被问到的问题。&/p&&p&不过以前并没有思考过这个问题,面试时又太紧张,并没有答好。&/p&&p&&br&&/p&&p&&b&在我看来 TypeScript 相对于 JavaScript ,除了静态类型外没带来任何东西。&/b&&/p&&p&&br&&/p&&p&既然如此&/p&&h2&静态类型有什么好处?&/h2&&p&静态类型的好处到处都有说,这里就不说得太详细了,随便列一点。&/p&&ul&&li&杜绝手误导致的变量名写错。&/li&&li&自动完成。&/li&&li&重构支持。&/li&&li&类型可以一定程度上充当文档&/li&&/ul&&p&对我来说最有用的就是这几点,特别是自动完成。&/p&&p&本人天生脑容量小,难以驾驭动态类型语言。&/p&&p&静态类型解放脑容量,自动完成让我不需要记忆哪个变量里有哪些属性,也不需要记完整的变量名。&/p&&p&函数上的类型约束外加尽量主动写纯函数让我在写函数实现的时候不需要关注函数之外的任何东西,注意力聚焦在当前函数。&/p&&p&&br&&/p&&p&当然,也不只有好处。&/p&&h2&静态类型有哪些不足?&/h2&&ul&&li&类型标注麻烦。&/li&&li&现阶段大部分静态类型语言的类型系统还不够强。&/li&&li&eval 和 new Function() 这种骚操作类型系统管不到。&/li&&li&需要编译,类型检查会增加编译时长,语法和类型系统复杂的话时间特别特别长,比如 scala。&/li&&/ul&&p&标注麻烦的问题无法根绝,但是类型推导能解决大部分的类型标注问题。&/p&&p&类型系统不够强的问题会随着时间慢慢变好。&/p&&p&编译的问题在 ts 可能也并不算问题,ts 的类型检查并不影响 ts 编译成 js。&/p&&p&也就是说就算类型检查不通过 ts 也能跑起来。所以对 ts 来说类型检查可以从编译中提取出来,作为独立的编译和类型检查两部分。&/p&&p&先编译输出,再做类型检查,编译的部分相当于 babel 这种工具做的事。&/p&&p&类型检查也可以单独运行。&/p&&p&&br&&/p&&p&那么,&/p&&h2&TypeScript 的类型系统有哪些特点?&/h2&&ul&&li&&a href=&https://link.zhihu.com/?target=https%3A//github.com/Microsoft/TypeScript/issues/14833& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&图灵完备&/a&。(虽然不太清楚这意味着什么)&/li&&li&渐进的类型系统,所有类型标注都是可选的,既是天使又是恶魔的 &a href=&https://link.zhihu.com/?target=https%3A//github.com/Microsoft/TypeScript/blob/master/doc/spec.md%233.1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&any&/a& 类型。(被 Haskell 大牛 &a href=&https://www.zhihu.com/people/axurez& class=&internal&&Colliot&/a& 称为 ts 类型系统的漏洞)&/li&&li&支持&a href=&https://link.zhihu.com/?target=https%3A//www.typescriptlang.org/docs/handbook/type-inference.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&局部类型推导&/a&。&/li&&li&丰富的类型层面的计算,如 &a href=&https://link.zhihu.com/?target=https%3A//www.typescriptlang.org/docs/handbook/advanced-types.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&index types, mapped types, conditional types 等等&/a&。&/li&&li&&a href=&https://link.zhihu.com/?target=https%3A//www.typescriptlang.org/docs/handbook/type-compatibility.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&支持鸭子类型&/a&。(或叫结构子类型?)&/li&&li&像 js 支持对象字面量一样支持方便的对象字面类型(object literal type),字符串和数字还有布尔值字面类型。&/li&&li&空安全。&/li&&li&基于控制流的类型分析。&/li&&/ul&&p&还有许多我觉得比较平常的点就没有列出来,比如支持类型别名,泛型,协变逆变双变等等。&/p&&p&ts 是一门非常非常非常工程的语言,很强大,但是可能和优雅沾不上半点关系。&/p&&p&可选的类型标注搭配类型推导,让 ts 的类型系统更像是工具,而不是枷锁。好的产品是用完即走的。&/p&&p&有时候,稍微开个洞,能让事情变简单很多。比如 any。&/p&&p&鸭子类型加上上面提到的特性可以让你依旧感觉和 js 一样,像大海里的鱼一样自由。&/p&&p&&a href=&https://link.zhihu.com/?target=https%3A//www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Null References: The Billion Dollar Mistake &/a&,而 js 里有两个 null(null 和 undefined),虽然前端通常不会造成非常严重的损失,但是 js 也慢慢被应用到不仅仅是前端的许多地方了。&/p&&p&&br&&/p&&p&ts 这么好,&/p&&h2&怎么学 TypeScript?&/h2&&p&成也渐进,败也渐进,有部分人通过可选的类型标注,一步一步无痛地过渡到学会 ts。&/p&&p&而另一部分人玩了一会儿,发现和写 js 并没有一丁点区别,而且还离开了熟悉的环境,就放弃了。&/p&&p&ts 并不会强迫你使用类型,所以就需要更强的动力来推动自己学习。&/p&&p&&br&&/p&&p&如果身边有会 ts 的朋友的话,对学习 ts 会比较有帮助。&/p&&p&多让会 ts 的朋友看自己的代码,改良自己的写法。多写,很容易就能学会。&/p&&p&&br&&/p&&p&如果身边没有会 ts 的人,其实我更建议先用 &a href=&https://link.zhihu.com/?target=https%3A//github.com/Microsoft/TypeScript/wiki/JSDoc-support-in-JavaScript& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JSDoc&/a&。&/p&&p&使用 vscode 或者 webstorm 的时候直接写 JSDoc 就行了,vsc 或 webstorm 会依靠 ts 来提供类型推导和自动完成。&/p&&p&这样可以在工作或自己写东西的时候慢慢习惯并且主动去使用类型标注。&/p&&p&在使用一段时间后感觉 JSDoc 已经不够用了,满足不了自己的需求了,再开始使用 ts。&/p&&p&同时也要多主动去了解和学习一些 ts 的代码,不然的话,不知道 ts 有多好,自然就不会觉得 JSDoc 不够用。&/p&
这是一个之前面试被问到的问题。不过以前并没有思考过这个问题,面试时又太紧张,并没有答好。 在我看来 TypeScript 相对于 JavaScript ,除了静态类型外没带来任何东西。 既然如此静态类型有什么好处?静态类型的好处到处都有说,这里就不说得太详细了,随…
&p&哎,就在今天,我关注了多年的博客 &a href=&https://link.zhihu.com/?target=http%3A//ruanyifeng.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ruanyifeng.com&/a& 无法访问了。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-3af92fac9fdc7df30537a4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1336& data-rawheight=&802& class=&origin_image zh-lightbox-thumb& width=&1336& data-original=&https://pic1.zhimg.com/v2-3af92fac9fdc7df30537a4_r.jpg&&&/figure&&p&&br&&/p&&p&本文讲述了阮一峰在过去 7 年对我的影响,文章很长,看完需要耐心。&/p&&p&&br&&/p&&h2&初识阮一峰&/h2&&p&我从大学的时候就开始关注阮一峰的博客。&/p&&p&我还记得那时我刚刚学编程,什么都不懂,经常搜着搜着就搜到「阮一峰」的博客。于是我就看了一下他的百度百科:&/p&&blockquote&阮一峰,70后,英文名Frank。他原是上海财经大学世界经济博士研究生。主要研究宏观金融、货币政策与美国经济。于2008年6月获得博士学位。目前在上海一所当地大学(上海金融学院 国际经贸学院)任教。&/blockquote&&p&原来他的专业并不是前端,而是一个经济学博士。但是我当时觉得他写的技术文章真的是好。&/p&&p&2012 年,我基本把阮一峰过往的所有文章全都读了,觉得没有学习动力的时候,就会去看阮的博客。虽然我几乎没有跟他交流过,但是看他的文字的时候我觉得是在跟一个友善的人对话。&/p&&p&同年我在「阮一峰的博客为什么人气很高」这个知乎问答里回答道:&/p&&blockquote&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&深入浅出,如沐春风&/a&。&/blockquote&&p&阮的文章,永远都是用朴素语言给读者解释一些事物。虽然有时候算不上深刻,但是能让你恍然大悟。&/p&&p&那个时候 Google Reader 还没有关停,我几乎是每天上班第一件事是就是先刷一下 Google Reader 看看阮一峰有没有新的博客。&/p&&p&当时我跟我的每一个同事都推荐了阮一峰的博客,我希望更多人能看到他的博客。&/p&&p&现在我在教前端的时候也依然向我的每一个学生推荐阮一峰的博客。&/p&&p&&br&&/p&&h2&阮一峰对我的影响&/h2&&p&读阮一峰的博客这么多年,我受到了阮一峰的很多影响。&/p&&p&&br&&/p&&p&&b&1 坚持写博客&/b&&/p&&p&我入行的时候经常听前辈们说:要多写博客。但是我发现这些前辈自己却没有践行这一句话。&/p&&p&后来我发现阮一峰做到了,他在 2006 年发表了一篇《为什么要写Blog?》写道:&/p&&blockquote&到今年12月为止,&b&我写Blog已经满3年了&/b&,一共写了接近600篇,平均每2天写一篇。今后应该还会继续写下去。&br&3年前,我开始写的时候,并没有想过自己会坚持这么久。3年中,也遇见过几次有人问我&为什么要写Blog?&&br&是啊,为什么要写Blog?毕竟这里没有人支付稿酬,也看不出有任何明显的物质性收益。&br&Darren Rowse在他的Blog上,讲到了7个理由,我觉得说得很好。&br&……&br&总之,正是因为以上7个理由,所以我强烈建议,每一个朋友都应该有一个自己的Blog,尝试将自己的生活和想法记录下来,留下一些印记。&/blockquote&&p&他在 2014 年发表了一篇《我的博客文集上架了!》写道:&/p&&blockquote&&b&这个博客写了十年&/b&,累积了1000多篇文章。&br&我一直想整理一本文集,这个月终于完成了。&br&书名叫做《如何变得有思想?》&/blockquote&&p&阮真的是在「坚持写博客」。受阮一峰的鼓舞,我不管加班多累都会每个月写一些博客,而这些博客令我成长很快。&/p&&p&我在每个技术团队里都是写博客最勤快的,但是不管我多勤快,我都知道阮一峰比我写得更勤快,我做得还不够。&/p&&p&&br&&/p&&p&&b&2 打开编程的大门&/b&&/p&&p&虽然我在大学里学计算机编程,但是大学老师们似乎并不怎么向我们介绍编程文化,只是讲书本上的内容。我无法体会到世界上其他程序员跟我有什么联系。&/p&&p&我是从阮一峰那里了解到了一些生动而有趣的编程文化的,这些文化对我的影响一直持续到现在。&/p&&p&&br&&/p&&p&&b&日,阮一峰发表了《我要翻译&Joel on Software&了!》文中写道:&/b&&/p&&blockquote&上个月,人民邮电出版社下属的图灵公司写信问我,是否愿意翻译他的精华文章结集More Joel on Software。&br&&br&我立刻答应下来。世界上有些东西,你是巴不得自己的名字与它联系在一起的。所以,如果一切顺利的话,明年春天,这本书的中文版就会上市。&br&&br&说实话,我是不该接这本书的。因为我的事情本来就多得做不完,每周都觉得睡眠不足。现在又多出这样一件事,时间就更紧张了。不过,既然接了,那就只有挤时间拼命做了。&br&&br&对我来说,这件事的难点有两个:&br&1)虽然我会一些编程,但是总的来说,我在技术上是外行,翻译这样一本程序员的专业读物有技术上的难度。&br&2)Joel在文章大量使用口语、俚语和双关语,很难翻译得贴切。&br&&br&对于第一点,由于Joel的文章更像是对软件业的整体思考,而且面向新手,通常不涉及技术细节,所以问题还不大。我比较头痛的是第二点。举例来说,Joel的这本书有一个近乎戏谑的副书名:&br&&br&Further Thoughts on Diverse and Occasionally Related Matters That Will Prove of Interest to Software Developers, Designers, and Managers, and to Those Who, Whether by Good Fortune or Ill Luck, Work with Them in Some Capacity&br&&br&怎么译?......&br&&br&我差不多花了二十分钟琢磨,最后才勉强译出来:&br&&br&程序员、软件设计师、软件经理、以及其他有幸或不幸与软件打交道的人员,感兴趣的各种相关内容&br&&br&我对这个翻译依然不满意,觉得有意思漏掉了。如果你有更好的翻译,欢迎指教。&/blockquote&&p&这本书是 Joel Spolsky 的博客集,他是大名鼎鼎的 Trello 和 Stackoverflow 的创始人。Joel Spolsky 的英文文章极难翻译,阮经常会问网友如何翻译更妥当,我从来没有见过一个译者如此认真。&/p&&p&我得知阮在翻译这本书的时候就已经迫不及待地想购买了。&/p&&p&&br&&/p&&p&&b&2009 年这本书发布了,名叫《软件随想录》。&/b&&/p&&p&我毫不犹豫地购买了这本书,书拿到手后,除了吃饭睡觉,一口气全部看完了。&/p&&p&虽然我的专业用的教材都是比较新的国外教材,但是观念依然是趋于保守的。《软件随想录》让我看到了一个大师级程序员对软件开发的独特见解,令我佩服不已。&/p&&p&&br&&/p&&p&&b&2012 年阮发表了一篇文章《&Linus Torvalds自传&摘录》。&/b&&/p&&blockquote&除了程序员,大概很少人知道Linux操作系统。&br&&br&它的发明者Linus Torvalds,知道的人就更少了。&br&&br&他本人也很低调,深居简出,很少出席公众场合或接受媒体采访,通常只在专业开发者的邮件列表中发言。提起他的名字,人们的第一反应往往是&哦,传说中那个22岁就发明Linux的芬兰大学生......&,其他就一片空白了。&br&&br&他的自传《Just For Fun》出版于十年前(2001年),已经几乎被遗忘了。&br&&br&星期六下午,我在硬盘里偶然翻到这本书(中译本),不经意地读了第一页。Linus Torvalds正在谈他的写作计划:&br&&br&&我们可以在第一章里对人们解释生命的意义何在。这样可以吸引住他们。一旦他们被吸引住,并且付钱买了书,剩下的章节里我们就可以胡扯了。&&br&&br&我觉得有点意思,接着往下面读。他继续谈生命的意义:&br&&br&&人类的追求分成三个阶段。第一是生存,第二是社会秩序,第三是娱乐。最明显的例子是性,它开始只是一种延续生命的手段,后来变成了一种社会行为,比如你要结婚才能得到性。再后来,它成了一种娱乐。&&br&&br&我心里嘀咕,这个理论有点离经叛道啊,不过看上去似乎有道理。但是,它跟Linux有什么关系呢?&br&&br&&技术最初也是为了生存,为了生存得更好。现在技术大体上还处于社会的层面,但正在朝娱乐的阶段发展。......(Linux的开发模式)为人们提供了依靠兴趣与热情而生活的机会。与世界上最好的程序员一起工作,是一种无与伦比的享受。&&br&&br&我被吸引住了,整个周末都在读它,越读越入迷。此书极其有趣,一点不枯燥,充满了各种好玩的笑料,以及对技术和软件的严肃思考。如果你是一个程序员,我高度推荐此书。&br&&br&我从没料到Linus Torvalds是一个如此幽默有趣的人,我摘录了一些他的妙语,请大家欣赏。&/blockquote&&p&我看完这篇文章之后十分惭愧,因为我本人就是一个立志做程序员的人,为什么我没有了解一下 Linus 和 Linux 呢。很快我就邮购了这本《Just For Fun》。&/p&&p&这本书让我知道了 Linus 大神的一些事迹,也让我了解了开源世界的魅力。&/p&&p&&br&&/p&&p&&b&2013 年阮翻译了一本书,名叫《黑客与画家》。&/b&&/p&&p&书刚发布我就买了,依然一口气读完。&/p&&p&这本书让我见识到一名黑客的热忱、远见和智慧。也许是从那时起,我就已经在心里埋下了创业的想法。&/p&&p&&br&&/p&&p&我很感谢阮一峰给我开启了一道道大门,大门里面是世界上最厉害的程序员。&/p&&p&阮一峰就像一个热心的前辈,向我娓娓道来这个程序员如何如何好,那个程序员如何如何厉害。&/p&&p&如果没有阮一峰,我可能要在门外徘徊很久很久……&/p&&p&因为现实生活里,并没有人向我传授这些知识。&/p&&p&&br&&/p&&p&&b&3 让我学会了写文章的技巧&/b&&/p&&p&为什么我这么喜欢看阮一峰的文章?因为其他人的文章基本没法看……&/p&&p&这么多年,我喜欢的中文博主只有几个:阮一峰、陈皓、Matrix67。&/p&&p&这几位博主的文章都有一个特点:平易近人。&/p&&p&阮在解释一个事物的时候,从来不会引入更复杂的概念,而是以大家都懂的语言或图片来阐述。&/p&&p&我举个例子,很多人在解释 JS 的 this 的时候会提到「词法作用域」和「动态作用域」。然而,对于一个前端新人来说,「词法作用域」比 this 复杂多了,这样解释 this 根本就不能令人明白。&/p&&p&而阮的文章,都是对新人非常友好,同时又能把事情讲清楚的。&/p&&p&&br&&/p&&p&比如下图:&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-7e2cdbf579fddec9598fa_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1855& data-rawheight=&1063& class=&origin_image zh-lightbox-thumb& width=&1855& data-original=&https://pic3.zhimg.com/v2-7e2cdbf579fddec9598fa_r.jpg&&&/figure&&p&&br&&/p&&p&在阮一峰发布这种图片之前,我对各种软件开源许可证毫无概念,根本就分不清楚。&/p&&p&直到我遇到了阮一峰……&/p&&p&&br&&/p&&p&之后我写文章一直都在模仿阮一峰,虽然没有他那么平易近人,但是依然坚持用朴素的语言把事情说清楚。&/p&&p&&br&&/p&&p&&b&4 让我知道「如何学习」&/b&&/p&&p&我时常想,为什么阮一峰可以知道这么多优质的知识,而我不知道?&/p&&p&想着想着就发现阮的两个重要特点:&/p&&ol&&li&看英文资料。阮的很多知识都是只能在英文世界获取到的。因此我应该也把英文学好。&/li&&li&看大牛推荐的大牛。阮发现大牛 A 不错,就会去看 A 的博客,然后从 A 的博客里发现大牛 B,然后就去看大牛 B 的博客,以此类推,最后发现了一堆厉害的人。因此我也要学习这种学习方式。&/li&&/ol&&p&&br&&/p&&h2&与阮一峰的两次见面&/h2&&p&我以为我这辈子都不会跟阮一峰有什么交集。&/p&&p&直到我到了阿里,而阮一峰也到了阿里。&/p&&p&&br&&/p&&p&那应该是 2014 年,阿里内网有一篇邮件,说阮一峰要在支付宝大楼做一次分享。&/p&&p&当时我心里挺开心,觉得公司真厉害,能请来我一直仰慕的阮一峰。&/p&&p&我再仔细一看不得了,邮件里还说阮一峰已经入职阿里巴巴了,那这么说的话,我跟阮一峰不就是同事了!&/p&&p&仅仅因为这,我当天就开心得不行了,有一种做梦的感觉。&/p&&p&我当然是马上抢先报名去听这次演讲。&/p&&p&&br&&/p&&p&演讲的内容,我今天还记得。&/p&&blockquote&阮一峰说,他在整理自己过去十年的博客的时候发现了一件事情。&br&那就是这十年里,虽然他写了很多博客,帮助了很多人。&br&但是自己却没有做出什么事情,没有创造出什么东西。&br&他在想这辈子都在学校里教书是不是太平淡了。&br&&br&正好阿里巴巴有意向让阮一峰加入,所以阮一峰觉得这是一个契机。&br&&br&在入职阿里之前,阮想做一件事情:去一个他从来没去过的地方。&br&于是他坐飞机去一个沙漠旅游(具体哪个沙漠我忘记了,名字挺长)。&br&到了沙漠之后,&br&大失所望……&br&因为这里虽然被沙漠环绕,但是酒店、泳池、饮用水一应俱全,&br&跟在上海没什么区别。&br&&br&阮一峰觉得这并不是「自己从来没有去过的地方」。&br&&br&也许自己应该不再做大学老师,去互联网企业看看。&br&那才是「自己从来没有去过的地方」。&/blockquote&&p&&br&&/p&&p&我坐在第二排,听得真切。现在看来这次演讲的内容对我内心的影响也是很大的。我敢于跳出阿里,跟若愚两个前端出来办网校,很可能也是因为想去「自己从来没有去过的地方」。&/p&&p&阮一峰讲完之后,正好坐在了我的前方。&/p&&p&&br&&/p&&p&我拿出准备好的《软件随想录》让他给我签名,然后跟他合影留念了。&/p&&p&这就是我跟阮一峰的第一次见面。并没有过多的交谈。&/p&&p&阮一峰给我的印象,是一个温和的学者,跟他的文章给我的印象一致。&/p&&p&&br&&/p&&p&后来我抽空又去支付宝大楼参加了一次阮一峰组织的技术分享会,他本人没有演讲,在一旁专注地敲着电脑,我就没有过去打扰他了。&/p&&p&我知道,他已经从老师,变成了一个程序员了。&/p&&p&&br&&/p&&h2&画风突变&/h2&&p&在阮一峰加入阿里之后,网上对阮一峰的评论突然开始变了。&/p&&p&这个转变大概要从「朴灵评注阮一峰」事件开始。&/p&&a href=&https://www.zhihu.com/question//answer/& data-draft-node=&block& data-draft-type=&link-card& class=&internal&&怎么看待朴灵评注阮一峰老师的最新文章这件事?&/a&&p&朴灵和阮一峰都是阿里的,当然不会因为此事交恶,但是网友们似乎发现怼阮一峰是一件很容易的事情,并乐于围观别人怼阮一峰。&/p&&p&实话说,在我获取了一些专业知识之后,确实发现阮一峰写得技术文章存在一些问题,这跟他的技术积累有关。&/p&&p&但我并不觉得他写得技术入门文章比其他技术入门文章差。其他文章看似没有问题,但是却令新人看不懂。如果新人看不懂,那么还能帮助新人吗?&/p&&p&大家指出阮一峰文章中存在的问题可以,但是对阮一峰全盘否定是不能接受的。连我自己也在知乎指出过阮一峰推特中对技术的解读存在错误,但我依然尊敬阮一峰。阮一峰的推特几乎每天都在更新,偶尔出现几个错误太正常不过了。大部分读者都是有自己的判断能力的。&/p&&p&&br&&/p&&p&后来,微博上的一些前端就经常对阮一峰文章中的错误进行吐槽了。&/p&&p&阮一峰为前端写了两本书《JavaScript 标准参考教程》和《ES6标准入门》。&/p&&p&阮一峰在写书的过程中,时常遇到不是很理解的地方,于是就会在推特和微博上发表出来,看看大家怎么说。我记得有一次阮一峰对 ES6 的圆括号作用域没有搞清楚,于是一批前端就开始在评论里冷嘲热讽了。&/p&&p&基本上只要阮一峰出一个错,就会引起这些人的兴奋。&/p&&p&&br&&/p&&p&然而阮一峰从来都没有反驳过他们,依然写着自己的书,帮助前端新人们。&/p&&p&而这群批评阮一峰的人,其中大部分人,都没有为前端做哪怕一点点贡献。&/p&&p&&br&&/p&&p&正因为没有反驳,所以他们原来越大胆了,一直到最近的这篇&/p&&a href=&https://link.zhihu.com/?target=https%3A//juejin.im/post/5afa07abf728c40& data-draft-node=&block& data-draft-type=&link-card& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&面试官:阮一峰版的快速排序完全是错的 - 掘金&/a&&p&确实,阮一峰写得快排不是完美的,但绝对不是「完全是错的」。&/p&&p&&br&&/p&&p&我不知道中国的前端现在是怎么想的,新人毫无头绪,老人天天看戏。&/p&&p&他们似乎分不清谁是好谁是坏,什么应该被鼓励什么应该被唾弃。&/p&&p&&br&&/p&&p&气得我都开始押韵了!&/p&&p&&br&&/p&&p&&br&&/p&&h2&网站无法访问&/h2&&figure&&img src=&https://pic4.zhimg.com/v2-7ea4fec46_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1158& data-rawheight=&592& class=&origin_image zh-lightbox-thumb& width=&1158& data-original=&https://pic4.zhimg.com/v2-7ea4fec46_r.jpg&&&/figure&&p&今天阮一峰发了两条推特,表示他的博客站点被攻击,无法访问了。&/p&&p&我并不知道是谁在做这种令人恶心的事情。但我知道,阮一峰应该被我们鼓励。&/p&&p&&br&&/p&&p&遂有此文。&/p&&p&希望攻击者早日认识到自己的幼稚,&/p&&p&希望 &a href=&https://link.zhihu.com/?target=http%3A//ruanyifeng.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ruanyifeng.com&/a& 早点恢复访问,&/p&&p&也希望阮一峰不要再遭受这些无端的攻击了。&/p&&p&&br&&/p&&p&目前如果你想看阮一峰的博客,只能用 Google 的缓存功能查看。&/p&&p&&br&&/p&&h2&更新&/h2&&figure&&img src=&https://pic3.zhimg.com/v2-653e14b55edb72d0f773f00dedb3096b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2130& data-rawheight=&1874& class=&origin_image zh-lightbox-thumb& width=&2130& data-original=&https://pic3.zhimg.com/v2-653e14b55edb72d0f773f00dedb3096b_r.jpg&&&/figure&&p&&/p&
哎,就在今天,我关注了多年的博客
无法访问了。 本文讲述了阮一峰在过去 7 年对我的影响,文章很长,看完需要耐心。 初识阮一峰我从大学的时候就开始关注阮一峰的博客。我还记得那时我刚刚学编程,什么都不懂,经常搜着搜着就搜到「阮一峰…
&figure&&img src=&https://pic4.zhimg.com/v2-df3d8e3bbca00_b.jpg& data-rawwidth=&1920& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic4.zhimg.com/v2-df3d8e3bbca00_r.jpg&&&/figure&&p&文字版:&a href=&http://link.zhihu.com/?target=https%3A//www.zybuluo.com/catscarf/note/986628& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&概率论与数理统计 公式大全&/a&&/p&&p&目录与导航:&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&概率论与数理统计笔记 目录与导航&/a&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-c5fc9f00bfe2c9416042_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2480& data-rawheight=&3505& class=&origin_image zh-lightbox-thumb& width=&2480& data-original=&https://pic3.zhimg.com/v2-c5fc9f00bfe2c9416042_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-9a4b6623_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2480& data-rawheight=&3505& class=&origin_image zh-lightbox-thumb& width=&2480& data-original=&https://pic4.zhimg.com/v2-9a4b6623_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-59b5af869ab7c9dd2f87f4e1c8d88215_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2480& data-rawheight=&3505& class=&origin_image zh-lightbox-thumb& width=&2480& data-original=&https://pic2.zhimg.com/v2-59b5af869ab7c9dd2f87f4e1c8d88215_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-061ed005f8d2fe6fd2c5e818bd922a21_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2480& data-rawheight=&3505& class=&origin_image zh-lightbox-thumb& width=&2480& data-original=&https://pic2.zhimg.com/v2-061ed005f8d2fe6fd2c5e818bd922a21_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-35ac291a3e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2480& data-rawheight=&3505& class=&origin_image zh-lightbox-thumb& width=&2480& data-original=&https://pic3.zhimg.com/v2-35ac291a3e_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-01eedf81cfdc72b5e9a4baeb9909da06_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2480& data-rawheight=&3505& class=&origin_image zh-lightbox-thumb& width=&2480& data-original=&https://pic3.zhimg.com/v2-01eedf81cfdc72b5e9a4baeb9909da06_r.jpg&&&/figure&&p&&/p&
文字版:目录与导航:
&figure&&img src=&https://pic2.zhimg.com/v2-932fead36f55bc1d5fe329_b.jpg& data-rawwidth=&752& data-rawheight=&172& class=&origin_image zh-lightbox-thumb& width=&752& data-original=&https://pic2.zhimg.com/v2-932fead36f55bc1d5fe329_r.jpg&&&/figure&&p&一天偶然发现知乎上有篇关于对python编程中的if __name__ == 'main'的理解陈述,看完之后,自己觉得不够简单明了,于是在其文章底部写了一句话,突然收获各位乎友满满的赞同&/p&&figure&&img src=&https://pic2.zhimg.com/v2-932fead36f55bc1d5fe329_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&752& data-rawheight=&172& class=&origin_image zh-lightbox-thumb& width=&752& data-original=&https://pic2.zhimg.com/v2-932fead36f55bc1d5fe329_r.jpg&&&/figure&&p&相信初学者在学习Python的过程中,不可避免的总会遇到if __name__ == 'main'语句,虽然一直知道它的作用,但是可能一直比较模糊,今天菜鸟分析就与大家一起举例说说我的理解。&/p&&p&举个例子,我们在下面在test.py中写入如下代码:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&print('恋习Python')
def main():
print('恋习Python')
if __name__ == '__main__':
print('跟着菜鸟分析,练习Python越练越恋')
&/code&&/pre&&/div&&p&运行代码,则输出结果为:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-5fbc499d1a095_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&635& data-rawheight=&173& class=&origin_image zh-lightbox-thumb& width=&635& data-original=&https://pic3.zhimg.com/v2-5fbc499d1a095_r.jpg&&&/figure&&p&然后,在同一文件夹新建名称为import_test.py的脚本,只输入代码:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import test
&/code&&/pre&&/div&&p&运行代码,则输出结果为:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-c7d075c9a75afdc3e9f4c1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&639& data-rawheight=&135& class=&origin_image zh-lightbox-thumb& width=&639& data-original=&https://pic4.zhimg.com/v2-c7d075c9a75afdc3e9f4c1_r.jpg&&&/figure&&p&与之前test.py代码运行结果比较,只有输出恋习Python,也就是if __name__==&__main__&: 之前的语句被执行,之后的没有被执行。&/p&&p&这是为什么呢?别急,菜鸟分析继续给你举例子说明,绝对让你满意为止,最后有一种豁然开朗的感觉。&/p&&p&现在,我们在test.py脚本的if __name__==&__main__&:之前加入print __name__,即将__name__打印出来,则最后运行结果如下:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-facba558c6de9121dceac_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&641& data-rawheight=&165& class=&origin_image zh-lightbox-thumb& width=&641& data-original=&https://pic2.zhimg.com/v2-facba558c6de9121dceac_r.jpg&&&/figure&&p&可以看出,此时变量__name__的值为&__main__&。&/p&&p&再执行import_test.py,模块内容和执行结果如下:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-35f6d5f6ab6cd48e4c213baf84c7f63b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&640& data-rawheight=&136& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic1.zhimg.com/v2-35f6d5f6ab6cd48e4c213baf84c7f63b_r.jpg&&&/figure&&p&此时,import_test.py中的__name__变量值为test,不满足__name__==&__main__&的条件,因此,无法执行其后的代码。&/p&&p&哈哈,是不是一下明白啦,觉得不错,给菜鸟分析点个赞哦!&/p&&p&再仔细想想,其运行原理也就是:&/p&&p&由于每个python模块(python文件)都包含内置的变量__name__,当运行模块被执行的时候,__name__等于文件名(包含了后缀.py)。如果import到其他模块中,则__name__等于模块名称(不包含后缀.py)。&b&而“__main__”等于当前执行文件的名称(包含了后缀.py)。&/b&所以当模块被直接执行时,__name__ == '__main__'结果为真;而当模块被import到其他模块中时,__name__ == '__main__'结果为假,就是不调用对应的方法。&/p&&p&简而言之就是:__name__ 是当前模块名,当模块被直接运行时模块名为 __main__ 。当模块被直接运行时,代码将被运行,当模块是被导入时,代码不被运行。&/p&&p&一句话,秒懂!若还不懂,来私信我,VX:,直到你懂为止!&/p&
一天偶然发现知乎上有篇关于对python编程中的if __name__ == 'main'的理解陈述,看完之后,自己觉得不够简单明了,于是在其文章底部写了一句话,突然收获各位乎友满满的赞同相信初学者在学习Python的过程中,不可避免的总会遇到if __name__ == 'main'语句,…
&p&谢邀。&/p&&p&&br&&/p&&p&文章很长,麻烦大家耐心看,一定有收获。&/p&&p&&br&&/p&&p&我用React较多,我就说React。我问一个问题:&b&我们为什么需要React?&/b&&/p&&h2&&b&一些废话&/b&&/h2&&p&或许在你看到这个话题的时候,脑海里一定会想&/p&&ul&&li&&b&组件化&/b&&/li&&li&&b&性能好&/b&&/li&&li&&b&大家都在用,好找工作&/b&&/li&&/ul&&p&在现在MVVM框架横行的年代里,大家学习前端基本上都是直奔三大框架而去,这是没错的,毕竟熟练框架的操作,确实能很快的找到一份像样的工作,但是很可能就不会知道「&b&为什么会出现这些框架&/b&」了,这意味着,在使用框架之后的很长一段时间里,你都是知其然不知所以然。&/p&&p&&br&&/p&&p&这个带来的问题就是,每当一个框架「蹦」出来的时候,你总会非常非常的紧张,觉得「他妈的又有要学的东西了,蛋疼」。之前的 React 协议的问题,着实把很多还没入行的朋友吓的直哆嗦,很多粉丝也都在问我,React是否还有学习的必要...&/p&&p&&br&&/p&&h2&&b&一)无框架的年代,我们如何开发的?&/b&&/h2&&figure&&img src=&https://pic2.zhimg.com/50/v2-0a2ec9a894dcc46bef136a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&102& data-rawheight=&68& class=&content_image& width=&102&&&/figure&&p&我们需要开发这样的一个功能,点击+号按钮,上面的数字就加1。HTML代码如下:&/p&&div class=&highlight&&&pre&&code class=&language-html&&&span class=&nt&&&div&/span& &span class=&na&&class=&/span&&span class=&s&&&wrap&&/span&&span class=&nt&&&&/span&
&span class=&nt&&&div&/span& &span class=&na&&class=&/span&&span class=&s&&&text&&/span&&span class=&nt&&&&/span&0&span class=&nt&&&/div&&/span&
&span class=&nt&&&button&/span& &span class=&na&&class=&/span&&span class=&s&&'plus'&/span&&span class=&nt&&&&/span&
&span class=&nt&&&/button&&/span&
&span class=&nt&&&/div&&/span&
&/code&&/pre&&/div&&p&再来一段Javascript的代码,我们的功能就能完备了:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&o&&&&/span&&span class=&nx&&script&/span&&span class=&o&&&&/span&
&span class=&c1&&//document.querySelector,其实就是DOM的api,选择一个元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrap&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.wrap'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&plus&/span& &span class=&o&&=&/span& &span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.plus'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text&/span& &span class=&o&&=&/span& &span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text'&/span&&span class=&p&&)&/span&
&span class=&kd&&let&/span& &span class=&nx&&number&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&c1&&//dom api,给元素添加一个监听器&/span&
&span class=&nx&&plus&/span&&span class=&p&&.&/span&&span class=&nx&&addEventListener&/span&&span class=&p&&(&/span&&span class=&s1&&'click'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&number&/span&&span class=&o&&++&/span&
&span class=&nx&&text&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&p&&},&/span& &span class=&kc&&false&/span&&span class=&p&&)&/span&
&span class=&o&&&&/span&&span class=&err&&/script&&/span&
&/code&&/pre&&/div&&p&上古时期的开发们大约就是这样去书写代码,因为功能非常的简单,所以代码量也很少,思路很清晰。随着页面的元素越来越多,你这个「点击加1按钮」的功能可能被复用,那么你现在用一个最快的办法对其进行复用:&b&复制HTML-&复制JS代码-&粘贴HTML和JS代码&/b&&/p&&p&&br&&/p&&p&这种方法是很挫的.....于是为了简单化我们的流程,我们想出了一个聪明的办法去复用&/p&&h2&&b&1.1看似聪明的办法&/b&&/h2&&p&&i&(前提:因为FB总部被炸了,正在修理,导致ES6出来了,React还没发布)&/i&&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&o&&&&/span&&span class=&nx&&script&/span&&span class=&o&&&&/span&
&span class=&kr&&class&/span& &span class=&nx&&Add&/span& &span class=&p&&{&/span&
&span class=&nx&&render&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&err&&`&/span&
&span class=&o&&&&/span&&span class=&nx&&div&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s2&&&text&&/span&&span class=&o&&&&/span&&span class=&mi&&0&/span&&span class=&o&&&&/span&&span class=&err&&/div&&/span&
&span class=&o&&&&/span&&span class=&nx&&button&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s1&&'plus'&/span&&span class=&o&&&&/span&
&span class=&o&&+&/span&
&span class=&o&&&&/span&&span class=&err&&/button&`&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrap&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.wrap'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&add&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Add&/span&&span class=&p&&()&/span&
&span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&add&/span&&span class=&p&&.&/span&&span class=&nx&&render&/span&&span class=&p&&()&/span&
&span class=&kr&&const&/span& &span class=&nx&&plus&/span& &span class=&o&&=&/span& &span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.plus'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text&/span& &span class=&o&&=&/span& &span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text'&/span&&span class=&p&&)&/span&
&span class=&kd&&let&/span& &span class=&nx&&number&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&nx&&plus&/span&&span class=&p&&.&/span&&span class=&nx&&addEventListener&/span&&span class=&p&&(&/span&&span class=&s1&&'click'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&number&/span&&span class=&o&&++&/span&
&span class=&nx&&text&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&p&&},&/span& &span class=&kc&&false&/span&&span class=&p&&)&/span&
&span class=&o&&&&/span&&span class=&err&&/script&&/span&
&/code&&/pre&&/div&&p&代码稍微的一改,我们用一个class Add代替了HTML,当调用这个类的render函数的时候,就会返回一段字符串,这段字符串就是我们想要的组件。&/p&&p&&br&&/p&&p&由此,我们的组件复用方法变成了:&b&复制JS代码-&粘贴JS代码&/b&&/p&&p&&br&&/p&&p&这么一来啊,我们就简化了我们组件复用的流程。但是我们可以看到,我们手动操作DOM的次数太多了,而且逻辑非常的重复,因此,我们把这部分逻辑抽象一下,使得我们组件复用更加简单。&/p&&p&&br&&/p&&h2&&b&1.2 更加简单的组件复用&/b&&/h2&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&o&&&&/span&&span class=&nx&&script&/span&&span class=&o&&&&/span&
&span class=&kr&&class&/span& &span class=&nx&&Add&/span& &span class=&p&&{&/span&
&span class=&nx&&createWrapper&/span&&span class=&p&&(&/span&&span class=&nx&&string&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&c1&&//document.createElement, DOM api,根据标签名字创建DOM元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrapper&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&createElement&/span&&span class=&p&&(&/span&&span class=&s1&&'div'&/span&&span class=&p&&)&/span&
&span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&string&/span&
&span class=&k&&return&/span& &span class=&nx&&wrapper&/span&
&span class=&p&&}&/span&
&span class=&nx&&render&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&kr&&const&/span& &span class=&nx&&domString&/span& &span class=&o&&=&/span& &span class=&err&&`&/span&
&span class=&o&&&&/span&&span class=&nx&&div&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s2&&&text&&/span&&span class=&o&&&&/span&&span class=&mi&&0&/span&&span class=&o&&&&/span&&span class=&err&&/div&&/span&
&span class=&o&&&&/span&&span class=&nx&&button&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s1&&'plus'&/span&&span class=&o&&&&/span&
&span class=&o&&+&/span&
&span class=&o&&&&/span&&span class=&err&&/button&`&/span&
&span class=&c1&&//生成DOM元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrapper&/span& &span class=&o&&=&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&createWrapper&/span&&span class=&p&&(&/span&&span class=&nx&&domString&/span&&span class=&p&&)&/span&
&span class=&c1&&//DOM中查找元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&plus&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.plus'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text'&/span&&span class=&p&&)&/span&
&span class=&kd&&let&/span& &span class=&nx&&number&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&nx&&plus&/span&&span class=&p&&.&/span&&span class=&nx&&addEventListener&/span&&span class=&p&&(&/span&&span class=&s1&&'click'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&number&/span&&span class=&o&&++&/span&
&span class=&nx&&text&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&p&&},&/span& &span class=&kc&&false&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&nx&&wrapper&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrap&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.wrap'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&add&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Add&/span&&span class=&p&&()&/span&
&span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&appendChild&/span&&span class=&p&&(&/span&&span class=&nx&&add&/span&&span class=&p&&.&/span&&span class=&nx&&render&/span&&span class=&p&&())&/span&
&span class=&o&&&&/span&&span class=&err&&/script&&/span&
&/code&&/pre&&/div&&p&现在我们的这个组件复用就非常的简单了,我们只需要将class Add 通过export的方法导出以后,你可以在任何地方使用几行代码,就可以使用他,我们复用我们的组件就变成了:&b&复制三行JS代码-&粘贴三行JS代码&/b&&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&kr&&const&/span& &span class=&nx&&wrap&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.wrap'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&add&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nx&&Add&/span&&span class=&p&&()&/span&
&span class=&nx&&wrap&/span&&span class=&p&&.&/span&&span class=&nx&&appendChild&/span&&span class=&p&&(&/span&&span class=&nx&&add&/span&&span class=&p&&.&/span&&span class=&nx&&render&/span&&span class=&p&&())&/span&
&/code&&/pre&&/div&&p&&br&&/p&&h2&&b&二)数据驱动组件&/b&&/h2&&p&什么是数据驱动呢?简单的来说,就是「&b&数据是什么,我们就展示什么&/b&」。回顾我们之前的组件内部&/p&&div class=&highlight&&&pre&&code class=&language-js&&
&span class=&c1&&//生成DOM元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrapper&/span& &span class=&o&&=&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&createWrapper&/span&&span class=&p&&(&/span&&span class=&nx&&domString&/span&&span class=&p&&)&/span&
&span class=&c1&&//DOM中查找元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&plus&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.plus'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text'&/span&&span class=&p&&)&/span&
&span class=&kd&&let&/span& &span class=&nx&&number&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&nx&&plus&/span&&span class=&p&&.&/span&&span class=&nx&&addEventListener&/span&&span class=&p&&(&/span&&span class=&s1&&'click'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&number&/span&&span class=&o&&++&/span&
&span class=&nx&&text&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&p&&},&/span& &span class=&kc&&false&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&我们在其中大量的使用了,querySelector这种api,使得我们需要各种手动的去操作DOM元素,如果我们的组件变成&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&o&&&&/span&&span class=&nx&&div&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s2&&&wrap&&/span&&span class=&o&&&&/span&
&span class=&o&&&&/span&&span class=&nx&&div&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s2&&&text&&/span&&span class=&o&&&&/span&&span class=&mi&&0&/span&&span class=&o&&&&/span&&span class=&err&&/div&&/span&
&span class=&o&&&&/span&&span class=&nx&&div&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s2&&&text_2&&/span&&span class=&o&&&&/span&&span class=&mi&&0&/span&&span class=&o&&&&/span&&span class=&err&&/div&&/span&
&span class=&o&&&&/span&&span class=&nx&&div&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s2&&&text_3&&/span&&span class=&o&&&&/span&&span class=&mi&&0&/span&&span class=&o&&&&/span&&span class=&err&&/div&&/span&
&span class=&o&&&&/span&&span class=&nx&&button&/span& &span class=&kr&&class&/span&&span class=&o&&=&/span&&span class=&s1&&'plus'&/span&&span class=&o&&&&/span&
&span class=&o&&+&/span&
&span class=&o&&&&/span&&span class=&err&&/button&&/span&
&span class=&o&&&&/span&&span class=&err&&/div&&/span&
&/code&&/pre&&/div&&p&然后我需要点一下按钮,三个标签都得变化,那我们的代码很可能就需要对每一个text进行选择:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&c1&&//生成DOM元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&wrapper&/span& &span class=&o&&=&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&createWrapper&/span&&span class=&p&&(&/span&&span class=&nx&&domString&/span&&span class=&p&&)&/span&
&span class=&c1&&//DOM中查找元素&/span&
&span class=&kr&&const&/span& &span class=&nx&&plus&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.plus'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text_2&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text_2'&/span&&span class=&p&&)&/span&
&span class=&kr&&const&/span& &span class=&nx&&text_3&/span& &span class=&o&&=&/span& &span class=&nx&&wrapper&/span&&span class=&p&&.&/span&&span class=&nx&&querySelector&/span&&span class=&p&&(&/span&&span class=&s1&&'.text_3'&/span&&span class=&p&&)&/span&
&span class=&kd&&let&/span& &span class=&nx&&number&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&nx&&plus&/span&&span class=&p&&.&/span&&span class=&nx&&addEventListener&/span&&span class=&p&&(&/span&&span class=&s1&&'click'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&number&/span&&span class=&o&&++&/span&
&span class=&nx&&text&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&nx&&text_2&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&nx&&text_3&/span&&span class=&p&&.&/span&&span class=&nx&&innerHTML&/span& &span class=&o&&=&/span& &span class=&nx&&number&/span&
&span class=&p&&},&/span& &span class=&kc&&false&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&这种}

我要回帖

更多关于 定义二个全局变量,并赋值 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信