javascript作用域和作用域链详解

目录
  • 一、javascript的作用域
    • 1、全局作用域
    • 2、局部作用域
  • 二、javascript的作用域链
  • 三、作用域链和优化
  • 四、改变作用域链
    • 1、with语法改变作用域链
    • 2、catch语法
  • 总结

一、javascript的作用域

1、全局作用域

1、最外层函数和最外层函数定义的变量
var age = 20
function func1() {
  var sex = "男"
  function func2() {
    console.log("hello func2")
  }
  func2()
}
console.log(age)    //20
console.log(func1)  //正常执行
console.log(func2)  //报错
console.log(sex)    //报错
2、所有未直接声明的变量,直接赋值为全局变量
function func1() {
  var age = 20
  sex = "男"
}
func1()
console.log(sex)    //男
console.log(age)    //报错
3、window对象上面的属性具有全局作用域
function func1() {
  var age = 20
  sex = "男"
  console.log(top)   //window....

}
func1()
console.log(sex)   //"男"
console.log(top)   //window....

2、局部作用域

和全局作用域相反,局部作用域只在函数内部可以访问到。function func1() {  var age = 20  func1()  function func1() {    console.log("func1")  }}func1()和全局作用域相反,局部作用域只在函数内部可以访问到。
function func1() {
  var age = 20
  func1()

  function func1() {
    console.log("func1")
  }
}
func1()

二、javascript的作用域链

函数也是对象,在函数内部存在一个属性[[scope]],该属性包含可以访问属性的集合。决定了哪些属性在函数中可以访问到。
下面我们以一个函数的例子来详细解说一下,函数作用域链。
1、在函数函数创建出来时。代码如下所示
function add(num1, num2) {
  return num1 + num2
}

函数初始化时,会将自己的作用域链中放入全局变量
var total = add(10, 20)
这里是函数执行时,当执行时会创建一个新的对象放入作用域链中,这个对象中包括
arguments, 形参,this,以及返回值。

active object是活跃对象,是函数执行时创建的对象,然后scope chain类似于栈结构,函数执行前压入栈中,函数执行结束就从栈中弹出。函数访问属性的过程就是沿着scope chain从上往下一次查找。

三、作用域链和优化

从上面的例子中,我们可以看出,访问全局作用域是最慢的,因为需要依次从上往下进行查找,应当尽可能少的使用全局变量,应该尽可能使用局部变量。如果在函数
中,使用多次全局变量,我们可以将全局变量转化为局部变量,然后在使用局部变量。
function changeColor(){
    document.getElementById("btnChange").onclick=function(){
        document.getElementById("targetCanvas").style.backgroundColor="red";
    };
}
上面代码我们使用了两次document,但是document作为全局变量,此时我们应该将其转化为局部变量来使用,所以下面为转化后的代码。
function changeColor(){
    var doc=document;
    doc.getElementById("btnChange").onclick=function(){
        doc.getElementById("targetCanvas").style.backgroundColor="red";
    };
}

四、改变作用域链

1、with语法改变作用域链

with语法的作用就是为了解决代码重写问题,是对象快捷书写方式,但是这么好的方式,为什么不大力推广使用呢?因为性能存在一些问题。function initUI(){    with(document){        var bd=body,            links=getElementsByTagName("a"),            i=0,            len=links.length;        while(i < len){            update(links[i++]);        }        getElementById("btnInit").onclick=function(){            doSomething();        };    }}这里使用with语法省略了document。with语法的作用就是为了解决代码重写问题,是对象快捷书写方式,但是这么好的方式,为什么不大力推广使用呢?
因为性能存在一些问题。
function initUI(){
    with(document){
        var bd=body,
            links=getElementsByTagName("a"),
            i=0,
            len=links.length;
        while(i < len){
            update(links[i++]);
        }
        getElementById("btnInit").onclick=function(){
            doSomething();
        };
    }
}
这里使用with语法省略了document。

with传入的对象的属性放入最上层,剩余的都往下压,导致局部变量的访问代价增大,所以with的性能不好。

2、catch语法

我们在使用try--catch时,当代码执行错误时,会执行catch函数,catch函数中参数是错误对象,就是这个错误对象,会放到作用域链的头部。
但是try--catch我们在必要的使用得使用,我们可以这样解决。
try{
    doSomething();
}catch(ex){
    alert(ex.message); //作用域链在此处改变
}

处理后:
try{
    doSomething();
}catch(ex){
    handleError(ex); //委托给处理器方法
}
解决方案是:将catch错误处理交给另外一个函数进行处理。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 图解javascript作用域链

    先来一段简单的javascript代码: window.onload=function(){ function sub(a,b){ return a-b; } var result=sub(10,5); } 这段代码中的执行环境已经数清楚了,可是执行环境只是代码在预编译过程中javascript引擎所做的事情,当代码在window onload事件被触发,且sub函数被执行的时候会发生什么事情呢? 1.javascript引擎会在页面加载脚本被执行时为每个函数创建一个作用域(执行上下文)及作用域

  • 全面了解JavaScript的作用域链

    JavaScript的作用域链 这是一个非常重要的知识点了,了解了JavaScript的作用域链的话,能帮助我们理解很多'异常'问题. 下面我们来看一个小例子,前面我说过的声明提前的例子. var name = 'Skylor.min'; function echo() { alert(name); var name = 'mm'; alert(name); alert(age); } echo(); 对于这个例子,没有接触过这方面的时候,第一反应是会纠结下,这第一个的name,到底调用全局变量

  • 详解JavaScript作用域和作用域链

    前言 JavaScript 中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! 作用域(Scope) 1. 什么是作用域 作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性.换句话说,作用域决定了代码区块中变量和其他资源的可见性.可能这两句话并不好理解,我们先来看个例子: function outFun2() { var inVariable = "内层变量2&

  • js作用域和作用域链及预解析

    变量---->局部变量和全局变量, 作用域:在某个空间范围内,可以对数据进行读写操作 局部作用域和全局作用域 js中没有块级作用域-一对括号中定义的变量,这个变量可以在大括号外面使用 函数中定义的变量是局部变量 作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了 层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错 在 JavaScript 中, 对象和函数同样也是变量. 在 JavaScript 中, 作用域为可访问变量,对象,函数的集合. JavaScr

  • JavaScript中的执行环境和作用域链

    前言 JS 中的执行环境和作用域链是非常重要的概念,它们是 JS 引擎在处理 JS 代码的时候对变量和函数的处理方式,这两个概念的正确理解能够帮助我们更好地理解和预测代码的行为. 执行环境 执行环境定义了变量或者函数有权访问的数据集合,每一个执行环境都有一个与之关联的变量对象,该执行环境中定义的所有变量和函数都保存在这个对象中.我们无法直接访问这个对象,这个对象只是在解析器处理数据的时候使用. 我们平时说的全局变量就是在最外围的一个执行环境中定义的变量,全局执行环境根据 ECMAScript 的

  • 图解JavaScript作用域链底层原理

    目录 前言 作用域 1.什么是作用域 2.[[Scopes]]属性 3.作用域链 4.图解查找变量原理 总结 前言 在学习JavaScript时大家一定都知道,外部空间不能访问内部变量,我们往往只知道这一基本规则,那实现这一基本规则的基本底层原理是什么呢?今天我将从小白的角度来带大家理解作用域链,希望能给大家一些帮助! 作用域 1.什么是作用域 简单来说,作用域(英文:scope)是据名称来查找变量的一套规则,可以把作用域通俗理解为一个封闭的空间,这个空间是封闭的,不会对外部产生影响,外部空间不

  • JavaScript中原型和原型链详解

    javascript中的每个对象都有一个内置的属性prototype,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用.意思是是prototype属性保存着对另一个JavaScript对象的引用,这个对象作为当前对象的父对象. 复制代码 代码如下: A.prototype = new B(); 理解prototype不应把它和继承混淆.A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍.A能使用B的方法和属性.这里强调的是克隆而不是

  • JavaScript三大重点同步异步与作用域和闭包及原型和原型链详解

    目录 1. 同步.异步 2. 作用域.闭包 闭包 作用域 3. 原型.原型链 原型(prototype) 原型链 如图所示,JS的三座大山: 同步.异步 作用域.闭包 原型.原型链 1. 同步.异步 JavaScript执行机制,重点有两点: JavaScript是一门单线程语言 Event Loop(事件循环)是JavaScript的执行机制 JS为什么是单线程 最初设计JS是用来在浏览器验证表单操控DOM元素的是一门脚本语言,如果js是多线程的,那么两个线程同时对一个DOM元素进行了相互冲突

  • JS难点同步异步和作用域与闭包及原型和原型链详解

    目录 JS三座大山 同步异步 同步异步区别 作用域.闭包 函数作用域链 块作用域 闭包 闭包解决用var导致下标错误的问题 投票机 闭包两个面试题 原型.原型链 原型对象 原型链 完整原型链图 JS三座大山 同步异步 前端中只有两个操作是异步的: 定时器异步执行; ajax异步请求 编译器解析+执行代码原理: 1.编译器从上往下逐一解析代码 2.判断代码是同步还是异步 同步:立即执行 异步:不执行.放入事件队列池 3.等所有同步执行完毕开始执行异步 同步异步区别 api : 异步有回调,同步没有

  • 基于ES6作用域和解构赋值详解

    ES6 强制开启严格模式 作用域 •var 声明局部变量,for/if花括号中定义的变量在花括号外也可访问 •let 声明的变量为块作用域,变量不可重复定义 •const 声明常量,块作用域,声明时必须赋值,不可修改 // const声明的k指向一个对象,k本身不可变,但对象可变 function test() { const k={ a:1 } k.b=3; console.log(k); } test()解构赋值 { let a, b, 3, rest; [a, b, c=3]=[1, 2]

  • 基于Python函数的作用域规则和闭包(详解)

    作用域规则 命名空间是从名称到对象的映射,Python中主要是通过字典实现的,主要有以下几个命名空间: 内置命名空间,包含一些内置函数和内置异常的名称,在Python解释器启动时创建,一直保存到解释器退出.内置命名实际上存在于一个叫__builtins__的模块中,可以通过globals()['__builtins__'].__dict__查看其中的内置函数和内置异常. 全局命名空间,在读入函数所在的模块时创建,通常情况下,模块命名空间也会一直保存到解释器退出.可以通过内置函数globals()

  • JavaScript原型链详解

    目录 1.构造函数和实例 2.属性Prototype 3.属性__proto__ 4.访问原型上的方法 5.构造函数也有__proto__ 6.构造函数的原型也有__proto__ 7.Object.prototype这个原型对象很特殊 8.总结 1.构造函数和实例 假设你声明一个方法叫做Foo() ,那么我们可以通过new Foo()来声明实例. function Foo() { console.log("我是一个构造方法"); } const f1 = new Foo(); 现在你

  • Java开发学习之Bean的作用域和生命周期详解

    目录 一.Bean 的作用域 二.Spring 的执行流程 三.Bean 的生命周期 一.Bean 的作用域 在之前学习Java基础的时候,有接触到作用域这样的概念.一个变量并不一定在任何区域都是有效的,限定这个变量的可用性的代码范围就是该变量的作用域. 但是在这里 Bean 的作用域的概念和以前所认为的作用域有所不同. Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式. 接下来,将会举一个案例来讲讲什么是作用域,什么是行为模式 案例概要: 创建一个共有的 Bean

  • Javascript 严格模式use strict详解

    严格模式:由ECMA-262规范定义的JavaScript标准,对javascrip的限制更强. (非严格的模式,被称为"马虎模式/稀松模式/懒散模式".) 一.严格模式的使用 严格模式可以在脚本或函数级别实现.(即全局和局部模式) 1.全局 在js文件的最前面添加    "use strict" 2.局部 在函数内部添加   "use strict",如下 function fn() { "use strict"; //so

  • JavaScript闭包原理及作用详解

    目录 简介 闭包的用途 柯里化 实现公有变量 缓存 封装(属性私有化) 闭包的原理 垃圾收集 简介 实际开发中的优化 简介 说明 本文介绍JavaScript的闭包的作用.用途及其原理. 闭包的定义 闭包是指内部函数总是可以访问其所在的外部函数中声明的变量和参数,即使在其外部函 数被返回(寿命终结)了之后. 闭包的作用(特点) 1.函数嵌套函数 2.内部函数可以引用外部函数的参数或者变量 3.外部函数的参数和变量不会被垃圾回收,因为被内部函数引用. 闭包与全局变量 闭包的用途 柯里化 可以通过参

  • JavaScript 执行上下文的视角详解this使用

    目录 前言 全局执行上下文中的 this 函数执行上下文中的 this this 的设计缺陷以及应对方案 1. 嵌套函数中的 this 不会从外层函数中继承 2. 普通函数中的 this 默认指向全局对象 window 前言 在对象内部的方法中使用对象内部的属性是一个非常普遍的需求.但是 JavaScript 的作用域机制并不支持这一点,基于这个需求,JavaScript 有另外一套 this 机制. this 是和执行上下文绑定的,也就是说每个执行上下文中都有一个 this.执行上下文主要分为

随机推荐