1.常量
ES6新增:自定义常量
const 常量名称 = 常量取值; //常量一经定义不可修改
const NUM = 666;
console.log(NUM); // 666
2.变量
ES6之前:var 变量名;
- 如果定义了同名变量,则后定义的变量会覆盖先定义的变量
<script>
var num = 1;
var num = 2;
console.log(num) //2
</script>
- 可以先使用变量,再定义变量(预解析)
<script>
console.log(num);
var num = 123;
预处理之后的代码:
var num;
console.log(num); // undefined
num = 123;
</script>
ES6之后:let 变量名;
- 不能重复定义同名变量
let num =1;
let num =2;//报错:Identifier 'num' has already been declared
- 不能先使用变量,再定义变量(不会预解析)
console.log(num)
let num =1;//Cannot access 'num' before initialization
3.预解析
由于JavaScript是一门解释型的语言, 会边解析边执行, 浏览器在解析JavaScript代码之前还会进行一个操作–预解析(预处理)
预解析(预处理)步骤:
将当前JavaScript代码中所有变量的定义和函数的定义放到所有代码的最前面
<script>
/*
1.什么是预解析?
浏览器在执行JS代码的时候会分成两部分操作:预解析以及逐行执行代码
也就是说浏览器不会直接执行代码, 而是加工处理之后再执行,
这个加工处理的过程, 我们就称之为预解析
2.预解析规则
2.1将变量声明和函数声明提升到当前作用域最前面
2.2将剩余代码按照书写顺序依次放到后面
3.注意点
通过let定义的变量不会被提升(不会被预解析)
*/
/*
// 预解析之前
console.log(num); //undefined
var num = 123;
// 预解析之后
var num;
console.log(num);
num = 123;
*/
/*
// 不会预解析之前
console.log(num); // 报错
let num = 456;
*/
// ES6之前定义函数的格式
/*
console.log(say);
say();
// ES6之前的这种定义函数的格式, 是会被预解析的, 所以可以提前调用
function say() {
console.log("hello it666");
}
*/
/*
// 预解析之后的代码
function say() {
console.log("hello it666");
}
say();
*/
/*
console.log(say);
say(); // say is not a function
// 如果将函数赋值给一个var定义的变量, 那么函数不会被预解析, 只有变量会被预解析
var say = function() {
console.log("hello itzb");
}
*/
/*
var say; //undefined
say();
say = function() {
console.log("hello itzb");
}
*/
// ES6定义函数的格式
say(); // say is not defined
let say = () => {
console.log("hello itzb");
}
</script>
<script type="text/javascript">
/*
* 函数的声明提前:
* 1.使用函数声明创建的函数function 函数名() {}
* 会在所有的代码执行前被创建,所以可以在函数声明前被调用
* 2.使用函数表达式创建的函数 var 函数名= function(){}
* 不会被提前创建,所以不能在声明前调用
*/
fun1();//输出是 fun1函数
//函数声明.会被提前创建
function fun1()
{
console.log("fun1函数");
}
fun2(); //输出是 Uncaught TypeError: fun2 is not a function
//函数表达式,不会被提前创建
var fun2=function(){
console.log("fun2函数");
}
</script>
预解析练习
<script>
// 1.下列程序的执行结果是什么?
var num = 123;
fun();
function fun() {
console.log(num);
var num = 666;
}
/*
var num;
function fun() {
var num;
console.log(num); // undefined
num = 666;
}
num = 123;
fun();
*/
</script>
<script>
// 1.下列程序的执行结果是什么?
var a = 666;
test();
function test() {
var b = 777;
console.log(a);
console.log(b);
console.log(c);
var a = 888;
let c = 999;
}
/*
var a;
function test() {
var b;
var a;
b = 777;
console.log(a); // undefined
console.log(b); // 777
console.log(c); // 报错
a = 888;
let c = 999;
}
a = 666;
test();
*/
</script>
4.作用域
在ES6之前,没有块级作用域的概念。只有全局作用域和局部作用域(函数作用域)
{
// 块级作用域
var num = 123; // 全局变量
}
console.log(num);
在局部作用域中,通过var定义的变量是局部变量
{
// 块级作用域
}
if(false){
// 块级作用域
}
while (false){
// 块级作用域
}
for(;;){
// 块级作用域
}
do{
// 块级作用域
}while (false);
switch () {
// 块级作用域
}
function say() {
// 局部作用域
}
4.1 全局作用域
<script type="text/javascript">
/*
* 作用域
* 1.全局作用域:定义在script标签中,在页面打开时创建,关闭时销毁
* 在全局作用域中有一个全局对象window(浏览器的一个窗口,由浏览器创建),可以直接使用
* 在全局作用域中,创建的变量都会作为window对象的属性保存
*/
var a = 10;
console.log(window.a); //a是window的属性
/*
* 变量的声明提前:使用var关键字声明的变量,会在所有的代码执行前被声明(但是不会赋值)
*/
console.log(b); //输出是 undefined
var b= 123;
//不使用var关键字,则该变量不会被提前声明
console.log(c); //Uncaught ReferenceError: c is not defined
c = 123;
</script>
4.2 函数作用域
<script type="text/javascript">
/* 函数作用域
* 调用函数时创建函数作用域,函数执行完毕后作用域销毁
* 每调用一次函数会创建一个函数作用域,他们之间相互独立
* 在函数作用域中,可以访问全局变量
* 在全局作用中,无法访问函数作用域中的变量
* 当在函数作用域中操作一个变量中,会先在自身作用域中寻找,如果有就直接使用
* 如果没有,就在上一级作用域中寻找,直到在全局作用域中寻找
* 如果在全局作用域中依然没有找到,报错
* 在函数作用域中寻找全局变量,使用window.变量名
*/
//变量a在全局作用域和函数作用域中都有定义,在函数中局部变量的优先级更高
var a = 1;
function fun1()
{
var a = "fun1函数中的a";
console.log(a);
}
fun1(); //输出是:fun1函数中的a
//调用函数fun2访问变量a,没有找到,向上一级寻找
var a = 1;
function fun1()
{
var a = "fun1函数中的a";
function fun2()
{
console.log(a);
}
fun2();
}
fun1(); //输出是:fun1函数中的a
//调用函数fun2访问变量a,一直向上一级寻找,在全局作用域中也没有找到,报错
function fun1()
{
function fun2()
{
console.log(a);
}
fun2();
}
fun1(); //输出是: Uncaught ReferenceError: a is not defined
//在函数作用中寻找全局变量,使用window.变量名
var a = "全局变量a";
function fun1()
{
var a = "fun1中的a";
function fun2()
{
var a = "fun2中的a";
console.log(window.a);
}
fun2();
}
fun1(); //输出是: 全局变量a
</script>
- 函数作用域中也有变量和函数的提前声明
<script type="text/javascript">
/*
* 在函数作用域中使用var声明的变量,会在函数的所有代码被执行之前声明,但没有赋值
* 函数声明也会在该函数的所有代码执行前执行
*/
var a = "全局变量a";
function fun1()
{
console.log(a);
var a = "fun1中的a";
}
fun1(); //输出是: undefined
</script>
- 在函数作用域中 有var VS 没有var:
<script type="text/javascript">
/*
* 在函数作用域中使用var声明的变量,会在函数的所有代码被执行之前声明,但没有赋值
* 函数声明也会在该函数的所有代码执行前执行
*/
var a = "全局变量a";
function fun1()
{
//没有使用var,在函数作用域中不会对a进行提前声明,在函数中找不到a,向上一级寻找
console.log(a); //找的是局部变量a,没有找到,输出全局变量a,此时的值还是"全局变量a"
//在函数中没有使用var,此时的a还是全局变量a,相当于对全局变量a进行重新赋值
a = "fun1中的a"; //此时全局变量a的值已经是"fun1中的a"
}
fun1(); //输出是: 全局变量a
//在全局作用域中寻找a,找到的是全局变量a,在fun1中已经对全局变量a的值进行修改
console.log(a); //输出是: fun1中的a
</script>
- 在函数作用域中定义某个变量,但不使用var关键字,此时该变量为全局变量
<script type="text/javascript">
function fun1()
{
b = "没有var的局部变量b";
// b没有使用var关键字,设置为全局变量
}
fun1();
//在全局寻找b
console.log(b); //输出是: 没有var的局部变量b
</script>
- 如果变量和函数同名,函数的优先级高于变量
<script>
console.log(value); // 会输出函数的定义
var value = 123;
function value() {
console.log("fn value");
}
console.log(value); // 会输出123
以上代码在预解析之后:
/*
function value() {
console.log("fn value");
}
console.log(value);
var value;
value = 123;
console.log(value);
*/
</script>
4.3 块级作用域
ES6开始,如果{}没有和函数名结合在一起,就是块级作用域
- 在块级作用域中,通过var定义的变量是全局变量
{
// 块级作用域
var num = 123; // 全局变量
}
console.log(num); // 123
- 在局部作用域中,通过var定义的变量是局部变量
<script>
function test() {
var value = 666; // 局部变量
}
test();
console.log(value); // value is not defined
</script>
- 无论是在块级作用域还是在局部作用域, 省略变量前面的let或者var就会变成一个全局变量
<script>
function test() {
num = 123; // 全局变量
}
test();
console.log(num);// 123
</script>
<script>
{
num = 678; // 全局变量
}
console.log(num);//678
</script>
- let 和var
无论是var还是let定义在{}外面都是全局变量
将var定义的变量放到一个单独的{}里面, 还是一个全局变量
{
var num = 123;
}
console.log(num); //不会报错
将let定义的变量放到一个单独的{}里面, 是一个局部变量
{
let num = 123;
}
console.log(num); //会报错
4.4 作用域练习
/*
* 计算一下代码的执行结果:
*/
5. var a = 123;
function fun()
{
console.log(a); //在函数作用域中没有找到变量a,向上一级寻找
}
fun(); //123
6. var a = 123;
function fun()
{
console.log(a);
var a = 456;
//使用var关键字在函数作用域中对局部变量a进行提前声明,但没有赋值
}
fun(); //undefined
console.log(a); //查找全局变量,a=123
7. var a = 123;
function fun()
{
console.log(a); //a 还是全局变量123
a = 456;
//在函数作用域中没有使用var关键字声明a,所以将全局变量a修改成456
}
fun(); //123
console.log(a); //456
8. var a = 123;
function fun(a) //定义形参a=声明局部变量a
{
console.log(a); //123
a = 456; //改变的是局部参数a,没有改变全局变量
}
fun(); //没有传递实参,相当于在函数内没有对局部变量a赋值,输出undefined
console.log(a);//123
9. var a = 123;
function fun(a) //定义形参a=声明局部变量a
{
console.log(a);
a = 456; //改变的是局部参数a,没有改变全局变量
}
fun(123); //123
console.log(a);//123
<script>
// 1.找出下列哪些是全局变量,哪些是局部变量
/*
var num1 = 123; // 全局变量
function test() {
var num2 = 456; // 局部变量
}
{
var num3 = 789; // 全局变量
}
function test() {
num4 = 666; // 全局变量
}
*/
// 2.找出下列哪些是全局变量,哪些是局部变量
/*
let num1 = 123; // 全局变量
function test() {
let num2 = 456; // 局部变量
}
{
let num3 = 789; // 局部变量
}
function test() {
num4 = 666; // 全局变量
}
*/
// 3.下列代码运行是否会报错
/*
var num = 123;
var num = 456; // 不会报错
*/
/*
{
var num = 123;
{
var num = 456; // 不会报错
}
}
*/
/*
console.log(num); // 不会报错
var num = 123;
*/
// 4.下列代码运行是否会报错
/*
let num = 123;
let num = 456; // 会报错
*/
/*
{
let num = 123;
{
// 注意点: 在不同的作用域范围内, 是可以出现同名的变量的
let num = 456; // 不会报错
}
}
*/
/*
console.log(num); // 会报错
let num = 123;
*/
// 5.下列代码运行是否会报错
/*
// 注意点: 只要出现了let, 在相同的作用域内, 就不能出现同名的变量
let num = 123;
var num = 456; // 会报错
*/
/*
var num = 123;
let num = 456; // 会报错
*/
</script>