执行环境,作用域理解
JS核心知识梳理
JS核⼼知识梳理前⾔本⽂⽬标从JS的运⾏,设计,数据,应⽤四个⾓度来梳理JS核⼼的知识点主题⼤纲1. JS运⾏变量提升执⾏上下⽂作⽤域let作⽤域链闭包事件循环2. JS设计原型原型链thiscallapplybindnew继承3. JS数据数据类型数据的存储(深浅拷贝)数据类型判断(隐式转换,相等和全等,两个对象相等)数据的操作(数组遍历,对象遍历)数据的计算(计算误差)4. JS应⽤防抖,节流,柯⾥化⼀. JS运⾏⼤概分为四个阶段1. 词法分析:将js代码中的字符串分割为有意义的代码块,称为词法单元浏览器刚拿到⼀个JS⽂件或者⼀个script代码段的时候,它会认为⾥⾯是⼀个长长的字符串这是⽆法理解的,所以要分割成有意义的代码块,⽐如: var a = 12. 语法分析:将词法单元流转换成⼀颗抽象语法树(AST),并对⽣成的AST树节点进⾏处理,⽐如使⽤了ES6语法,⽤到了let,const,就要转换成var。
为什么需要抽象语法树呢?抽象语法树是不依赖于具体的,不依赖于语⾔的细节,⽅便做很多的操作另⼀⽅⾯说,现在有许多语⾔,C,C++,Java,Javascript等等,他们有不同的语⾔规范但是转化成抽象语法树后就都是⼀致的了,⽅便编译器对其进⾏进⼀步的增删改查等操作,3. 预解析阶段:会确定作⽤域规则变量和函数提升4. 执⾏阶段:创建执⾏上下⽂,⽣成执⾏上下⽂栈执⾏可执⾏代码,依据事件循环1.作⽤域指定了函数和变量的作⽤范围分为全局作⽤域和函数作⽤域,JS不像C,JAVA语⾔⼀样,没有块级作⽤域,简单说就是花括号的范围2.变量和函数提升全局变量和函数声明会提升函数声明⽅式有三种,function foo() {}var foo = function () {}var foo = new Function()可归为两类,直接创建和变量赋值变量赋值函数和赋值普通变量的优先级按位置来,变量名相同前者被覆盖函数直接创建优先级⾼于变量赋值,同名取前者,与位置⽆关,也就是说函数直接创建即使再变量声明后⾯,也是优先级最⾼3. 执⾏上下⽂有不同的作⽤域,就有不同的执⾏环境,我们需要来管理这些上下⽂的变量执⾏环境分为三种,执⾏上下⽂对应执⾏环境全局执⾏环境函数执⾏环境eval执⾏环境(性能问题不提)1. 全局执⾏上下⽂先找变量声明,再找函数声明2. 函数执⾏上下⽂先找函数形参,和变量声明把实参赋值给形参找函数声明多个函数嵌套,就会有多个执⾏上下⽂,这需要执⾏上下⽂栈来维护,后进先出执⾏上下⽂⾥包含着变量环境和词法环境变量环境⾥就包含着当前环境⾥可使⽤的变量当前环境没有⽤哪的, 这就说到了作⽤域链4. 作⽤域链引⽤JS⾼程的定义:作⽤域链来保证对执⾏环境有权访问的变量和函数的有序访问变量的查找顺序不是按执⾏上下⽂栈的顺序,⽽是由词法作⽤域决定的词法作⽤域也就是静态作⽤域,由函数声明的位置决定,和函数在哪调⽤⽆关,也就js这么特殊5. 静态作⽤域和动态作⽤域词法作⽤域是在写代码或者定义时确定的⽽动态作⽤域是在运⾏时确定的(this也是!)var a = 2;function foo() {console.log(a); // 静态2 动态3}function bar() {var a = 3;foo();}bar();复制代码闭包由于作⽤域的限制,我们⽆法在函数作⽤域外部访问到函数内部定义的变量,⽽实际需求需要,这⾥就⽤到了闭包引⽤JS权威指南定义:闭包是指有权访问另⼀个函数作⽤域中的变量的函数1. 闭包作⽤for循环遍历进⾏事件绑定输出i值时为for循环的长度+1这结果显⽰不是我们想要的, 因为JS没有块级作⽤域,var定义的i值,没有销毁,存储与全局变量环境中在事件具体执⾏的时候取的i值,就是全局变量中经过多次计算后的i值for(var i = 0;i < 3;i++){document.getElementById(`item${i+1}`).onclick = function() {console.log(i);//3,3,3}}复制代码闭包特性:外部函数已经执⾏结束,内部函数引⽤外部函数的变量依然保存在内存中,变量的集合可称为闭包在编译过程中,对于内部函数,JS引擎会做⼀次此法扫描,如果引⽤了外部函数的变量,堆空间创建换⼀个Closure的对象,⽤来存储闭包变量利⽤此特性给⽅法增加⼀层闭包存储当时的i值,将事件绑定在新增的匿名函数返回的函数上for(var i = 0;i < 3;i++){document.getElementById(`item${i+1}`).onclick = make(i);}function make(e) {return function() {console.log(e)//0,1,2};复制代码闭包注意我们在不经意间就写成了闭包,内部函数引⽤外部函数的变量依然保存在内存中,该销毁的没有销毁,由于疏忽或错误造成程序未能释放已经不再使⽤的内存,就造成了内存泄漏同时注意闭包不会造成内存泄漏,我们错误的使⽤闭包才是内存泄漏事件循环JS代码执⾏依据事件循环JS是单线程,通过异步保证执⾏不被阻塞1. 执⾏机制简单说就是,⼀个执⾏栈,两个任务队列发现宏任务就放⼊宏任务队列,发现微任务就放⼊微任务队列,执⾏栈为空时,执⾏微任务队列所有微任务,再取宏任务队列⼀个宏任务执⾏如此循环2. 宏&微任务 macroTask: setTimeout, setInterval, I/O, UI rendering microTask: Promise.then⼆. JS设计1. 原型1. JS的设计有new操作符,构造函数,却没有类的概念,⽽是使⽤原型来模拟类来实现继承2. JS设计⼼路历程JS在设计之初,给的时间较短,并且定义为简单的⽹页脚本语⾔,不⽤太复杂,且想要模仿Java的理念,(这也是为什么JS叫JavaScript的原因)因此就借鉴了Java的对象、构造函数、new操作符理念,⽽抛弃掉了了复杂的class(类)概念3. 继承机制需要有⼀种继承的机制,来把所有对象联系起来,就可以使⽤构造函数但是构造函数⽣成实例对象的缺点就是⽆法共享属性和⽅法4. prototype属性为解决上⾯问题,就引⼊了prototype属性,就是我们常说的原型为构造函数设置⼀个prototype属性,实例对象需要共享的⽅法,都放在此对象上,整个核⼼设计完成后,后⾯的API也就顺理成章原型每⼀个js对象在创建的时候就会与之关联另⼀个对象这个对象就是原型,每个对象都会从原型继承属性proto每个对象都有⼀个属性叫proto,该属性指向对象的原型构造函数的prototype属性等于实例化对象的proto属性此属性并不是ES5 中的规范属性,只是为了在浏览器中⽅便获取原型⽽做的⼀个语法糖,我们可以使⽤Object.getPrototype()⽅法获取原型constructor 原型没有指向实例,因为⼀个构造函数可以有多个对象实例但是原型指向构造函数是有的,每个原型都有⼀个constructor属性指向关联的构造函数function Per() {} // 构造函数const chi = new Per() // 实例对象chi.__proto__ === Per.prototype // 获取对象的原型也是就构造函数的prototype属性Per.prototype.constructor === Per // constructor属性获取当前原型关联的构造函数复制代码实例与原型读取实例属性找不到时,就会查找与对象关联的原型的属性,⼀直向上查找,这种实例与原型之间的链条关系,这就形成了原型链function Foo() {} = 'tom'const foo = new Foo() = 'Jerry'console.log(); // Jerrydelete console.log(); // tom复制代码2.原型链⾸先亮出⼤家熟悉的⽹图就是实例与构造函数,原型之间的链条关系实例的 proto 指向原型构造函数的 prototype 属性指向原型原型的 constructor 属性指向构造函数所有构造函数的 proto 指向 Function.prototypeFunction.prototype proto 指向 Object.prototypeObject.prototype proto 指向 null函数对象原型(Function.prototype)是负责造构造函数的机器,包含Object、String、Number、Boolean、Array,Function。
js中VO解析
js中VO解析执⾏环境(环境)执⾏环境的⽤处执⾏环境定义了变量或函数有权访问的其他数据,每⼀个执⾏环境都存在⼀个关联的变量对象(VO),代码⽆法访问,内部解析器会使⽤它,如果环境为函数,则将函数的AO作为VO,函数执⾏时,会创建⼀个以当前函数VO为前端的作⽤域链,以保证执⾏环境有权访问的所有变量和函数的有序访问。
顶级AO对象全局全局对象(Global object) 是在进⼊任何执⾏上下⽂之前就已经创建了的对象;这个对象只存在⼀份,它的属性在程序中任何地⽅都可以访问,全局对象的⽣命周期终⽌于程序退出那⼀刻。
全局对象初始化全局对象初始创建阶段将Math、String、Date、parseInt作为⾃⾝属性,等属性初始化,同样也可以有额外创建的其它对象作为属性(其可以指向到全局对象⾃⾝)。
例如,在DOM中,全局对象的window属性就可以引⽤全局对象⾃⾝(当然,并不是所有的具体实现都是这样)global = {Math: <...>,String: <...>......window: global //引⽤⾃⾝};证据Chrome打印global对象时,显⽰了Window类型对象,⾥⾯有⼀个属性叫window就是global本⾝可以看到global和global.window是指向同⼀对象全局对象访问// 相当于 global.String(10)String(10);// 相当于 global.window.a = 10 === global.a = 10window.a = 10;// 相当于 // global.b = 20;this.b = 20;函数的VO对象AO函数AO对象⽣成过程函数执⾏前1.分析参数1.1 函数接收参数,添加到AO的属性上⾯,值被初始化为undefined1.2 接收实参,形成AO对应的属性值2.分析变量声明,如 var a,2.1:如果AO上还没有a属性键名,则添加a属性键名并且初始化为undefined2.2:如果AO 上⾯已经有了a属性,则不做任何操作3.分析函数的声明,如果 funcion a(){},3.1:⽆论是否该函数名存在,都会覆盖当前函数名对应的属性函数执⾏时4.对已经存在的变量声明进⾏赋值操作实例function test(a, b) {var c = 10;function d() {}var e = function _e() {};(function x() {});}test(10); // call1.分析参数1.1 函数接收参数,添加到AO的属性上⾯,值被初始化为undefinedAO(test) = {a: undefined,b: undefined}1.2 接收实参,形成AO对应的属性值AO(test) = {a: 10,b: undefined}2.分析变量声明,如 var a,2.1:如果AO上还没有a属性键名,则添加a属性键名并且初始化为undefined AO(test) = {a: 10,b: undefined,c: undefined,e: undefined}2.2:如果AO 上⾯已经有了a属性,则不做任何操作3.分析函数的声明,如果 funcion a(){},3.1:⽆论是否该函数名存在,都会覆盖当前函数名对应的属性AO(test) = {a: 10,b: undefined,c: undefined,d: <reference to FunctionDeclaration "d">,e: undefined}函数执⾏时4.对已经存在的变量声明进⾏赋值操作AO(test) = {a: 10,b: undefined,c: 10,d: <reference to FunctionDeclaration "d">,e: <reference to FunctionExpression "_e">}。
js底层原理
js底层原理JavaScript(简称js)是一种轻量级、解释型的编程语言,主要用于在网页上实现交互功能。
在学习和使用JavaScript的过程中,了解其底层原理是非常重要的。
本文将介绍JavaScript底层原理的相关知识,希望能够帮助读者更好地理解和运用JavaScript。
首先,让我们来了解一下JavaScript的执行环境。
在浏览器中,JavaScript引擎负责解释和执行JavaScript代码。
常见的浏览器中的JavaScript引擎包括V8(Chrome浏览器)、SpiderMonkey(Firefox浏览器)、Chakra(Edge浏览器)等。
这些引擎在执行JavaScript代码时,会将其转换为字节码或机器码,然后由计算机进行执行。
接下来,我们来看一下JavaScript的数据类型。
JavaScript中的数据类型分为基本数据类型和引用数据类型。
基本数据类型包括undefined、null、boolean、number、string和symbol(ES6新增),它们存储在栈内存中,通过按值访问。
引用数据类型包括object、array、function等,它们存储在堆内存中,通过引用地址访问。
了解数据类型的存储方式有助于我们更好地理解JavaScript的内存管理和数据操作。
此外,JavaScript的作用域和闭包也是我们需要了解的重要内容。
作用域指的是变量的可访问范围,JavaScript采用的是词法作用域,也就是静态作用域。
而闭包是指函数和函数内部引用的变量组成的组合,它可以让我们访问外部函数的变量,实现一些特殊的功能。
理解作用域和闭包有助于我们写出更加优雅和高效的JavaScript代码。
另外,JavaScript的原型和原型链也是JavaScript底层原理中的重要内容。
JavaScript中的对象是基于原型的,每个对象都有一个原型对象,而原型对象又有自己的原型对象,形成了原型链。
javascript 核心原理pdf
javascript 核心原理pdf全文共四篇示例,供读者参考第一篇示例:JavaScript是一种广泛应用于前端开发的编程语言,它是实现Web页面交互性的重要工具。
要想掌握JavaScript编程,了解其核心原理至关重要。
本文将深入探讨JavaScript的核心原理,并提供一份《JavaScript核心原理PDF》供读者参考。
JavaScript的核心原理主要包括以下几个方面:数据类型、变量、运算符、控制流程、函数、对象、数组、闭包等。
首先我们来介绍JavaScript的数据类型。
JavaScript有七种基本数据类型,分别是字符串(String)、数字(Number)、布尔值(Boolean)、undefined、null、Symbol和BigInt。
除了基本数据类型外,JavaScript还有一种复杂数据类型——对象(Object),对象是一种无序的数据集合,包含键值对。
变量是存储数据的容器,使用var、let或const关键字声明一个变量。
JavaScript支持赋值运算符(=)、算术运算符(+、-、*、/等)、比较运算符(==、!=、>、<等)、逻辑运算符(&&、||、!等)等。
控制流程是编程中的基本元素,主要包括条件语句(if、else if、else)、循环语句(for、while、do while)、跳转语句(break、continue、return)等。
函数是JavaScript中的重要概念,函数是一段可重复使用的代码块,可以接受参数并返回值。
JavaScript中的函数可以嵌套定义,函数也是一种对象,因此函数可以作为对象的属性。
JavaScript中还有一种特殊的函数——匿名函数,匿名函数没有名称,通常用于定义回调函数。
对象是JavaScript编程中的核心概念,对象是一种复杂数据类型,是由键值对组成的无序集合。
JavaScript中的对象可以是内置对象(如Array、Math、Date等)、宿主对象(由JavaScript外部环境提供的对象,如浏览器对象)或自定义对象。
Web前端开发技术学习方式探讨
1前端开发常用技术概述HTML、CSS、JavaScript是Web前端开发的3大技术核心,简单说就是用HTML进行页面的结构排版,用CSS进行页面布局和样式的设计,用JavaScript实现页面的交互和数据请求。
1.1HTML5HTML5是万维网的核心与通用语言,HTML5在2008年正式发布,在2012年形成稳定版本,相比HTML4, HTML5增加了图形绘制、多媒体等元素和功能, HTML5是Web前端开发者需要掌握的首要技术。
1.2CSS3CSS即层叠样式表,它可以对网页布局、元素等进行精确控制,CSS3是CSS技术的升级版本,主要包括盒子模型、多栏目布局等模块[2]。
Div+CSS布局的优点非常多,比如可以有效减少页面代码量并提高页面显示速度,代码结构清晰明了,更容易被搜索引擎收录[3]。
1.3JavaScriptJavaScript是一种Web前端的弱语言类型、解释型语言,是一种基于事件和对象驱动的、安全性好的脚本语言。
它在客户端运行(node.js例外),是一种通用的,不需要在专门的语言环境下运行,在插入HTML页面后,可由所有的现代浏览器执行[4]。
1.4jQueryjQuery是一个快速、轻量级、兼容多浏览器且功能丰富的JavaScript库。
它使用户的像操作文档对象、选择文档对象模型元素、创建动画效果、处理事件、以及开发Ajax程序等的网页操作变得更加容易,同时赋予了开发人员提供了在网页上创建插件的能力。
1.5Bootstrap框架Bootstrap框架简洁灵活,兼容绝大部分的JQuery 插件,形成了一套独特清新的网站显示风格并风靡一时。
Bootstrap最精彩的部分就是响应式布局,通过响应式布局可以实现只用一套代码就可以完美支持PC端、PAD及手机移动端的页面访问[5]。
1.6AjaxAjax即异步的JavaScript和XML,它是按需加载数据,而不再像传统网页一样要更新一点点内容,就得重新加载整个网页。
JSinDeep1_探索执行环境_ES3
JSinDeep1:探索执行环境(Execution Context)-ES3篇声明JSinDeep系列文章主要内容为作者对ECMA-262标准中一些概念的理解和探究,同时意在帮助大家快速理解。
本着严谨的态度,同时又需避免API式的枯燥细节罗列。
文章会以适当插图、例子去诠释概念,致力于通俗易懂。
更具体、严谨、完整的描述建议阅读ECMA262文档。
碍于作者水平有限,文中若有错误,欢迎大家批评指正。
概要在我们写JavaScript代码时会定义一些变量、函数等。
解释器在执行这些代码时是如何处理并找到我们定义的这些数据的?在程序执行时,引用这些变量等操作的背后都发生了什么?本文主要探讨ECMA-262-3标准中的执行环境(Execution Context)及与之相关的一些内部机制和模型。
定义当程序执行的控制权转移至ECMAScript可执行代码时,会进入到一个执行环境中(Execution Context,缩写为EC)。
在一个EC内也可能进入到一个新的EC,这些EC逻辑上○1会形成一个栈(Stack)。
EC是程序运行时动态创建的。
例如:每一个函数在被调用时都会创建一个EC,重复调用函数(包含递归调用的情形)会重新创建新的EC,而后放置在逻辑栈中。
逻辑栈会在程序运行时随着新的函数调用、函数return、未处理的异常抛出等情况动态变化,但逻辑栈的最顶部总是当前正运行的EC,它的最底部总是全局EC(Global Context)。
图:运行时的逻辑EC栈○1这里的“逻辑上”是因ECMA262标准避免限制实现者的思路,具体实现在遵循标准的前提下不受其它限制。
因此这里所说的逻辑上的栈在具体实现时未必是通常意义上的栈。
后面我们简称为:“逻辑栈”。
可执行代码的分类由定义部分可知,“每一段可执行代码都有对应的EC”,为方便按不同情况讨论,先了解几种可执行代码的类型。
a). 全局代码全局代码是指在任何被解析为函数体的代码以外的最外层的代码。
详细图解作用域链与闭包
详细图解作⽤域链与闭包因此本⽂的⽬的就在于,能够清晰明了得把闭包说清楚。
⼀、作⽤域与作⽤域链在详细讲解作⽤域链之前,我默认你已经⼤概明⽩了JavaScript中的下⾯这些重要概念。
这些概念将会⾮常有帮助。
基础数据类型与引⽤数据类型内存空间垃圾回收机制执⾏上下⽂变量对象与活动对象作⽤域在JavaScript中,我们可以将作⽤域定义为⼀套规则,这套规则⽤来管理引擎如何在当前作⽤域以及嵌套的⼦作⽤域中根据标识符名称进⾏变量查找。
这⾥的标识符,指的是变量名或者函数名JavaScript中只有全局作⽤域与函数作⽤域(因为eval我们平时开发中⼏乎不会⽤到它,这⾥不讨论)。
作⽤域与执⾏上下⽂是完全不同的两个概念。
我知道很多⼈会混淆他们,但是⼀定要仔细区分。
JavaScript代码的整个执⾏过程,分为两个阶段,代码编译阶段与代码执⾏阶段。
编译阶段由编译器完成,将代码翻译成可执⾏代码,这个阶段作⽤域规则会确定。
执⾏阶段由引擎完成,主要任务是执⾏可执⾏代码,执⾏上下⽂在这个阶段创建。
作⽤域链⽣命周期,如下图。
执⾏上下⽂⽣命周期我们发现,作⽤域链是在执⾏上下⽂的创建阶段⽣成的。
这个就奇怪了。
上⾯我们刚刚说作⽤域在编译阶段确定规则,可是为什么作⽤域链却在执⾏阶段确定呢?之所有有这个疑问,是因为⼤家对作⽤域和作⽤域链有⼀个误解。
我们上⾯说了,作⽤域是⼀套规则,那么作⽤域链是什么呢?是这套规则的具体实现。
所以这就是作⽤域与作⽤域链的关系,相信⼤家都应该明⽩了吧。
我们知道函数在调⽤激活时,会开始创建对应的执⾏上下⽂,在执⾏上下⽂⽣成的过程中,变量对象,作⽤域链,以及this的值会分别被确定。
之前⼀篇⽂章我们详细说明了变量对象,⽽这⾥,我们将详细说明作⽤域链。
作⽤域链,是由当前环境与上层环境的⼀系列变量对象组成,它保证了当前执⾏环境对符合访问权限的变量和函数的有序访问。
为了帮助⼤家理解作⽤域链,我我们先结合⼀个例⼦,以及相应的图⽰来说明。
作用域链的理解
作用域链的理解作用域链是JavaScript中一个重要的概念,是许多程序员的福音。
它有助于我们更好地理解JavaScript代码的执行过程。
在本文中,我们将向您介绍作用域链及其相关概念,帮助您更好地理解它们的工作原理。
步骤1:理解作用域作用域是一个定义变量和函数的区域。
在JavaScript中,有局部作用域和全局作用域。
函数内定义的变量只能在该函数内部访问,称为局部变量,而在函数外部定义的变量和函数则称为全局变量和函数。
步骤2:理解词法作用域词法作用域是由代码中变量和函数声明的位置决定的,也称为静态作用域。
在JavaScript中,使用var关键字声明的变量,会被限制在其定义所在的函数内部或全局作用域中。
而使用let、const关键字声明的变量,则受块级作用域限制。
步骤3:了解作用域链在JavaScript中,每个函数都有一个作用域,作用域中包含局部变量、参数、全局变量和外部封闭函数的变量。
当函数访问一个变量时,JavaScript会首先查找当前函数作用域中是否有该变量;如果没有找到,则会沿着函数创建时的作用域链向上查找,直到找到该变量所在的作用域为止。
如果在全局作用域中也找不到该变量,就会抛出引用错误。
步骤4:深入了解作用域链当一个函数被调用时,JavaScript会创建一个新的执行环境。
该执行环境会包含一个变量对象(VO),其中包含该函数内定义的所有变量和函数。
函数的作用域链是在创建该执行环境时进行设置的。
作用域链中包含了本地变量对象和所有外部封闭函数的变量对象。
在本地变量对象中定义的变量和函数名将优先于外部函数中定义的变量和函数名。
步骤5:结合实例理解作用域链我们来看一个简单示例,帮助您更好地理解作用域链的工作原理:```var name = "Alice";function greet() {var name = "Bob";function sayHello() {var message = "Hello, " + name + "!";console.log(message);}sayHello();}greet();```在这个示例中,我们定义了一个全局变量name,以及一个greet函数和sayHello函数。
google_v8 pdf
它们其实没有太大的差别,只是作用域不一样,Handle 和 Local 一样会在 C++的作用域中被 同域的 HandleScope(后面再解释)释放掉。而 Persistent 则相当于是永久性的实例,它所 持有 javascript 对象只有调用 Despose()的时候再会显示释放。
2.1.2 作用域(Scope)
cmd /k ""C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86
进入 v8 源码目录,执行 Scons --help 可查看编译选项。因为我是用来学习的,所以我编 译 debug 版本, 并且选择打印尽可能多的消息。 在 windows 下, 尽量选择编译为动态库吧, 在为静态的 v8.lib 有 160MB 之巨,一个 helloworld 程序都要链接个半天。 我的编译选项:
一般情况下,函数的开始部分都放一个 HandleScope, 这样此函数中的 Handle 就不需要 再理会了释放资源了。而 Context::Scope 仅仅做了:在构造中调用 context->Enter(),而在析 构函数中调用 context->Leave()。
1 / 18
Google v8 学习笔记
一、Google v8 整体印象
1.1 Google v8 是什么,能做什么?
v8 是一款 Javascript 脚本引擎,它开放源代码,由 Google 丹麦开发,是 Google Chrome 的一部分。 和其它脚本语言(php,lua,python 等)一样,Javascript 也可以内嵌于应用程序,和编译 性语言(c/c++等)交互。 由于 v8 是用 C++写的, 所以在 C++中使用 javascript 显得更加的自然。 通过在应用程序中引入脚本解析器, 将一些业务逻辑交由脚本实现, 可以使得系统更加灵活。 C/C++的高效,Javascript 的灵巧多变,使得我们的应用程序可以兼顾性能和效率。 说得再具体直白一点,就是我们可以通过编写 javascript 脚本来操作 C++提供的类,可 以编写 javascript 函数供 C++调用。像下面这样写 javascript 一定非常爽吧?
作用域和作用域链的理解
作用域和作用域链的理解1.作用域的定义作用域是一个定义了变量和函数可访问性的规则集合。
它决定了在特定区域内定义的变量和函数在哪里可见和可访问。
2.作用域的分类作用域通常分为两种类型:全局作用域和局部作用域。
- 全局作用域:全局作用域是在整个程序中都可访问的作用域。
在JavaScript中,全局作用域是指在脚本中定义的变量和函数可以在整个脚本中的任何位置被访问。
-局部作用域:局部作用域是指在函数或块级作用域中定义的变量和函数只能在其所在的函数或块级作用域中被访问。
3.作用域链的定义作用域链是指在嵌套的作用域中,变量和函数的访问规则。
当一个程序中存在多个嵌套的作用域时,每个作用域都有一个连接到父级作用域的链,这些链组成了作用域链。
4.作用域链的工作原理在JavaScript中,函数在创建时会保存一个内部属性[[Scope]],该属性包含了函数所在的作用域,即创建时的上下文环境。
当函数被调用时,会创建一个称为活动对象的对象,它包含了函数的参数和局部变量。
同时,JavaScript解释器会通过作用域链来查找变量的值。
作用域链的查找过程是由内向外的,即从当前作用域开始一级一级向上查找,直到找到所需的变量或到达全局作用域。
如果在局部作用域中找不到变量,它会沿着作用域链向上查找,直到找到变量或到达最外层的全局作用域。
以下是一个示例来说明作用域链的工作原理:```var a = 1; // 全局变量function outevar b = 2; // 外部函数变量function inner(var c = 3; // 内部函数变量console.log(a + b + c);}inner(;outer(; // 输出结果:6```在以上示例中,全局作用域中有一个变量a。
在outer(函数中,有一个变量b。
在inner(函数中,有一个变量c。
当inner(函数被调用时,它会先从自身作用域中查找变量c,如果找不到,就会向上一级作用域outer(中查找变量b,再找不到就继续向上查找全局作用域,直到找到全局作用域中的变量a。
什么是闭包?请举例说明(面试题目)
什么是闭包?请举例说明(⾯试题⽬)⼀、变量的作⽤域要理解闭包,⾸先必须理解Javascript特殊的变量作⽤域。
变量的作⽤域⽆⾮就是两种:全局变量和局部变量。
Javascript语⾔的特殊之处,就在于函数内部可以直接读取全局变量。
Js代码 var n=999; function f1(){ alert(n); } f1(); // 999另⼀⽅⾯,在函数外部⾃然⽆法读取函数内的局部变量。
Js代码 function f1(){ var n=999; } alert(n); // error这⾥有⼀个地⽅需要注意,函数内部声明变量的时候,⼀定要使⽤var命令。
如果不⽤的话,你实际上声明了⼀个全局变量!Js代码 function f1(){ n=999; } f1(); alert(n); // 999--------------------------------------------------------------------------------------------------------⼆、如何从外部读取局部变量?出于种种原因,我们有时候需要得到函数内的局部变量。
但是,前⾯已经说过了,正常情况下,这是办不到的,只有通过变通⽅法才能实现。
那就是在函数的内部,再定义⼀个函数。
Js代码 function f1(){ n=999; function f2(){ alert(n); // 999 } }在上⾯的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。
但是反过来就不⾏,f2内部的局部变量,对f1 就是不可见的。
这就是Javascript语⾔特有的“链式作⽤域”结构(chain scope),⼦对象会⼀级⼀级地向上寻找所有⽗对象的变量。
所以,⽗对象的所有变量,对⼦对象都是可见的,反之则不成⽴。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!Js代码function f1(){ n=999; function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999--------------------------------------------------------------------------------------------------------三、闭包的概念上⼀节代码中的f2函数,就是闭包。
变量的作用域
变量的作⽤域变量的作⽤域:作⽤:起作⽤。
域:范围,区域。
1,变量的⽣命周期。
2,哪⾥可以访问变量。
----------------作⽤域-----------1,全局作⽤域全局都可以访问的变量的区域2,局部作⽤域:主要就是函数作⽤,理解为:函数体内部的执⾏环境。
不存在的变量或函数会报错;不存在的属性或⽅法,返回undefined;javascript 没有块级作⽤域:⽐如{ ...... } //在这个花括号⾥⾯的变量就叫块级作⽤域,但JS中没有块级作⽤。
⽐如:if(){......} for(){.....)等等:<script>if (true) {var a=0;//属于全局变量,因为JS不存在块级作⽤域,即:{}花括号之间的作⽤域,其他语⾔会有}for (var i = 0; i < elements.length; i++) {var b=1;//属于全局变量,因为JS不存在块级作⽤域,即:{}花括号之间的作⽤域,其他语⾔会有}</script>----------------------------------------<script>function fn(){var x=y=1;console.log(x);//返回 1console.log(y);//返回 1}// console.log(x);//报错,因为x是局部变量,不能再函数体以外进⾏访问。
fn();//如果不执⾏该⽅法,则输出下⾯y就会报错: y is undefinedconsole.log(y);//返回 1</script>---------js没有块级作⽤,所以变量都是全局作⽤域------------script type="text/javascript">if (true) {var name="xm"; //在js中没有块级作⽤域,所以,这⾥的name是全局变量。
软件工程考试重点
2.软件过程:是为了获得高质量软件所需要完成的一系列任务的框架,它规定了完成各项任务的工作步骤。
6.模块化:是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性8.逐步求精:将现实问题经过几次抽象(细化)处理,最后到求解域中只是一些简单的算法描述和算法实现问题9.信息隐藏:应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的10.局部化:所谓局部化是指把一些关系密切的软件元素物理地放得彼此靠近。
11.模块独立性:是指模块内部各部分及模块间的关系的一种衡量标准,由内聚和耦合来度量。
14.模块的作用域:为受该模块内一个判定影响的所有模块的集合。
15.模块的控制域:模块本身以及所有直接或间接从属于它的模块的集合。
16.结构化程序设计:是进行以模块功能和处理过程设计为主的详细设计的基本原则17.改正性维护:诊断和改正错误的过程.18.适应性维护:为了和变化了的环境适当地配合而进行的修改软件的活动,是即必要又经常的维护活动。
19.完善性维护:是指增加新功能或修改已有的功能。
通常占软件维护工作的大部分。
20.预防性维护:为了改进未来的可维护性或可靠性,或为了给未来的改进奠定更好的基础而修改,这项维护活动相对比较小。
21.可移植性:把程序从一种计算环境转移到另一种计算环境的难易程度.22.可重用性:是指同一事物不做修改或稍加改动就不同环境中多次重复使用。
23.继承:子类自动地共享基类中定义的数据和方法的机制。
25.验收测试:把软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,但是它是在用户积极参与下进行的,而且可能主要使用实际数据进行测试。
26.集成测试:是测试和组装然件的系统化技术.单元测试集中检测软件设计的最小单元是模块27.多态:指子类对象可以像父类对象那样使用21.简述数据流图的绘制步骤。
首先画系统的输入输出,即先画顶层数据流图。
软件工程(名词解释)
1、软件:能完成预定功能、性能,并对相应数据进行加工的程序和描述数据及其操作的文档。
2、软件工程:是采用工程的概念、原理、技术和方法,并结合正确的管理技术和当前能够得到的最先进的技术方法,经济高效地开发和维护软件的一门工程学科。
3、软件过程:软件过程是指软件开发人员为了开发出高质量的软件产品所需完成的一系列任务的框架,它规定了完成各项任务的工作步骤。
4、软件生命周期:一个软件从定义、开发、使用和维护直至最后被废弃要经历的漫长时期。
5、软件危机:是指计算机软件的开发和维护过程中所遇到的一系列严重的问题。
页脚6、结构化分析:是面向数据流自顶向下逐步求精获取的方法,适用于数据处理系统的需求分析。
7、实体—联系图:描述系统所有数据对象的组成和属性及数据对象关系的图形语言。
8、数据字典:由数据条目组成,数据字典描述、组织和管理数据流图中的数据流、加工、数据存储等数据元素。
9、结构化设计:基于数据流的设计方法,将数据流图转换为软件结构。
10、模块化:是指解决一个复杂问题时自顶向下逐层把软件系统划分成若干模块的过程。
页脚11、逐步求精:是一种自顶向下的设计策略,是人类解决复杂问题时常用的一种技术。
是为了能集中精力解决主要问题而尽量推迟考虑问题的细节。
12、信息隐蔽:在设计中确定模块时使得一个模块的所包含的信息,对于不需要这些信息的模块来说,是不能访问的。
13、耦合:也称模块之间的联系。
指在软件系统结构中,各模块间相互联系紧密程度的度量。
模块之间的联系越紧密,其耦合程度就越强,模块的独立性就越差。
14、内聚:也称块内联系,指模块的功能强度的度量,是一个模块内部各元素之间彼此结合紧密程度的度量。
15、作用域:是指受该模块内的一个判断影响的所有模块的集合。
页脚16、控制域:指模块本身以及其所有直接或间接从属于它的模块集合。
17、扇出:指一个模块直接调用模块的数目。
18、扇入:指有多少个上级模块直接调用它。
19、模块独立性:每个模块独立完成一个相对独立的特定子功能,并且和其他模块之间的关系很简单。
js 中context方法
js 中context方法在JavaScript中,Context方法是一个重要的概念,用于控制函数内部的this值。
它对于理解函数的执行环境和作用域非常重要。
在本文中,我们将逐步介绍Context方法,从基本概念到高级应用。
1. 什么是Context方法?Context方法是JavaScript中一种控制函数内部this值的机制。
在JavaScript中,每个函数都有一个默认的this值,它取决于函数的调用方式。
而Context方法允许我们手动指定函数内部this值,从而改变函数的执行环境。
2. 默认的this值在JavaScript中,函数的this值默认指向函数的调用者。
例如:function sayHello() {console.log("Hello, " + );}var person = {name: "Alice",sayHello: sayHello};person.sayHello(); 输出:Hello, Alice在上面的例子中,person对象的sayHello方法被调用时,this指向了person对象本身。
3. 使用Context方法改变this值有时候,我们需要手动改变函数内部的this值,以改变函数的执行环境。
JavaScript提供了三种Context方法:call、apply和bind。
- call方法call方法用于调用函数,并且可以指定函数内部的this值和参数列表。
例如:function sayHello() {console.log("Hello, " + );}var person1 = {name: "Alice"};var person2 = {name: "Bob"};sayHello.call(person1); 输出:Hello, AlicesayHello.call(person2); 输出:Hello, Bob在上面的例子中,通过调用sayHello.call()方法,我们可以指定函数内部的this值为person1或person2对象。
js的执行原理
js的执行原理JavaScript的执行原理是将代码逐行解析并执行。
以下是JavaScript执行的一般流程:1. 解析:首先,JavaScript引擎会将代码解析为可执行的语法树。
这个过程包括词法分析和语法分析。
词法分析将代码分割成一个个的词元,例如标识符、操作符和常量。
语法分析将词元组成一个语法树,表示代码的结构和关系。
2. 创建执行环境:在执行之前,JavaScript引擎会创建一个执行环境(Execution Context)。
执行环境包括变量对象、作用域链和this指向。
全局执行环境是JavaScript程序的最顶层执行环境。
3. 逐行执行:从语法树中的根节点开始,JavaScript引擎按照从上到下的顺序逐行执行代码。
每一行代码都会生成执行上下文,如果是函数调用,还会生成函数执行上下文。
4. 标识符解析:在执行过程中,当遇到标识符(变量名、函数名等)时,JavaScript引擎会通过作用域链在当前环境中查找对应的值。
如果在当前环境中找不到,会继续在上层环境中查找,直到找到全局环境。
5. 执行结果:每行代码执行后,都会产生一个执行结果。
执行结果可以是一个新的值、对变量的赋值、函数的调用等。
如果是函数调用,会创建一个新的执行环境,并将执行流程切换到函数内部执行。
6. 垃圾回收:在代码执行过程中,JavaScript引擎会自动进行垃圾回收机制,用于回收不再使用的变量和对象,释放内存空间。
以上是JavaScript的一般执行原理,实际执行过程可能会受到具体的JavaScript引擎优化和各种执行环境的影响。
在使用JavaScript开发时,了解其执行原理可以帮助我们更好地理解代码的行为和性能优化。
什么是作用域作用域链
什么是作用域作用域链
作用域是指在程序中定义变量的可访问区域,即变量的有效范围。
作用域可以控制变量的可见性和生命周期,决定了在哪些地方可以访问到变量。
在大多数编程语言中,作用域可以分为全局作用域和局部作用域。
全局作用域是指在整个程序中都可访问的变量,而局部作用域是指仅在一些特定代码块中可访问的变量。
作用域还可以根据嵌套关系进行划分,即内层作用域可以访问外层作用域的变量,而外层作用域不能访问内层作用域的变量。
作用域链的构建过程是在函数定义的时候确定的。
当函数被创建时,它的作用域链包含了所有父级作用域的变量对象。
当函数被调用时,会创建一个新的执行上下文,并为该执行上下文创建一个变量环境,该变量环境包含了函数自身的变量对象和在调用时传递的参数。
该执行上下文的作用域链被设置为函数定义时的作用域链,这样函数内部的变量查找机制就被确定下来了。
当我们在函数内部引用一个变量时,引擎会先在作用域链的当前作用域中查找该变量,如果找到了就使用该变量,如果没找到就会去上一级作用域链中查找,直到找到或者到达全局作用域。
如果在全局作用域中还找不到该变量,那么就会抛出一个异常。
作用域链的存在可以提供一定的安全性和隔离性。
因为不同作用域中的同名变量不会相互影响,每个作用域都有自己的变量对象,互不干扰。
同时,作用域链也可以保护变量的访问权限,使得外部无法访问到局部变量,提高了程序的安全性。
总结起来,作用域是指变量的可访问区域,作用域链是指变量查找的路径。
作用域链的构建过程是在函数定义时确定的,通过作用域链可以实现变量的隔离和访问控制,提高程序的安全性。
benevolent的用法 -回复
benevolent的用法-回复什么是执行环境?执行环境是指在程序运行时所创建的一个“容器”,它提供了程序运行所需的所有资源,包括变量、函数、内存空间等。
在该环境中,程序的每一行代码都会被逐一执行,从而实现程序的功能。
执行环境是程序运行时的一个复杂的组织结构,包含了许多不同的组件和部分。
下面将逐步介绍执行环境的各个组成部分。
1. 全局环境:在程序启动时会自动创建一个全局环境,用于存储全局变量和函数。
全局环境是所有其他环境的父环境,可以通过其他执行环境来访问全局环境中的变量和函数。
2. 函数环境:每当一个函数被调用时,都会创建一个新的函数环境。
函数环境是一个独立的环境,负责存储函数内部定义的变量和函数,并且可以访问父环境中的变量和函数。
3. 块级作用域:块级作用域是指在代码块内部创建的一个独立的执行环境,它只在块级作用域内部有效。
块级作用域常见于条件语句、循环语句和函数中的局部变量。
4. 闭包环境:闭包环境是指一个函数的作用域外部,但是仍然对函数内部的变量和函数有访问权限的环境。
当一个函数引用了外部环境的变量或函数时,就会创建一个闭包环境。
5. 模块环境:模块环境是指在使用模块化开发时创建的一个独立的执行环境。
模块环境将函数、变量和其他资源进行封装,使其在模块内部可以进行私有化处理,同时可以通过导出功能向外部暴露部分资源。
执行环境的创建和销毁是动态的过程,会根据程序的运行状态不断地进行调整。
当一个函数被调用时,就会创建一个新的函数环境,并将该环境压入执行环境栈。
当函数执行完毕后,函数环境会被弹出执行环境栈,销毁该环境,程序回到上一个执行环境继续执行。
总结:执行环境是程序运行时所创建的一个“容器”,用于存储变量、函数和其他资源。
它包含了全局环境、函数环境、块级作用域、闭包环境和模块环境等组成部分。
执行环境的创建和销毁是动态的过程,根据程序的运行状态进行调整。
了解执行环境的概念和组成部分,有助于我们理解程序的运行原理和调试错误。
《Python快速编程入门》——课后题答案
Python课后题答案第1章Python概述一、填空题1.对象2.可移植3.字节码4.UTF-85.pyc二、判断题1.对2.对3.对4.对5.错6.错7.对8.错9.对10.错三、选择题1.C2.ABCD3.ABCD4.C5.D四、简答题。
1.Python具有的特点如下:简单易学●开源●高级语言●可移植性●解释性●面向对象●可扩展性●丰富的库●规范的代码2. Python可以应用在下列领域:●web应用开发●操作系统管理、服务器运维的自动化脚本 ●科学计算●桌面软件●服务器软件(网络软件)●游戏●构思实现,产品早期原型和迭代3. Python2.x和Python3.x的区别如下:(1)在python2.x中,输出数据使用的是print语句。
但是在python3.x中,print语句没有了,取而代之的是print()函数(2)python2有ASCII Str()类型,unicode()是单独的,不是byte类型。
在python3.x版本的源代码中,默认使用的是UTF-8编码,从而可以很好的支持中文字符。
(3)在python 2.x中,使用运算符/进行除法运算,整数相除的结果是一个整数,浮点数除法会保留小数点的部分得到一个浮点数的结果。
在python 3.x 中使用运算符/进行除法,整数之间的相除,结果也会是浮点数。
(4)相比python2.x版本,python3.x版本在异常方面有很多改变:▪在python2.x版本,所有类型的对象都是直接被抛出的,但是,在python3.x版本中,只有继承自BaseException的对象才可以被抛出。
▪在python2.x版本中,捕获异常的语法是except exc,var。
在python3.x版本中,引入了as关键字,捕获异常的语法变更为except exc as var。
▪在python2.x版本中,处理异常使用raise Exception(args)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Javascript学习---2、执行环境,作用域
作者:名刘天下来源:博客园发布时间:2010-12-10 17:03 阅读:155 次原文链接[收藏]在javascript的学习中,执行环境、作用域是2个非常非常重要和基本的概念,理解了这2个概念对于javsacript中很多脚本的运行结果就能明白其中的道理了,比如搞清作用域和执行环境对于闭包的理解至关重要。
一、执行环境(exection context,也有称之为执行上下文)
所有JavaScript 代码都是在一个执行环境中被执行的。
执行环境是一个概念,一种机制,用来完成JavaScript运行时在作用域、生存期等方面的处理,它定义了变量或函数是否有权访问其他数据,决定各自行为。
在javascript中,可执行的JavaScript代码分三种类型:
1. Global Code,即全局的、不在任何函数里面的代码,例如:一个js文件、嵌入在HTML页面中的js代码等。
2. Eval Code,即使用eval()函数动态执行的JS代码。
3. Function Code,即用户自定义函数中的函数体JS代码。
不同类型的JavaScript代码具有不同的执行环境,这里我们不考虑evel code,对应于global code和function code存在2种执行环境:全局执行环境和函数执行环境。
在一个页面中,第一次载入JS代码时创建一个全局执行环境,全局执行环境是最外围的执行环境,在Web浏览器中,全局执行环境被认为是window对象。
因此,所有的全局变量和函数都是作为window对象的属性和方法创建的。
当调用一个JavaScript 函数时,该函数就会进入与该函数相对应的执行环境。
如果又调用了另外一个函数(或者递归地调用同一个函数),则又会创建一个新的执行环境,并且在函数调用期间执行过程都处于该环境中。
当调用的函数返回后,执行过程会返回原始执行环境。
因而,运行中的JavaScript 代码就构成了一个执行环境栈。
function Fn1(){
function Fn2(){
alert(document.body.tagName);//BODY
//other code...
}
Fn2();
}
Fn1();
//code here
(图1 执行环境栈摘自:笨蛋的座右铭的博文)
程序在进入每个执行环境的时候,JavaScript引擎在内部创建一个对象,叫做变量对象(Variable Object)。
对应函数的每一个参数,在Variable Object上添加一个属性,属性的名字、值与参数的名字、值相同。
函数中每声明一个变量,也会在Variable Object上添加一个属性,名字就是变量名,因此为变量赋值就是给Variable Object 对应的属性赋值。
在函数中访问参数或者局部变量时,就是在variable Object上搜索相应的属性,返回其值。
(另外注意:一般情况下Variable Object是一个内部对象,JS 代码中无法直接访问。
规范中对其实现方式也不做要求,因此它可能只是引擎内部的一种数据结构。
)
大致处理方式就这样,但作用域的概念不只这么简单,例如函数体中可以使用全局变量、函数嵌套定义时情况更复杂点。
这些情况下怎样处理?JavaScript引擎将不同执行位置上的Variable Object按照规则构建一个链表,在访问一个变量时,先在链表的第1个Variable Object上查找,如果没有找到则继续在第2个Variable Object上查找,直到搜索结束。
这就是Scope/Scope Chain的大致概念。
二、Scope/Scope Chain(作用域/作用域链)
当代码在一个环境中执行时,都会创建基于Variable Object的一个作用域链。
作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。
整个作用域链是由不同执行位置上的Variable Object按照规则所构建一个链表。
作用域链的最前端,始终是当前正在执行的代码所在环境的Variable Object。
如果这个环境是函数(比如Fn2),则将其活动对象(activation object)作为变量对象。
活动对象在最开始时只包含一个变量,就是函数内部的arguments对象。
作用域链中的下一个Variable Object来自该函数(Fn2)的包含环境(也就是Fn1),而再下一个Variable object来自再下一个包含环境。
这样,一直延续到全局执行环境,全局执行环境的Variable Object始终是作用域链中的最后一个对象。
如上所述,作用域链感觉就是一个Variable Object链表,当访问一个变量时,先在链表的第一个Variable Object(最前端)上查找,如果没有找到则继续在第二个Variable Object上查找,直到搜索结束,也就是搜索到全局执行环境的Variable Object中。
这也就形成了Scope Chain的概念。
与上面Code1代码对应的作用域链图如下所示(摘自:笨蛋的座右铭的博文,这个图感觉不是很理想,不如下面的图3更形象,把右侧这部分调个个就好了。
)
(图2 作用域链图)
如上图所示,对于Code1代码中的函数Fn2所对应的作用域链为:Fn2 Variable Object->Fn1 variable Object->全局对象。
也就是说,在Fn2函数中进行变量访问时,首先会在Fn2 Variable object访问内进行寻找,如果没有找到,则向上,搜索Fn1 Variable Object中是否存在,直至找到,停止搜索。
再拿《javascript高级程序设计第二版》中提到的例子来说明一下。
代码如下所示:
在Code2代码中,涉及3个执行环境全局环境、changecolor函数的局部环境和swapcolor局部环境。
该段代码的作用域链如下图所示。
(图3摘自:《javascript高级程序设计第二版》)
上图中,
∙-》全局环境有1个变量color和1个函数changecolor()。
∙-》changecolor()函数的局部环境中具有1个anothercolor属性和1个swapcolors函数,当然,changecolor函数中可以访问自身以及它外围(也
就是全局环境)中的变量。
∙-》swapcolor()函数的局部环境中具有1个变量tempcolor。
在该函数内部可以访问上面的2个环境(changecolor和window)中的所有变量,因为那2个环境都是它的父执行环境。
通过上面的分析,我们可以得知内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。
这些环境之间是线性、有次序的。
每个环境都可以向上搜索作用域链,以便查询变量和函数名;但任何环境不能通过向下搜索作用域链条而进入另一个执行环境。
对于上述例子的swapcolor()函数而言,其作用域链包括:swapcolor()的变量对象、changecolor()变量对象和全局对象。
swapcolor()的局部环境开始先在自己的Variable Object中搜索变量和函数名,找不到,则向上搜索changecolor作用域链。
以此类推。
但是,changecolor()函数是无法访问swapcolor中的变量。
关于作用域总结以下几条:
1、javascript没有块级作用域。
上述代码运行后会返回10,为什么呢?如果是同样的java或是c#代码,则不会是10,可能会提示运行错误,因为i只存在于for循环体重,在运行完for循环后,for 中的所有变量就被销毁了。
而在javascript中则不是这样的,在for中的变量声明将会
添加到当前的执行环境中(这里是全局执行环境),因此在for循环完后,变量i依旧存在于循环外部的执行环境。
因此,会输出10。
2、声明变量
使用var声明变量时,这个变量将被自动添加到距离最近的可用环境中。
对于函数而言,自然声明的变量就会被添加到函数的局部环境中,变量在整个函数环境内都是可用的。
但是,如果变量没有是用var进行声明,将会被添加到全局环境,也就是说成位全局变量了。
所以在函数体内,进行声明时,一般要在开头用var进行声明。
最后出几个小例题:
为什么会是代码中所说明的结果呢?
我认为和2个事情有关:作用域和预解析。
我们可以很容易得出上述代码的作用域链。
window全局环境和rain()函数局部环境。
window全局环境中存在全局变量x 和rain,而rain()函数的局部环境中包括:局部变量x。
因此,在执行rain()函数时,不可能去访问全局变量x的了,因为在当前的rain()函数内已经有局部变量x。
所以alert出1,
但为什么第一次alert出undefined呢?这可能和预解析有关。
在代码执行时,首先会解析出变量和函数的定义,上述代码等价于下面的代码。