这 10 个 JavaScript 的难点你都懂吗?

来源:互联网 发布:李荣浩 喜剧之王 知乎 编辑:程序博客网 时间:2024/05/16 16:13

点击上方“中兴开发者社区”,关注我们

每天读一篇一线开发者原创好文640?wx_fmt=png&wxfrom=5&wx_lazy=1

译       者| Fundebug

英文原文|10 JavaScript concepts every Node.js programmer must master

为了保证可读性,本文采用意译而非直译,并且对示例代码进行了大量修改。另外,本文版权归原作者所有,翻译仅用于学习。


1. 立即执行函数

立即执行函数,即Immediately Invoked Function Expression (IIFE),正如它的名字,就是创建函数的同时立即执行。它没有绑定任何事件,也无需等待任何异步操作:


640?wx_fmt=png&wxfrom=5&wx_lazy=1


function(){…}  是一个匿名函数,包围它的一对括号将其转换为一个表达式,紧跟其后的一对括号调用了这个函数。立即执行函数也可以理解为立即调用一个匿名函数。立即执行函数最常见的应用场景就是:将 var 变量的作用域限制于你们函数内,这样可以避免命名冲突。


2. 闭包


对于闭包(closure),当外部函数返回之后,内部函数依然可以访问外部函数的变量。


640?wx_fmt=png

代码中,外部函数 f1 只执行了一次,变量 N 设为 0 ,并将内部函数 f2 赋值给了变量 result 。由于外部函数 f1 已经执行完毕,其内部变量N应该在内存中被清除,然而事实并不是这样:我们每次调用 result 的时候,发现变量 N 一直在内存中,并且在累加。为什么呢?这就是闭包的神奇之处了!


3. 使用闭包定义私有变量


通常,JavaScript 开发者使用下划线作为私有变量的前缀。但是实际上,这些变量依然可以被访问和修改,并非真正的私有变量。这时,使用闭包可以定义真正的私有变量:


640?wx_fmt=png

代码中,对象 p 的的 name 属性为私有属性,使用 p.name 不能直接访问。


4. prototype


每个 JavaScript 构造函数都有一个 prototype 属性,用于设置所有实例对象需要共享的属性和方法。prototype 属性不能列举。JavaScript 仅支持通过 prototype 属性进行继承属性和方法。


640?wx_fmt=png

代码中,x 和 y 都是构造函数 Rectangle 创建的对象实例,它们通过 prototype 继承了 getDimensions 方法。


5. 模块化

JavaScript 并非模块化编程语言,至少 ES6 落地之前都不是。然而对于一个复杂的 Web 应用,模块化编程是一个最基本的要求。这时,可以使用立即执行函数 来实现模块化,正如很多 JS 库比如 jQuery 以及我们 Fundebug 都是这样实现的。


640?wx_fmt=png

所谓模块化,就是根据需要控制模块内属性与方法的可访问性,即私有或者公开。在代码中,module 为一个独立的模块,N 为其私有属性,print 为其私有方法,decription 为其公有属性,add为其共有方法。


6. 变量提升


JavaScript 会将所有变量和函数声明移动到它的作用域的最前面,这就是所谓的变量提升 (Hoisting)  。也就是说,无论你在什么地方声明变量和函数,解释器都会将它们移动到作用域的最前面。因此我们可以先使用变量和函数,而后声明它们。

但是,仅仅是变量声明被提升了,而变量赋值不会被提升。如果你不明白这一点,有时则会出错:


640?wx_fmt=png

上面的代码等价于下面的代码:


640?wx_fmt=png

为了避免 Bug,开发者应该在每个作用域开始时声明变量和函数。


7. 柯里化


柯里化,即 Currying ,可以是函数变得更加灵活。我们可以一次性传入多个参数调用它;也可以只传入一部分参数来调用它,让它返回一个函数去处理剩下的参数。


640?wx_fmt=png

代码中,我们可以一次性传入 2 个 1 作为参数 add(1)(1) ,也可以传入 1 个参数之后获取 add1 与 add10 函数,这样使用起来非常灵活。


8. apply, call 与 bind 方法


JavaScript 开发者有必要理解 apply 、call  bind 方法的不同点。它们的共同点是第一个参数都是 this ,即函数运行时依赖的上下文。

三者之中,call 方法是最简单的,它等价于指定 this  值调用函数:


640?wx_fmt=png

apply 方法与 call 方法类似。两者唯一的不同点在于,apply 方法使用数组指定参数,而 call 方法每个参数单独需要指定:

  • apply(thisArg, [argsArray])

  • call(thisArg, arg1, arg2, …)


640?wx_fmt=png

使用 bind 方法,可以为函数绑定 this 值,然后作为一个新的函数返回:

640?wx_fmt=png


9. Memoization

Memoization 用于优化比较耗时的计算,通过将计算结果缓存到内存中,这样对于同样的输入值,下次只需要中内存中读取结果。


640?wx_fmt=png

代码中,第 2 次计算 fibonacci (100) 则只需要在内存中直接读取结果。


10. 函数重载


所谓函数重载(method overloading) ,就是函数名称一样,但是输入输出不一样。或者说,允许某个函数有各种不同输入,根据不同的输入,返回不同的结果。凭直觉,函数重载 可以通过 if…else 或者 switch 实现,这就不去管它了。jQuery 之父 John Resig 提出了一个非常巧( bian )妙( tai )的方法,利用了闭包。

从效果上来说,people 对象的 find 方法允许 3 种不同的输入: 0 个参数时,返回所有人名;1 个参数时,根据 firstName 查找人名并返回;2 个参数时,根据完整的名称查找人名并返回。

难点在于,people.find 只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定 3 个函数 find0 ,find1  与 find2  啊!这里的关键在于 old 属性。

由 addMethod 函数的调用顺序可知,people.find 最终绑定的是 find2 函数。然而,在绑定 find2 时,old 为 find1 ;同理,绑定 find1 时,old 为 find0 。3 个函数 find0 ,find1  与 find2 就这样通过闭包链接起来了。

根据 addMethod 的逻辑,当 f.length 与 arguments.length 不匹配时,就会去调用 old ,直到匹配为止。


640?wx_fmt=jpeg

640?wx_fmt=jpeg

                </div>
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 郸城到郑州汽车时刻表 郸城丁艳丽图片 郸酒42度多少钱一瓶 郸城属于哪里 郸城连锁酒店 郸城公司 郸城妇幼疝气科电话 郸城鲜花店 郸城一高2019高考成绩表 亳州到郸城的汽车站时刻表 南阳有几个县 郑州郑东新区 南阳市宛城区 河南南阳有几个县 郸城招标网 郸城会计 郸城房产 郸城图 郸城是哪里 郸城一高校花照片 郸城教育吧 郸城招聘 郸城吧 郸城信息网 周口郸城网 周口到郸城 周口市郸城 郸城论坛 42度郸酒价格 郸酒价格图片 郸酒 河南酒 南阳酒 河南白酒 这世界与你我都要 这世界与你我都要免费阅读 这世界与你我都要林宜 这个世界与你我都要 这世界与你我都要蒋牧童 世界与你我都要 每晚都与主角一起看同人