JavaScript中的变量范围是什么?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中的变量范围是什么?相关的知识,希望对你有一定的参考价值。
javascript中的变量范围是什么?它们的内部是否与函数外部相同?或者甚至重要吗?另外,如果变量是全局定义的,那么它们存储在哪里?
我认为我能做的最好的事情就是给你一些学习的例子。 Javascript程序员实际上根据他们理解范围的程度来排名。它有时可能非常违反直觉。
- 全局范围的变量
// global scope var a = 1; function one() { alert(a); // alerts '1' }
- 本地范围
// global scope var a = 1; function two(a) { // passing (a) makes it local scope alert(a); // alerts the given argument, not the global value of '1' } // local scope again function three() { var a = 3; alert(a); // alerts '3' }
- 中级:没有JavaScript中的块范围(ES5; ES6引入
let
) 一个。var a = 1; function four() { if (true) { var a = 4; } alert(a); // alerts '4', not the global value of '1' }
湾var a = 1; function one() { if (true) { let a = 4; } alert(a); // alerts '1' because the 'let' keyword uses block scoping }
- 中级:对象属性
var a = 1; function Five() { this.a = 5; } alert(new Five().a); // alerts '5'
- 高级:关闭
var a = 1; var six = (function() { var a = 6; return function() { // JavaScript "closure" means I have access to 'a' in here, // because it is defined in the function in which I was defined. alert(a); // alerts '6' }; })();
- 高级:基于原型的范围解析
var a = 1; function seven() { this.a = 7; } // [object].prototype.property loses to // [object].property in the lookup chain. For example... // Won't get reached, because 'a' is set in the constructor above. seven.prototype.a = -1; // Will get reached, even though 'b' is NOT set in the constructor. seven.prototype.b = 8; alert(new seven().a); // alerts '7' alert(new seven().b); // alerts '8'
- 全球+本地:一个额外复杂的案例
var x = 5; (function () { console.log(x); var x = 10; console.log(x); })();
这将打印出undefined
和10
而不是5
和10
,因为JavaScript总是将变量声明(不是初始化)移动到作用域的顶部,使得代码等效于:var x = 5; (function () { var x; console.log(x); x = 10; console.log(x); })();
- Catch子句范围的变量
var e = 5; console.log(e); try { throw 6; } catch (e) { console.log(e); } console.log(e);
这将打印出5
,6
,5
。在catch子句中,e
会影响全局变量和局部变量。但是这个特殊范围仅适用于捕获的变量。如果你在catch子句中写var f;
,那么它就像你在try-catch块之前或之后定义它一样。
我发现许多刚接触JavaScript的人很难理解默认情况下语言中的继承是可用的,到目前为止,函数范围是唯一的范围。我为去年年底写的一个名为JSPretty的美化家提供了扩展。功能颜色代码中的函数范围,并始终将颜色与该范围中声明的所有变量相关联。当在不同范围内使用具有来自一个范围的颜色的变量时,可视地演示闭合。
尝试以下功能:
观看演示:
查看以下代码:
- http://prettydiff.com/lib/jspretty.js
- https://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js
目前,该功能支持深度为16的嵌套函数,但目前不对全局变量着色。
JavaScript只有两种类型的范围:
- 全局范围:全局只不过是一个窗口级别的范围。这里,整个应用程序中存在变量。
- 功能范围:使用
var
关键字在函数内声明的变量具有功能范围。
无论何时调用函数,都会创建一个变量范围对象(并包含在范围链中),后面跟着JavaScript中的变量。
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
范围链 - >
- 窗口级别 -
a
和outer
函数在范围链中处于顶层。 - 当外部函数称为新的
variable scope object
(并包含在范围链中)时,在其中添加了变量b
。
现在当变量a
需要它时,它首先搜索最近的变量范围,如果变量不存在,则移动到变量范围链的下一个对象。在这种情况下,它是窗口级别。
只是为了添加其他答案,范围是所有声明的标识符(变量)的查找列表,并强制执行一组严格的规则,以确定当前执行的代码如何访问它们。该查找可以用于分配给变量的目的,该变量是LHS(左手侧)参考,或者它可以用于检索其值,即RHS(右手侧)参考。这些查找是JavaScript引擎在编译和执行代码时在内部执行的操作。
所以从这个角度来看,我认为一张图片可以帮助我在Kyle Simpson的Scopes and Closures电子书中找到:
引用他的电子书:
该建筑代表我们程序的嵌套范围规则集。无论您身在何处,建筑的第一层代表您当前执行的范围。建筑的顶层是全球范围。您可以通过查看当前楼层来解决LHS和RHS参考,如果找不到,请将电梯带到下一层,然后查看下一层,依此类推。一旦你到达顶层(全球范围),你要么找到你要找的东西,要么找不到。但你不得不停下来。
值得一提的是,“一旦找到第一场比赛,范围查找就会停止”。
这种“范围级别”的概念解释了为什么“这个”可以用新创建的范围进行更改,如果它是在嵌套函数中查找的话。这是一个链接,所有这些细节,Everything you wanted to know about javascript scope
运行代码。希望这会给出一个关于范围界定的想法
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"
Local Scope : " + Name +
"
Object Scope : " + this.Name +
"
Current document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
全球范围:
全局变量与全球明星(成龙,纳尔逊曼德拉)完全一样。您可以从应用程序的任何部分访问它们(获取或设置值)。全球活动就像全球活动(新年,圣诞节)。您可以从应用程序的任何部分执行(调用)它们。
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
本地范围:
如果你在美国,你可能会认识Kim Kardashian,臭名昭着的名人(她不知何故设法制作小报)。但美国以外的人不会认出她。她是当地的明星,与她的领土相连。
局部变量就像本地恒星。您只能在范围内访问它们(获取或设置值)。本地函数就像本地事件 - 您只能在该范围内执行(庆祝)。如果要从作用域外部访问它们,则会出现引用错误
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
Check this article for in-depth understanding of scope
ALMOST只有两种类型的JavaScript范围:
- 每个var声明的范围与最直接封闭的函数相关联
- 如果var声明没有封闭函数,则它是全局范围
因此,除函数之外的任何块都不会创建新范围。这解释了为什么for循环覆盖外部范围变量:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
使用函数代替:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
在第一个示例中,没有块作用域,因此最初声明的变量被覆盖。在第二个示例中,由于函数有一个新的作用域,因此最初声明的变量是SHADOWED,而不是被覆盖。
除了以下内容之外,您几乎只需要知道JavaScript范围;
- try / catch仅为异常变量本身引入新范围,其他变量没有新范围
- with-clause显然是另一个例外,但是使用with-clause它非常气馁(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)
所以你可以看到JavaScript范围实际上非常简单,尽管并不总是直观的。有几点需要注意:
- var声明被提升到范围的顶部。这意味着无论var声明发生在何处,对于编译器来说就像var本身发生在顶部一样
- 组合了同一范围内的多个var声明
所以这段代码:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
相当于:
var i = 1;
function abc() {
var i; // var declaration moved to t以上是关于JavaScript中的变量范围是什么?的主要内容,如果未能解决你的问题,请参考以下文章