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决定块作用域

letconst创建的变量只在块作用域中有效。它们只存于包含它们的块中。下面演示的代码,通过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 解析步骤,易于我们理解。


谢谢你阅读到了最后~
期待你关注、收藏、评论、点赞~
让我们一起 变得更强

参考
JavaScript 作用域

推荐阅读
理解js中this的指向(几条规则加例子+call,apply,bind改变this指向)

猜你喜欢

转载自blog.csdn.net/weixin_42752574/article/details/110661818