[Effective JavaScript 笔记] 第13条:使用立即调用的函数表达式创建局部作用域

function wrapElements(a){

var res=[],i,n;

for(i=0,n=a.length;i<n;i++){

res[i]=function(){return a[i]};

}

return res;

}

var wrapped=wrapElements([10,20,30,40,50]);

var f=wrapped[0];

f();//undefined

这个可以由之前的闭包来讲,res里的每个函数都是一个闭包,它们都可以访问上一个函数的作用域内的变量,所以每个函数都可以访问到i,但这个i是for循环运行过的i,它的值应该是a.length。所以f里对应的应该就是a[a.length],这时数组已经溢出了,所以是undefined。

注意闭包存储的是其外部变量的引用而不是值。

下面这个是一种解决方法

function wrapElements(a){

var res=[],i,n;

for(i=0,n=a.length;i<n;i++){

(function(j){

res[j]=function(){return a[j]};

})(i)

}

return res;

}

var wrapped=wrapElements([10,20,30,40,50]);

var f=wrapped[0];

f();//10

这是使用立即调用的函数表达式或叫IIFE(immediately-invoked function expression)。这是一种解决js缺少块级作用域的方法

使用IIEF来创建局部作用域注意点:

  1. 代码块不能包含任何跳出块的break和continue语句。
  2. 如果代码块引用了this或特别的arguments变量,会得到错误的含义。

提示

  • 理解绑定与赋值的区别
  • 闭包通过引用而不是值捕获它们的外部变量
  • 使用立即调用的函数表达式(IIFE)来创建局部作用域
  • 当心在立即调用的函数表达式中包裹代码块可能改变其行为的情形
时间: 2024-10-17 18:29:55

[Effective JavaScript 笔记] 第13条:使用立即调用的函数表达式创建局部作用域的相关文章

第 13 条:使用立即调用的函数表达式创建局部作用域

第 13 条:使用立即调用的函数表达式创建局部作用域这段程序(Bug 程序)输出什么? function wrapElements(a) { var result = [], i, n; for (i = 0, n = a.length; i < n; i++) { result[i] = function() { return a[i]; }; } return result; } var wrapped = wrapElements([10, 20, 30, 40, 50]); var f

[Effective JavaScript 笔记]第17条:间接调用eval函数优于直接调用

eval函数不仅仅是一个函数.大多数函数只访问定义它们所在的作用域,而不能访问除此之外的作用域(词法作用域).eval函数具有访问调用它时的整个作用域的能力.编译器编写者首次设法优化js时,eval函数很难高效地调用任何一个函数,因为一旦调用的函数是eval函数,那么每个函数调用都需要确保在运行时整个作用域对eval函数是可访问的.语言标准演化出辨别两种不同的调用eval的方法.第一种方式:函数调用涉及eval标识符,被认为是一种“直接”调用eval函数的方式.编译器需要确保被执行的程序具有完全

[Effective JavaScript 笔记]第31条:使用Object.getPrototypeOf函数而不要使用__proto__属性

ES5引入Object.getPrototypeOf函数作为获取对象原型的标准API,但由于之前的很多js引擎使用了一个特殊的__proto__属性来达到相同的目的.但有些浏览器并不支持这个__proto__属性,所以并不是完全兼容的.例如对于拥有null原型的对象,不同的环境结果就不同了. var empty=Object.create(null); '__proto__' in empty;//一些环境会返回false,另一些会返回true 这就导致结果的不一致,从而影响到依赖这个判断的相关

[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

[Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //"number" typeof "s";//"string" typeof null;//"object":ECMAScript把null描述为独特的类型,但返回值却是对象类型,有点困惑. 可以使用Object.prototype.t

深入理解JavaScript系列(4):立即调用的函数表达式

前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法也不一定完全对,主要是看个人如何理解,因为有的人说立即调用,有的人说自动执行,所以你完全可以按照你自己的理解来取一个名字,不过我听很多人都叫它为“自执行”,但作者后面说了很多,来说服大家称呼为“立即调用的函数表达式”. 本文英文原文地址:http://benalman.com/news/2010/11/immedia

[Effective JavaScript 笔记]第15条:当心局部块函数声明笨拙的作用域

嵌套函数声明.没有标准的方法在局部块里声明函数,但可以在另一个函数的顶部嵌套函数声明. function f(){return "global"} function test(x){ var result=[]; function f(){return "local";}//block-local if(x){ result.push(f()); } result.push(f()); return result; } test(true);//["loc

[Effective JavaScript 笔记] 第6条:了解分号插入的局限

分号可以省略 js可以在语句结束不强制加分号.(建议还是添加,不添加分号往往会出现不易发现的BUG) function Point(x,y){ this.x=x||0; this.y=y||0; } Point.prototype.isOrigin=function(){ return this.x===0 && this.y===0 } 上面代码可以运行,是由于js可以自动插入分号,它是一种程序解析技术.能推断出某些上下文中省略的分号,然后有效地自动地将分号"插入"到