zoukankan      html  css  js  c++  java
  • 简述JavaScript作用域与作用域链

        关于变量作用域的知识,相信学习JavaScript的朋友们一定早已经接触过,这里简单列举:  

    • JavaScript中变量是以对象属性的形式存在的:全局变量是全局对象的属性;局部变量是声明上下文对象的属性。(声明上下文对象是一个对用户不可见的内部实现,无法被引用,每当函数调用便创建这个对象以存放局部变量)
    • JavaScript虽然是解释型语言,但也存在预处理过程,其中便包含了声明提前。JavaScript解释器运行前,会先将整个程序中的变量声明(包括函数)提前到作用域顶部执行。所以在程序中变量的使用语句可以出现在声明语句之前。
    • JavaScript中没有块级作用域(像C语言那样用方括号{}划分作用域),而是使用函数作用域;
    • 不在任何函数体内声明的变量为全局变量,拥有全局作用域,可以在程序的任何位置被访问;而在函数内声明的变量(包括函数的参数)为局部变量,拥有局部作用域,只在函数内部有定义;
    • 若局部变量与全局变量重名,局部变量优先级高,可以遮盖全局变量;
    • 局部作用域可以相互嵌套(因为函数可以嵌套)

        而作用域链的概念,接触过的人就没那么多了。其实作用域链很好理解,上方第一条已经明确了,JavaScript中变量是以对象属性的形式存在的,而作用域链其实就是这些对象组成的一个链表。全局变量是全局对象的属性,局部变量是声明上下文对象的属性。这些对象按从内向外的顺序链接,链尾当然就是全局对象。当函数运行中需要查找某一个变量的时候,就会沿着作用域链依次查询每个对象是否拥有与该变量同名的属性,如果存在则直接使用;若整条链上都不存在这个属性,便抛出ReferenceError。 在函数定义的时候,便创建了作用域链,链上的对象顺序便确定下来,当函数被调用,创建相应的对象添加到作用域链中,作用域链会随着函数的定义调用而更新。在嵌套函数中更是如此,每次调用外部函数时,内部函数又会重新定义,随之带来的就是作用域链的相应变化。关于作用域链的数量,可以用树来比喻,全局对象是根节点,函数的嵌套代表着树节点的层级关系,那么一个程序中作用域链的数量等于对应树中叶子节点的数量。
    var a = 1;// 最外层的作用域链上只有全局对象
    
    function func1(){
    	var a = 2; // 这一层的作用域链: func1的声明上下文对象 ——> 全局对象
    	function func2(){
    		var a = 3; // 这一层的作用域链: func2的声明上下文对象 ——> func1的声明上下文对象 ——> 全局对象
    		console.log("in func2's scope a= " + a + "  ");
    	}
    	func2();
    	console.log(console.log("in func1's scope a= " + a + "  ");) 
    }
    func1();
    console.log(console.log("a= " + a + "  "););

        运行结果可以很清楚的反映出作用域链的查询顺序。

         关于作用域链还不得不提with语句,它可以进行临时性作用域链扩展。它的语法是这样的:with(object){ statement }。 它将object添加到作用域链的顶部,然后执行语句,执行完毕后将作用域链恢复到原始状态。在对象嵌套层次很深的时候,可以使用with语句简化代码。下面的两段代码是等价的:
    var object = {
    		object1: {
    			name : {
    				firstName: "hello",
    				lastName: "world",
    				nickName: "Jeff"
    			}
    		}
    	};
    object.object1.name.firstName = "aaa";
    object.object1.name.lastName = "bbb";
    object.object1.name.nickName = "ccc";

    var object = {
    		object1: {
    			name : {
    				firstName: "hello",
    				lastName: "world",
    				nickName: "Jeff"
    			}
    		}
    	};
    
    with(object.object1.name){
    	firstName = "aaa";
    	lastName = "bbb";
    	nickName = "ccc";	
    }
    

         with语句在严格模式中是被禁止使用的,在非严格模式也不推荐使用。使用with语句的代码难以优化,并且运行速度更慢。所以上面这种情况我们可以使用下面的方法等价使用,减少代码:
    var object = {
    		object1: {
    			name : {
    				firstName: "hello",
    				lastName: "world",
    				nickName: "Jeff"
    			}
    		}
    	};
    var temp = object.object1.name;
    temp.firstName = "aaa";
    temp.lastName = "bbb";
    temp.nickName = "ccc";	
    



  • 相关阅读:
    板邓:php获取数组元素个数
    板邓:PHP解决Using $this when not in object context in【转】
    板邓:MYSQL distinct关键字查询重复值只显示一条记录
    板邓: php 过滤文章的html标签方法
    板邓:PHP使用mb_strimwidth截取中文字符串方法大全
    板邓:php str_replace单双引号的替换问题
    板邓:PHP下利用PHPMailer配合QQ邮箱下的域名邮箱发送邮件(转)
    板邓:wordpress自定义伪静态 WP_Rewrite
    板邓:wordpress获取当前页面的id、别名
    获取文件夹名
  • 原文地址:https://www.cnblogs.com/zhuwq585/p/7492841.html
Copyright © 2011-2022 走看看