JavaScript 作用域
你越是认真生活,你的生活就会越美好
——弗兰克·劳埃德·莱特
《人生果实》经典语录
JavaScript 作用域
作用域
是可访问变量
的集合。
在 JavaScript 中, 对象和函数
同样也是变量。
在 JavaScript 中, 作用域为可访问变量,对象,函数的集合
。
JavaScript 函数作用域
: 作用域在函数内修改。
JavaScript 局部作用域
变量在函数内声明
,变量为局部作用域。
局部变量:只能在函数内部访问
。
// 此处不能调用 carName 变量
function myFunction() {
var carName = "Volvo";
// 函数内可调用 carName 变量
}
因为局部变量
只作用于函数内
,所以不同的函数
可以使用相同名称的变量
。
局部变量
在函数开始执行时创建,函数执行完后
局部变量会自动销毁
。
JavaScript 全局变量
变量在函数外
定义,即为全局变量
。
全局变量有全局作用域
: 网页中所有脚本
和函数均可使用。
var carName = " Volvo";
// 此处可调用 carName 变量
function myFunction() {
// 函数内可调用 carName 变量
}
如果变量在函数内没有声明
(没有使用 var 关键字),该变量为全局变量
。
以下实例中 carName 在函数内,但是为全局变量。
function myFunction() {
carName = "Volvo";
// 此处可调用 carName 变量
}
myFunction()
// 此处可调用 carName 变量 前提是myFunction函数执行过
console.log(carName) // Volvo
JavaScript 变量生命周期
JavaScript 变量生命周期
在它声明时初始化
。
局部变量
在函数执行完毕后销毁
。
全局变量
在页面关闭后销毁
。
函数参数
函数参数
只在函数内
起作用,是局部变量
。
HTML 中的全局变量
在 HTML 中, 全局变量是 window 对象: 所有数据变量都属于 window 对象。
function myFunction() {
carName = "Volvo";
}
myFunction()
//此处可使用 window.carName
console.log(window.carName)
PS:
你的全局变量,或者函数,可以覆盖 window 对象的变量或者函数。
局部变量,包括 window 对象可以覆盖全局变量和函数。
ES6中的变量和作用域
通过let和const决定块作用域
let
和const
创建的变量只在块作用域中
有效。它们只存于包含它们的块中。下面演示的代码,通过let在if语句块中声明一个tmp变量。这个变量仅在if语句中有效。
function func() {
if (true) {
let tmp = 123;
console.log(tmp); // => 123
}
}
func() // 123
console.log(tmp); // => ReferenceError: tmp is not defined
相比之下,var声明的变量
作用域的范围是函数范围内
的:
function func() {
console.log(tmp) // undefined 变量声明提升 还没赋值
if (true) {
var tmp = 123
console.log(tmp) // 123
}
console.log(tmp) // 123
}
func()
console.log(tmp) // Uncaught ReferenceError: tmp is not defined
块作用域意味着你可在有函数内有变量的阴影。
function func() {
let foo = 5;
console.log(foo) // 5
if(true) {
let foo = 10;
console.log(foo) // 10
}
console.log(foo) // 5
}
func()
const创建不可变的变量
由let
创建的变量是可变的:
let foo = 'abc'
foo = 'def'
console.log(foo) // def
由const
创建的是变量是一个常量
,这个变量是不可变
的:
const foo = 'abc'
foo = 'def' // Uncaught TypeError: Assignment to constant variable.
如果一个常量指的是一个对象
,那么const并不影响常量本身的值
是否是可变的,因为它总是指向那个对象,但是对象本身仍然是可以被改变的。
const obj = {
}
obj.prop = 123
console.log(obj.prop) // 123
console.log(obj) // {prop: 123}
obj = {
} // Uncaught TypeError: Assignment to constant variable.
如果你想让obj
真正成为一个常量
,你必须冻结它的值
:
const obj = Object.freeze({
});
obj.prop = 123;
console.log(obj) // {}
也就是说,如果const定义
的常量指向的是一个对象。这个时候,它实际上指向的是当前对象的地址。这个地址是在栈里面的,而这个真实的对象是在堆栈里面的。所以,我们使用const定义这个对象后,是可以改变对象的内容的。但是这个地址是不可以改变的
。意思也就是不可以给这个对象重新赋值,比如const obj= {}, obj = {}
,即使是这样,obj好像什么也没有改变,但还是错误的。
然而在普通模式
下,并没有报错,而obj.name = 'abc’这是完全可以的。这跟JavaScript存储引用对象的值的方式有密切的关系。
const obj = Object.freeze({
})
const newObj = {
}
obj.name = 'w3cplus'
newObj.name = 'damo';
console.log(obj) // {}
console.log(newObj) // {name: "damo"}
使用Babel把上面ES6的代码编译成ES5代码:
'use strict';
var obj = Ob
JavaScript 变量提升
-
JavaScript 中,
函数及变量的声明
都将被提升到函数的最顶部
。 -
JavaScript 中,
变量可以在使用后声明
,也就是变量可以先使用再声明
。 -
类
不存在变量提升
以下两个实例将获得相同的结果:
例子1
x = 5; // 变量 x 设置为 5
elem = document.getElementById("demo"); // 查找元素
elem.innerHTML = x; // 在元素中显示 x
var x; // 声明 x
例子2
var x; // 声明 x
x = 5; // 变量 x 设置为 5
console.log(x) // 5
要理解以上实例就需要理解 “hoisting(变量提升)
”。
变量提升
:函数声明
和变量声明
总是会被解释器悄悄地被"提升"到方法体的最顶部
。
类
不存在变量提升
new Foo() // Uncaught ReferenceError: Foo is not defined
class Foo {
}
JavaScript 初始化不会提升
JavaScript 只有声明的变量会提升,初始化的不会。
实例1
var x = 5; // 初始化 x
var y = 7; // 初始化 y
console.log(x) // 5
console.log(y) // 7
实例2
var x = 5; // 初始化 x
console.log(x) // 5
console.log(y) // undefined
var y = 7; // 初始化 y
实例 2 的 y 输出了 undefined,这是因为变量声明 (var y) 提升了,但是初始化(y = 7) 并不会提升,所以 y 变量是一个未定义的变量。
实例 2 类似以下代码:
var x = 5; // 初始化 x
var y; // 声明 y
console.log(x) // 5
console.log(y) // undefined
y = 7; // 设置 y 为 7
在头部声明你的变量
对于大多数程序员来说并不知道 JavaScript 变量提升
。
如果程序员不能很好的理解变量提升,他们写的程序就容易出现一些问题。
为了避免这些问题,通常我们在每个作用域开始前声明
这些变量,这也是正常的 JavaScript 解析步骤,易于我们理解。
谢谢你阅读到了最后~
期待你关注、收藏、评论、点赞~
让我们一起 变得更强