JS函数——作用域

一 : 作用域的相关概念

首先看下 变量作用域 的概念:一个变量的作用域是程序源代码中定义这个变量的区域。————————《javascript权威指南》第六版
全局变量拥有全局作用域,函数体内定义的局部变量拥有函数作用域。

就个人理解,作用域(scope),顾名思义,是一块区域领域 ,并且有某些对象(包括变量,属性,方法等)能够在这里起作用;作用域是在定义的时候决定的,和什么时候执行无关;这时候问题来了:

问题1:区域在那儿?

他是一个概念,是看不到摸不着的;在这个区域内原本是什么都没有的,但是与作用域密切相关的一个概念  执行上下文(EC),他却是与作用域相呼应,哪些变量、参数、this值等统统的会保存在上下文中(上下文是一个对象,变量参数等作为他的属性保存);全局作用域 对应 全局执行上下文,函数作用域 对应相应的 函数执行上下文; 而上下文是在代码执行的时候产生的,他保存在内存中,这个上下文中的变量等 则属于 其相对应的作用域(全局作用域或函数作用域);详见下一节【执行上下文】。

问题1:某些对象是谁?
这块区域中定义了谁,对象就有谁。全局作用域中定义了变量a和声明了函数 fun,那么a和fun就在全局作用域中起作用;fun域中定义了变量m ,则m 就在fun域中起作用(这时候变量a 也是起作用的,原理可查看后面作用域链 概念);另外还有this值,当前函数参数;主要就包含这三类对象。

问题2:这些对象啥时候起作用?

执行时,指全局函数执行时,生成执行上下文,变量等起作用;局部函数执行时,生成函数执行上下文,函数体内变量等起作用;详细查看 执行上下文。

js变量具有 的 向下透明 和 向上封闭 特性,向下透明,指fun,fn可以在当前作用域访问全局变量a,fn可以访问a,m,但在函数体内,局部变量的优先级高于同名上级变量。 向上封闭,指全局作用域 不可以访问 fun域中的变量m,更不可以访问 fn中的变量n,fun作用域也不可以访问他内部嵌套的fn域中变量n;还涉及到的一个概念就是 作用域链(scope chain):是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。

当全局作用域中没有函数定义时,作用域链上就只有一个对象,全局对象,这个对象定义了相关的变量信息;一般所谓链,都是指多个穿起来才叫链,这儿比较特殊,是只有一个元素的链。

当全局作用域中包含多个嵌套函数时,随着函数一级一级执行展开,作用域链将会变成由多个对象组成的链表;这个链表是动态的,随着代码的执行而不停的增加和释放内存。

上图可见,向下透明,向上封闭的原理,例如b变量保存的值是一个指针,那么在a域内,大家能看到的就是这个指针值,而不能看到b域内的变量,因此 b域 相对于a域是封闭的,也就是向上封闭;说到这儿,是不是感觉有点和闭包相似呢,闭包就是封闭的,只留一个接口(等同于a)给外界,包里都有啥不让别人直接看见。js之所以会出现闭包,可能就是因为这种存储机制造成的——变量保存为引用类型!闭包就是这样,但凡函数返回值是引用类型,都会产生闭包。

js是基于 词法作用域  的语言:通过阅读包含变量定义在内的数行源码,就能知道变量的作用域。

二 :作用域的分类

作用域 可分为两种,全局作用域函数作用域;函数作用域是由函数创建的,至于全局作用域,我们也可以将全局作用域当作是 window函数 创建的,并且这个函数只有一个,而我们所写的所有代码都在这个函数之内。所以总结一句话:只有 函数 才能创建作用域  

引申:这个全局函数 和 pareInt()等全局函数是什么关系呢?

默全局作用域从代码运行开始就一直存在着;

函数作用域:

变量在声明他们的函数体以及这个函数体内嵌套的任意函数体内都是有定义的。
在函数内声明的所有的变量在函数体内始终是可见的。                                                                    
                                                                                                                     -------------《javascript权威指南》第六版

三个要点:所有变量    始终可见、都有定义

1、所有变量  ————    函数参数  +  函数体变量+  for循环/if 语句/while语句 变量

如上图中所标出的所有变量,都 属于当前 函数作用域,这些变量向下透明,而向上封闭,既fn2函数体内可以访问fun函数以及全局变量,但是全局和fun却不能直接访问fn2中的变量。

注:一段带有大括号的代码,经常会被称为 代码块;而这种称呼,在Js中可能会带来误解;JS中 没有 块级作用域 ,这个概念与其他编程语言(如C等), 是不一样的;如果一定要用代码块来理解的话,js 只识别 全局代码块 和 函数代码块 当作其作用域。

例如下C++代码:

void fun(int x){
   int a;                           //变量a的作用域在函数fun中
   for(int i=0;i<=10;i++){i++}      //变量i在块级作用域 for 代码块中
}

  

2、始终可见—————— 指变量在书写 声明源代码 之前已经可用

js中声明包含两种声明 变量声明(var) 和 函数声明 (function);变量声明时,只定义了变量名,类型不确定;函数声明时,将函数名当作变量名,类型是函数。

这个特性被称为 声明提前 ,即当前函数体内的声明所有变量(不涉及赋值)代码,都被提前到函数体顶部;通俗的说,就是指只要是在函数体内声明了变量,不论代码写在了什么位置,在函数体内的任意位置都可以访问到。事实上这和Js引擎规定如何执行代码顺序有关,他会先查找有关声明的关键词var 和 function 来保存在执行上下文中,这个工作是在 形成执行上下文 的初始化阶段 完成的,而赋值则是在

举例,执行如下代码:

function fn(){
console.log(a);       //underfined
var a=3;
}fn(); 

等同于下面代码:

function fn(){
var a;                //变量声明提前
console.log(a);       //变量已声明未赋值时默认值是underfined
a=3;
}fn();

引申疑问:声明提前 这步工作 是在什么时候做的呢?

这就涉及到了另外一个概念,执行上下文环境 ,变量/函数的声明 工作都是在 代码执行的时候才做的;

例如 文件运行开始,就生成了 全局执行上下文环境,这个环境的生成分为两个阶段完成,分别是 初始化阶段 +  赋值阶段 ,那么声明提前 就包含在 初始化阶段中。详情见下一节。

 3、都有定义—————— 变量在当前函数体内有定义

根据定义,变量在声明他们的函数体以及这个函数体内嵌套的任意函数体内都是有定义的,可见,函数体内不论包括啥函数,包括多少层函数,当前函数体内定义的变量一直在众多嵌套函数中是有效可用的;也就是上面提到的向下透明特性。

时间: 2024-10-12 09:02:06

JS函数——作用域的相关文章

js 函数作用域, 块级作用域和词法作用域

函数作用域, 块级作用域和词法作用域 0 作用域: 0.1 作用域是程序源代码中定义变量的区域. 0.2 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限. 0.3 ECMAScript6之前只有全局作用域和函数作用域. 0.4 JavaScript采用词法作用域(lexical scoping),也就是静态作用域. var scope = "global scope"; function checkscope(){ var scope = "local sc

JS 函数作用域

函数的作用域 在JavaScript中使用的是函数作用域,变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的 ES6标准中的作用域 为什么需要块级作用域 全局作用域和函数作用域,没有块级作用域,容易出现下列问题: 1) 变量提升导致内层变量可能会覆盖外层变量 var i = 5;   function func() {   console.log(i);   if (true) {   var i = 6;   }   }   func(); // undefined 2) 用来计

js函数作用域

var msg = 'String A'; function test() { alert(msg);           //undefined var msg = 'String A'; alert(msg); } test(); 以上代码等价于:var msg = 'String A';function test() {var msg;       //函数顶部重新申明变量alert(msg);msg = 'String A';alert(msg);}test();在函数内部声明的变量在函

浅谈js中函数作用域问题(一)

本人学习js时间并不长,前几天,写一段js代码时,在js指定一个按钮事件的匿名函数中加入一个同级函数,具体代码可见如下: var mainOb=document.getElementById("divObject");                                        var start=document.getElementById("start"); var a=10; start.onclick=funcrion(){ functi

js没有块级作用域但有函数作用域

任何一对花括号中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域. 作用域永远都是任何一门编程语言中的重中之重,因为它控制着变量与参数的可见性与生命周期.首先我们理解两个概念:块级作用域与函数作用域. 什么是块级作用域呢? 任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域. 函数作用域就是定义在函数中的参数和变量在函数外部是不可见的. 大多数类C语言都拥有块级作用域,JS却没有.请看下文de

在iframe里调用parent.func()引出的js函数运行在它们被定义的作用域里,而不是它们被执行的作用域里

有个document里定义了一个函数func(),同时在document里嵌入了一个iframe,在这个iframe里调用父窗口的方法:parent.func(),本来我以为这个函数的运行环境是在这个iframe自己里面,测试发现虽然是在iframe里面调用的这个函数,但是运行环境依然是在父窗口里. 所以也验证了JS权威指南中的:js函数运行在它们被定义的作用域里,而不是它们被执行的作用域里. 又比如 var a=1; function f1(){console.log(a);}; functi

JS 字符串对象 数组对象 函数对象 函数作用域

一.内置对象 object对象:ECMAScript 中的所有对象都由这个对象继承而来:Object 对象中的所有属性和方法都会出现在其他对象中 ToString() : 返回对象的原始字符串表示.ValueOf() : 返回最适合该对象的原始值.对于许多对象,该方法返回的值都与 ToString() 的返回值相同 11种内置对象 包括: Array ,String , Date, Math, Boolean, Number  Function, Global, Error, RegExp ,

通过原型链解析js函数一些难以理解的的作用域问题

基本原理 js函数在执行时,系统会创建一个隐式的属性scope,scope中存储的是函数的作用域链. 通过对这个scope的分析,就能解释JavaScript中许多难以理解的问题: 例1: function demo(){} demo(); scope属性是在函数执行时创建,如果这个函数是一个全局函数,他的scope里会保存一个Global object和一个activation object. global object保存的是全局的信息,而activition object保存的是函数内部的

js 的作用域

js的作用域 一. 方式1.常用方式: function test (参数) { ………….方法的实现……………….. }这种方式的函数声明的先后位置与调用无关,可以在调用的前面声明,也可以在调用的后面声明;2.匿名函数: 把方法赋给一个变量,此时这个变量是一种方法类的变量;Var a = function (参数) {………..方法的实现……………………}这种方式的函数声明必须放在调用的前面;匿名函数直接调用的方式,例如: alert(function () {} 二. 参数的管理:每一个函数