ECMAScript–es5语法 BOM DOM
变量提升
变量提升是JavaScript中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于var声明变量)
- 变量提升出现在当前作用域的最前面
- 提升时,只提升变量声明,不提升变量赋值
- let/const声明的变量不存在变量提升
- 实际开发中推荐先声明在访问变量
// var 变量提升
// 1.变量的提升会提升到当前作用域的最前面
// 2.只提升变量声明,不提升变量赋值
console.log(age); //undefined
var age = 18
console.log(age); //18
/*
var age;
console.log(age);//undefined
age=18;
console.log(age);//18
*/
console.log("---------------------");
function fn(){
console.log(uname); //undefined
var uname ='lucy';
}
fn();
/*
function fn(){
var uname;
console.log(uname); //undefined
uname ='lucy';
}
fn();
*/
函数提升
函数提升于变量提升比较类似
- 函数提升提升到当前作用域最前面
- 函数提升只提升声明,不提升调用
- 函数表达式不存在提升的现象
- 函数提升能够使函数的声明调用更灵活
// - 函数提升提升到**当前作用域最前面**
// - 函数提升**只提升声明,不提升调用**
// - 函数表达式**不存在提升**的现象
// - 函数提升能够使函数的声明调用更灵活
fn();
function fn(){
console.log("函数提升")
}
fun() //fun is not a function
var fun = function(){
console.log("函数表达式不存在提升");
}
/*
var fun;
fun()
fun = function(){
console.log("函数表达式不存在提升")
}
*/
总结
定义函数有两种
- function 定义 ,因为function定义的函数有函数提升,所以 调用函数可以在定义前也可以在定义后
- 函数表达式 函数表达式不存在变量的提升,函数表达式定义的函数,调用只能在定义之后
ECMAScript 6
https://es6.ruanyifeng.com/
ECMAScript 和 JavaScript 的一种体现(规格)
ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等
Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在老版本的浏览器执行
let,const,var
let
- let有块级作用域
- 暂时性死区(在声明之前访问不到)
- let没有变量的提升
- let在for循环中形成了块级作用域
const
- 不能声明重名变量
- 暂时性死区(在声明之前访问不到变量)
- 没有变量的提升
- 有块级作用域
- 声明必须赋值
- 值不可修改
- 对于引用数据类型,因为栈中存放地址,堆中存放内容数据,可以修改其对象(数组)内容
面试题:let const var的区别
①重复声明 ②变量提升 ③暂时性死区 ④块级作用域 ⑤window对象的属性和方法(全局作用域中)
- 区别一:重复声明
var允许重复声明,let、const不允许
【需要注意的是重复声明指的是:已经存在的变量或常量,又声明了一遍(形参也算已经声明的变量)】
- 区别二:变量提升
var会提升变量的声明到作用域的顶部,但let和const不会(说白了就是let和const没有变量提升)(无论是常量还是变量最好还是声明后再进行定义)
- 区别三:暂时性死区
只要作用域内存在let、const,它们所声明的变量或常量就会自动“绑定”这个区域,不再受外部作用域的影响,var没有暂时性死区
【简单说明一下:这个暂时性死区说白了就是在函数作用域内部声明的变量将会与对应的函数作用域进行绑定(当然没有的话还是会向上查找),当函数内部存在重复声明或者变量提升时,就算外面的作用域已经声明了这个变量,它的运行还是认准的该函数作用域中的声明情况】
- 区别四:window对象的属性和方法(全局作用域中)
全局作用域中,var声明的变量,通过function声明的函数,会自动变为window对象的变量,属性或方法,但const和let不会
// let,const
let a = 11
console.log(window.a === a) // false
let b = 9
console.log(window.b === b) // false
let fn1 = function () { return 1 }
console.log(window.fn1 === fn1) // false
// var
var c = 13
console.log(window.c === c) // true
var fn2 = function () { return 1 }
console.log(window.fn2 === fn2) // true
- 区别五:块级作用域
var没有块级作用域,let和const有块级作用域
解构
数组解构
// let a = 1
// let b = 2
// let c = 3
// let d = 4
// 数组的解构
// let [a, b, c, d] = [1, 2, 3, 4];
// console.log(c) // 3
let [a, b, c, d] = [1, [2, 3], 4]
console.log(a, b, c, d) // 1 [2, 3] 4 undefined
let [ , , third] = ["foo", "bar", "baz"];
console.log(third)
let [aa, [bb], dd] = [1, [2, 3], 4];
console.log(aa,bb,dd);//aa=1 bb=2 dd =4
对象解构
// 对象解构
let {name,age} ={age:12,name:"zs"}
console.log(name,age);
let {uname,score,student,student:{num}} = {
uname:"zs",
score:[12,23,45],
student:{
num:12
}
}
console.log(uname,score,student,num)
// num:n num 重命名为 n
let {unum:n} = {
unum:123
}
// console.log(unum) //unum is not defined
console.log(n) //123
字符串扩展
// 模板字符串
let a =10;
function fn(){
console.log(123)
}
let str = `
aldjfaldfjal
fasldjldsajfla
${a}
${fn()}
`
函数扩展
// 函数参数默认值
function fun(x,y='word'){
// 形参是默认声明的 不能使用let const再次声明
// let x=2 Identifier 'x' has already been declared
console.log(x,y)
}
fun(1);
fun(1,2);
let [x, y = 'b'] = ['a'];
console.log(x,y);
// 参数默认值与解构默认值结合使用
function foo({x,y = 5}){
console.log(x,y)
}
foo({}) //undefined 5
foo({x:1})// 1 5
foo({x:1,y:4}) //1 4
// foo() //Cannot destructure property 'x' of 'undefined' as it is undefined. 参数为对象才能解构
function foo1({x,y=5}={}){
console.log(x,y)
}
foo1() //undefined 5
严格模式
// 只有函数参数使用了默认值 解构赋值 扩展运算符...
// 函数内部就不能显式设定为严格模式 否则会报错
// function doSomeThing(a,b=3){
// 'use strict'
// }
// const doSomeThing1=function({a,b}){
// 'use strict'
// }
// const doSomeThing1=function(...a){
// 'use strict'
// }
箭头函数
/*
箭头函数 => 定义函数
作用
1.简写
2.改变this指向(后面讲)
*/
// function fn(){
// }
var fn = ()=>{
console.log(123)
}
// fn()
// function fn1(a,b){
// console.log(a+b)
// }
var fn1 =(a,b)=>{
console.log(a+b)
}
// fn1(2,3)
// function fn2(a){
// console.log(a)
// }
var fn2= a=>{
console.log(a)
}
fn2(1)
// function fn3(a,b){
// return a+b
// }
// var fn3 =(a,b)=>{
// return a+b
// }
var fn3 = (a,b)=>a+b
console.log(fn3(4,5))
// function fn4(){
// return {a:1}
// }
var fn4 =()=>({a:1})
console.log(fn4())
数组扩展
// 扩展运算符
// spread (...) 将数组转为用逗号分隔的参数序列
console.log(...[1,2,3]); //1 2 3
console.log(1,...[2,3,4],5); //1 2 3 4 5
function fn(arr,...items){
arr.push(...items)
console.log(arr);
}
// ...items = 2,3,4,5
fn([1],2,3,4,5)
function add(x,y){
return x+y
}
const numbers = [4,23];
console.log(add(...numbers));//27
// 扩展运算符作用
// 1 复制数组
// const a1 = [1,2];
// const a2 = a1
// a2[1]=9
// console.log(a2,a1)
const a1 = [2,3];
const a2 = [...a1]
a2[0]=0
console.log(a1,a2);
// 2.合并数组
const arr1 = ['1','2'];
const arr2 = ['c'];
const arr3 = ['d','e'];
const arr5 = [...arr1,...arr2,...arr3]
console.log(arr5);
// 3.与解构赋值结合
let [first,...rest] = [1,2,3,4,5]
console.log(first,rest)//1 ,[2,3,4,5]
// Array.from() 将两类对象转为真正的数组
let arrLike = {
'0':'a',
'1':'b',
'2':'c',
length:3
}
let arrL =Array.from(arrLike);//['a','b','c']
// console.log(arrL);
// Array.of() 将一组值,转换为数组
console.log(Array.of(2,3,5,6)); // [2, 3, 5, 6]
console.log(Array.of());//[]
console.log(Array.of(1));//[1]
// find() 找出第一个符合条件的数组成员
// findIndex() 找出第一个符合条件的数组成员的下标
let newArr=[1,2,3,5,6,7].find(val=>val<3)
console.log(newArr); //1
let newIndex=[1,2,3,5,6,7].findIndex(val=>val<3)
console.log(newIndex) //0
// includes() 返回一个布尔值 表示某个数组是否包含给定的值
console.log([1,2,3].includes(1)) //true
// 第二个参数 表示搜索的起始位置 默认是0
console.log([1,2,3].includes(3,3)); //false
console.log([1,2,3].includes(3,1));//true
对象扩展
let foo =1
let obj={
// foo:foo
// 简写
foo
}
console.log(obj) //{foo: 1}
// 属性名可以是表达式
let obj1 = {
[1+2]:1,
[foo]:2
}
console.log(obj1) //{1: 2, 3: 1}