JavaScript作用域、上下文环境、函数对象的定义与调用、匿名函数的定义与调用、闭包

提到闭包总给人很高深的感觉,网上的例子也数不胜数。但是我发现相当一部分并不容易理解。根据我的观察,是因为这些例子把标题中提到的概念糅杂在了一起,往往越看越糊涂。所以我希望化整为零,拆成简单例子来解释。

1.先看作用域:

JavaScript作用域只有两种——全局作用域和函数内作用域,没有代码块作用域。示例:

function loop(){

for(var i=0;i<5;i++){

//doSomething;

}

alert(i);

}

loop(); //执行函数结果为5。

尽管变量i已经脱离了循环代码块,但因为JavaScript没有代码块级作用域,所以i的作用域是在整个函数内。循环结束后仍然保持为5。当然作为局部变量,函数执行完毕就释放了。

全局作用域就好理解了。变量在整个页面的执行环境下都有效。定义的方法有两种:一是在所有函数外定义的变量即为全局变量;二是定义变量时不加var,此时被认为是全局变量。

例如:

<script>

var i=10; //全局变量

function f1(){

times=3; //全局变量

}

</script>

2.上下文环境与"this"

上下文环境说的是对象(函数)的“继承关系”,而非函数之间的调用关系。函数间的互调用并不改变上下文环境,体现函数间互调用有另外一个变量caller表示。示例:

function a(){

b();

}

function b(){

alert(this);//被别的函数调用不改变上下文环境,仍然指向window。

}

a();

体现函数互调用关系的是caller:

function a(){

b();

}

function b(){

alert(b.caller);

}

a();

通过this可以很好的观察某个对象(函数)的上下文环境,在传统语言里this不难理解,指的是对象本身。在JavaScript中,函数也是个对象。如果此函数是个独立执行的函数,那么this就意味着最外层的上下文环境,也即window;如果函数定义为某个对象的属性,那么它的上下文环境就指向了这个对象。

示例:

function a(){

alert(this.name);

}

var obj1={

name:"I am obj1",

method:a  //属性是一个函数

}

obj1.method();  //函数对象的上下文是obj1

此外使用关键字call、apply可以显式改变函数的上下文环境

例如:

function a(){

alert(this.name);

}

var obj1={

name:"I am obj1",

}

a.call(obj1);  //函数的上下文是obj1

3.函数对象的定义和调用

这个本来不值一提,定义是定义,调用是调用————调用是加"()"。但是我经常看走眼,年纪大了老眼昏花。但也确实有不太好分辨的时候。比如这样:

var foo=function outer(){

return function inner(){

alert(this);

};

}();

foo();

这个例子中,foo是outer的执行结果。outer的执行结果返回的还是一个函数,所以foo也还是一个函数(其实就是inner啦,但此时并没有执行inner)。那么再执行foo的时候,上下文其实是window,自然也返回window。

4.匿名函数

匿名函数因为没有被哪个变量“记住”,所以只能定义完立即执行,通常执行的上下文是window。

比如这样:

(function(){

alert(this);

})()

更复杂一点的:

(function outter(){

return function inner(){

alert(this);

};

})()();  //此处和3小节的代码效果是一模一样的

5.闭包指的是有权访问另一个函数作用域中的变量的函数。很多开发人员混淆闭包和匿名函数——书上说的。这是因为闭包时常是以匿名函数形式来实现的,但其实二者无关。匿名函数可以单独执行,如4小节示例;闭包也可以由非匿名函数实现,例如:

function fout(){

var n=123;

return function fin(){

alert(n); //123

}

}

var f=fout();

f();  //fin访问了fout中的变量,所以尽管fout已执行完毕,但局部变量n仍被保留,从而形成闭包。

当然改成匿名函数也并非难事:

function fout(){

var n=123;

return function(){

alert(n); //123

}

}

var f=fout();

f();

总之,JavaScript是一门很有特色的语言。参考我的另一篇《JavaScript特点》

时间: 2024-12-23 20:54:54

JavaScript作用域、上下文环境、函数对象的定义与调用、匿名函数的定义与调用、闭包的相关文章

python--函数式编程 (高阶函数(map , reduce ,filter,sorted),匿名函数(lambda))

1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层的函数,可以把复杂的任务分解成简单的任务,这种一步一步的分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. 函数式编程:是使用一系列函数去解决问题,函数式编程就是根据编程的范式来的出想要的结果,只要是输入时确定的,输出就是确定的. 1.2高阶函数 能把函数作为参数传入,这样的函数就称为高阶函数. 1.2.1函数即变量 以python的内置函数print()为列,调用该函数一下代码 >>> pri

python_递归_协程函数(yield关键字)_匿名函数_模块

协程函数(yield) 协程函数:生成器:yield关键字的另一种用法 例:装饰器自动初始化函数(生成器函数)deco 1 yield的语句形式: yield 1 2 #yield的表达式形式: x=yield 3 4 5 6 #协程函数 7 8 def deco(func): 9 def wrapper(*args,**kwargs): 10 res=func(*args,**kwargs) 11 next(res) 12 return res 13 return wrapper 14 15

javascript执行上下文环境

今天,想对javascript的执行上下文环境做一个深入的理解.之前一直都有这打算的,但无奈忙着忙着就忘记了.今天看了一篇博客,对执行上下文环境的理解可以说是醍醐灌顶. 一.对一段代码的理解开始 在浏览器的控制台输入以下代码段: 这个结果说明,代码在一句句执行之前,浏览器已经做了一些准备工作,所以,后面两个都没有报错.下面再看一段代码: 这个结果说明,函数声明时,把整个函数赋值了,而函数表达式和变量一样,只是申明. 我们总结一下,在"准备工作"中完成了哪些工作: 变量.函数表达式--变

再看javascript执行上下文、变量对象

突然看到一篇远在2010年的老文,作者以章节的形式向我们介绍了ECMA-262-3的部分内容,主要涉及到执行上下文.变量对象.作用域.this等语言细节.内容短小而精悍,文风直白而严谨,读完有酣畅淋漓.醍醐灌顶之感,强烈推荐!!! 原文链接:这里 本想翻译成文,原来早已有人做了,这里.真生不逢时,何其遗憾啊! 做个笔记,聊慰我心. 执行上下文 ExecutionContext 每当控制器(control)转换到ECMAScript可执行代码时,都会创建并进入到一个可执行上下文. 一段简短的句子,

[二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type used to indicate that an interface * type declaration is intended to be a <i>functional interface</i> as * defined by the Java Language Specificat

16/8/23-jQuery子调用匿名函数

通过创建一个自调用匿名函数,创建一个特殊的函数作用域,该作用域中的代码不会和已有的同名函数.方法和变量以及第三方库冲突. 自调用匿名函数写法 方法一: (function(){ //... })(); 方法二: (function(){ //... }()); 方法三: !function(){ //... }(); jQuery.extend使用介绍 jQuery.extend( [deep ], target, object1 [,objectN ] )

调用匿名函数的骚操作

问:如何将1输出: function(){console.log(1)}() 答: (function(){console.log(1)}()) 1,function(){console.log(1)}() +function(){console.log(1)}() -function(){console.log(1)}() ~function(){console.log(1)}() !function(){console.log(1)}() new function(){console.log

Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)...啊啊啊

函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. 而函数式编程(请注意多了一个"式"字)--Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算. 我们首先要搞明白计算机(Computer)和计算(Compute)的概念. 在计算机的层次上,CPU执行的是加减乘除的指令代码

Day10:内置函数、匿名函数、递归函数

一.内置函数 1.数学运算类 2.集合类操作 内置函数个别使用示例 1.any 集合中的元素有一个为真的时候为真, 特别的,若为空串返回为False 1 print(any([0,''])) 2 print(any([0,'',1])) 执行结果 1 False 2 True 2.divmod 取商得余数,用于做分页显示功能 1 print(divmod(10,3)) #取商得余数,用于做分页显示 执行结果 1 (3, 1) 3.eval  把字符串中的数据结构给提取出来 1 dic={'nam

Python学习笔记(十)匿名函数

摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431843456408652233b88b424613aa8ec2fe032fd85a000 本文章完全用于个人复习使用,侵删: 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时,除了定义一个f(