javascript中变量的范围是什么?它们在函数内部的作用域与在函数外部的作用域相同吗?或者这有关系吗?此外,如果变量是全局定义的,那么变量存储在哪里?
当前回答
现代J、ES6+、“const”和“let”
您应该像大多数其他主要语言一样,为创建的每个变量使用块范围。var已过时。这使您的代码更安全,更易于维护。
95%的病例应使用常量。它使变量引用不能更改。数组、对象和DOM节点财产可以更改,并且应该是常量。
let应该用于任何期望重新分配的变量。这包括在for循环中。如果在初始化之后更改值,请使用let。
块范围意味着变量只能在声明它的括号内使用。这扩展到内部范围,包括在范围内创建的匿名函数。
其他回答
运行代码。希望这能提供一个关于范围界定的想法
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 +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
我发现许多新接触JavaScript的人很难理解继承在默认情况下在语言中是可用的,而函数作用域是迄今为止唯一的作用域。我为去年年底我写的一个名为JSprety的美化者提供了一个扩展。功能为代码中的函数范围着色,并始终将颜色与该范围中声明的所有变量相关联。当在不同的范围中使用来自一个范围的颜色的变量时,可以直观地演示闭包。
尝试以下功能:
http://prettydiff.com/jspretty.xhtml?c=white&jsscope
观看演示:
http://prettydiff.com/jspretty.xhtml?c=white&jsscope&s=http://prettydiff.com/lib/markup_beauty.js
在以下位置查看代码:
http://prettydiff.com/lib/jspretty.jshttps://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js
目前,该功能支持深度为16个嵌套函数,但目前不为全局变量着色。
老式JavaScript
传统上,JavaScript实际上只有两种类型的作用域:
全局范围:从应用程序开始,变量在整个应用程序中都是已知的(*)函数作用域:变量在声明它们的函数中是已知的,从函数开始(*)
我不会详细说明这一点,因为已经有许多其他答案可以解释这一差异。
现代JavaScript
最新的JavaScript规范现在还允许第三个范围:
块作用域:标识符从其声明的作用域的顶部开始“已知”,但在其声明的行之后才能分配或取消引用(读取)。这一过渡时期被称为“时间死区”
如何创建块范围变量?
传统上,您可以这样创建变量:
var myVariable = "Some text";
块范围变量的创建方式如下:
let myVariable = "Some text";
那么,功能范围和块范围之间的区别是什么?
要了解功能范围和块范围之间的区别,请考虑以下代码:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
在这里,我们可以看到变量j只在first for循环中知道,而在前后都不知道。然而,我们的变量i在整个函数中是已知的。
此外,考虑到块范围的变量在声明之前是未知的,因为它们没有被提升。也不允许在同一块内重新声明同一块范围内的变量。这使得块作用域变量比全局或函数作用域变量更不容易出错,这些变量被提升,在多个声明的情况下不会产生任何错误。
现在使用块范围变量安全吗?
今天使用它是否安全取决于您的环境:
如果您正在编写服务器端JavaScript代码(Node.js),则可以安全地使用let语句。如果您正在编写客户端JavaScript代码并使用基于浏览器的转译器(如Traceur或babel standalone),则可以安全地使用let语句,但是您的代码在性能方面可能不是最佳的。如果您正在编写客户端JavaScript代码并使用基于节点的转译器(如traceur shell脚本或Babel),则可以安全地使用let语句。而且,由于您的浏览器将只知道转译的代码,因此性能缺陷应该受到限制。如果您正在编写客户端JavaScript代码,而不使用转译器,则需要考虑浏览器支持。以下是一些根本不支持let的浏览器:Internet explorer 10及以下Firefox 43及以下Safari 9及以下Android浏览器4及以下版本Opera 27及以下Chome 40及以下Opera Mini和黑莓浏览器的任何版本
如何跟踪浏览器支持
有关阅读此答案时哪些浏览器支持let语句的最新概述,请参阅“我可以使用”页面。
(*)全局和函数范围的变量可以在声明之前初始化和使用,因为JavaScript变量被提升。这意味着声明总是位于范围的顶部。
全局声明的变量具有全局范围。在函数中声明的变量的作用域是该函数,并隐藏同名的全局变量。
(我相信真正的JavaScript程序员可以在其他答案中指出许多微妙之处。特别是我在这个页面上看到了这到底意味着什么。不过,希望这个更为介绍性的链接足以让你开始。)
ECMAScript 6引入了let和const关键字。这些关键字可以用来代替var关键字。与var关键字相反,let和const关键字支持在块语句中声明局部范围。
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
推荐文章
- AngularJS:工厂和服务?
- js:将一个组件包装成另一个组件
- 父ng-repeat从子ng-repeat的访问索引
- JSHint和jQuery: '$'没有定义
- 模仿JavaScript中的集合?
- 用JavaScript验证电话号码
- 如何在HTML5中改变视频的播放速度?
- 谷歌地图API v3:我可以setZoom后fitBounds?
- 在Bash中传递带有空格的字符串作为函数参数
- ES6/2015中的null安全属性访问(和条件赋值)
- 在R函数中指定可选参数的“正确”方法
- 与push()相反;
- JS字符串“+”vs concat方法
- AngularJS使用ng-class切换类
- 访问Handlebars.js每次循环范围之外的变量