ES6
-
ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现
-
在webstrom中使用时需要配置
- 流程图
babel是什么
是一个工具链,主要用于在旧的浏览器或环境中奖ECMAScript2015+代码转换为向后兼容版本的JavaScript代码
- 转换语法
- Polyfill实现目标环境中缺少的功能
- 源代码转换
安装babel
-
先安装cnpm
- npm install -g cnpm --registry=https://registry.npm.taobao.org
-
再安装babel
- npm install babel-cli -g-dev
- npm install babel-preset-es2015 -g-dev
-
配置一个package.json文件
{ "presets":[ "latest" ], "plugins":[], "devDependencies": { "babel-cli": "^6.26.0", "babel-preset-es2015": "^6.24.1" }, "scripts":{ "build":"babel src -d lib" } }
-
运行命令npm run build 完成转换
块级作用域
/*
在ES6提供了块级作用域
* 使用let关键字定义块级作用域的变量
*/
if(true){
//块级作用域 - 定义的变量只能在当前块级作用域中被访问
let v = 100;
console.log(v);
}
//在全局作用域中访问变量v
console.log(v);//v is not defined
let与var的区别
/*
let与var关键字的区别 - 都是定义变量
* let - 提供了块级作用域
* 也可以在全局作用域和函数作用域定义变量
* var - 提供了全局作用域和函数作用域
*/
//全局变量 - 在全局作用域中定义
var m = 100
let n = 1000
console.log(m);
console.log(n);
let不允许声明提前
//使用var关键字定义变量 - 存在声明提前的现象
console.log(m);
var m = 10
//等价于
//只声明变量,并不初始化 - 默认值为undefined
var m
console.log(m);
m = 10
//使用let关键字定义变量时 - 不存在声明提前
console.log(v);
let v = 10
暂时性死区
ECMAScript6标准明确规定,如果在一个代码块中使用let或const声明变量或常量时,当前代码块中对这些声明的变量或常量形成了一个封闭的区域
在这个代码块中,在使用let或const声明之前,该变量或常量都是不可用的,称为“暂时性死区”
let不允许重复声明
//使用let关键字不允许重复声明
let v = 100;
console.log(v);
let v = 1000;
console.log(v);
let允许重新赋值
//使用let关键字允许重新赋值
let v = 100;
console.log(v);
v = 1000;
console.log(v);
与函数的关系
//使用var允许声明提前
var v = 100
function fn(){
console.log(v);
var v = 10
console.log(v);
}
fn()
//使用let关键字声明变量将当前环境封闭
let v = 100
function fn(){
//函数作用域封闭 - 全局作用域中的变量与当前函数作用域物无关
console.log(v);
let v = 10
console.log(v);
}
fn()
与函数参数的关系
//使用var关键字声明局部变量与形参的关系
function fn(a){
console.log(v);//undefined
var v = 10
}
fn(100)
function fn(a){
console.log(v);
let v = 20//Cannot access 'v' before initialization
}
fn(10)
块级作用域
- 块级作用域只能使用let关键字
- let关键字不仅可以声明块级作用域,还可以用在全局作用域和函数作用域
//全局作用域
let a = 100 //全局变量
(function(){
//函数作用域
let b = 1000//局部变量 b is not defined
})()
if(true){
//块级作用域
let c = 10 //局部变量
}
console.log(a);
console.log(b);
为什么需要块级作用域
- 局部变量可能覆盖全局变量
- 在循环体中用于计数的变量泄漏为全局变量
//全局作用域
for(var i = 0;i<10;i++){
console.log(i);
}
console.log(i);//10
//块级作用域
for(let i = 0;i<10;i++){
console.log(i);
}
//全局作用域
console.log(i);//i is not defined
面试题(经典)
var arr = []
for(var i = 0;i<10;i++){
arr[i] = function(){
return i
}
}
//值都是10
console.log(arr[0]());
函数的声明
/*
if(true){
//块级作用域
let fn = function(){
console.log("111");
}
}
//全局作用域
fn() //fn is not defined
*/
if(true){
//全局作用域
function fn(){
console.log("111");
}
}
//全局作用域
fn() //111
变量的解耦赋值
解耦赋值是什么
-
ECMAScript允许按照一定模式从数组或对象中提取值,对变量进行赋值
-
变量的解耦赋值 - 从指定的数组或对象中提取值,为指定变量进行赋值
- 语法结构
- var/let[变量名称1,变量名称2,…] = 数组或对象
- 注意 - 变量的索引值对应值的索引值
let [a,b,c] = [1,2,3] console.log(a,b,c);//1 2 3
- 语法结构
解耦赋值失败
-
变量的的索引值应该对应值的索引值
//解耦赋值失败 let [a] = [] console.log(a);//Identifier 'a' has already been declared
-
避免解耦赋值失败 - 定义变量的数量与值的数量保持一致
不完全解耦赋值
-
不完全解耦赋值 - 定义变量的数量小于值的数量
let [a,b] = [1,2,3] console.log(a,b);//1 2
默认值
-
解耦赋值失败时,变量的默认值为undefined
-
默认值 - 指的就是在解耦赋值失败时,重写undefined默认值
let [a = true] = [100] console.log(a);//100 let [x,y = 100] = [10] console.log(x,y);// 10 100
-
ES6底层将为变量赋值的值与undefined进行比较(全等于),指定的默认值生效
let [m,n = 100] = [10,undefined] console.log(m,n); //10 100
-
ES6底层将为变量赋值的值只是与undefined进行比较(null等没有意义的)
let [m,n = 100] = [10,null] console.log(m,n); //10 null
对象的解耦赋值
-
对象的解耦赋值 - 从对象中提取值,为变量进行赋值
-
变量名称与对象的属性名称一一对应
- 如果不对应,导致解耦赋值失败
let {x,y} = { x:10, y:20 } console.log(x,y);//10 20
-
解耦赋值 - 赋值运算符的量变格式保持一致
let [m,n] = { x:10, y:20 } console.log(m,n);//{(intermediate value)(intermediate value)} is not iterable
-
-
注意:
-
数组的解耦赋值 - 变量的索引值与值的索引值保持一致
-
对象的解耦赋值 - 变量的名称与对象属性的名称保持一致
let [[a,b],c] = [[1,2],3] console.log(a,b,c);//1 2 3 let {m:{name,age},n} = { m:{ name:'12', age:19 } } console.log(name,age); //12 19
-
字符串的解耦赋值
-
变量的数量与字符串中字符的数量进行对应
/* let [a,b,c] = 'xyz' console.log(a,b,c);//x y z */ /* let [a,b,c] = 'xxyyzz' console.log(a,b,c);//x x y */ let [a,b,c] = '大前端' console.log(a,b,c); //大 前 端
数值与布尔值的解耦赋值
-
数字值的解耦赋值 - 作为值的是一个数字值
-
结果 - 报错:数字值是不能被迭代遍历的
-
解耦赋值 - 作为值的类型必须是可迭代遍历的
/* let [a] = 100 console.log(a); //100 is not iterable */ /* let num = new Number(100) console.log(typeof num.toString()); //string */ let {toString:m} = 100 //console.log(m);//[Function: toString] console.log(m()); //Number.prototype.toString requires that 'this' be a Number
-
函数参数的解耦赋值
-
函数定义 - 形参,相当于在函数作用域中定义了一个局部变量(没有赋值)
-
函数调用 - 实参,相当于在函数作用域中为定义的变量进行赋值
function fn(a,b){ console.log(a,b); } fn(10,20)//10 20 function f([a,b]){ console.log(a,b); } f([1,2]) //1 2 function f({n,m}){ console.log(m,n); } f({ m:10, n:10 })//10 10
小括号问题
- 对于解析器来讲,语句中到底是模式还是表达式,没有办法从开始就知道,必须解析到赋值运算符时才能知晓
- ECMAScript6的规则是只要有可能导致解耦赋值的歧义,就不得使用小括号
- 建议只要有可能就不要再模式中使用小括号
- 不能使用小括号的内容
- 变量声明语句
- 函数参数:函数参数也属于变量声明,因此不能带有小括号
- 赋值语句的模式
解耦赋值的用途
-
交换变量的值
let x = 1,y = 2; [x,y] = [y,x] console.log(x,y);//2 1
-
从函数返回多个值
let [a,b,c] = fn() console.log(a,b,c);//1 2 3
-
函数参数的定义
function f([a,b,c=2]){ console.log(a,b,c); } f([2,3])//2 3 2
-
提取JSON数据
字符串的扩展
字符串判断是否包含
-
ES5提供判断是否包含的方法
-
string.indexOf(searchStr)方法
-
作用 - 返回指定字符串中包含指定子字符串的索引值
-
结果
- 包含 - 返回第一个匹配的索引值
- 不包含 - 返回-1
let str = 'solongxueyuan' console.log(str.indexOf('o'));//1 console.log(str.lastIndexOf('o'));//3
-
-
ES6提供的判断是否包含的方法
-
includes()方法是区分大小写的
console.log(str.includes('o'));//true console.log(str.includes('o',3));//true console.log(str.includes('o',5));//false console.log(str.includes('O'));//false
-
基于includes()方法实现一个不区分大小写的判断
function fun(str,searchStr,index){ //toLowerCase()将字符串全部转化为小写格式 str = str.toLowerCase() if(typeof index === 'number'){ return str.includes(searchStr,index) }else{ return str.includes(searchStr) } } console.log(fun(str,'o'));//true
-
startsWith()也区分大小写
-
startsWith()方法不是表示指定字符串是以另一个字符串开始的
-
表示指定字符串的指定索引值开始是否以另一个字符串开始的
console.log(str.startsWith('long',2));//true
-
-
-
重复字符串
-
repeat()方法用于将原字符串重复n次,返回一个新字符串
-
number - 表示将原字符串重复的次数
- 如果number参数小数的话,则会向下取整
- 如果number参数为负数或者无穷大的话,则会报错
- 如果number参数为NaN的话,则为0
- 如果number参数为字符串,则会先转换为数字值
//重复字符串 let str = 'abc' console.log(str.repeat(3));//abcabcabc //仅仅返回一个新的字符串(不会改变原有字符串的内容) let result = str.repeat(3) console.log(str,result);//abc abcabcabc //Number为小数,向下取整的 console.log(str.repeat(2.5));//abcabc //number为NaN,不报错 console.log(str.repeat(NaN));//没有任何输出 //number为负数,报错 //console.log(str.repeat(-2));//Invalid count value //number为零 console.log(str.repeat(0));//没有任何输出 //number为字符串或布尔值,先转换成数字值 console.log(str.repeat('3'));//abcabcabc console.log(str.repeat(true));//abc
-
模板字符串
-
替代原有的普通字符串
//定义一个普通的字符串 let str1 = 'this is 111' //定义一个模板字符串 - 充当普通字符串来使用 let str2 = `this is 111` console.log(str1,str2);//this is 111 this is 111
-
多行字符串
//定义一个普通的字符串 let str3 = 'this is\n111' console.log(str3);//this is //111 let str4 = 'this is' +'111' console.log(str4);//this is111 //定义一个模板字符串 - 充当普通字符串来使用 let str5 = `this is 111` console.log(str5);/*this is 111*/
-
字符串与变量配合使用
let name = '111' //定义一个普通的字符串 let str6 = 'hello' + name + '!' console.log(str6);//hello111! //定义一个模板字符串 let str7 = `hello ${name} !` console.log(str7);//hello 111 !
带标签的模板字符串
-
带标签的模板字符串
- 不是模板字符串的用法,而是函数调用的一种特殊形式
- 整体结构
- 函数名称
- 将模板字符串作为函数的参数
let str = '111' //普通字符串 console.log('this is'+ str + '.');//this is111. //模板字符串 console.log(`this is ${str}`);//this is 111 //带标签的模板字符串 console.log`this is ${str}`;//[ 'this is ', '' ] 111 function fn(a){ console.log(a instanceof Array);//true } //fn('this is' + str + '.') //fn(`this is ${str}`) fn`this is ${str}`//[ 'this is ', '' ]
原始字符串
-
应用在带标签的模板字符串
-
在函数的第一个参数中,存在着raw属性 - 获取到模板字符串的原始字符串
- 所谓的原始字符串
- 模板字符串被定义时的内容,而不是处理之后的内容
let str = 'funtion' function fn(a){ console.log(a.raw);//[ 'this is ', '.' ] console.log(a.raw[0]);//this is } fn`this is ${str}.`
- 所谓的原始字符串
数组的扩展
扩展运算符的应用
-
替代apply()方法
//定义一个数组 var arr = [1,2,3,4] console.log(...arr);//1 2 3 4 //定义一个函数 function f(a,b){ console.log(a+b); } var arg = [1,2] f(...arg)//3 /* call()与apply()方法的区别 * call(this,arg1,arg2,...) * 接收的参数为多个参数 * apply(this,arr) * 接收参数为一个数组 */ f.call(null,arg[0],arg[1])//3 f.apply(null,arg)//3
-
复制数组
-
利用扩展符复制数组为深复制
/* 数组的深复制和浅复制 * 深复制 - 复制数组的元素内容(数据) * 浅复制 - 复制数组的内存地址 */ var arr1 = [1,2,3,4,5] /* //浅复制 var arr2 = arr1 arr2[2] = 7 console.log(arr1,arr2);//[ 1, 2, 7, 4, 5 ] [ 1, 2, 7, 4, 5 ] */ /* //深复制 var arr2 = [] for(var i=0;i<arr1.length;i++){ arr2[i] = arr1[i] } console.log(arr1,arr2);//[ 1, 2, 3, 4, 5 ] [ 1, 2, 3, 4, 5 ] arr2[2] = 7 console.log(arr1,arr2);//[ 1, 2, 3, 4, 5 ] [ 1, 2, 7, 4, 5 ] */ //利用扩展运算符 //var arr2 = [...arr1] var [...arr2] = arr1 console.log(arr1,arr2);//[ 1, 2, 3, 4, 5 ] [ 1, 2, 3, 4, 5 ] arr2[2] = 7 console.log(arr1,arr2)//[ 1, 2, 3, 4, 5 ] [ 1, 2, 7, 4, 5 ]
-
合并数组
var arr1 = [1,2,3] var arr2 = [4,5,6] //ES5合并数组的方法 console.log(arr1.concat(arr2));//[ 1, 2, 3, 4, 5, 6 ] //利用扩展运算符 console.log([...arr1,...arr2]);//[ 1, 2, 3, 4, 5, 6 ]
-
与解耦赋值配合使用
var arr = [1,2,3,4,5] /* //ES5 var v = arr[0] var list = arr.splice('') console.log(v,list);//1 [ 1, 2, 3, 4, 5 ] */ //利用扩展运算符 //var [v,...list] = arr //console.log(v,list);//1 [ 2, 3, 4, 5 ] var [...list,v] = arr console.log(v,list)//Rest element must be last element
-
将字符串转换为数组
var str = 'hello' //ES5 console.log(str.split(''));//[ 'h', 'e', 'l', 'l', 'o' ] //ES6 console.log([...str]);//[ 'h', 'e', 'l', 'l', 'o' ]
-
与对象的使用
//注意 - 扩展运算符必须与可迭代(遍历)的对象配合使用 /* var obj = { name:'222', age:23, job:'333' } //console.log(...obj);//Found non-callable @@iterator console.log([...obj]);//obj is not iterable */ //注意 - 关联数组。不会报错,但没有结果 var arr = [] arr['name'] = '222' arr['age'] = 23 console.log(...arr);
-
Array提供的方法
-
Array.from()方法 - 从一个类似数组或可迭代对象中创建一个新的数组实例
//构建一个类数组的对象 - 1.可迭代 2.有效的length var obj = { 0:'111', 1:'222', 2:'333', length:3 } //console.log(obj);//{ '0': '111', '1': '222', '2': '333', length: 3 } /* for(var i=0;i<obj.length;i++){ console.log(obj[i]); } */ //ES5 console.log([].slice.call(obj));//[ '111', '222', '333' ] //ES6 console.log(Array.from(obj));//[ '111', '222', '333' ] /* //扩展运算符不能使用 console,log([...obj]) */ console.log(...Array.from(obj));//111 222 333 function fn(){ //arguments对象 - 用于接收所有的实参 console.log(...arguments); } fn(1,2,3)//1 2 3
-
Array.of()方法 - 用于创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
- 主要目的是为了弥补构造函数Array()的不足,因为参数个数不同,导致行为差异
//Array.of()如果传递一个参数时,表示一个元素内容 console.log(Array.of(5));//[ 5 ] console.log(Array.of(1,2,3));//[ 1, 2, 3 ] console.log(new Array(1,2,3));//[ 1, 2, 3 ] //new Array()如果只传递一个参数时,表示length console.log(new Array(5));//[ <5 empty items> ] console.log(Array(1,2,3));//[ 1, 2, 3 ] //new Array()如果传递一个参数时,表示length console.log(new Array(5)); console.log(Array.of());//[] console.log(new Array());//[] console.log(Array());//[] console.log([]);//[]
Array对象的方法
-
copyWithin()方法用于浅复制一部分到同一数组中的另一位置,并返回他,而修改其大小
-
作用 - 检索指定数组中从start到end区间的元素,复制到当前数组中的指定索引值
-
参数
- target - 该参数的值最大等于当前数组的length属性值-1
- start - 表示当前截取开始的索引值
- 如果当前参数值省略,自动从数组的开始位置进行截取
- end - 表示当前截取结束的索引值(不包括当前索引值的元素)
- 如果当前参数值省略,自动截取到当前数组的最后
-
注意
- 该方法不能改变数组的长度
- 修改了原有的数组
let arr = [1,2,3,4,5] //console.log(arr.copyWithin(3,0,4)); //[ 1, 2, 3, 1, 2 ] //console.log(arr.copyWithin(0,3));//[ 4, 5, 3, 4, 5 ] console.log(...arr.copyWithin(2));//[ 1, 2, 1, 2, 3 ] console.log(arr);//[1,2,3,4,5]
-
-
find(callback)方法
-
作用 - 返回find()方法的回调函数中符合表达式的第一个元素的值
-
callback参数 - 调用find()方法时的回调函数
-
funtion(element,index,array){}
- element - 指定数组中每一项元素的值
- index - 指定数组每一项元素的索引值
- array - 指定数组的本身
-
特点
- 数组调用find()方法,将制定数组进行遍历
let arr = [1,2,3,4,5] var result = arr.find(function(a,b,c){ return b>1 }) console.log(result);//3
-
findIndex()方法返回符合表达式结果的第一个元素的索引值
var result = arr.findIndex(function(a,b,c){ return b>1 }) console.log(result);//2
-
-
fill()方法
-
作用 - 将制定内容替换指定数组中的指定位置
-
参数
- value - 表示替换的内容(没有类型要求)
- start - 表示替换开始的位置
- end - 表示结束的位置(不包含)
-
let arr = [1,2,3,4] var result = arr.fill([6,7],2,3) console.log(result);//[ 1, 2, [ 6, 7 ], 4 ]
-
函数的扩展
函数参数的默认值
-
函数参数指定默认值
-
ES5中不允许为函数的形参设置其默认值
-
当定义形参,而不传递实参时 - 形参的默认值为undefined
-
人为的解决形参默认值的问题 (arg = arf || 0)
-
/* //ES5 function fn(a){ a = a || 0 console.log(a); } fn()//0 */ //ES6 function fn(a=1){ console.log(a); } //fn(0)//0 fn()//1
-
-
-
与解耦赋值的配合使用
-
参数的作用域
-
如果为函数的参数设置默认值的话,当函数声明进行初始化时,参数会形成一个独立的作用域,这个作用域会在函数初始化完毕时消失
-
let x = 1 function fn(y = x ){ let x = 2 console.log(x); } fn()//2
-
rest参数
-
用于获取函数多余的参数 - 定义的形参少于实参的个数
-
/* //ES5 - 利用arguments对象接收多余的参数 function fn(a,b){ console.log(a,b,arguments[2]); } fn(1,2,3)//1 2 3 */ //ES6 - 利用rest参数接收多余的参数(数组类型) function f(a,b,...arry){ console.log(a,b,arry);//1 2 [ 3, 4, 5 ] //console.log(a,b,...arry);//1 2 3 4 5 } f(1,2,3,4,5)
箭头函数
-
箭头函数是什么
-
相比函数表达式具有较短的语法并以词法的方式绑定this,箭头函数总是匿名的
-
/* //ES5 定义函数的方式 function fn(){} var fun = function(){} bar f = new Function() */ //ES6 箭头函数 var n = () => 5 /* //等价于 var n = function(){ return 5 } */ console.log(n());//5 /* function fn(a,b){ var result = a + b return result } */ //改为箭头函数 var f = (a,b) => a + b console.log(f(1,2));//3 /* function fn(x,y){ var t = x+y console.log(t); } */ //改为箭头函数 var h = (x,y) => { var t = x+y console.log(t); } h(1,3)//4
-
//ES5 定义函数时,使用this -> 指向调用函数时的上下文 function fn(){ console.log(this); } //将fn作为函数进行调用 fn()//当前执行环境中的全局对象 //使用call()或apply()方法调用函数fn let obj = {} fn.call(obj)//{} //函数作为对象obj2的方法 let obj2 = { sayMe:fn } obj2.sayMe()//{ sayMe: [Function: fn] } //ES6 声明箭头函数,函数中的this -> 指向的是定义箭头函数时的上下文对象 var n = () =>{ console.log(this); } n()//{} var obj3 = { sayMe:n } obj3.sayMe()//{}
-
-
箭头函数的语法结构有
- 基本语法结构
- 高级语法结构
-
箭头函数的注意事项
-
函数体内的this,就是定义时所在的对象,而不是使用时所在的对象
-
不可以当做构造函数
-
不可以使用arguments对象,该对象在函数体内不存在
-
/* //箭头函数不能当做构造函数使用 var fn = () => { this.name = '222' } var f = new fn() console.log(f);//fn is not a constructor */ let obj = { name:'222', sayMe:() => { console.log('1111'); } } obj.sayMe()//1111
-
函数的尾调用
-
就是指某个函数的最后一步是调用另一个函数
-
function g(x){ return x+2 } function fn(x){ return g(x) } console.log(fn(2));//4
对象的扩展
对象的属性
-
属性表示法
-
允许直接将变量和函数名
-
var name = '111' function fn(){ console.log('333'); } /* //ES5定义对象的属性和方法的方式 var obj = { name:name, fn:fn } */ //ES6 允许变量名和函数名直接作为对象的属性和方法的方式 var obj = { name, fn } console.log(obj.name);//111
-
Object的方法
-
Object.is()方法
-
相等运算符在比较值钱,会自动转换数据类型
-
全等运算符导致NaN与自身不等,+0等于-0等问题
-
//ES5 console.log(+0 === -0);//true console.log(NaN === NaN);//false //ES6 console.log(Object.is(+0.-0));//false console.log(Object.is(NaN,NaN));//true
-
-
Object.assign()方法
-
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象
-
var obj = { name:'222', age:23 } var arr = {} var result = Object.assign(arr,obj) console.log(result,arr);//{ name: '222', age: 23 } { name: '222', age: 23 } arr.name = '333' console.log(result.name);//333 console.log(obj.name);//222
-
super关键字
-
用于指向当前对象的原型对象
-
注意 - super关键字表示原型时,只能用在对象的方法中,用在其他地方都会报错
-
/* function Hero(){ this.name = '111' this.fn = function(){ console.log(this.name); } } Hero.prototype.age = 18 var hero = new Hero() hero.fn()//111 hero.sayYou = function(){ console.log(this.age); } hero.sayYou()//18 */ var prop = { age:19, } var obj = { name:'222', fn(){ console.log(super.age); } } //将prop对象作为obj对象的原型对象 Object.setPrototypeOf(obj,prop) // console.log(obj.name);//222 // console.log(obj.age);//19 obj.fn()//19
对象的扩展运算符
-
用于取出参数对象的所有可遍历属性,拷贝到当前对象中
-
var obj = { name:'222', age:23 } //将原对象的可枚举的属性复制到目标对象中 var arr = {...obj} // Object.assign(arr,obj) console.log(arr);//{ name: '222', age: 23 }
键值对集合
Set集合
-
Set集合是什么
-
是值的集合,可以按照插入的顺序迭代它的元素,Set集合中的元素只会出现一次
-
/* ECMAScript 6提供了Set构造函数,创建Set对象 * 集合 - 值(唯一的)的集合 * 应用 - 利用Set集合为数组元素去重 */ const arr = [1,1,2,2,3,4,5] let set = new Set(arr) console.log(set);//Set { 1, 2, 3, 4, 5 } /* NaN、undefined等值允许被存储在Set集合中 * NaN值在Set集合中被认为是相等的 */ console.log(undefined === undefined);//true let set2 = new Set([NaN,NaN,undefined,undefined,null,null]) console.log(set2);//Set { NaN, undefined, null } /* Set集合中存储复杂数据类型(数组、对象及函数等) * 多个空数组和空对象表示多个值 */ console.log([] === []);//false let set3 = new Set([[],[],{},{},function(){},function(){}]) console.log(set3);//Set { [], [], {}, {}, [Function], [Function] }
-
-
Set集合的属性与方法
-
Set对象提供了size属性用于返回Set对象的个数
-
console.log(set.size);//5
-
add(value) - 向Set集合的尾部添加新的元素
- 返回值 - 添加新元素后的Set集合
-
var result = set.add(8) console.log(set,result);//Set { 1, 2, 3, 4, 5, 8 } Set { 1, 2, 3, 4, 5, 8 }
-
delete(value) - 从Set集合删除指定元素
- value - 表示Set集合中的元素内容(值)
- 返回值 - 布尔值 true表示删除成功,false表示删除失败
-
var result = set.delete(1) console.log(set,result);//Set { 2, 3, 4, 5, 8 } true
-
has(value) - 判断指定Set集合中是否包含指定元素
- value - 表示Set集合中的元素内容(值)
- 返回值 - 布尔值 true表示包含,false表示不包含
-
var result = set.has(1) console.log(result);//false
-
-
Set对象提供了用于遍历Set集合的方法
-
value()方法 - 返回一个迭代器对象(SetIterator)
- 没有length属性值 - 常规的循环语句无法使用
- 不能for…in循环语句
- 只能使用for…of进行循环
-
let set = new Set([1,2,3,4]) /* var arr = set.values() for(var name of arr){ console.log(name);//1 2 3 4 } */ /* 虽然Set集合具有size属性 - 表示当前Set集合中元素的个数 但是Set集合获取每一个元素内容,不能使用set[索引值]的方式 */ /* for(let i=0;i<set;i++){ console.log(set[i]); } */ console.log(set.values());[Set Iterator] { 1, 2, 3, 4 }
-
keys()方法 - 返回当前Set集合中所有键的迭代器对象
-
console.log(set.keys());//[Set Iterator] { 1, 2, 3, 4 }
-
entries()方法 - 返回当前Set集合中所有键值的迭代器对象
-
console.log(set.entries());//[Set Entries] { [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ] }
-
Set集合提供forEach()方法
- 作用 - 用于遍历当前的Set集合(为Set集合中每个元素调用callback函数)
- 回调函数
- funtion(value,key,set){}
- value - 表示当前Set集合中每一个值
- key - 表示当前Set集合中每一个键
- set - 表示当前遍历的Set集合
- funtion(value,key,set){}
-
set.forEach(function(v,k,s){ console.log(v,k,s); }) /* 1 1 Set { 1, 2, 3, 4 } 2 2 Set { 1, 2, 3, 4 } 3 3 Set { 1, 2, 3, 4 } 4 4 Set { 1, 2, 3, 4 } */
-
-
Set集合与Array对比
- 数组中用于判断元素是否存在的indexOf()函数效率低下
- Set对象允许根据值删除元素,而数组中必须使用基于下标的splice()方法
- 数组的indexOf()方法无法找到NaN值
- Set对象存储不重复的值,所以不需要手动处理包含重复值的情况
WeakSet集合
-
WeakSet是什么
- 是一些对象值的集合,并且其中的每个对象值只能出现一次
- WeakSet对象与Set对象的区别
- WeakSet对象中只能存放对象引用,不能存放值,而Set对象都可以
- WeakSet对象中存储的对象值都是被弱引用的,如果没有其它的变量或属性引用这个对象值,则这个对象值会被当成垃圾回收掉,WeakSet对象是无法被枚举的,没有办法拿到WeakSet集合包含的所有元素
-
WeakSet集合的方法
-
var ws = new WeakSet() var obj = {} var obj2 = {} ws.add(obj) ws.add(obj2) //WeakSet集合不可枚举,无法打印 console.log(ws);//WeakSet { <items unknown> }
Map集合
-
Marp集合是什么
-
是键值对的集合,任何值都可以作为Map集合的键或值,Map集合可以按照插入的顺序迭代它的元素
-
let map = new Map() let num = 10,str = '222',obj = {},fn=function(){} map.set('num',num) map.set('fn',fn) map.set('obj',obj) map.set('str',str) console.log(map); /* Map { 'num' => 10, 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' } */ console.log(map.get('str'));//222 map.delete('num') console.log(map);//Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' } /* map.clear() console.log(map);//Map {} */ var result = map.has('str') console.log(result);//true
-
-
Map集合的属性与方法
-
console.log(map.values());//[Map Iterator] { [Function: fn], {}, '222' } console.log(map.keys());//[Map Iterator] { 'fn', 'obj', 'str' } console.log(map.entries());/* [Map Entries] { [ 'fn', [Function: fn] ], [ 'obj', {} ], [ 'str', '222' ] } */ map.forEach(function(v,k,s){ console.log(v,k,s); }) /* [Function: fn] fn Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' } {} obj Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' } 222 str Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' } */
-
-
Map集合键的相等
- 判断使用与 === 相似的规则
- -0和+0相等
- NaN与自身相等
-
Map集合与Object对比
- Object的键均为String类型,在Map里键可以是任意类型的
- 必须手动计算Object的尺寸,但是可以很容易地获取使用Map的尺寸
- Object的遍历循环元素的插入顺序
- Object有原型,所以映射中有些缺省的键
WeakMap集合
- 同WeakSet集合
Promise对象
Promise对象是什么
-
Promise对象是什么
- 该对象允许对延迟和异步操作流程进行控制,一个Promise对象就是一个代表一个异步操作最终完成或者失败的对象
- 开发人员可以使用由其他函数创建并返回的Promise对象,Promise对象本质上就是一个绑定了回调的对象,而不是将回调传进函数内部
- Promise的几种状态
- pending:初始状态,既不成功,也不是失败状态
- fulfilled:意味着操作成功完成
- rejected:意味着操作失败
-
创建Promise对象
-
Promise构造函数执行时立即调用executor函数,resolve和reject两个函数作为参数传递给executor(executor函数在Promise构造函数返回新建对象前被调用,executor表示带有resolve和reject两个参数的函数)
-
resolve和reject函数被调用时,分别将Promise的状态改为fulfilled(完成)或rejected(失败)
-
/* 创建Promise对象 let promise = new Promise(funtion(resolve,reject){}) * 当前的构造函数Promise接收一个回调函数 funtion(resolve,reject){} * resolve - 是一个函数,将Promise的状态改为fulfilled(完成) * reject - 是一个函数,将PromiseDe状态改为rejected(失败) */ /* let promise = new Promise(function(res,rej){ setTimeout(function(){ res("测试成功") //rej("测试失败") },200) }) promise.then(function(value){ console.log(value);//测试成功 /*(node:19392) UnhandledPromiseRejectionWarning: 测试失败 (node:19392) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:19392) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. */ // }) //Promise对象由其他函数创建并返回 function fn(){ return new Promise((res,rej) => { setTimeout(() => { res('111') },200) }) } var promise = fn()
-
-
Promise对象的约定
- 在JavaScript事件队列的当前运行完成之前,回调函数永远不会被调用
- 通过then实行添加的回调函数,甚至都在异步操作完成之后才被添加的函数,都会被调用
- 通过多次调用then,可以添加多个回调函数,他们会按照插入顺序并且独立运行
-
Promise对象的链式操作
-
连续执行两个或者多个异步操作
-
//创建Promise对象 let promise = new Promise((res,rej) => { setTimeout(() => { res('成功了') },200) }) //then()方法返回一个新的Promise对象 let promise2 = promise.then((data) => { console.log(data);//成功了 }) //promise和promise2是两个不同的对象 // console.log(promise === promise2);//false // console.log({}==={});//false
-
Promise对象原型的方法
-
then()方法
- 第一个回调函数,当Promise变为接收状态(fulfillment)时,该参数作为回调函数被调用,该函数有一个参数,即接受的最终结果
- 第二个回调函数,当Promise变成决绝状态(rejection)时,该参数作为回调函数被调用,该函数有一个参数,即拒绝的原因
-
catch()方法
- 返回一个Promise对象,并且处理决绝的情况,同then()方法
- 回调函数:当Promise呗rejected时,被调用该回调函数,该函数具有一个参数,即rejected的原因
-
finally()方法
- 返回一个Promise对象,在执行then()和catch()后,都会执行finally指定的回调函数
-
//创建Promise对象 let promise = new Promise((res,rej) => { setTimeout(() => { //res('成功了') rej('失败了') },200) }) //成功时执行then()方法,失败时执行cathc()放法,不管成功还是失败都会执行finally()方法 promise.then((data) => { console.log(data);//成功了 }).catch((value) => { console.log(value);//失败了 }).finally(() => { console.log('111'); })
Promise对象的方法
-
Promise.all()方法
- 是以所有Promise对象的状态都改变时,表示整合后的Promise对象成功或失败
-
Promise.race()方法
- 是以某个Promise对象的状态改变时,表示整合后的Promise对象成功或失败
-
Promise.resolve()方法
-
Promise.reject()方法
-
let promise1 = new Promise((res,rej) => { setTimeout(() => { res('111') },100) }) let promise2 = new Promise((res,rej) => { setTimeout(() => { res('222') },200) }) let promise3 = new Promise((res,rej) => { setTimeout(() => { res('333') },300) }) //Promise.all()方法将多个Promise对象整合成一个Promise对象 let promise = Promise.all([promise1,promise2,promise3]) //Promise.race()方法不管Promise成功还是失败都快执行最先完成的 Promise.race([promise1,promise2,promise3]).then((data) => { console.log(data);//111 }) promise.then((data) => { console.log(data);//[ '111', '222', '333' ] })
Promise对象的应用
-
加载图片
-
const fun = function(path){ return new Promise((res,rej) => { const image = new Image() //图片加载成功 image.onload = res //图片加载完毕 image.onerror = rej image.src = path }) }
-
-
通过Ajax加载图片
-
function imga(url){ return new Promise((res,rej) => { var request = new XMLHttpRequest() request.open('GET',url) request.onload = function(){ if(request.status === 200){ res(request.response) }else{ rej(Error('error code:'+request.statusText)) } } request.onerror = function(){ rej(Error('It is a network error.')) } request.send() }) }
-
Promise对象的原理剖析
async函数
async函数是什么
-
最主要的目的就是简化使用Promise异步调用的操作,并对一组Promise执行某些操作
-
function fn(){ return new Promise((res) => { setTimeout(() => { res('111') },200) }) } /* async function fun(){ console.log('222'); var result = await fn() console.log(result); } fun()//222 111 */ let promise = fn() promise.then((data) => { console.log(data);//111 })
语法结构
-
异步函数声明式
- 用于定义一个返回Promise对象的异步函数
- 异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的Promise返回其结果
- async funtion name([param[,param[,…param]]]){statements}
- name - 表示函数名称
- param - 要传递给函数的参数的名称
- statements - 表示函数体语句
-
异步函数表达式
- 用于在表达式中定义异步函数
- let name = async funtion([param[,param[,…param]]]){statements}
- name - 表示函数名称
- param - 要传递给函数的参数的名称
- statements - 表示函数体语句
-
返回Promise对象
-
async函数内部return语句返回的值,会成为then方法回调函数的参数
-
//async函数返回Promise对象 async function fn(){ return '111' } let promise = fn() // console.log(promise);//Promise { '111' } promise.then((data) => { console.log(data);//111 })
-
await表达式
-
用于等待一个Promise对象,它只能在异步函数中使用
-
function fn(){ return new Promise((res,rej) => { setTimeout(() => { res('111') },200) }) } async function fun(){ console.log('2222'); var result = await fn() console.log(result); } fun()//2222 111
注意事项
-
使用try…catch语句
-
function fn(){ return new Promise((res,rej) => { setTimeout(() => { res('成功了') //rej('111') },200) }) } async function fun(){ console.log('2222'); try{ var result = await fn() console.log(result); }catch(e){ console.log(result); } } fun()
-
-
多个await同时触发
-
let promise1 = new Promise((res,rej) => { setTimeout(() => { res('111') },100) }) let promise2 = new Promise((res,rej) => { setTimeout(() => { res('222') },200) }) let promise3 = new Promise((res,rej) => { setTimeout(() => { res('333') },300) }) async function fn(){ let result1 = await promise1 console.log(result1); let result2 = await promise2 console.log(result2); let result3 = await promise3 console.log(result3); } fn()//111 222 333
-
-
await表示的限制
- await表达式只能用于async函数之中
迭代器与生成器
Symbol
-
Symbol是什么
-
新增的第六种原始类型Symbol(符号)类型,Symbol类型是唯一的并且是不可修改的
-
/* JavaScript五种原始类型 * number - Number * string - String * boolean - Boolean * undefined - Undefined * null - null */ let num = 100; let str = '111' let boo = true /* Symbol类型是ES6新增的第六种原始类型 * Symbol 类型是唯一的并且是不可以修改的,只能修改变量的值 let symbol = Symbol() */ let symbol = Symbol() console.log(typeof symbol);//symbol let symbol2 = Symbol('222') console.log(symbol2);//Symbol(222) let symbol3 = Symbol(5) console.log(symbol3);//Symbol(5)
-
-
Symbol的注意事项
-
Symbol的方法
-
Symbol.for()方法
-
该方法会根据给定的键key,来从运行时的symbol注册表中找到对应的symbol
-
/* Symbol.for()方法 * 作用 - 从Symbol类型中查找指定的key * 如果存在这个key,返回 * 如果不存在这个key,创建 */ let t = Symbol('foo')//创建 console.log(t); let t = Symbol('foo')//查找 console.log(t);
-
-
Symbol.keyFor() - 同for()方法
-
-
Symbol与for…in
-
Symbols在for…in迭代中不可枚举,Object.getOwnPropertyNames()不会返回symbol对象的属性,但是可以使用Object.getOwnPropertySymbols()得到
-
var obj = {} obj[Symbol('a')] = 'a' obj[Symbol('b')] = 'b' obj['c'] = 'c' obj['d'] = 'd' for(var i in obj){ console.log(i);//c d }
-
迭代器
-
ECMAScript5规范表示集合的数据结构有数组(Array)和对象(Object),ECMAScript6规范又新增了Set和Map两种集合,这样在JavaScript中就具有四种集合,需要一种统一的机制进行操作
-
迭代器(Iterator)就是这样的一种机制,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作
-
迭代器(Iterator)具有三种作用
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某次次序排列
- ECMAScript6新增了for…of循环语句,用于遍历迭代器
-
Iterator接口
-
是一个对象,该对象提供了next()方法用于返回序列中的下一项,该方法返回包含done和value两个属性的对象
-
function fn(arr){ var index = 0 return { next:function(){ return index<arr.length?{ done:false, value:arr[index++] }:{ done:true } } } } var arr = ['11','22','33','44'] let iterator = fn(arr) console.log(iterator.next());//{ done: false, value: '11' } console.log(iterator.next());//{ done: false, value: '22' } console.log(iterator.next());//{ done: false, value: '33' } console.log(iterator.next());//{ done: false, value: '44' }
-
一种数据结构只要部署了Iterator接口,就可以称这种数据结构“可遍历的”
-
Symbol.iterator属性本身是一个函数,就是当前数据结构默认的迭代器生成函数
-
const obj = { [Symbol.iterator]:function(){ return{ next:function(){ return{value:1,done:true} } } } }
-
-
迭代协议
- 允许JavaScript对象去定义或定制他们的迭代行为
- 就是这个对象(或者它原型链上的某个对象)必须有一个名字是Symbol.iterator的属性
-
迭代器协议
- 定义了一种标准的方式来产生一个有限或无线序列的值
- 当一个对象被认为是一个迭代器时,它实现了一个next()的方法并且有以下含义
- 返回一个对象的无参函数,被返回对象拥有两个属性
- done(boolean)
- 如果迭代器已经经过了迭代序列时为true,这时value可能描述了该迭代器的返回值
- 如果迭代器可以产生序列中的下一个值,则为false,这等效于连同done属性也不指定
- value - 迭代器返回的任何JavaScript值,done为true时可省略
- done(boolean)
- 返回一个对象的无参函数,被返回对象拥有两个属性
for…of语句
-
for…of语句的用法
-
用于遍历迭代器
-
let arr = [1,2,3,4,5] for(let attr of arr){ //得到数组的元素内容
-
-
返回迭代器对象的方法
-
entries()方法 - 返回一个新的迭代器对象,这个对象的元素是用来遍历[键名,键值]组成的数组
-
keys()方法 - 返回一个新的迭代器对象,用来遍历所有的键名
-
values()方法 - 返回一个新的迭代器对象,用来遍历所有的键值
-
let set = new Set(arr) for(let attr of set){ //得到set集合的元素内容 console.log(attr);//1 2 3 4 5 } let map = new Map() let num = 10,str = '222',obj = {},fn=function(){} map.set('num',num) map.set('fn',fn) map.set('obj',obj) map.set('str',str) for(let attr of map){ //得到map集合的key/value对 console.log(attr);//[ 'num', 10 ] [ 'fn', [Function: fn] ] [ 'obj', {} ] [ 'str', '222' ] } let string = 'hahahha' for(let attr of string){ console.log(attr);//h a h a h h a }
-
-
与forEach()方法的区别
- forEach()方法无法跳出循环,break语句和continue语句无效
- for…of语句不仅可以使用break语句和continue语句,还可以配合使用return语句
-
与for…in语句的区别
-
for…in不仅遍历自身,还会遍历手动添加的,甚至包括原型链的
-
如果用于遍历数组的话,遍历得到的键名为字符串类型的数字值
-
Object.prototype.objCustom = function(){} Object.prototype.arrCustom = function(){} let iterator = [3,5,7] iterator.foo = 'hello' /* for(let i in iterator){ console.log(i);//0 1 2 foo objCustom arrCustom } */ for(let i of iterator){ console.log(i);//3 5 7 }
-
生成器
-
Generator函数是什么
-
作为生成一个迭代器的特殊函数,该函数被调用时返回一个Generator对象,该对象是符合可迭代协议和迭代器协议的
-
Generator函数与普通函数的区别
-
funtion*这种声明方式会定义一个生成器函数,它返回一个Generator对象
-
yield关键字用来暂停和恢复一个生成器函数
-
function* fn(){} let result = fn() console.log(result);//Object [Generator] {}
-
-
-
funtion*表达式
- 定义一个生成器函数,它返回一个Generator对象
-
yield表达式
-
用来暂停和恢复一个生成器函数
-
//定义一个生成器函数 function* fn(){ let arr = ['11','22','33','44'] for(let i=0;i<arr.length;i++){ yield arr[i] } } //生成器函数调用返回生成器对象 let t = fn() //生成器对象就是ES6提供的迭代器 console.log(t.next());//{ value: '11', done: false } console.log(t.next());//{ value: '22', done: false } console.log(t.next());//{ value: '33', done: false } console.log(t.next());//{ value: '44', done: false } console.log(t.next());//{ value: undefined, done: true }
-
-
yield*表达式
-
用于委托给另一个Generator或可迭代对象
-
function* fn(){ yield 2; yield 3; } function* fnu(){ yield 1 yield* fn() yield 4 } var t = fnu() console.log(t.next());//{ value: 1, done: false } console.log(t.next());//{ value: 2, done: false } console.log(t.next());//{ value: 3, done: false } console.log(t.next());//{ value: 4, done: false } console.log(t.next());//{ value: undefined, done: true }
-
-
Generator对象的方法
- next()方法 - 返回一个包含属性done和value的对象,该方法也可以通过接受一个参数用以向生成器传值
- return()方法 - 返回给定的值并结束生成器
- throw()方法 - 用于向生成器抛出异常,并恢复生成器的执行,返回带有done及value两个属性的对象
class关键字
类的声明
-
类是什么
-
类作为对象的模板,只是一个语法糖。class关键字只是让对象原型的写法更加清晰、更像面相对象编程的语法而已
-
/* //ES5创建构造函数 function Hero(){ this.name = '111' this.sayMe = function(){ console.log('222'); } } Hero.prototype = { age:19, fun:function(){ console.log('333'); } } var hero = new Hero() console.log(hero.sayMe());//222 */ //ES6 class student{ //构造器 constructor(){ this.name = '111' this.sayMe = function(){ console.log('222'); } } } var t = new student() console.log(t.name);//111
-
-
类的声明
-
类的声明方式
-
类的表达式方式
- 不同于类表达式,类声明不允许再次声明已经存在的类,否则将会抛出一个类型错误
-
/* 1.类的声明方式 class className{ 内部结构 } * class关键字 - 用于创建类 * className - 表示创建的类名 */ class Hero{} /* 2.类的表达式方式 const/var/let myClass = class[className]{ 内部结构 } * class关键字 - 用于创建类 * myclass/className - 表示创建的类名 * myClass - 类名,用于后面的代码逻辑进行调用 */ let hero = new Hero()
-
-
构造函数
-
在一个类中只能有一个名为“constructor”的特殊方法。一个类中出现多次构造函数(Constructor)方法将会抛出一个SyntaxError错误
-
在一个构造方法中可以使用super关键字来调用一个父类的构造方法
-
如果没有显示指定构造方法,则会添加默认的constructor方法
-
如果不指定一个构造函数(constructor)方法,则使用一个默认的构造函数
-
/* 创建类 - 结构 * 外层的类的语法结构 * 内层的构造器的语法结构 */ class Hero{ //构造器 constructor(){ this.name = '111' this.sayMe = () => { console.log('22'); } } } let t = new Hero() console.log(t);//Hero { name: '111', sayMe: [Function] }
-
-
getter与setter
-
对某个属性设置存值函数和取值函数,拦截该属性的存取行为
-
/* //ES5 function fn(){ var v = 10//局部变量 return{ get:() =>{ return v }, set:(data) => { v = data } } } var obj = fn() obj.set(20) console.log(obj.get());//20 */ /* function fn(){ var v = 20 this.get = () => { return v } this.set = (data) => { v = data } } var obj = new fn() obj.set(220) console.log(obj.get());//220 */ //ES6 class fn{ constructor(){ this.v = 10 } get t(){ return this.vs } set s(data){ v = data } } var obj = new fn() obj.v = 22 console.log(obj.v);//22 // console.log(obj);//fn { v: 10 } // obj.t()//obj.t is not a function
-
-
不允许声明提前
-
不允许重复声明
静态方法
-
静态方法的语法
- statochi关键字为一个类定义了一个静态方法,静态方法不会在类的实例上被调用,被类本身调用
-
/* class fn{ constructor(){ this.name = '111' } static t(){ console.log('222'); }
}
//通过类直接调用方法
fn.t()//222let v = new fn()
console.log(v);//fn { name: ‘111’ } *///ES5 构造函数和对象的概念
function fn(){
this.name = ‘111’
}
fn.hero = () => {
console.log(222);
}
var t = new fn()
console.log(t);//fn { name: ‘111’ }
fn.hero()//222 -
静态方法的语法
- 从另一个静态方法调用
-
class Hero{ constructor(){ //构造器 - 创建对象时,初始化的属性和方法 this.name = '111' this.sayMe = () => { console.log('222' + this.name); //在构造器中调用静态方法的话,类名直接调用 //Hero.sayYou() this.constructor.sayYou() } } toString(){ console.log('333' + this.name); } static sayYou(){ console.log('444' + this.name); } static sayHe(){ //当前静态方法中,调用另一个静态方法 console.log('555' + this.name); this.sayYou() }
}
let t = new Hero()
//t.sayMe()//222111
// console.log(t);//Hero { name: ‘111’, sayMe: [Function] }
// t.toString()//333111
// Hero.sayHe()//555Hero 444Hero
//t.sayYou()//t.sayYou is not a function
t.sayMe()//222111 444Hero
类的继承
-
实现类的继承
-
class fn{ constructor(){ this.name = '111' this.sayMe = () => { console.log('222'); } } sayYou(){ console.log('333'); } static sayHe(){ console.log('444'); } } class fun extends fn{ constructor(){ super() //super - 指向当前子类的父类的构造器 this.age = 19 } } let t = new fun() console.log(t);//fun { name: '111', sayMe: [Function], age: 19 } //类中的普通方法不能用类名直接调用 console.log(t.sayYou());//333 console.log(fun.sayHe());//444
-
-
继承与内置对象
-
class fun extends Date{ constructor(){ super() } Time(){ var month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] return this.getDate() + '--' + month[this.getMonth()] + '--' + this.getFullYear } } let t = new fun() console.log(t.Time());//29--Oct--function getFullYear() { [native code] } var arr = [1,2,3,4,5] class array extends Array{ constructor(){ super() } say(a){ return new Set(a) } } let a = new array() console.log(a.say(arr));//Set { 1, 2, 3, 4, 5 }
-
-
super关键字
- super关键字作为函数调用时,代表父类的构造函数,ECMAScript6要求子类的构造函数必须执行一次super函数
- super作为对象时,在普通方法中,指向父类的原型对象,在静态方法中,指向父类
完整示例
//定义一个类
class Parent{
//表示当前类的构造器(如果省略,JavaScript会自动生成) - 创建实例对象时的初始化
constructor(name){
this.name = name;
}
//当前类的(实例对象的)方法,不是当前类地原型方法
toString(){
console.log('Parent toString');
}
static staticMethod(){
console.log('Parent staticMethod');
return 'Parent staticMethod'
}
}
//定义类原型上的方法
Parent.prototype.sayMe = () => {
console.log('Parent sayMe');
return 'Parent 11 sayMe'
}
class Child extends Parent{
constructor(name,age){
super(name);//指向父类的构造器
this.age = age
//以下用法 - 指向父类的实例对象(具有隐式原型),自动调用一次对应的方法
super.sayMe();//指向父类的原型对象
super.toString()//指向父类的实例对象
}
sayMe(){
//super -> 指向父类的原型对象
console.log('Child sayMe' + super.sayMe());
}
static staticMethod(){
//指向父类
console.log('Child staticMethod' + super.staticMethod());
}
}
let t = new Child('你好',29)
//console.log(t);//Child { name: '你好', age: 29 }
//父类和子类的相同方法同时调用
t.sayMe()
/* Parent sayMe
Child sayMeParent sayMe */
Child.staticMethod()
/* Parent staticMethod
Child staticMethodParent staticMethod */
前端模块化
前端开发领域发展到目前阶段
- 零件化 - 最终呈现给用户是一个完整的产品(由各个零件组成的)
- 降低生成成本 - 多人协作(每个人各司其职)
- 降低使用成本 - 各个零件之间是低耦合的
- 组件化 - 将一个完整的产品划分成各个组件
- 目前,前端开发中更多是指HTML页面和CSS样式
- 组件化与模块化的关系
- 将一个完整的产品,划分成若干的组件
- 将每一个组件划分成若干的模块
- 组件化与模块化的特点
- 是低耦合的 - 软件开发的统一原则
- 是热插拔的 - 指的就是需要时使用,不需要时去掉
前端模块化是什么
- 模块化的特点
- 独立性 - 可以针对一个模块单独进行设计、研发、相对工作量和难度变小
- 复用性 - 一些通用模块(例如登录或注册)可以被重复使用,而不用每次重新开发
- 解耦性 - 模块与模块之间,将相互影响降到最低,使得更换、升级或添加某个模块,不影响其他模块的工作
- 灵活性 - 通过选择和组合不同的模块,可以快速构建一个新的产品
ECMAScript5的模块化
-
没有模块化概念
-
函数的封装、
- 污染了全局命名空间(无法在全局作用于再定义一个outer()函数)
-
对象的定义
- 解决了全局命名空间可能出现的冲突问题,因为所有的模块成员都是作为一个对象的属性或方法存在的
- 模块成员之间也存在着某种关系,因为被定义在同一个JavaScript对象中,作为属性或方法存在,而这个对象名称为了所有模块成员对外的一个统一的模块名称
-
自调函数
- 会产生一些意外的安全问题,而这个问题可以通过自调函数来进行解决
-
最终模块化结构
-
var t = (function(){ var v = '111' var interface = { getAttr:function(){ return v; }, inner:function(){ return 'this is inner funtion' } } return interface })()
-
ECMAScript6的模块化
- ECAMSCript6的模块化
- ECMAScript2015的模块自动开启严格模式即使没有写use strict
- 可以在模块中使用import和export命令
- export命令
- 将当前JavaScript文件当作是一个模块
- 当前的JavaScript模块文件自动开启严格模式
- 使用export命令将当前模块内容导出(给其他模块使用)
- 将当前JavaScript文件当作是一个模块
- import命令
- ECMAScript6提供import命令导入其他模块
- import{…}from modulePath
- {…} - 与导入模块的导出部分保持一致
- modulPath - 表示导入模块的路径
- import导入其他模块时,允许定义别名
console.log(‘Parent toString’);
}
static staticMethod(){
console.log(‘Parent staticMethod’);
return ‘Parent staticMethod’
}
}
//定义类原型上的方法
Parent.prototype.sayMe = () => {
console.log(‘Parent sayMe’);
return ‘Parent 11 sayMe’
}
class Child extends Parent{
constructor(name,age){
super(name);//指向父类的构造器
this.age = age
//以下用法 - 指向父类的实例对象(具有隐式原型),自动调用一次对应的方法
super.sayMe();//指向父类的原型对象
super.toString()//指向父类的实例对象
}
sayMe(){
//super -> 指向父类的原型对象
console.log(‘Child sayMe’ + super.sayMe());
}
static staticMethod(){
//指向父类
console.log(‘Child staticMethod’ + super.staticMethod());
}
}
let t = new Child(‘你好’,29)
//console.log(t);//Child { name: ‘你好’, age: 29 }
//父类和子类的相同方法同时调用
t.sayMe()
/* Parent sayMe
Child sayMeParent sayMe /
Child.staticMethod()
/ Parent staticMethod
Child staticMethodParent staticMethod */
### 前端模块化
#### 前端开发领域发展到目前阶段
- 零件化 - 最终呈现给用户是一个完整的产品(由各个零件组成的)
- 降低生成成本 - 多人协作(每个人各司其职)
- 降低使用成本 - 各个零件之间是低耦合的
- 组件化 - 将一个完整的产品划分成各个组件
- 目前,前端开发中更多是指HTML页面和CSS样式
- 组件化与模块化的关系
- 将一个完整的产品,划分成若干的组件
- 将每一个组件划分成若干的模块
- 组件化与模块化的特点
- 是低耦合的 - 软件开发的统一原则
- 是热插拔的 - 指的就是需要时使用,不需要时去掉
#### 前端模块化是什么
- 模块化的特点
- 独立性 - 可以针对一个模块单独进行设计、研发、相对工作量和难度变小
- 复用性 - 一些通用模块(例如登录或注册)可以被重复使用,而不用每次重新开发
- 解耦性 - 模块与模块之间,将相互影响降到最低,使得更换、升级或添加某个模块,不影响其他模块的工作
- 灵活性 - 通过选择和组合不同的模块,可以快速构建一个新的产品
#### ECMAScript5的模块化
- 没有模块化概念
- 函数的封装、
- 污染了全局命名空间(无法在全局作用于再定义一个outer()函数)
- 对象的定义
- 解决了全局命名空间可能出现的冲突问题,因为所有的模块成员都是作为一个对象的属性或方法存在的
- 模块成员之间也存在着某种关系,因为被定义在同一个JavaScript对象中,作为属性或方法存在,而这个对象名称为了所有模块成员对外的一个统一的模块名称
- 自调函数
- 会产生一些意外的安全问题,而这个问题可以通过自调函数来进行解决
- 最终模块化结构
- ```
var t = (function(){
var v = '111'
var interface = {
getAttr:function(){
return v;
},
inner:function(){
return 'this is inner funtion'
}
}
return interface
})()
```
#### ECMAScript6的模块化
- ECAMSCript6的模块化
- ECMAScript2015的模块自动开启严格模式即使没有写use strict
- 可以在模块中使用import和export命令
- export命令
- 将当前JavaScript文件当作是一个模块
- 当前的JavaScript模块文件自动开启严格模式
- 使用export命令将当前模块内容导出(给其他模块使用)
- import命令
- ECMAScript6提供import命令导入其他模块
- import{....}from modulePath
- {...} - 与导入模块的导出部分保持一致
- modulPath - 表示导入模块的路径
- import导入其他模块时,允许定义别名
- import{导出的名称 as 别名} from modulePath