ES6语法
在ES6中,提供了let关键字和const关键字,都具有块级作用域
let关键字的使用let关键字
仅仅在自己的块级作用域内起作用
不存在变量提升,必须先进行变量的声明(否则会报错)
在同一个块级作用域内,不允许声明同名的变量
在函数内不能使用let关键字重新声明函数的参数
1 2 3 4 5 6 function demo (ts ){ let ts = "哈哈" ; alert (ts) } demo (Hi );
在for循环中使用let关键字可以解决闭包问题
1 2 3 4 5 <div id ="dv" > <button > 测试</button > <button > 测试</button > <button > 测试</button > </div >
1 2 3 4 5 6 7 var node = document .getElementByTagName ("button" );for (let i=0 ;i<node.length ;i++){ node[i].onclick = function ( ){ node[i].innerHTML = "成功了" } }
不影响作用域链
总结:使用let关键字声明的变量只在跨级作用域中起作用,比较适合for循环中,同时不会出现变量提升的现象; 且同一个代码块内,不可以重复声明相同的变量,也不可以重复声明函数内的参数。
const关键字的使用
只在块级作用域内起作用
声明后的值不可以被修改
不存在变量提升,必须先声明后才能使用
不可以重复声明同一个变量,且声明后必须赋值
const常量可以是一个对象类型或数组,内部的数据是可以修改的
总结:==var & let & const关键字之间的差异==
var 是在全局起作用的,而const和let关键字都是只在自己的块级作用域起作用的
const和let关键字都是不存在变量提升的,必须先进行声明;且不可以重复声明同一个变量
使用const关键字在声明时必须同时赋值,而var和let关键字可以将声明和赋值分开进行
const关键字声明后的值不可以被修改,而var和let却可以
let关键字不能在函数内重新声明函数的参数
解构赋值
数组的解构赋值
1 2 var [a,b,c] = [10 ,20 ,30 ]; var [a,,c] = [10 ,20 ,30 ];
对象的解构赋值,用到谁就解构谁
1 2 var {foo,bar} = {bar :"aaa" ,foo :"bbb" };
复杂结构的解构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const person = { name : "超哥" , age : 28 , dog : { Dname : "Bruce" , Dage : 10 }, sayHi : function ( ) { console .log ("Hi, I am chao" ) } } const {name,age,dog :{Dname ,Dage },sayHi} = person;console .log (Dname ,Dage ); sayHi ();
对象的简化写法
对象的属性和方法都可以使用外部定义的属性或者函数
对象中的方法,可以不使用function关键字来定义,直接书写最简单的方式
箭头函数
基本语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var f = (a,b )=>{ return a+b; } function f (a,b ){ return a+b; } var f = ( )=> 5 ;var sum = (a,b )=>a+b;var f = a=> a;var getItem = id=>({ id :id,name :"item" })const full =({first,last} )=>{ return first + "" +last; }
使用场景(定时器,数组中常用的方法,事件的回调函数。。。)
1 2 3 4 5 6 7 8 9 10 setTimeout (()=> { console .log ("test" ); },1000 ) arr.forEach ((item,index )=> { console .log (item); })
不能作为构造函数去使用
==箭头函数的this是不能改变的==,与this有关的操作都不适合用箭头函数。(例如:对象里面的方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 function foo ( ){ setTimeout (()=> { console .log ("id:" ,this .id ) },1000 ) } var id = 21 ;foo.call ({id :42 });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Timer ( ) { this .s1 = 0 ; this .s2 = 0 ; setInterval (() => this .s1 ++, 1000 ); setInterval (function ( ) { this .s2 ++; }, 1000 ); } var timer = new Timer ();setTimeout (() => console .log ('s1: ' , timer.s1 ), 3100 );setTimeout (() => console .log ('s2: ' , timer.s2 ), 3100 );
this指向的固定化,是因为箭头函数没有自己的this,导致内部的this就是外层代码的this;
this 的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var box = document .getElementById ("box" );box.addEventListener ("click" ,function ( ){ var _this = this ; setTimeout (function ( ){ _this.style .width = "300px" ; _this.style .height = "300px" ; },1000 ) },false ) var box = document .getElementById ("box" );box.addEventListener ("click" ,function ( ){ setTimeout (()=> { this .style .width = "300px" ; this .style .height = "300px" ; },1000 ) },false )
箭头函数中的arguments是不能使用的,用rest参数代替(args)
函数参数的默认值设置
ES6允许给函数形参赋值初始值;形参可以有默认值,==一般默认值靠后==;与解构赋值结合使用,解构赋值的形式先后顺序不影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function f1 ({name="超哥" ,age} ){ console .log (name,age) } var obj = { name :"强哥" , age :18 } f1 (obj);function f1 ({name="超哥" ,age} ){ console .log (name,age) } var obj = { age :18 } f1 (obj);
rest参数
ES6中引入rest参数(真数组),代替arguments;arguments是对象(伪数组)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function f1 (...args ){ console .log (args) } f1 (100 ,200 ,300 ); var obj1 = { name :"小猪佩琪" , age :10 } var obj2 = { gender :"男" , height :180 } var obj = { ...obj1, ...obj2 } console .log (obj);var arr1 = [...arr];
扩展运算符(spread)的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var arr = [...arr1,...arr2];console .log (arr); var obj = { ...obj1, ...obj2 } console .log (obj); var newCars = [...cars];var btnObjs = document .getElementById ("btn" ); var btnObjs2 = [...btnObjs];
Symbol数据类型
Symbol是为了防止属性名的冲突,保证每一个属性名都是独一无二的。
1 2 3 4 5 6 let s1 = Symbol ("foo" );let s2 = Symbol ("foo" );s1 === s2 Symbol .for ("bar" ) === Symbol .for ("bar" );
创建方式
1 2 3 4 5 6 7 const s1 = Symbol ();console .log (s1); const s2 = Symbol ("强哥" );console .log (s2);
应用1(通过Symbol向对象中添加方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const person = { eat ( ){ console .log ("今晚吃什么" ) }; run ( ){ console .log ("赶紧去" ) } }; person.eat = function ( ){ console .log ("没想好" ) } person.run = function ( ){ console .log ("跑不动" ) } person.eat (); person.run (); const obj = { eat : Symbol ("eat" ), run : Symbol ("run" ) } person[obj.eat ] = function ( ){ console .log ("新的eat方法" ) } person[obj.run ] = function ( ){ console .log ("新的run方法" ) } person.eat (); person.run (); person[obj.eat ](); person[obj.run ]();
应用2(通过Symbol创建对象属性)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var obj = { age : 20 , [Symbol ("name" )]:"小强" , [Symbol ("look" )](){ console .log ("快看" ) } }; const result = Reflect .ownKeys (obj);console .log (result); for (var i=0 ;i<result.length ;i++){ console .log (result[i]); } for (var i=0 ;i<result.length ;i++){ console .log (obj[result[i]]); } for (var key in result){ console .log (key); }
Symbol 内置的属性值
ES6中新引入的遍历命令,for-of循环
Iterator接口主要提供for-of消费,数组可以使用for-of遍历,是因为内部实现了iterator接口
1 2 3 4 var arr = [10 ,20 ,30 ,40 ];var iterator = arr[Symbol .iterator ()];
for-of不能遍历对象,因为for-of无法遍历自己定义的属性,这是因为它的内部没有实现迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var obj = { name :"强哥" , age :47 , cars :["奔驰" ,"宝马" ,"奥迪" ,"捷达" ], [Symbol .iterator ]:function ( ){ let that = this ; let index = 0 ; return { next : function ( ){ if (index>=that.cars .length ){ return { value :"undefined" , done :true } }else { return { value : that.cars [index++], done :false } } } } } } for (var key of obj){ console .log (key); }
Generator生成器函数
ES6提供的解决异步编程的方案之一,Generator函数是一个状态,内部封装了不同状态数据,用来生成遍历对象。
声明的语法特殊
调用时返回的结果是指针对象
允许出现yield语句,相当于代码的分隔符,后面的代码不会执行
每执行一次next方法,执行一段js代码,并返回yield语句的结果
1 2 3 4 5 6 7 8 9 function * gen ( ){ console .log ("强哥好可爱" ); yield "AAA" ; console .log ("超哥好帅哦" ); } const iterator = gen (); console .log (iterator.next ()); console .log (iterator.next ());
生成器函数的参数
1 2 3 4 5 6 7 8 9 10 11 function * gen (args ){ console .log (args); let result1 = yield "AAA" ; console .log (result1); let result2 = yield "BBB" ; console .log (result2); } const iterator = gen ("000" );console .log (iterator.next ()); console .log (iterator.next ("111" )); console .log (iterator.next ("222" ));
生成器函数的实践1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function one ( ){ setTimeout (()=> { console .log ("111" ); iterator.next (); },1000 ) } function two ( ){ setTimeout (()=> { console .log ("222" ); iterator.next (); },1000 ) } function three ( ){ setTimeout (()=> { console .log ("333" ); console .log (iterator.next ()); },1000 ) } function * gen ( ){ yield one (); yield one (); yield three (); yield "终于结束了" ; } var iterator = gen ();iterator.next ();
生成器函数的实践2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 function getLogin ( ){ setTimeout (()=> { const user = "用户信息" ; iterator.next (user); },1000 ) } function getProduct ( ){ setTimeout (()=> { const product = "商品信息" ; iterator.next (product); },1000 ) } function getOrder ( ){ setTimeout (()=> { const order = "订单信息" ; iterator.next (order); },1000 ) } function * gen ( ){ const login = yield getLogin (); console .log (login); const product = yield getProduct (); console .log (product); const order = yield getOrder (); console .log (order); } var iterator = gen ();iterator.next ();
for-in 与 for-of循环的区别
一般来说,for-in遍历对象(Object),for-of遍历数组会比较方便。
但是,for-of不能循环出自定义的属性。这是因为for-of循环的是可迭代的对象的的value,而for-in循环的是可迭代的对象的key值。
for-of不可以循环普通的对象,对于普通对象的属性遍历推荐使用for-in循环。
Set集合的属性和方法
Set对象是值的集合,可以按照插入的顺序迭代它的元素,且Set集合中的数据是唯一的 ,重复元素在set中自动被过滤掉。
==Set()中放入的内容是可以通过for-of进行遍历的数据==:数组、字符串都可以,自定义的对象不行
1 2 3 4 5 6 7 8 9 10 11 const num = new Set ([1 ,2 ,3 ,4 ,5 ]);const name = new Set ("abcdef" );num.add (100 ); num.delete (10 ); num.has (100 ); num.clear ();
Set集合的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 var arr1 = ["强哥" ,"小强" ,"小强" ];var arr2 = [...new Set (arr1)];console .log (arr2);var arr3 = [10 ,20 ,30 ,40 ,50 ];var arr4 = [20 ,30 ,50 ,60 ,70 ];var arr5 = [...new Set (arr3)];var arr6 = arr5.filter (item => { let s = new Set (arr4); return s.has (item) }) console .log (arr6);var arr5 = [...new Set (arr3)].filter (item =>new Set (arr4).has (item));console .log (arr5);var arr7 = [10 ,20 ,30 ,40 ];var arr8 = [10 ,20 ,40 ,60 ];var arr9 = [...new Set ([...arr7,...arr8])];console .log (arr9);var arr10 = [10 ,20 ,30 ,40 ];var arr11 = [10 ,20 ,40 ,60 ];var arr12 = [...new Set (arr10)].filter (item => !(new Set (arr11).has (item)));console .log (arr12);
Map集合的属性和方法
Map容器:无序的key,不重复的多个key-value的集合体,放入的内容是可以通过for-of进行遍历的数据
由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值覆盖掉
1 2 3 4 5 6 7 8 9 10 11 12 13 var m = new Map ([["Bruce" ,18 ],["Michael" ,25 ]]);m.set ("name" ,"强哥" ); m.get (key); m.delete (key); m.has (key); m.clear (); m.size ;
Class实例化对象
ES5中创建对象的方式:new Object() / 构造函数 / {}
ES6中可以直接通过class定义类(代替了ES5中的构造函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Person { constructor (name,age ){ this .name = name; this .age = age; } eat ( ){ console .log ("今晚吃什么?" ) } run ( ){ console .log ("怎么去?" ) } } var per = new Person ("强哥" ,18 );console .log (per.name ,per.age );per.eat (); per.run ();
class实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class SellBrother { constructor (name,age,gender,phone ){ this .name = name; this .age = age; this .gender = gender; this .phone = phone; } cook ( ){ console .log ("红烧肉" ); } gave ( ){ console .log ("送饭来了,请接收" ); } } var ge = new SellBrother ("小黄" ,35 ,"男" ,151 );ge.cook (); ge.gave ();
ES6实现静态成员
属性------静态属性和实例属性
方法------静态方法和实例方法
静态成员是构造函数对象的(函数对象上的,直接通过==函数名字点属性名==出来的,
调用时,静态成员是通过类来调用的,而不是通过实例对象调用的。
ES5中添加静态成员的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function Person (age ){ this .age = age; this .eat = function ( ){ console .log ("下雨了" ); } } Person .age = 100 ;Person .run = function ( ){ console .log ("快跑啊" ); } var per = new Person (20 );console .log (per.age ); console .log (Person .age ); per.eat (); Person .eat ();
ES6中添加静态成员的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person { constructor (age ){ this .age = age; } static name = "人类" ; static eat ( ){ console .log ("人都要吃饭" ); } } console .log (Person .name );Person .eat ();
ES6中实现继承的方法
ES5中实现继承的方式(==借用构造函数==实现继承和==改变原型指向==实现继承)
对象中—proto—,
函数中prototype
—proto—的指向必然是所在的实例对象使用的构造函数中的prototype,
函数也是对象,函数都是Function的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function Person (name,age ){ this .name = name; this .age = age; } Person .prototype .eat = function ( ){ console .log ("吃饭了" ); } function Student (name,age,gender,score ){ Person .call (this ,name,age); this .gender = gender; this .score = score; } Student .prototype = new Person ();Student .prototype .sayHi = function ( ){ console .log ("好长一段话啊" ); } var stu = new Student ("强哥" ,18 ,"男" ,100 );stu.eat (); stu.sayHi ();
ES6中实现继承的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Person { constructor (name,age ){ this .name = name; this .age = age; } sayHi ( ){ console .log ("你好" ); } } class Student extends Person { constructor (name,age,score ){ super (name,age); this .score = score; } } const stu = new Student ("强哥" ,20 ,50 );stu.sayHi ();
getter 和 setter方法的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person { get name (){ return this .myName ; } set name (val ){ this .myName = val; } } var per = new Person ();per.name = "强哥" ; console .log (per.name );
数值的扩展
进制数(二进制、八进制、十进制、十六进制)
对象扩展
1 2 3 4 5 6 7 8 Object .is (1 ,1 );Object .assign (obj1,obj2,obj3);
深拷贝和浅拷贝
复制对象(数组),依据就是创建的新对象修改是否会影响原来的数组。
会产生影响的是浅拷贝,不会产生影响的是深拷贝
浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var arr = [1 ,2 ,3 ,{a :4 }];var newArr = arr.concat ();newArr[3 ].a = 5 ; console .log (arr); console .log (newArr); const arr = [1 ,2 ,3 ,{a :4 }];const newArr = arr.slice (0 );newArr[3 ].a = 100 ; console .log (arr); console .log (newArr); const arr = [1 ,2 ,3 ,{a :4 }];const newArr = [...arr];newArr[3 ].a = 100 ; console .log (arr);console .log (newArr);
复制对象
1 2 3 4 5 6 7 8 9 10 const obj = { name : "guigu" , xueke :["java" ,"大数据" ,"前端" ] } const newObj = {}Object .assign = (newObj,obj);newObj.xueke [0 ] = "H5" ; console .log (obj);console .log (newObj);
深拷贝
JSON
JSON.stringify( ) 将js对象转换成字符串,为了保存和传递 。
JSON.parse( ) 将JSON格式的字符串,转换为JS对象。
1 2 3 4 5 6 7 8 9 10 11 const school = { name :"guigu" , } let str = JSON .stringify (school);let newSchool = JSON .parse (str);newSchool.name = "新对象" ;
递归实现深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 const school = { name :"guigu" , xueke :["前端" ,"JAVA" ,"大数据" ,"云计算" ], founder :{ name :"刚哥" , age : 42 }, improve :function ( ){ console .log ("提高技能" ) } } const newSchool = {};newSchool.name = school.name ; newSchool.xueke = []; newSchool.xueke [0 ] = school.xueke [0 ]; newSchool.xueke [1 ] = school.xueke [1 ]; newSchool.xueke [2 ] = school.xueke [2 ]; newSchool.xueke [3 ] = school.xueke [3 ]; newSchool.founder = {}; newSchool.founder .name = school.founder .name ; function getDataType (data ){ return Object .prototype .toString .call (data).slice (8 ,-1 ) } function deepClone (data ){ let type = getDataType (data); console .log (type); let container; if (type === "Array" ){ container = []; } if (type === "Object" ){ container = {}; } for (let i in data){ let t = getDataType (data[i]); if (t === "Array" || t === "Object" ){ container[i] = deepClone (data[i]); }else if (t === "Function" ){ container[i] = data[i].bind (container); }else { container[i] = data[i]; } } return container; }
Less
嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 .container { min-height : 500px ; header { border : 1px solid #ddd ; } > section { height : 200px ; position : relative; & ::after { content :"" ; position :absolute; width : 100px ; height : 5px ; } .left { width : 70% ; height : 400px ; background :#789 ; & :hover { background :yellow; } @media screen and (min-width :1200px ){ background : yellowgreen; } @media screen and (max-width :1200px ) and (min-width :992 ){ background : skyblue; } @media screen and (max-width :992px ){ background : orange; } } } }
混合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 .header { width :100px ; height :100px ; } .center { .header (); } .center (){ position :absolute; left :50% ; top :50% ; transform : translate (-50% ,-50% ); } .bg (@color ){ background :@color ; } .h (@height ){ height :@height ; } footer { .bg (#798 ); .h (100px ); } @flag = 1 ;.border (@border )when (@flag = 1 ){ border :2px solid @color ; } #test { .h (100px ); .bg (#aef ); .border (#145 ); }
变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @color: #aef ;@height : 100px ;header { background : @color ; height : @height ; } @selector: #section;@{selector} { height : 400px ; background : #899 ; } @one: section;@two: footer;@s: ~'@{one},@{two}' ;@{s} { background : #999 ; } header { height : 100px + 200px ; }
文件导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @import "button" ;button { .btn (); } .btn (){ padding : 10px 12px ; border : none; outline :none; border-radius :5px ; }
Less的内置函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 header { width : ceil (100px /3 ); height : floor (100 /6px ); } @color: #980 ;section { width : percentage (1 /3 ); background :fadein (rgba (100 ,200 ,120 ,0.4 ),10% ); }
Map
1 2 3 4 5 6 @color: #379 ;#color (){ base: @color; abc :darken (@color ,10% );}
封装(Bootstrap)
栅格系统容器的实现
JavaScript中的错误对象
JavaScript定义了7种错误类型:
Error错误
EvalError全局错误
RangeError范围错误
ReferenceError引用错误
SyntaxError语法错误
TypeError类型错误
URIError编码错误
Error
基础类,其他错误类型都继承自该类型。很少见,如果有也是浏览器抛出的。
EvalError 全局错误
在使用eval()函数时发生异常时抛出的错误。
TypeError
类型错误,对象表示值的类型非预期类型时发生的错误。
当传入函数的操作数或参数的类型并非操作符或函数所预期的类型时,会抛出这个错误
ReferenceError
引用错误,对象表明一个不存在的变量被引用。当你尝试引用一个未被定义的变量时,将会抛出这个错误
RangeError
试图传递一个number参数给一个范围内不包含该number的函数时会引发这个错误
SyntaxError
对象尝试解析语法上不合法的代码时引发的错误,可能是丢失运算符或者转译字符等。