用来定义变量或常量
var username = 'Alex';
let age = 18;
const sex = 'male';
console.log(username,age,sex);
let和const区别
var、let定义变量,初始化后还可重新赋值
const 定义常量,初始化后不能重新赋值
const 定义常量
适用于初始化后不希望重新赋值
例如:性别
若重新赋值则会报错,语法上杜绝问题的发生
定义和赋值必须同时
错误
const sex;
sex='male';
正确
const sex='male'
复杂数据类型可修改值
复杂/引用数据类型不是以重新赋值方式修改值
而是找到对象的属性,改变属性值
const person = {
username: 'Alex'
};
person.username = 'ZhangSan';
基本数据类型不可修改值
基本数据类型是以重新赋值方式修改值
const sex = 'male';
sex = 'female';//报错
let和const特点
不允许重复定义
重复声明:已经存在的变量或常量,又声明了一遍;
var允许重复声明
错误示例1
let a = 1;
let a = 2;
错误示例2
function func(a) {
let a = 1;
}
func();
不存在变量提升
var存在变量提升
console.log(a);//报错:a未初始化
let a = 1;
有块级作用域
for (let i = 0; i < 3; i++) {
console.log(i); //0 1 2
}
console.log(i);//报错:i未定义
var 无块级作用域,定义的变量存在于全局中
for (var i = 0; i < 3; i++) {
console.log(i); //0 1 2
}
console.log(i);//3
不会自动变成window对象的属性和方法
let age = 18;
const add = function () { }
console.log(window.age === age);//false
console.log(window.add === add);//false
全局作用域中, var声明的变量会自动变成window对象的属性,
声明的函数会自动变成window对象的方法;
var age = 18;
function add() { }
console.log(window.age === age);//ture
console.log(window.add === add);//ture
暂时性死区
声明的变量/常量会‘绑定’该区域,使变量或常量不受外部作用域影响
let a = 1;
function func() {
console.log(a);//报错:未初始化a;
//不会去函数外的全局中找变量a
let a = 2
}
func();
块级作用域常见类型
一般来讲,存在{},比如:
1){}
2)循环语句:for(){},while(){},do{}while()
3)条件语句:if(){},switch(){}
特别地,
1)函数:function(){}构成函数作用域
2)对象:const person={}不构成任何作用域,其中方法构成函数作用域
立即执行函数(function 函数名{})() 可模拟模拟块级作用域
作用域链-查找变量的顺序
内层作用域-外层作用域-…-全局作用域
function func() {
for (let i = 0; i < 3; i++) {
console.log(i);//0 1 2
}
}
func();
console.log(i);// 报错:i未定义
应用-块级作用域
问题:点击0,1,2这3个按钮后输出都是3,如何使其对应呢
<button class="btn">0</button>
<button class="btn">1</button>
<button class="btn">2</button>
<script>
var btns = document.getElementsByClassName('btn');
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log(i);
}, false);
}
</script>
解析:
1)var声明的变量是全局的,代码按顺序执行后i = 3
2)点击按钮触发事件,调用函数,形成一个个函数作用域
但函数作用域其中都没有定义i,故输出的i是全局的值
方法一:IIFE模拟块级作用域
var btns = document.getElementsByClassName('btn');
for (var i = 0; i < btns.length; i++) {
(function (index) {
btns[index].addEventListener('click', function () {
console.log(index);
}, false);
})(i);
}
原理:
1)立即执行函数IIFE
触发事件后,调用第一层函数(点击事件函数),形成了第一层函数作用域;
012通过i分别传入参数index,调用第二层函数IIFE,形成第二层函数作用域
2)函数作用域链(闭包)
console.log(index);从当前层开始,逐层向上寻找index,在IIFE函数作用域找到
方法二:let和const有块级作用域
let btns = document.getElementsByClassName('btn');
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log(i);
}, false);
}
原理:
1)let和const有块级作用域
for循环对应形成3个块级作用域,对应i的值分别为0,1,2
2)函数作用域链
触发事件,调用第一层函数(点击事件函数),形成了第一层函数作用域;
console.log(i);从当前层开始,逐层向上寻找i,在for循环的块级作用域找到了