JS的三大组成部分
- JS语法 -->
ECMAScript
-->es5 -->es6 DOM
-->Document Object Model
(文档对象模型) 可以操作html+cssBOM
-->Browser Object Model
(浏览器对象模型)
let
/const
和var
的区别
在es5
和es6
中如何声明一个变量
如何声明一个变量(es5
)
var a = 1;//var (es5)声明变量的关键词
console.log(a);
如何声明一个变量(es6
)
let b = 1;//let (es6)声明变量的关键词
console.log(b)
声明变量let
和var
的区别
let
和var
关键词能否在同一个作用域中重复中声明一个变量吗??
var
可以在同一个作用域中重复中声明一个变量吗??
var a = 1;
var a = 2;
console.log(a);
var
关键词:能够在同一个作用域中重复声明一个变量
let
可以在同一个作用域中重复中声明一个变量吗??
let b = 1;
let b = 2;
console.log(b)
会报错:SyntaxError
表示语法错误 ,declared
表示这个变量已经被声明过了。
let
关键词:不能够在同一个作用域中重复声明一个变量
用var
声明的变量和用let
声明的变量都是在本地占用内存的
那么用var
和let
声明的变量,会挂在全局window
对象上面吗??
用var
声明的变量会挂在全局window
对象上面吗??
var a = 2;
console.log(window.a);
局作用域中var
声明的变量,会自动成为window
对象的属性
用let
声明的变量会挂在全局window
对象上面吗??
let b = 2;
console.log(window.b)
全局作用域中let
声明的变量,不会自动成为window
对象的属性
在
es5
中用var
关键词声明的变量会自动挂在全局window
对象自动成为window
对象上面的属性(首先你要身处于全局),这种声明变量的现象很诡异,那么es6
中用let
声明的变量就杜绝了这种现象(不合理现象)
es6
用let
声明的变量,能够让全局对象更干净,一些不该有的变量不会成为全局对象上面的属性(es6
用let
声明的变量让你的代码更严谨一些)
那么用var
和let
声明的变量,都会有变量提升吗??
用var
声明的变量会有变量提升吗吗??
console.log(typeof a);//typeof检测不存在的变量他是结果是undefined
var a = 2;//var 关键词会变量提升
/*
JS引擎会把这种情况拆解一下代码来解析
var a;//第一步会把var声明的变量提升到最前面
console.log(a);//第二步一个变量没有赋值那么就是under
a = 2;//从新给变量a赋值
*/
用var
声明的变量他是,用变量提升的
用let
声明的变量会有变量提升吗吗??
console.log(typeof b);//用let声明的变量,在声明变量之前的所有代码,如果使用了b那么就会报错
var b = 2;//let 关键词会变量提升
报错:引用错误 initialization
表示b在初始化之前不能赋值(没有b这个变量)access
表示通道,机会,使用权
用let
声明的变量他是,用变量提升的,在该变量之前称为暂时性死区 ==>TDZ(Template Dead Zone,暂时性死区的本质是变量已经在当前作用域中了,但是不能够使用
let b = b;
console.log(b);
/*
JS引擎会把上面的代码解析成一下代码
//在该变量之前称为暂时性死区(TDZ)
let b;
//TDZ暂时性死区的区域,还包括等号的右侧,如果在这个范围内使用变量b的话那么就会报错
b = b;
console.log(b)
*/
在es5
中用var
关键词声明的变量如果没有赋值那么结果是undefined
在es6
中用let
关键词声明的变量如果没有赋值那么就会报错
那用var
关键词和用let
关键词,声明的变量能生成块级作用域吗??
那用var
关键词,声明的变量能生成块级作用域吗??
if (true) {//块级作用域是像if这样存放代码的区域(这样的区域也可以理解为代码块)
var a = 2;
}
console.log(a);
/*
JS引擎解析代码如下
var a;//用var声明的变量不赋值,值是undefined
if(true){//true为真走一下代码块
var a = 2;//让变量提升的a从新赋值是 a = 2
}
console.log(a);//在全局window对象上面找到变量a值是2,打印2
*/
在es5
中用var
关键词声明的变量不能够让{}
生成块级作用域
那用let
关键词,声明的变量能生成块级作用域吗??
if (true) {//块级作用域是像if这样存放代码的区域(这样的区域也可以理解为代码块)
let b = 2;
}
console.log(b);
通过let
关键词声明的变量,那么这个let
关键词就能让花括号{}
自动的生成一个块级作用域,那么用let
关键词声明变量,全局作用域的变量就不能访问,用let
声明的块级作用域里面的变量(否则会报错)
在es6
中用let
关键词声明的变量可以让{}
生成块级作用域
块级作用域
什么是块级作用域??
es5
只有全局作用域,函数作用域,es6
又新增了块级作用域的概念
for
循环的块级作用域
for(let i=0;i<5;i++){//用let声明的变量{}(代码块)自动成为块级作用域
let c = 0;
}
console.log(c);
会报错:当前没有c
这个变量(没有定义c
这个变量)
在全局作用域中,不能访问块级作用域里面的变量(否则就会报没有定义变量这个错误)
在for
循环中条件里面有,用let
声明的变量的i
,那么这个i
是身处于哪个作用域里面??
验证1
如果i
是在全局作用域里面,那么就会打印5
for(let i=0;i<5;i++){
let c = 0;
}
console.log(i);
报错:说明没有定义i
这个变量(没有i
),那么这个i
不是在全局作用域里面,因为在全局作用域里面没有找到这个变量i
(变量i
不是在全局作用域里面)
验证2
那么是不是在这个for
循环里面的{}
块级作用域里面呢
for(let i=0;i<5;i++){
let i = 'huasheng';
}
如果i
是在块级作用域里面,那么同一个作用域不能声明同一个变量(否则就会报错)结果是报错
当前没有打印任何数据,说明这个i
不在for
循环里面{}
块级作用域里面
那么不在全局作用域,也不在for
循环的{}
块级作用域里面,那么他就是在for
循环的()
里面是有一个块级作用域的,说明了变量i
就是在for
循环的()
里面自己形成了一个作用域
在for
循环中,不仅{}
会生成块级作用域,()
也会生成块级作用域
那么看一下案例
为什么用var
关键词声明的变量i会打印5次5??
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i)
},1000);
};
首先是for
循环他是可以会很快的执行完的,然后你开一个定时器1秒钟执行一次回调函数,回调函数内部要打印i
,回调函数是没有i
的我自然要去父级作用域去找i
,而这个函数的作用域父级作用域是全局作用域,我会找全局的i
而这个全局的i
是for
循环结束后的i(i=5)
,那么就会执行for
循环代码在1秒后就打印5次5
那用let
关键词声明的变量,打印的结果是什么
for(let i=0;i<5;i++){
setTimeout(function(){
console.log(i)
},1000);
};
i=0 0<5 回调函数
i=1 1<5 回调函数
i=2 2<5 回调函数
i=3 3<5 回调函数
i=4 4<5 回调函数
i=5 5<5 5<5=false 条件为假条出for循环
let
关键词声明变量,()
号里面是有个块级作用域的{}
号里面也是有一个块级作用域的
当定时器的回调函数里面要打印i
,现在回调函数是在块级作用域中,这个块级作用域中是没有i
的那我会顺着()
括号这个块级作用域去找(父级),而父级作用域里面是有i的所以说我找到了,在回调函数打印i
的时候其实就找到了()
括号作用域里面的i
值是0,如此循环反复5圈
回调函数所处环境就是{}
号块级作用域内,这个块级作用域所处的环境是()
号块级作用域中,所以说就连成一条链。
这个回调函数所处的环境不像var
声明的变量了,var
是在全局作用域中,但是let
声明的变量不一样,let
就延长了匿名函数的作用域链,匿名函数所处环境–>{}块级作用域–>()作用域–>全局作用域(这是一条作用域链被延长了)
那么用闭包怎么整呢??
for(var i=0;i<5;i++){
(function(i){
setTimeout(function(){
console.log(i)
},1000)
})(i)
}
用闭包也是延长这个回调函数的作用域链,让这个回调函数所处的环境是在这个立即执行函数中存储了变量i
也是延长了作用域链
现在用es6
新增的let
声明变量就可以,自动的延长作用域链了
单独的{}
也会生成块级作用域的
{//用let声明变量的话他会让{}生成一个块级作用域的
let b = 2;
}
console.log(b);//在全局作用域里面不能使用用let关键词生成块级作用域里面的变量的(否则会报错)
let b = 2;//全局作用域的变量b
{
let b = b;//用let声明的变量自动成为块级作用域
console.log(b)
}
首先等号右侧你要使用变量b
,let
是用变量提升的然后,let
是有占时性死区的特性(变量b
的前面和变量b
的右侧),所以你使用打印变量b
就会报错
const
const
的作用:const
关键词是用来声明变量的。 ==>举个例子 圆周率 光速 等不会改变的量
const
在声明常量的同时必须要赋值,不然会报错
const PI = Math.PI; //圆周率就是常量
//现在定义一个常量PI就是存放着Math.PI这个圆周率的,
//这个常量是不会变换的(声明的常量是不能让值变换了)否则会报错(表示不能被修改)
const
声明常量的两个情况
如果该常量是 原始值,则该常量不能被修改
const num = 10;
console.log(num);//正常情况系打印常量num
const num = 10;
num = 12;
console.log(num);//改变把原始值赋值给常量,然后在改变这个原始值
表示使用const
赋值错误 (赋值给常量变量)
如果该常量是 引用值,可以 保证在不修改常量地址的情况下,是可以 修改常量的数据结构的
const PI = [1,2];
PI.push(3);//只要不改变常量存放的地址不被更改,那么就不会报错 push方法是不改变原来的数组的
console.log(PI)
const PI = [1,2];//原先PI的地址是[1,2]这个数组
PI = [3];//现在是新赋值了一个数组,把这个新的数组的地址有给了PI,
//这个常量存放这另一个引用的地址那么自然就会报错
var
和let
的区别,就是,var
和const
的区别
,
逗号运算符
- 使用逗号操作符(
,
)可以在一条语句中执行多个操作 - 逗号操作符多用于声明多个变量
- 在用于赋值时,逗号操作符总会返回表达式中的最后一项
var num=(5,'name',false,null,undefined,[1,2],{});
console.log(num)
//num的值为{}在这种情况下必须写()否则会报错
//由于0是表达式中的最后一项,因此num的值就是0
练习题目
for(let i = (setTimeout( function(){console.log(i)} , 2000) , 0); i<2; i++){};//打印出来是0