Loading

Javascript 变量

有 3 个关键字可以声明变量: var 、 const 和 let。

变量可以用于保存任何类型的数据。

var 关键字

var message; //不初始化的情况下,变量会保存一个特殊值 undefined
var message = "hi"; // 声明并且初始化变量

var 声明作用域

使用 var 操作符定义的变量会成为包含它的函数的局部变量

function test() {
  var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错!

在函数内定义变量时省略 var 操作符,可以创建一个全局变量

function test() {
  message = "hi"; //  全局变量
}
test();
console.log(message); // "hi"

虽然可以通过省略 var 操作符定义全局变量,但不推荐这么做。在局部作用域中定
义的全局变量很难维护,在严格模式下,如果像这样给未声明的变量赋值,则会导致抛出 ReferenceError 。

一次定义多个变量

var message = "hi",
    found = false,
    age = 29;

声明提升(hoist)

function foo() {
  console.log(age);
  var age = 26;
}
foo(); // undefined

上一段不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:

即,把所有变量声明提升到作用域顶部

function foo() {
    var age;
    console.log(age);
    age = 26;
}
foo(); // undefined

因此多次声明同一个变量也没有问题

function foo() {
    var age = 16;
    var age = 26;
    var age = 36;
    console.log(age);
}
foo(); // 36

let 关键字

let 声明的范围是块作用域

var 声明的范围是函数作用域。

块作用域是函数作用域的子集.

if (true) {
    var name = 'Matt';
    console.log(name); // Matt
}
console.log(name); // Matt
if (true) {
    let age = 26;
    console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义

let 不允许同一个块作用域中出现冗余声明

var name;
var name; // 不会报错

let age;
let age; // SyntaxError;标识符 age 已经声明过了

嵌套使用相同的标识符不会报错

let age = 30; // 作用域是整个块
console.log(age); // 30
if (true) {
    let age = 26; // 作用域是if块
    console.log(age); // 26
}

这两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在

var name;
let name; // SyntaxError
let age;
var age; // SyntaxError

let 不会提升(hoist)

console.log(age); // ReferenceError:age 没有定义
let age = 26;

let 全局作用域声明不会成为 window 对象

var 声明的变量会成为 window 对象的属性

var name = 'Matt';
console.log(window.name); // 'Matt'

let age = 26;
console.log(window.age); // undefined

let 不能条件声明

<script>
	var name = 'Nicholas';
	let age = 26;
</script>
<script>
	// 假设脚本不确定页面中是否已经声明了同名变量
	// 那它可以假设还没有声明过
	var name = 'Matt';
	// 这里没问题,因为可以被作为一个提升声明来处理
	// 不需要检查之前是否声明过同名变量
	let age = 36;
	// 如果 age 之前声明过,这里会报错
</script>

对于 let 这个新的 ES6 声明关键字,不能依赖条件声明模式

<script>
	let name = 'Nicholas';
	let age = 36;
</script>
<script>
	// 假设脚本不确定页面中是否已经声明了同名变量
	// 那它可以假设还没有声明过
	if (typeof name === 'undefined') {
		let name;
	}
	// name 被限制在 if {} 块的作用域内
	// 因此这个赋值形同全局赋值
	name = 'Matt';
	try {
		console.log(age); // 如果 age 没有声明过,则会报错
	}
	catch(error) {
	let age;
	}
	// age 被限制在 catch {}块的作用域内
	// 因此这个赋值形同全局赋值
	age = 26;
</script>

for 循环中的 let 声明不会渗透到循环体外部

for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5

for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义

const 声明

  • const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量

  • 尝试修改 const 声明的变量会导致运行时错误

const age = 26;
age = 36; // TypeError: 给常量赋值
  • const 声明的限制只适用于它指向的变量的引用。如果 const 变量引用的是一个对象,那么修改这个对象内部的属性并不违反 const 的限制
const person = {};
person.name = 'Matt'; // ok
  • 不能用 const 来声明迭代变量(因为迭代变量会自增)
for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值
  • 如果你只想用 const 声明一个不会被修改的 for 循环变量,那也是可以的。也就是说,每次迭代只是创建一个新变量
let i = 0;
for (const j = 7; i < 5; ++i) {
    console.log(j);
}
// 7, 7, 7, 7, 7

for (const key in {a: 1, b: 2}) {
    console.log(key);
}
// a, b

for (const value of [1,2,3,4,5]) {
    console.log(value);
}
// 1, 2, 3, 4, 5

关键字使用原则

  1. 不使用 var
  2. const 优先, let 次之

使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发者认为应该优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。

本文是JavaScript高级程序设计(第四版)学习笔记

posted @ 2020-12-29 20:29  大台灯  阅读(145)  评论(0编辑  收藏  举报