var message
定义了一个名为message的变量,可以保存任何类型的值(不初始化的情况下,变量会保存一个特殊值undefined)。
var message = 'hi'
给message赋值以后,不仅能改变保存的值,还可以改变值的类型。(不推荐)
使用var操作符定义的变量会成为包含它的函数的局部变量。比如,使用var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁。
function test() {
var message = "hi"; // 局部变量
mess = "hi"; // 全局变量
}
test()
console.log(message,mess) // message报错,mess成功输出
关键字声明的变量会自动提升到函数作用域顶部,var重复声明也没有问题。
function foo() {
// var age 声明提升到了这里
console.log(age);
var age = 26;
}
foo(); // undefined 这里不会报错,因为age的声明被提升.
在let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError
console.log(message) // 报错
let message = "hi"
let与var最大的区别是,let声明的范围是块作用域,而var声明的范围是函数作用域。let不允许重复声明。
函数作用域 > 块作用域
// if是块作用域,非函数作用域,var出了块作用域不会被销毁。
if (true) {
var name = 'Matt';
console.log(name); // Matt
let age = 26;
console.log(age); // 26
}
console.log(name); // Matt
console.log(age); // ReferenceError: age没有定义
使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)
var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined
是用var定义for循环的迭代变量会渗透到循环体外部
for (var i = 0; i < 5; ++i) { // 循环逻辑
}
console.log(i); // 5
var没有块作用域
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
实际输出5,5,5,5,5
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
实际输出1,2,3,4,5
由于var无块级作用域,JS中当同步和异步代码同时存在时,异步代码会在同步代码全部执行完成后再调用。而setTimeout就是异步代码(就算延迟为零也是异步),它会在代码最后执行。所以是for循环执行完以后,再去settimeout()。
同样如果在for循环中嵌套function(),程序是顺序执行的,所以function这种复杂数据类型会存在堆里面,当for循环执行完了函数才开始被调用。
函数立即执行,可以避免这种情况
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
var btns = document.getElementsByTagName('button');
for(var i=0; i<btns.length; i++){
(function(num){
btns[i].addEventListener('click',function(){
console.log('第' + num + '个按钮被点击')
})
})(i)
}