首先看下这条语句:

(function($) {…})(jQuery);

1.原理:

function(arg){…}
这就定义了一个匿名函数,参数为arg

而调用函数时,是在函数后面写上括号和实参的,由于操作符的优先级,函数本身也需要用括号,即:
(function(arg){…})(param)
这就相当于定义了一个参数为arg的匿名函数,并且将param作为参数来调用这个匿名函数

而(function($){…})(jQuery)则是一样的,之所以只在形参使用$,是为了不与其他库冲突,所以实参用jQuery
相当于

funtion output(s){…};

output(jQuery);

或者

var fn=function(s){…};fn(jQuery);

2.作用:

这种写法的最大好处是形成闭包。在(function($) {…})(jQuery)在内部定义的函数和变量只能在此范围内有效。

形成私有函数、私有变量的概念。

几个概念:

1、执行环境(execution context):

每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行后,栈将其环境弹出,把控制权返回给之前的执行环境。

2、作用域链(scope chain):

函数的内部环境可以通过作用域链访问到所有的外部环境,但是外部环境却不可以访问外部环境,这就是作用域

ES5中只有全局作用域和函数作用域,没有块级作用域。

(但在ES6中多了一个let,他可以保证外层块不受内层块的影响。即内层块形成了一个块级作用域,这是let的一个特点。

它不简单,因为在许多的函数嵌套的情景下,只有对它理解深刻,才能更好的去分析。)

3、闭包 :指有权访问另一个函数作用域中的变量的函数

创建闭包的常见方式,就是在一个函数内部创建另一个函数(通常是匿名函数)。

在一个函数a内部定义的另一个函数b,当b在a之外被执行时,就会形成闭包。同时b函数仍然可以访问到a函数中的局部变量与函数。

弊端:闭包会携带包含他的函数的作用域,会比其他函数占用更多的内存。所以请慎用闭包

function fn(){
var array=[];
for(var i=0;i<10;i++){
array[i]=function(){
return i;
}
}
return array;
}
fn();//[ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ]

我们的本意是得到这个数组中每个函数都能返回自己的索引值,可是得到的是每个函数却都返回了10.

闭包保存的是定义它的那个函数内部的局部变量丶参数和其他内部函数,也就是说保存的是这个函数执行上下文中的整个VO,而不是一个变量。上面代码中的函数作用域链中都保存着fn的活动对象,他们引用的都是一个i,当fn返回时,i的值是10,所以每个函数都引用保存i那个变量的同一个变量。我们如果想得到原先想得到的那个结果,可以加上另一个匿名函数改变他的父作用域(其实应该是创建它的作用域),将它包裹起来。

function fn(){
var array=[];
for(var i=0;i<10;i++){
array[i]=function(num){
return function(){
return num;
};
}(i);
}
return array;
}

这个匿名函数有一个参数num,同时是返回值。在调用每个匿名函数时,传入了变量i。由于参数是按值传递的,所以i就会复制给num,而这个匿名函数的内部又创建了一个访问num的闭包,返回后能够访问到该匿名函数中的VO(包括参数),于是每个函数返回的都是num的一个副本,所以可以得到不同的值。

其实,说了这么多,我们只要熟悉闭包的两个应用场景,就能比较好的理解闭包的意义。

一.作为函数的返回值.。作为函数返回值被执行后仍然可以访问定义它的那个函数环境的VO。

function f(){
var a=1;
return function(){
console.log(a);
}
} var g=f();
g();//1;

二.作为一个函数的参数。作为函数返回值被当做另一个函数的参数传入时,仍然是访问定义它的那个函数环境的VO

function f(){
var a=1;
return function(){
console.log(a);
}
}
var g=f();
g();//1; function F(fn){
var a=2;
fn();
}
F(g);//

上面两个小例子也正好说明了闭包可以访问定义它的那个函数作用域下的内部变量和内部函数。其实是整个VO,所以还包含参数。

关于this对象

我们知道,this对象是在运行时基于函数的执行环境绑定的,全局函数中,this=window;

当某个函数被作为某个对象的方法调用时,this=对象

匿名函数的执行环境具有全局性,因此其this对象通常指向window

所以在闭包中使用this对象或arguments对象,必须将该对象的引用保存到闭包能够访问到的另一个变量中。

javascript 执行环境,作用域链和闭包的更多相关文章

  1. javascript深入浅出图解作用域链和闭包

    一.概要 对于闭包的定义(红宝书P178):闭包就是指有权访问另外一个函数的作用域中的变量的函数. 关键点: 1.闭包是一个函数 2.能够访问另外一个函数作用域中的变量 文章首发地址于sau交流学习社 ...

  2. 《浏览器工作原理与实践》<10>作用域链和闭包 :代码中出现相同的变量,JavaScript引擎是如何选择的?

    在上一篇文章中我们讲到了什么是作用域,以及 ES6 是如何通过变量环境和词法环境来同时支持变量提升和块级作用域,在最后我们也提到了如何通过词法环境和变量环境来查找变量,这其中就涉及到作用域链的概念. ...

  3. javascript 执行环境,变量对象,作用域链

    前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体. 通过上网查资料,特来总结,以备回顾和修正. 要讲的依次为: EC( ...

  4. JavaScript 执行环境以及作用域链

    执行环境(execution context,为简单起见,有时也称为"环境")是 JavaScript 中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们 ...

  5. 个人理解的javascript作用域链与闭包

    闭包引入的前提个人理解是为从外部读取局部变量,正常情况下,这是办不到的.简单的闭包举例如下: function f1(){ n=100; function f2(){ alert(n); } retu ...

  6. JavaScript 执行环境、作用域、内存管理及垃圾回收机制

    前言 JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存. [原理]找出那些不再继续使用的变量,然后释放其占用的内存.为此,垃圾收集器会按照固定的时间间隔( ...

  7. 图解Javascript——作用域、作用域链、闭包

    什么是作用域? 作用域是一种规则,在代码编译阶段就确定了,规定了变量与函数的可被访问的范围.全局变量拥有全局作用域,局部变量则拥有局部作用域. js是一种没有块级作用域的语言(包括if.for等语句的 ...

  8. 【进阶2-2期】JavaScript深入之从作用域链理解闭包(转)

    这是我在公众号(高级前端进阶)看到的文章,现在做笔记   https://github.com/yygmind/blog/issues/18 红宝书(p178)上对于闭包的定义:闭包是指有权访问另外一 ...

  9. 1--面试总结-js深入理解,对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This

    参考一手资料:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/中文翻译版本:https://zhuanlan.zhihu.com/p ...

  10. 理解JavaScript中的作用域链

    理解了作用域链,闭包就不难理解了,所以本文主要谈一谈我对作用域链的理解.   关于JavaScript中变量的作用域,全局变量在程序中始终都有定义.局部变量在声明它的函数体内以及其内部所嵌套的函数内始 ...

随机推荐

  1. 标准的 C++ 由三个重要部分组成

    标准的 C++ 由三个重要部分组成: 核心语言,提供了所有构件块,包括变量.数据类型和常量,等等.C++ 标准库,提供了大量的函数,用于操作文件.字符串等.标准模板库(STL),提供了大量的方法,用于 ...

  2. VS2010 快捷键设置,快速编码1

    全屏:Shift+Alt+Enter注释选定内容:Ctrl+E+C/Crtr+E+U代码格式化:ctrl+E+F VS2008 使用小技巧——快捷键1. 怎样调整代码排版的格式?选择:编辑—>高 ...

  3. par函数family参数-控制文字的字体

    family用于控制文字的字体, 标准的取值范围为serif, sans, mono, 其中sans 为默认值 基本用法,代码示例: par(mfrow = c(1,3)) par(cex = 1.5 ...

  4. 立即调用的函数表达式---IIFE

    有些人则称为“自执行的匿名函数” 在闭包中,我们经常需要使用到匿名函数,我感觉闭包就是一种匿名函数,子集. 但是直接在匿名函数后面调用函数是会出错的.比如: function () { alert(& ...

  5. win7 64位下android开发环境的搭建

    本文转自:http://www.cfanz.cn/index.php?c=article&a=read&id=65289 最近换了新电脑,装了win7 64位系统,安装了各种开发环境, ...

  6. Java精选笔记_IO流(转换流、常用流、流操作规律、字符编码)

    IO流 用来处理设备之间的数据传输,java对数据的操作是通过流的方式,java用于操作流的对象都在IO包中 按操作数据分为:字节流和字符流:按流向分为:输入流和输出流. 程序从输入流中读取数据,向输 ...

  7. swift - UIStepper的用法

    在网上查看学习资料的时候,看到有这个控件,所以就自己写了下,感觉在某些特定的地方用的还是挺方便的! 不过,个人感觉,局限性太大! 1.初始化(创建个label是为了让大家看到具体的数值) let st ...

  8. Swift学习笔记之--类和对象

    通过在 class后接类名称来创建一个类.在类里边声明属性与声明常量或者变量的方法是相同的,唯一的区别的它们在类环境下.同样的,方法和函数的声明也是相同的写法 class Shape { func s ...

  9. js中如何删除json对象的某一个选项

    我有一个这样一个对象,getData, 但是我不想要每一项的id,那怎么去删除呢(使用delete)? getData.map((item) =>{ delete item["id&q ...

  10. 新版本读取老版本文件崩溃BUG

    读取文件匹配代码 BOOL CWBPage::LoadFromFile(CFile *pFile, LONGLONG& lOff, ULONGLONG lFileLength) { if (p ...