es6官方名称叫做es2015,每年2月都会一些新增的语法
是语法层面的更新,比如原来的var 声明变量,let声明变量
我们书写代码不需要考虑语法层面的兼容性,因为会有一些工具可以将我们写的es6代码转换为es5的语法,babel:https://www.babeljs.cn/ 可以看到将es6转为es5
es6新增了两个定义变量的关键字:
let 和const
-
let const一起和var的区别:
-
var会进行预解析,let和const不会进行预解析,必须先定义再使用
-
var可以重复声明变量,let和const不能声明重复的变量名
var a=100; let a=200; //---这样也不可以,因为变量a已经用过了,let不能再使用a声明变量
-
var 没有块级作用域,let和const有块级作用域
-
块级作用域: 被代码块限制变量的使用方法
var只有函数私有作用域才能限制使用的范围,let和const只要是能书写代码段的{}都能限制使用范围
if(true){ //全局变量 var num=100; //全局变量 let num2=200; //---let定义的变量num2离开这个if的{}就用不了了 } console.log(num); //100 console.log(num2); //报错
if(true){ let num2=200; 本质是将{}内使用let声明的num转换为了_num ,换了个变量名,所以在外面就获取不到了 console.log(num2); //200 } let num2=300; console.log(num2);//300
<div class="box1">1</div> <div class="box2">2</div> <div class="box3">3</div> ----------------js var div=document.querySelectorAll('div'); --使用var 声明变量 for(var i=0;i<=div.length-1;i++){ console.log(i) // 给每一个div元素绑定一个点事件,当点击div元素的时候,打印出的i都是3 // 这是因为var 声明的i是全局变量,在div元素被点击时,for循环已经执行完毕,i自增为了3 //所以点击元素时打印出的是自增后的全局变量i 为3 div[i].οnclick=function(){ console.log('点击————',i) } } 本质 var i { i=0; ... } { i=1; ... } { i=2; ... } i=3;//i自增为3 -------------------------- ---使用let声明变量 for(let i=0;i<=div.length-1;i++){ console.log(i) // 给每一个div元素绑定一个点事件,当点击div元素的时候,打印出的i分别是0 1 2 //这是因为使用let声明的变量会有快级作用域只能在当次循环的{}内使用 div[i].οnclick=function(){ console.log('点击————',i) } } ---------本质 /* { let i=0; .... } { let i=1; .... } { let i=2; .... } */
-
let和const的区别
-
let可以在声明时不赋值
let a; console.log(a)//undefined
const 声明是必须赋值,声明时不赋值会报错
const a; //报错
-
let 声明的变量可以被修改
const修改的常量不能被修改,一旦修改就报错
给定义的常量赋值为数组或者对象,对数组和对象里的元素的修改,不算对常量的修改,不会报错
因为常量存储的是数组和对象的内存地址,地址没有发生变化
-
const 一般常亮命名采用大写(潜规则)
-
-
let声明变量
-
使用let声明变量不能重复声明
let str='adc'; let str='adc'; //重复声明会报错
-
块级作用域
if(true){ let str='122'; } console.log(str);//报错 Uncaught ReferenceError: str is not defined //如果使用var 声明变量就不会报错
-
不存在变量提升
console.log(ab); let ab='23';
-
不影响作用域链
{ let ab='12'; function fn() { console.log(ab) } } fn();// 12
-
-
const 声明常量
const STR='123'; //一定要赋初始值,否则就会报错 const AD; //报语法错误 Uncaught SyntaxError: Missing initializer in const declaration
-
一般常量命名采用大写(潜规则)
-
常量的值不能修改
-
块级作用域
{ const AD=2; } console.log(AD);//报错
-
给定义的常量赋值为数组或者对象,对数组和对象元素的修改,不算对常量的修改,不会报错
因为常量存储的是数组和对象的内存地址,地址没有发生变化
const TIME=[1.23,4,56,7]; TIME[0]="步步高"; console.log(TIME);//["步步高", 4, 56, 7]
-
箭头函数
一种新的函数定义方式:对于函数表达式的简写方式(匿名函数)
-
匿名函数使用场景:
var fn=function(){}; var onj={ fn:function(){} }; setTimeout(function(){},1000); setInterval(function(){},1000); [].map(function(){}); div.οnclick=function(){}; div.addEventListener('click',function(){});
-
箭头函数的语法:
()=>{}; (): 设置形参的位置 =>: 箭头函数的标志 {}: 代码段 ---- var fn=(a,b)=>{ console.log(999,a,b); }; fn(1,2);//正常调用
-
箭头函数的特性
-
一个形参的时可以省略小括号不写
-
一句代码执行语句的时候可以省略大括号,并且自动return返回那一句语句的结果
var fn=a => a+4; //将a+4的结果当做fn函数的返回值 console.log(fn(2)); //6
-
箭头函数里面没有arguments,在箭头函数内没有办法使用arguments
-
箭头函数里面没有this
官方解释:箭头函数里面的this是上下文(context),外部作用域的this就是箭头函数内的this
私人解释:箭头函数的this就是,你的箭头函数写在哪一行,上一行的this就是箭头函数里面的this
var div=document.querySelectorAll('div')[0]; div.οnclick=function(){ console.log(this); // this为div元素 } div.οnclick=()=>{ console.log(this); // this为window }
var div=document.querySelectorAll('div')[0]; div.οnclick=function(){ console.log(this);// this为div元素 let fn=function(){ console.log(this); } fn();// 以函数的形式调用this指向window let fun=()=>{console.log('***8',this);}; //---这个箭头函数内的this就是上一行的this fun(); // 上一行所在函数的this是div,所以箭头函数this为div }
let obj={ fn:function(){ console.log('11111',this); }, fun:()=>{ console.log('22222',this); } }; obj.fn(); // this为obj obj.fun(); // this为window 因为obj实际为 let obj={fn:function(){console.log('11111',this);},fun:()=> {console.log('22222',this)}}; // 定义箭头函数的哪一行的上一行的this为window
var div=document.querySelectorAll('div')[0]; div.οnclick=function(){ console.log('$$$$$',this);// this为div元素 let obj={ name:'我是obj对象', fn:function(){ console.log('11111',this); }, fun:()=>{ console.log('22222',this); } }; obj.fn(); //---this为obj obj.fun(); //--this为div }
-
箭头函数内的this任何方法改变不了,因为箭头函数内没有this它用的是外部作用域的this
call apply bind不能改变箭头函数的this指向
var fn=()=>{ console.log(this); } let obj={ name:'sun', fun:fn } fn(); //---this为window obj.fun(); //---this为window fn.call(obj); //---this为window 箭头函数不能改变this指向
-
函数参数的默认值
作用:给函数的形参设置一个默认值
如传递了实参,就用实参,如果没有传递实参就用形参的默认值
格式:直接在形参后面使用等号(=)进行赋值
function fn(a=100,b){ console.log(a,b); } fn('你好','bubu');//传递实参使用实参 fn();//没有传递实参就使用形参设置的默认值,如果形参没有设置默认值,则默认值为undefined
箭头函数也可以书写参数的默认值
箭头函数只要你设置了参数默认值,不管多少个形参,都的写小括号
let fn=(a=100,b)=>{ console.log(a,b); } fn('你好','bubu');//传递实参使用实参 fn();//没有传递实参就使用形参设置的默认值,如果形参没有设置默认值,则默认值为undefined
模版字符串
模版字符串就是使用反引号包围的字符串
-
模版字符串可以直接换行书写
let ab=`12345 dfff ffff 444`; console.log(ab); //打印输出的内容,也是换行的 /* 12345 dfff ffff 444 */
-
可以使用变量拼接字符串
let name='安保'; let newStr=`122${naem}`
-
模版字符串可以调用函数
模版字符串的内容就是函数的参数
${}把字符串切开,组合成一个数组当做函数的第一个参数
从左到右开始依次是每一个${}里面的内容作为函数后面参数
function fn(a,b,c) { console.log(arguments); console.log('第一个参数',a); //['hello','word','你好'] console.log('第二个参数',b); //10 console.log('第三个参数',c); //20 } var num1=10; var num2=20; fn`hello${num1}word${num2}你好`; /* ---------- 执行步骤: 1: 用${}切开字符串 将切开的字符串放到一个数组里['hello','word','你好']作为函数第一个参数传入函数 2: ${num1} 里面的num1就是函数的第二个参数 3: ${num2} 里面的num2就是函数的第三个参数 作用:将模版字符串的各部分给你,你可以在函数内自由组合 不经常使用,但是面试常出 */
(...)点点点运算符
-
展开运算符
当在函数实参的位置或者数组或者对象里面使用的时候是展开
作用:就是将包裹的内容全部打开
let arr=[1,2,3,4,5]; console.log(...arr);// 1 2 3 4 5 console.log(Math.max(...arr)); // Math.max()方法不接受数组作为参数,我们可以使用展开运算符,将数组的每一项展开后依次作为该方法的参数 ---展开数组 let arr2=[6,7,8];// 将arr和arr2合并为一个数组 原来可以使用数组的concat方法 arr2=[...arr,6,7,8] console.log(arr2);// [1, 2, 3, 4, 5, 6, 7, 8] --- 展开对象 let obj={ name:'sun', age:18 } let obj2={ ...obj, skill:function(){console.log('你好')} } console.log(obj); //{name: "sun", age: 18} console.log(obj2);//{name: "sun", age: 18, skill: ƒ}
-
合并运算符
当你在函数的形参位置使用的时候是合并
箭头函数没有arguments,我们可以使用合并运算符整一个
function fn(...a){ // 定义一个变量a,从第一个实参开始到最后一个实参全部获取,合并放在一个数组里面 console.log(a);//[1, 2, 3, 4, 6, 7] } fn(1,2,3,4,6,7) function fn2(a,...b){ // 第一变量a,接受第一个实参 // 定义一个变量b,从第二个实参开始到最后一个实参全部获取,合并放在一个数组里面 console.log(a);// 1 console.log(b);// [2, 3, 4, 6, 7] } fn2(1,2,3,4,6,7) ....以此类推 ----箭头函数 var fn3=(...n)=>{ console.log(n); //[1, 2, "nihao"] } fn3(1,2,'nihao')
-
变量的解构赋值
(解析结构并赋值)
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这即是解构
-
解构数组
格式: let [变量1,变量2,...]=[数据1,数据2,...]
也可以解构多维数组
数组的结构重点是 等号两侧的结构模式一样
let [ni,hao,bei,jing]=['你','好','北','京']; console.log(ni); console.log(hao); console.log(bei); console.log(jing); //结构赋值获取数组里的成员,同时给4个变量赋值了 //本质就是es5的 let ni=['你','好','北','京'][0]; ...
// ---- 结构多维数组 let arr=['你','好','北',[1,2,[3]]]; let [a,b,c,[d,e,[f]]]=arr; console.log(a,b,c,d,e,f); // 你 好 北 1 2 3
-----使用结构赋值交换变量,可以直接交换不用使用中间变量 var a='你'; var b='好'; console.log(a,b); // 你 好 [b,a]=[a,b]; console.log(a,b); // 好 你
不完全结构. 等号左侧只匹配一部分等号右侧的数组
let [x,y]=[1,2,3]
-
解构对象(必须与对象属性名相同)
语法: let {key1,key2,...}={键值对1,键值对1,...};
const per={ name:'小明', age:'12', run:function(){ console.log('run666666') } }; let {name,age,run}=per; //解构赋值了3个变量 // 等价于 //let name=per.name; //let age=per.age; //let run=per.run; ----- let {run}=per; //也可以只解构赋值一个变量 console.log(name); //小明 console.log(age); //12 console.log(run); // ƒ (){ console.log('run666666') } 优点:可以直接调用方法 run() 不用像之前一样调用 per.run()
-
解构的时候可以给结构的变量起一个别名
let {key1:别名}={...}
const per={ name:'小明', age:'12', run:function(){ console.log('run666666') } }; //---------------------------------------------解构的时候可以给结构的变量起一个别名 let {name:n}=per; //等同于 let n=per.name console.log(name);//'小明' console.log(n);//'小明'
-
解构多维对象
let o1={ a:100, b:200, o2:{ c:300, o3:{ d:400 } } }; let {a,b,o2:{c,o3:{d}}}=o1; console.log(a,b,c,d); //100 200 300 400 /* -----案例分析 o2定义一个别名{c,o3:{d}}=o1.o2; 这又是 一个结构赋值 let {c,o3:{d}}=o1.o2; let c=o1.o2.c o3定义一个别名 let {d}=o1.o2.o3 所以d=o1.o2.o3.d */
-
简化对象写法
在es6标准下,对象的简写格式
当对象的key和value一模一样的时候,可以只写一个
即在对象花括号里直接写入变量名和函数,作为对象的属性和方法,这样的写法更简洁
let name="小明",age="18",run=function(){console.log("666666")}; const per={ name:name, //------------属性值是name变量可以简写 age:age, run:run, skill:'skill'//-----------属性值是字符串 是一个准确的值不能简写 } console.log(per);//{name: "小明", age: "18", run: ƒ} //-------------------------------------------------------es const per2={ name, age, run, song:function(){ console.log('77777') }, //--------------------------------方法可以省略 :function song2(){ console.log('77777') }, song3:()=>{...} //------------------箭头函数不能简写 } console.log(per2);//{name: "小明", age: "18", run: ƒ, song: ƒ, song2: ƒ}
对象的新增方法 Object.assign
Object.assign()方法。 做对象覆盖
-
作用:用于对象的合并,将源对象的属性,复制到目标对象
-
格式:Object.assign(目标对象,源对象1,源对象2)
第一个参数是目标对象,后面的参数都是源对象
-
注意:如果目标对象与源对象,或者多个源对象有同名属性,后面的属性会覆盖前面的属性
let target={a:1}; let source1={a:2,b:8}; Object.assign(target,source1) console.log(target);//{a:2,b:8}
扩展:
-
Object.assign()方法实行的是浅拷贝,而不是深拷贝,即如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用(地址)
let target={a:1,m:'haha'}; let source1={a:2,b:8,c:{d:99,e:77}}; Object.assign(target,source1) console.log(target); //{a:2,m:'haha',b:8,c:{d:99,e:77}} target.c.d=0; console.log(source1.c.d); //0
-
对于这种嵌套的对象,一旦遇到同名属性,Object.assgin()的处理方式是替换,而不是添加
let target={a:{b:2}} let source1={a:{b:2,c:3}} Object.assign(target,source1) console.log(target);//{a:{b:2,c:3}}
使用案例:
//-------没有使用Object.assign()方法 function fn(options){ console.log('type',options.type); console.log('url',options.url); //调用成功的回调函数 options.succes(); //调用失败的回调函数 options.error(); } //调用fn的时候传入一个对象作为参数,每一次调用对象里的每一个成员都要设置 fn({ type:'get', url:'****', succes:function(){ console.log('成功') }, error:function(){ console.log('失败') } })
//-----使用Object.assign()方法 进行代码优化 function fn(options){ //设置一个默认值 var defaultValue={ type:'get', url:'****', succes:function(){ console.log('成功') }, error:function(){ console.log('失败') } } //用传进来的实参覆盖默认值 //如果实参与默认值的同名属性不一样,会用实参的值覆盖默认值 //这样我们就不用每次调用函数的时候对象里每一个成员属性都要设置了,没有设置的就采用默认值 Object.assign(defaultValue,options) console.log('type',defaultValue.type); console.log('url',defaultValue.url); //调用成功的回调函数 defaultValue.succes(); //调用失败的回调函数 defaultValue.error(); } //调用fn的时候传入一个对象作为参数 //这样我们就不用每次调用函数的时候对象里每一个成员属性都要设置了,没有设置的就采用默认值 fn({ type:'post', url:'www.baidu.com' }); //--调用函数 fn({ type:'@@@', })