解构赋值
1.什么叫做解构?
在ES6中按照一 定的模式从 数组中提取数值对对应的变量进行赋值的操作就叫做解构赋值 本质上讲解构赋值就是模式匹配
2.解构赋值
var [a,b,c] = [1,2,3];console.log(a,b,c);//1 2 3
1.如果想要解构赋值成功那么就必须保证两边的模式完全一样
var [a,b,c]=[1,2,{name : 'lucy'}];console.log(a,b,c); //1 2 {name:'lucy'}
2.如果解构不成功 那么变量的值就等于undefined
let [r]=[];console.log(r); //undefined
3.不完全解构的情况下也可以进行解构赋值只是后面放数值的数组都有多的数字
不完全解构:指的是等号左右两边模式-样但是只匹配到右边的一部分数据
let [x,y]=[1,2,3];console.log(x,y); //1 2
4.如果等号右边不是数组那么就会报错 因为模式一样
let [m]=1; //1 is not iterable
let [m]=false; //false is not iterable
let [m]=null; //null is not iterable
let [m]={}; //{} is not iterable 因为{}不可使用下标进行迭代s
3.注意点
1.解构赋值是允许设置默认值的 但是如果要启用默认值那么这个变量的值就必须严格等于undefined
let [a,b]=[1,2];
let [a,b = "abc"] = [1,2];console.log(a,b);//1,2
let [a,b = "abc"] = [1];console.log(a,b);//1,"abc"
let [a,b = "abc"] = [1,undefined];console.log(a,b);//1,"abc"
let [a,b = "abc"] = [1,null];console.log(a,b);//1,null
let [a,b = "abc"] = [1,""];console.log(a,b);//1,""
2.如果设置的默认是是一个表达式 那么这个表达式只是在需要启用默认值得时候才会运算
function fn(){
console.log(123);
}
let [s = fn()]=[12];console.log(s);//12
let [s = fn()] = [];console.log(s);//undefined 这 里的undefined不 是[]里面的undefined而 是fn调用之后的
let [s=fn]=[];console.log(s);//function fn(){console.log(123);}
3.默认值可以使用其他变量 但是前提是赋值的这个变量必须是提前声明过的
let d = 3;
let [x = d] = [];console.log(x);//3
//let [x = 2,y = x] = [];console.log(x,y);//2,2
let [x = y,y = 2] = [];console.log(x,y);//y is not defined
扩展运算符
var arr = [100,200,300];
//var arr1 = arr;
//arr[1]=20;
//console.log(arr1);//直接赋值 修改了原数组的值 arr1里面的值也会发生改变 因为他们指向同一块内存空间
var arr2 = [...arr];
arr[0] = 10;
console.log(arr2);//这是使用扩展运算符 就是一个一个加到新数组里面去 所以即使原数组发生变化 也不会影响新数组
1.扩展运算符的作用
1.数组合并 这里不管是concat方法还是扩展运算符 都是浅拷贝
浅拷贝:如果修改了原数组的指向 就会同步反应到新数组 就是浅拷贝
var arr1 = [1,2,3],arr2 = [10,20,30];
var arrSp = [...arr1,...arr2];
//这里就证明了合并后的数组和合并前的数组指向同一片内存空间所以证明了 都是浅拷贝
console.log(arrSp[1] === arr1[1]);//true
console.log(arrCon[1] === arr1[1]);//true
arr1 = [1,2,3,...arr2];console.log(arr1);//[1, 2, 3, 10, 20, 30]
2.数组的拷贝
2.1.浅拷贝
var arr = [1,[3],{name : '丽丽'}];
var arrSp = [...arr];
console.log(arrSp);//[1,[3],{name : '丽丽'}]
arr[2].name = '张三';
console.log(arrSp);//[1,[3],{name : '张三'}]
2.2.数组深拷贝 通常使用JSON.stringify()和JSON.parse()进行深拷贝
var str = JSON.stringify(arr);
var arr2 = JSON.parse(str);
console.log(arr2);//[1,[3],{name : '张三'}]
arr[2].name = '李四';
arr[1][0] = 4;
console.log(arrSp);//[1,[4],{name : '李四'}]
console.log(arr2);//[1,[3],{name : '张三'}]
3.与解构赋值结合 如果是普通变量 那么就按照模式赋值 如果使用了扩展运算符 那么就是后面的值依次放入数组
3.1.如果等号右边是空数组 那么仅仅是声明 变量为undefined 数组为[]
var [s,...t] = [1,2,3,4,5];console.log(s,t);//1 [2,3,4,5]
var [s,...t] = [];console.log(s,t);//undefined [] //等同 var s,t = [];
3.2.如果将拓展运算符用于数组赋值,必须放在最后的位置
let [a,...b,c] = [1,2,3,2,9];console.log(a,b,c);//报错 Rest element must be last element
let [a,c,...b] = [1,2,3,2,9];console.log(a,b,c);//1 2 [3,2,9]
3.3.扩展运算符可以将字符串转成真正的数组
console.log([...'hello']);//["h", "e", "l", "l", "o"]
var str = 'hello';
console.log( str.split(""));//["h", "e", "l", "l", "o"]
3.4.只有函数调用时 扩展运算符才可以放在圆括号里面 否则这种写法就直接报错
var arr1 = [12,45,25];
//(...arr1);//报错
console.log([...arr1]);//[12, 45, 25]
//console.log((...arr1));//报错
console.log(...arr1);//12 45 25
function sum(a,b){
return a + b;
}
console.log(sum(...arr1));//57
对象的扩展
1.对象属性的扩展
1.对象属性的简单赋值方式 可以将变量名直接放进对象中,解析的时候 将变量名解析为属性名 变量值解析为属性值
2.对象方法的简单赋值 可以省略function关键字
var obj = {
work(){}
}
3.super关键字:指向于当前对象的原型对象
使用注意点:
1.super关键字 只能在对象的方法中使用 在其他地方使用会报错
2.super关键字 目前只能在对象的简写方式里面去用 常规写法的方法会报错
var stu = {
name : '张三',
age : 16,
//正确用法
study(){
console.log("我是" + super.type = ",我的任务是" + super.tesk);
}
}
stu.__proto__ = {
type : 'student',
tecsk : '学习'
}
4.对象的计算属性名 使用方式[] 对象属性名进行计算 里面可以是变量名 表达式 也可以是函数
2.对象的新增的api
1.Object.is() 这个方法和js的严格判断(===)用法基本一致 只是在对与-0 和+0 以及NaN的判断上做了改善
console.log(-0 === +0); //true
console.log(NaN === NaN); //false
console.log(Object.is(-0 , +0); //false
console.log(Object.is(NaN , NaN)); //true
2.Object.assign() 是用来合并对象的
参数1 : 目标对象 参数2… :需要合并的对象
注意点:
1.返回值是传入的第一个目标对象,会把所有的对象合并上去在返回
2.第一个参数必须是对象 如果不是对象 就会把它转换成对象 例如如果是基本数据类型 就会把它转成对象(包装类)
3.如果是undefined或者null 没办法转成对象 那么就会报错
4.如果在需要合并的多个对象里面 有同名的属性 那么后面的属性会将前面的属性覆盖
5.如果undefined和null不是第一个参数 那么就不会报错 第一个参数返回
6.assign方法是浅拷贝 不是深拷贝
3.Object.setPrototypeOf 给一个对象设置原型对象
参数1 :目标对象 参数2 :原型对象 返回值 :目标对象
4.Object.getPrototypeOf(obj) 获取对象原型的方法 参数是需要查询的对象名称
5.Object.keys() 是将对象的所有属性名遍历 然后返回一个数组
6.Object.values() 是将对象的所有属性值遍历 然后返回一个数组
class关键字的基本使用
1.传统的构造函数的问题
传统的构造函数的缺点:
1.构造函数和原型方法属性分离 不便于维护 降低了可读性
2.原型对象的成员可以遍历
3.默认情况下构造函数也是可以被当成普通函数来调用的 所以 功能性不明显
4.类的方法不能作为构造函数使用
类:
1.class就是一个语法糖 本质上就是一个函数 就是使用ES5里面的函数封装的
2.在类里面去定义方法的时候 可以省略function关键字
类使用的注意点
1.类不可以枚举
2.类的用法跟let和const一样 都有暂时性死区 必须先定义 在调用
3.类的方法不能作为构造函数使用
4.类使用的时候 必须配合new关键字进行使用 否则就会报错
字符串的扩展
1.字符串新增的api
1.1.indexOf 是查找字符串中是否包含某一个字符串
参数1 : 需要查询的目标字符串 参数2:就是开始查询的索引(如果不写 默认从0开始)
var str = "abcdefghigkmn";
console.log(str.indexOf("cd")); //2 目标下标
console.log(str.indexOf("cd",5)); //-1 没找到
1.2.includes() 检测字符串或者数组中 是否包含某一个字符串或者元素
返回值 : 布尔类型
参数1 : 需要查询的目标字符串 参数2:就是开始查询的索引(如果不写 默认从0开始)
console.log(str.includes("hi",3)); //true
console.log(str.includes("km",9)); //true
indexOf 和 includes的区别
(1) 返回值 indexOf方法 返回找到的第一个字符串的位置索引 includes方法 找到了就返回true 否则为false
var arr = [15,20,60,50];
if(arr.includes(60)){console.log("咱们有踩线及格的");}
if(arr.indexOf(60) != -1){console.log("咱们有踩线及格的");}
(2) 如果数组里面包含NaN 但是我们又正好需要查数组里面有没有NaN 那么indexOf就不能用
var arr1 = [1,15,46,42,NaN];
console.log(arr1.indexOf(NaN)); //-1
console.log(arr1.includes(NaN)); //true
(3) 如果数组里面包含空值 那么使用indexOf判断会出错 只能使用includes
var arr2 = new Array(5);
console.log(arr2.indexOf(undefined)); // -1
console.log(arr2.includes(undefined)); //true
1.3.startsWith() endsWith() 判断是否以某一字符串开头或结尾
var sayHi = "hello world!";
console.log(sayHi.startsWith("hello")); // true
console.log(sayHi.endsWith("!")); // true
第二个参数 :
startsWith : 第二个参数 表示从索引为几的字符串开始找
endsWith : 第二个参数 表示的是从索引为n之前的元素里面去找(不算自身)
console.log(sayHi.startsWith("hello",3)); //false
console.log(sayHi.endsWith("!",11)); //false
console.log(sayHi.endsWith("!",16)); //true
2.字符串标记
var name = "jack",boy = "男孩",girl = "女朋友";
var str = `我的名字叫${name},我是一个穷穷的${boy},我有一个很漂亮的${girl}`;
console.log(str);//我的名字叫jack,我是一个穷穷的男孩,我有一个很漂亮的女朋友
2.1标签模版 它本质上不是模版 而是函数的另外一种调用函数 其实我们所说的标签 其实就是我们事先封装好的函数
参数1 : 被插入的变量分割而成字符串数组
/参数2…:都是被插入的变量
function intro(parts,a1,a2,a3,a4){
console.log(parts); //["",",我的名字叫",",我是一个","穷穷的",",我有一个很漂亮的",""]
// console.log(a1,a2,a3,a4);
console.log(arguments); //{0:["",",我的名字叫",",我是一个","穷穷的",",我有一个很漂亮的",""],1:"大家好",2:"jack",3:"很绅士的",4:"男孩",5:"女朋友"}
// 伪数组改真数组
let arr = [].slice.call(arguments,1)
console.log(arr);
var s = "";
for(let i=0;i<arr.length;i++){
s += `${parts[i]}${arr[i]}`;
}
s += `${parts[parts.length-1]}`;
return s;
}
var featave = "很绅士的";
var hi = "大家好";
// var str = intro`我的名字叫${name},我是一个${featave}穷穷的${boy},我有一个很漂亮的${girl}`;
var str = intro`${hi},我的名字叫${name},我是一个${featave}穷穷的${boy},我有一个很漂亮的${girl}`;
console.log(str); //"大家好,我的名字叫jack,我是一个很绅士的穷穷的男孩,我有一个很漂亮的女朋友"
console.log(666);
console.log();
var obj = new Object();
console.log(obj.p);
3.字符串标记的作用
将用户输入的<>换成< >
html:
<div>
<textarea name="" id="txt" cols="30" rows="10"></textarea>
<input type="button" value="点我" id="btn">
</div>
<div id="container"></div>
< >
<h1>我是一个粉刷家</h1>
js:
var txt = document.getElementById("txt");
var container = document.getElementById("container");
var btn = document.getElementById("btn");
btn.onclick = function(){
container.innerHTML = protect`<p>${txt.value}<p><h1>${txt.value}</h1>`;
}
function protect(parts){
var res = [].slice.call(arguments,1);
var str = "";
for(var i=0;i<res.length;i++){
var s = res[i].replace(/</g,"<").replace(/>/g,">");
str += parts[i] + s;
}
str += parts[i];
return str;
}
函数的扩展
1.ES6里面默认给参数设置默认值
1.1.为了防止报错 我们不用在特地在函数内部处理参数
1.2.设置了默认值即便所有的参数都不传我们的程序也不会报错
注意点:参数是在函数的局部作用域内设置的局部变量默认是在函数内部声明过的 所以不要再使用let在函数内部声明
function count(m = 20,n = 30){
//let n = 80; //报错
console.log(m + n);
}
2.函数的扩展的应用
html:
<div id="container"></div>
js:
function getContainer(id){//获取id
console.log(111);
return document.getElementById(id);
}
//添加元素
function createElement(name="p",container=getContainer("container"),content="你好 世界"){
//创建对象
var ele = document.createElement(name);
//添加属性或者内容
ele.innerHTML = content;
//添加到页面上
container.appendChild(ele);
}
createElement("p",document.getElementById("container"),"你好 世界");
createElement();
createElement(undefined,undefined,"今天天气不错");
//现调用3次createElement() 打印2次111
3.=> 箭头函数 ES6是允许使用箭头函数的
1.只有一个参数 并且函数体只有一句话 那么参数可以省略() 返回值可以省略reyurn 函数体省略了{}
var fn = n => 123;
var r = fn();console.log(r);//123
2.如果箭头函数没有参数 或者有多个参数 那么参数中的()就不能省略
3.如果箭头函数体有多条带码 那么就不能省略{}以及返回值也不能省略return
var study = () => {
var lesson = "语文";
return "好好学习天天向上";
}
4.如果函数体只有一句话 并且是对象 那么这个返回值必须使用()包起来
因为函数体使用的是{} 对象也是{}
var info = (name,age) => ({
name : name,
age : age
})
console.log(info("箩筐",16));//{name: "箩筐", age: 16}
5.如果对象只有一个键值对,那么就不会报错 但是也没有正确的值
因为js引擎在解析的时候 {}默认解析为函数体结构 函数体代码 name : name; 无实意
var p = (name) => {name : name}
console.log(p("lili"));//undefined