等号左边允许存在默认值。变量的取值按照顺序。
- //之前的写法
- var arr=[1,2];
- var a=arr[0];
- var b=arr[1];
- //ES6
- let [a,b]=[1,2];
- console.log(a,b) -> 1 2
- let [c,d]=[3]
- console.log(c,d) -> 3 undefined
- let [f=4,g=5,h=6]=[,undefined,null];
- console.log(f,g,h) -> 4 5 null
根据键值取值。
- let obj={
- name:'hua',
- age:18
- }
- //不同名,则把左边的属性的值赋给右边自定义的变量
- let {name:n,age:a}=obj;
- console.log(n,a) -> 'hua' 18
- console.log(name,age) ->打印报错 未声明
- //同名的可以将name:name省略成name
- let {age,name}=obj;
- console.log(name,age) -> 'hua' 18
此时字符串被转换成一个类似于数组的对象。
- let str='hello World';
- let [a,b,c]=str;
- console.log(a,b,c,typeof(a)) -> h e l string
用于获取函数的多余参数,会将多余的实参放进一个数组里。
- function fn(a,...arr){
- console.log(a); -> 1
- console.log(arr); -> ['a', 'b']
- console.log(arr[0]); -> a
- console.log(arr[2]); -> undefined
- }
- fn(1,'a','b');//方法中的定义了4个参数,但调用函数时只使用了3个参数,ES6 中并不会报错。
注意,res参数之后不能再有任何参数。函数的length属性(指明函数形参的个数)不包括res参数
- (function(a){}).length //1
- (function(...a){}).length //0
规定只要函数参数使用了默认值、解构赋值或者扩展运算符,那么函数内部就不能显示设定为严格模式,会报错。
- function fn(a,b=1){ //报错
- 'use strict';
- }
两种方式可以避免这种限制:
具名函数返回函数原本的名字,匿名函数返回实际的函数名
- function fn(){}
- let fun=function(){}
- fn.name //fn
- fun.name //fun (ES5中返回空字符串)
注意要点:
由于箭头函数this指向的特殊性,箭头函数不适用于定义对象的方法,且该方法内部包括this。
- s = 21;
- const obj = {
- s: 42,
- f: () => console.log(this.s)//继承作用域的上一层的this,指向全局
- };
- obj.f() // 21
可将类似数组的对象和可遍历的对象(包括新增的数据结构Set、Map)
伪数组:有索引,有长度,但是没有方法
- let arrayLike={
- '0':'a',
- '1':'b',
- '2':'c',
- length:3
- };
- const arr=Array.from(arryLike);
- console.log(arr); //['a','b','c']
- //length:2->['a','b'] length:4->['a','b','c',undefined]
实际应用开中,我们常见的伪数组就是DOM操作中返回的元素对象集合,以及函数的内置arguments对象。都能用Array.from()方法将伪数组转为真正的数组。
- let arrayLike=document.querySelectorAll('button');
- let a=document.getElementsByTagName('button');
- console.log(arrayLike,a);//NodeList(5) HtmlCollection(5)
- const arr=Array.from(arrayLike);
- console.log(arr);//(5)
⭐补充一下,DOM操作中三种方式返回的伪数组类型有些不同:
- querySelectorAll():NodeList类型,获取子节点操作中的childNodes属于该类型。即返回的集合中包含元素节点和文本节点(文字、空格)等;
- getElementsBytagName()和getElementsByClassName()返回的是HtmlCollection类型,获取子节点操作中的children就属于该类型.即返回的集合中只有元素节点。
将一组值转换为数组。
- console.log(Array.of(1,2,3)); //[1,2,3]
- console.log(Array.of(1,2,3).length); //3
Array.of() 返回由参数组成的数组,如果没有参数就返回一个空数组。这就弥补了数组构造函数中参数个数不同导致行为有差异的问题。
- //没有参数时,一致
- Array() //[]
- Array.of() //[]
- //一个参数时,一个是长度,一个是值
- Array(2) //[empty × 2] length:2
- Array.of(2) //[2]
- //多个参数时,一致
- Array(1,2) //[1,2]
- Array.of(1,2) //[1,2]
Object.defineProperty(obj, prop, descriptor) 定义新属性或修改原有的属性
- let obj={
- name:'hua',
- age:18
- }
- console.log(obj); //{name: 'hua', age: 18}
- /* 传统方式
- obj.sex='man';
- obj.age=19; */
- Object.defineProperty(obj,'sex',{
- value:'man'
- });
- Object.defineProperty(obj,'age',{
- value:19
- });
- console.log(obj); //{name: 'hua', age: 19, sex: 'man'}
第三个参数,以对象的形式书写
value: 设置属性的值,默认为undefined;
writable: 值是否可以重写,当属性是由该方法新创建的时候,默认值为false;
- console.log(obj); //{name: 'hua', age: 18}
- Object.defineProperty(obj,'sex',{
- value:'man',
- writable:true, //当属性是由该方法新创建的时候,默认值才为false
- });
- Object.defineProperty(obj,'sex',{
- value:1
- });
- Object.defineProperty(obj,'age',{
- value:20,
- writable:false
- });
- console.log(obj); //{name: 'hua', age: 20, sex: 1}
- obj.sex=0;
- obj.age=30;
- console.log(obj); //{name: 'hua', age: 20, sex: 0}
enumerable: 目标属性是否可以被枚举,当属性是由该方法新创建的时候,默认值为false;
- console.log(Object.keys(obj)); //['name', 'age']
- Object.defineProperty(obj,'sex',{
- value:'man',
- enumerable: true
- });
- console.log(Object.keys(obj)); //['name', 'age', 'sex']
- Object.defineProperty(obj,'age',{
- enumerable:false
- });
- console.log(Object.keys(obj)); //['name', 'sex']
configurable: 目标属性是否可以被删除或再次修改特性,当属性是由该方法新创建的时候,默认值为false。
- Object.defineProperty(obj,'sex',{
- value:'man',
- configurable:true
- });
- console.log(obj); //{name: 'hua', age: 18, sex: 'man'}
- delete obj.sex;
- console.log(obj); //{name: 'hua', age: 18}
- delete obj.name;
- Object.defineProperty(obj,'age',{
- configurable:false
- });
- delete obj.age;
- console.log(obj); //{age: 18}
- Object.defineProperty(obj,'sex',{
- value:'man',
- configurable:false
- });
- Object.defineProperty(obj,'sex',{
- value:1,
- writable:true
- });
- console.log(obj); //Error:Cannot redefine property: sex
Object.freeze()方法作用就是冻结一个对象,即让该对象无法修改。可以提升性能
- const a=1;
- //a=2; //报错
- const obj={b:2};
- obj.b=3;
- console.log(obj.b); //3
我们都知道,用const声明基本数据类型是无法进行修改的,但声明的对象的属性是可以修改的,因为赋给的变量里存的是该对象的地址。这时就可以使用Object.freeze()方法来冻结。
被冻结后的对象:
- let obj={
- name:'hua',
- age:18
- }
- console.log(obj); //{name: 'hua', age: 18}
- Object.freeze(obj);
- obj.sex='man';
- obj.age=19;
- console.log(obj); //{name: 'hua', age: 18}
- console.log(Object.freeze(obj))//{name: 'hua', age: 18}
//该方法返回的就是传入的对象本身,所以一般不用接收返回值。也可以冻结数组,毕竟数组的本质也是对象。
注意,该方式属于浅冻结。当冻结的对象里还有对象时,内层的对象仍可以被修改
- let obj={
- name:'hua',
- deep:{
- age:18
- }
- };
- Object.freeze(obj);
- obj.name=123;
- obj.deep.age=19;
- console.log(obj.name,obj.deep); //hua {age:19}
解决办法:封装一个深冻结函数,随时调用。
- function deepFreeze(obj){
- //获取所有属性
- let proName=Object.getOwnPropertyNames(obj);
- //遍历
- proName.forEach(item=>{
- let pro=obj[item];
- //如果某个属性的属性值是对象,则递归调用
- if(pro instanceof Object && pro!==null){
- deepFreeze(pro);
- }
- })
- return Object.freeze(obj);
- }
-
- deepFreeze(obj);
- console.log(obj.name,obj.deep); //hua 18
之前,实现对象的继承是通过原型链实现的。ES6提供了更多原型对象的操作。
Object.setPrototypeOf()方法的作用与__proto__相同,用来设置一个对象的原型对象,并返回参数对象本身。
- let obj={ x:1 };
- let proto={ y:function(){return 2} };
- Object.setPrototypeOf(obj,proto);
- proto.z=3;
- console.log(obj.x, obj.y(), obj.z); //1 2 3
- console.log(Object.setPrototypeOf(obj,proto)); // {x:1}
//将proto对象设为obj对象的原型,所以obj对象能够获取proto对象的属性
Object.getPrototypeOf
方法与Object.setPrototypeOf
方法配套,用于读取一个对象的原型对象。
console.log(Object.getPrototypeOf(obj)); // {y:f,z:3}
扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。 可以看作是res参数的逆运算。
- let arr=[1,2,3];
- ...arr //1,2,3
- console.log(...arr); //1 2 3
输出没有逗号是因为逗号被console.log方法当作参数分隔符了,所以不会输出逗号。
- 用途1:合并数组
- let arr1 = [1, 2, 3];
- let arr2 = [4, 5, 6];
- // 方法1
- let arr3 = [...arr1, ...arr2];
- console.log(arr3); // [1,2,3,4,5,6]
- // 方法2
- arr1.push(...arr2);
- console.log(arr1); // [1,2,3,4,5,6]
- 用途2:将伪数组或可遍历的对象转为数组
- let pa = document.getElementsByClassName('li');
- let arr = [...pa]; // 利用扩展运算符,将伪数组转为真正的数组
- //pa.push('a'); 报错 伪数组不支持
- arr.push('a');
- console.log(arr); //[li,li,a]
- //方法2
- let a=Array.from(pa);
- a.push('a');
- 用途3:避免指向同一个地址
- //对象是引用数据类型,赋给的变量存的是该对象的地址,所以
- let str1=[1,2];
- let str2=str1;
- //这两个变量存的是同一个对象的地址,通过任何一个变量对该数组进行改变,该数组都会发生相应的改变,
- //这时就可以通过扩展运算符
- let str2=[...str1]; //为str2开辟一个新的内存地址,就不会影响str1了
引入的原因:在读取对象内部的某个属性时,安全的做法是需要一层层的判断属性的上层对象是否存在。而这样层层判断十分麻烦,因此引入了链判断运算符" ?. "。
- //引入前
- let name = (message && message.user && message.user.name)||'default';
- //引入后
- let name = message?.user?.name || 'default';
当左侧的对象为null或undefined时,就不再往下运算,而是直接返回undefined。
常见形式:
- a?.b <=> a== null ? undefined : a.b //三元运算符:条件?满足的:不满足的
-
- a?.[x] <=> a==null ? undefined : a[x]
-
- a?.b() <=> a==null ? undefined : a.b() //如果是不满足的情况下且a.b不是函数不可调用就报错
-
- a?.() <=> a==null ? undefined : a() //如果是不满足的情况下且a不是函数就报错
字符串${变量}字符串
includes(str)
:判断是否包含指定的字符串startsWith(str)
:判断是否以指定字符串开头endsWith(str)
:判断是否以指定字符串结尾repeat(count)
:重复指定的次数
- 八进制0o表示,二进制0b;
Number.isFinite(n)
:判断是否为有限大的数。比如Infinity
这种无穷大的数,返回的就是 false。Number.isNaN(n)
:判断是否为 NaN。Number.isInteger(n)
:判断是否为整数。Number.parseInt(str)
:将字符串转换为对应的数值。Math.trunc(n)
:去除小数部分。
地址:前端面试题库
地址:前端技术导航大全
地址 :开发者颜色值转换工具