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

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

每天读一篇一线开发者原创好文

译       者| Fundebug

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

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


1. 立即执行函数

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



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


2. 闭包


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


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


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


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


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


4. prototype


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


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


5. 模块化

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


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


6. 变量提升


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

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


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


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


7. 柯里化


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


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


8. apply, call 与 bind 方法


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

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


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

  • apply(thisArg, [argsArray])

  • call(thisArg, arg1, arg2, …)


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


9. Memoization

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


代码中,第 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 ,直到匹配为止。


  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值