ES5 和ES6【ES2015】规范
ES5是2009年的制定的规则,ES6是2015年制定,可以说比ES5有了一个非常大的突破。接下来我们主要说说ES6的特性。
1. let、const和块级作用域
var 可以跨块访问,顶级window属性
let 只能在块作用域访问,不可跨函数
const 只能在块作用域访问,不可跨函数,声名时必须赋值,原始值不可修改
//报错 const一旦声明就必须赋值
const PI;
//报错 const一旦声明如果值是原始类型的值,值不能改变
const PI=3.1415926;PI = 3.14;
//报错 const一旦声明如果值是引用类型的值,地址值不能改变
const obj = {a:1,b:2}obj = {};
2.箭头函数(Arrow Function)
//优点
隐士返回,可省去return标识。解决this指向问题。写法简单。
//不可用的地方
构造函数。使用arguments对象。使用this处理点击对象的。
3. 模板字符串(Template String)
//es5 插入大段的html内容到文档中
$("div").append(
"There are <b>" + student.count + "</b> " +"students in your class "。
);
//es6可以这样写
$("#result").append(`
There are <b>${student.count}</b> students in your class。
`);
对象字面量扩展语法(Enhanced Object Literals)
4.表达式结构:解构(Destructuring)
let cat = 'andy'
let dog = 'gary'
let zoo = {cat, dog} //传统写法 let zoo = {cat:cat, dog:dog}
console.log(zoo) //Object {cat: "andy", dog: "gary"}
5.default reset
//es5
function student(name){
name= name|| 'no';
console.log(name);
}
student();
//如果用ES6我们而已直接这么写:
function student(name= 'no'){
console.log(name);
}
student();
6.函数参数表达、传参
//es5 arguments 不是数组
var f = function () {
console.log(arguments[0]); //1
console.log(arguments[1]); //2
};
f(1, 2);
//es6 rest ...是数组,剩余不确定参数,可以和固定参数分离
var f = function (count,...num) {
console.log(num[0]); //2
console.log(num[1]); //3
console.log(arguments[0],arguments[1],arguments[2],arguments.length);//1,2,3
count=5;
console.log(arguments[0]);//1 不会改变arguments原值
};
f(1, 2,3);
7.新的数据结构
//Set 数组不重复,无序
const s1 = new Set();
s1.add(1);
s1.add(2);
s1.add(1);//{1, 2}
s1.size //2
s1.delete(2);//{1}
s1.has(2);//false
s1.clear();//清零
for (let item of set.keys()) 和for (let item of set.values());//效果一样
//Set应用
//1.数组去重
let array = [1,2,1,4,3,'1'];
[...new Set(array)] // [1, 2, 4, 3, "1"]
//2.实现并集、交集、差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));// set {2, 3}
// 差集
let difference = new Set([...a].filter(x => !b.has(x)));// Set {1}
//WeakSet 较弱Set
1.成员只能是对象,而不能是其他类型的值。
2.没有size属性。
3.不可循环。因为垃圾回收不考虑weakset的引用。
4.优点是省内存,用完即被垃圾回收。
//Map 键值对,代替object
Map的键是跟内存地址绑定的,只要内存地址不一样,就视为两个键。键值是字符串,对象,甚至是一个函数。
var map = new Map();
var obj1 = ['m'];
var obj2 = ['m'];
map.set(obj1, 111);
map.set(obj2, 222);
map.get( obj1 ); //111
map.get( obj2 ); //222
map.has(obj1 ) // true
map.delete(obj1 ) // true
map.clear() //清除
//map循环
const map = new Map([['name', 'andy'],['age', 38]]);
for (let key of map .keys()) {console.log(key)}
// name
// age
for (let value of map . values()) {console.log(value)}
// andy
// 38
for (let item of map . entries()) {console.log(item[0], item[1])}
// name andy
// age 38
map .forEach((value, key) => console.log(key,value))
// name andy
// age 38
//Map 转为 Array,使用扩展运算符 ...
let map = new Map([['name', 'andy'], ['age', 38]]);
[...map]; // 返回值为 [["name","andy"],["age",38]]
//Array 转为 Map 数组必须是一个二维数组才可以
let arr = [[1, 5], [1, 10], ['name', 'andy'], ['name', 'gary']];
let map= new Map(arr);// 返回值为 Map(2) {1 => 10, "name" => "gary"}
WeakMap
WeakMap 与 WeakSet 作为一个比较新颖的概念,其主要特点在于弱引用,快速回收垃圾,减少内存占用量。
8.Promise
promise有三种状态: pendding fulfilled rejected
如果是接受状态,则继续下一个then。如果是拒绝状态则直接停止。
接受状态:调用resolve,或者返回一个值,或者无任何返回【传入参数会传到下一个then】
拒绝状态:调用reject,或者抛出一个异常
const promise = new Promise((resolve, reject) => {
// do something here ...
if (success) {
resolve(value); // fulfilled
} else {
reject(error); // rejected
}
});
//面试题1:红绿灯交替闪烁
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
var light = function (timmer, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
cb();
resolve();
}, timmer);
});
};
//面试题1答案
var step = function () {
Promise.resolve().then(function () {
return light(3000, red);
}).then(function () {
return light(2000, green);
}).then(function () {
return light(1000, yellow);
}).then(function () {
step();
});
}
step();
//面试题2:要求分别输出 1 2 3 done [1,2,3]
const timeout = ms => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, ms);
});
const ajax1 = () => timeout(2000).then(() => {
console.log('1');
return 1;
});
const ajax2 = () => timeout(1000).then(() => {
console.log('2');
return 2;
});
const ajax3 = () => timeout(2000).then(() => {
console.log('3');
return 3;
});
const mergePromise = ajaxArray => {
// 在这里实现你的代码
};
mergePromise([ajax1, ajax2, ajax3]).then(data => {
console.log('done');
console.log(data); // data 为 [1, 2, 3]
});
//面试题2答案
// 保存数组中的函数执行后的结果
var data = [];
// Promise.resolve方法调用时不带参数,直接返回一个resolved状态的 Promise 对象。
var sequence = Promise.resolve();
ajaxArray.forEach(function (item) {
// 第一次的 then 方法用来执行数组中的每个函数,
// 第二次的 then 方法接受数组中的函数执行后返回的结果,
// 并把结果添加到 data 中,然后把 data 返回。
// 这里对 sequence 的重新赋值,其实是相当于延长了 Promise 链
sequence = sequence.then(item).then(function (res) {
data.push(res);
return data;
});
})
// 遍历结束后,返回一个 Promise,也就是 sequence, 他的 [[PromiseValue]] 值就是 data,
// 而 data(保存数组中的函数执行后的结果) 也会作为参数,传入下次调用的 then 方法中。
return sequence;
Proxy
proxy翻译过来就是代理,对目标对象的外层搭建了一层拦截,外界对目标对象的一些操作【访问属性等】,可以进行某种需要的过滤。
//代理对象
var target = {
name: 'andy'
};
//代理对象的操作
var handler= {
get: function(target, key) {
console.log(`${key} 被读取`);
return target[key];
},
set: function(target, key, value) {
console.log(`${key} 被设置为 ${value}`);
target[key] = value;
}
}
//代理实例化
var proxy = new Proxy(target, handler);
proxy .name; //输出:name 被读取
proxy .name = 'gary'; //输出:name 被设置为 gary
console.log(target.name); //输出: gary
Generator 生成器函数
function* 用来声明一个函数是生成器函数,比普通多了一个*。yield暂停交出执行权,next继续恢复执行权,可以理解为异步编程。
function* test() {
console.log("this is generator");
//yield 代码会暂停
yield console.log("调用next 就往下执行一次");
}
var h = test();//输出: 无
h.next();//输出:this is generator
h.next();//输出:调用next 就往下执行一次
代码模块化
commonjs 和 amd 规范:详细看这里
ES5的代码模块化:
1.common.js规范:
同步加载,适合nodejs后端使用,通过module.exports定义模块
2.AMD规范[Asynchronous Module Definition]:
异步模块,适合浏览器前端使用,requrejs实现者,通过define方法,定义模块;通过require方法,加载依赖的模块。
3.CMD规范:
同步模块,SeaJS淘宝实现者,一个模块就是一个文件。
ES6的代码模块化:
通过export 定义模块,通过import 导入依赖模块。
// student.js start
let name = "andy";
let age= 10;
// score没有被导出,外界无法访问
let score= 30;
function info(){}
// 将本模块中的私有成员 暴露出去,供其他模块使用,default只可有一个
export default {
name,
age,
info
}
// student.js end
//test.js start
// 导入模块成员
import { name,age,info } from './student.js'
console.log(name) // 输出: andy
//test.js end
Symbol
ES6数据类型有: Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol。
Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。
let student = {name:"andy"};
//如果不小心这样写就覆盖上面的值了
student.name = "gary";
let student = {}
let name = Symbol("name");
let age = Symbol("name");
console.log(name === age);//输出:false
student[name]="andy";
student[age]=18;
Web Worker 子线程
ES6引入的子线程概念,可以使用new Worker(url),将url指向的js代码,放入子线程中执行。
1.主线程 worker.html
<html>
<head>
<title>ES6 子线程测试</title>
<meta charset="UTF-8"/>
<script>
var myWorker = new Worker("my_task.js",{name:'andy'});
//监听子域
myWorker.onmessage = (e)=> {
console.log('%c%s','color:green','收到子域:',e.data);
if(!e.data)return;
let action = e.data.action;
let param = e.data.param;
switch(action){
case "loadFile":
myWorker.postMessage({action:"end",param:""});
break;
}
};
//异常处理
myWorker.onerror=function (err) {
console.log('%c%s','color:red',"主域收到异常:",err.message);
}
// 向子域发送信息
myWorker.postMessage({action:"start",param:"info.txt"});
</script>
</head>
</html>
2.子线程 task.js
console.log("初始化子域:传入数据:",self.name);
//监听主域
self.addEventListener('message', (e)=> {
console.log("收到主域:",e.data);
if(!e.data)return;
let action = e.data.action;
let param = e.data.param;
switch(action){
case "start":
loadFile(param);
break;
case "end":
throw new Error('task is end!');
//强行关闭子线程
self.close();
break;
}
}, false);
function loadFile(fileName){
var xmlreq = new XMLHttpRequest();
xmlreq.responseType = "text";
xmlreq.onload = function (e) {
var data = e.currentTarget.response;
self.postMessage({action:"loadFile",param:data});
}
xmlreq.open("get",fileName);
xmlreq.send()
}
基础学习
1.字符串替换 详细看这里
//替换字符串可以插入下面的特殊变量名:$$ $&
"hello world".replace("h","9$&9");//输出 9h9ello world
2.前端错误信息监控 【详细看这里】
window.addEventListener('error', function (e) {
let logObj = {
msg: e["error"] ? e["error"].message : "",
errorObj: e["error"] && e["error"].stack ? e["error"].stack.toString() : ""
}
});
//当Promise被reject且没有reject处理器的时候
window.addEventListener('unhandledrejection', function (e) {
let logObj = {
msg: e["reason"] ? e["reason"].message : "",
errorObj: e["reason"] && e["reason"].stack ? e["reason"].stack.toString() : ""
}
});
3.Object对象属性排序
var obj={p120:{},p110:{},p50:{},p20:{}};
//排序函数
function objKeySort(obj) {
//先对原对象属性名字排序
var newkey = Object.keys(obj).sort((a,b)=>{
if(Number(a.replace("p",""))<Number(b.replace("p","")))
return -1;
else
return 1;
});
//按照排序的名字,重新赋值到一个新对象
var newObj = {};
for (var i = 0; i < newkey.length; i++) {
newObj[newkey[i]] = obj[newkey[i]];
}
return newObj;
}
obj=objKeySort(obj);
//结果显示:p20 p50 p110 8120
for(var key in obj){console.log(key)};
4.数学知识
//弧度和角度表示角的大小;正玄值,余玄值和正切值表示边与边的比例
/**
* 角度转成弧度
* @param angle 角度
*/
public static angleToRadian(angle:number):number{
return angle *Math.PI/180;
}
/**
* 弧度转成角度
* @param radian 弧度
*/
public static radianToAngle(radian:number):number{
return radian *180/Math.PI;
}
/**
* 获得弧度
* @param fromX
* @param fromY
* @param toX
* @param toY
* @return [-π,π]
*/
public static getRadian(fromX:number,fromY:number,toX:number,toY:number):number{
return Math.atan2(fromY-toY,fromX-toX);
}
//正玄值和余玄值 [-1,1]
正玄:Math.sin(弧度值) = 对边/斜边
余玄:Math.cos(弧度值) = 临边/斜边
正切:Math.tan(弧度值) = 对边/临边
//弧度 [-π/2,π/2]
弧度:Math.asin(正玄值)
弧度:Math.acos(余玄值)
弧度:Math.atan(正切值)
浏览器方法
1.得到用户浏览器语言
function getBrowserLang(){
var lang = navigator.languages? navigator.languages[0] : (navigator.language || navigator.userLanguage);
lang = lang?lang.toLowerCase():"en";
lang = lang.slice(0, 2)
return lang;
}
2.得到用户浏览器类型
function getBrowser() {
var u = navigator.userAgent;
var bws = [{
name: 'sgssapp',
it: /sogousearch/i.test(u)
}, {
name: 'wechat',
it: /MicroMessenger/i.test(u)
}, {
name: 'weibo',
it: !!u.match(/Weibo/i)
}, {
name: 'uc',
it: !!u.match(/UCBrowser/i) || u.indexOf(' UBrowser') > -1
}, {
name: 'sogou',
it: u.indexOf('MetaSr') > -1 || u.indexOf('Sogou') > -1
}, {
name: 'xiaomi',
it: u.indexOf('MiuiBrowser') > -1
}, {
name: 'baidu',
it: u.indexOf('Baidu') > -1 || u.indexOf('BIDUBrowser') > -1
}, {
name: '360',
it: u.indexOf('360EE') > -1 || u.indexOf('360SE') > -1
}, {
name: '2345',
it: u.indexOf('2345Explorer') > -1
}, {
name: 'edge',
it: u.indexOf('Edge') > -1
}, {
name: 'ie11',
it: u.indexOf('Trident') > -1 && u.indexOf('rv:11.0') > -1
}, {
name: 'ie',
it: u.indexOf('compatible') > -1 && u.indexOf('MSIE') > -1
}, {
name: 'firefox',
it: u.indexOf('Firefox') > -1
}, {
name: 'safari',
it: u.indexOf('Safari') > -1 && u.indexOf('Chrome') === -1
}, {
name: 'qqbrowser',
it: u.indexOf('MQQBrowser') > -1 && u.indexOf(' QQ') === -1
}, {
name: 'qq',
it: u.indexOf('QQ') > -1
}, {
name: 'chrome',
it: u.indexOf('Chrome') > -1 || u.indexOf('CriOS') > -1
}, {
name: 'opera',
it: u.indexOf('Opera') > -1 || u.indexOf('OPR') > -1
}];
for (var i = 0; i < bws.length; i++) {
if (bws[i].it) {
return bws[i].name;
}
}
return 'other';
}
3.得到用户系统
function getOS() {
var u = navigator.userAgent;
if (!!u.match(/compatible/i) || u.match(/Windows/i)) {
return 'windows';
} else if (!!u.match(/Macintosh/i) || u.match(/MacIntel/i)) {
return 'macOS';
} else if (!!u.match(/iphone/i) || u.match(/Ipad/i)) {
return 'ios';
} else if (!!u.match(/android/i)) {
return 'android';
} else {
return 'other';
}
}
4.全屏
launchIntoFullscreen: function () {
element = document.getElementById("flashcontent");
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {//火狐
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) {//chrome
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) {//ie11
element.msRequestFullscreen();
}
},
exitFullscreen: function () {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullScreen) {
document.msExitFullScreen();
} else if (document.msCancelFullScreen) {
document.msCancelFullScreen();
}
}
cookie使用
检测浏览器是否支持:window.navigator.cookieEnabled
function setCookie(key,value,day){
var cookie=key+'='+encodeURIComponent(value);
if(day>0){
var date=new Date();
date.setDate(date.getDate()+day);
cookie+=';expires='+date;
}
document.cookie=cookie;
}
function getCookie(key){
if(document.cookie.indexOf(key)<0){ return ""; }
var cookies=document.cookie.split(";");
for(var i=0; i<cookies.length; i++){
var temp=cookies[i].split("=");
if(temp[0].replace(/\s/g,'')==key){
return decodeURIComponent(temp[1]);
}
}
}
function deleteCookie(key){
setCookie(key,'',-1);
}