一,变量声明
像在es4中,使用var声明的变量存在变量提升,下面这样是不会报错的。但是在es6中使用的const和let不行,会报错!!
console.log(a);
var a = 5;
- 常量(const,不会变量提升,块级作用域,作用域内值不能改)
- 块级作用域(let,不会变量提升)
for (let i = 0; i<5; i++) {
setTimeout(() => {
console.log(i) //0 1 2 3 4
},30)
}
for (var i = 0; i<5; i++) {
setTimeout(() => {
console.log(i) //5 5 5 5 5
},30)
}
特别要说明一点的是 对于const和let都有暂存死区,所谓暂存死区就是: 如果作用域内 有这样一个变量 那么这个作用域内就会绑定这个变量,不会继续向上查找了,以下代码运行会报错。
const a = 1;
{
console.log(a);
const a = 2;
}
console.log(a)
二,解构赋值
所谓解构赋值就是 声明和赋值都放到了一起 一般都是数组 对 数组, 对象 对 对象, 数组能够设置默认值,对象也能够设置默认值,默认值必须采用等号的方式
let [zhan, si, xl = 5] = [3, 4];
console.log(zhan, si, xl) //3, 4, 5
let {name, age = 23} = {name: 'xl', bigAge: 24}
console.log(name, age) //xl, 23
特别的,可能有时会有关键字的情况可以通过:的形式来更改名字,看下面代码:
let { name, age: xl, default: d } = { name: 'xlei', age: 9, default: 'xxx' };
console.log(name, xl, d);
来一个默认值的具体应用吧:
function ajax({
url = new Error('url without'),
type = 'get',
data = xxx
}){
console.log(data, type) //{a: 5}, get
}
ajax({
url: '/test',
data: {a:5}
})
三,字符串
- 模板字符串(拼接方便,可以换行)
let exe1 = xlei
let exe2 = `${exe1}nihao
我也好`
- startWith, endWith 返回一个布尔值
let str1 = 'www.bsym.online'
let str2 = 'http://www.bsym.online'
console.log(str1.startsWith('http://')) //false
console.log(str2.startsWith('http://')) //true
console.log(str2.endsWith('online')) //true
- padStart, padEnd补全 -- 不会删除原有内容
// padStart padEnd 补全(记住只能增加,不能减少)
let str1 = 'nihao'
let newStr = str1.padStart(8,'xl')
let newStr2 = str1.padEnd(8,'xl')
console.log(newStr, newStr2) //xlxnihao, nihaoxlx
四,箭头函数(解决this问题,书写起来也更简单)
传统函数内的this是定义时所在的环境,而箭头函数内的this是使用时上下文的环境。
let aa = (arg1, arg2) => {
console.log(arg1, arg2)
}
aa(1, 2) //1, 2
;((arg1, arg2) => {
console.log(arg1, arg2)
})(3, 4);
这里顺带提一下,像上面的自执行匿名函数前后都要加分号,这样既不会被坑,也不会坑别人。另外不要使用箭头函数的argeuments
五,扩展运算符
- 数组的扩展运算符:将一个数组转为用逗号分隔的参数序列
let arr = [...[1, 2, 3], ...[4, 5, 6]]
console.log(arr) // 1, 2, 3, 4, 5, 6
console.log(Math.min(...arr)) // 1
- 对象的解构赋值
对象的 Rest 解构赋值用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面,注意Rest 解构赋值必须是最后一个参数,否则会报错。Rest解构赋值所在的对象,拷贝了对象obj的属性,Rest解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest解构赋值拷贝的是这个值的引用,而不是这个值的副本,解构赋值不会拷贝继承自原型对象的属性
let obj = {name: 'xl', age: 23, say:'ok', eat: {xl: 'okok'}}
let {name, age, ...z} = obj //尚未被读取的属性,分配到指定的对象上面,浅拷贝了对象obj的属性
obj.say = 'oo'
obj.eat.xl = 'o?o?'
console.log(name, age, z) //xl 23 { say: 'ok', eat: { xl: 'o?o?' } }
let z = {a: 3, b: 4, c:{
eat:'ok'
}}
let n = {...z} 注意这个地方和直接赋值的区别 let n = z; 一个是浅拷贝对象属性,一个是浅拷贝对象
z.a = 5
z.c.eat = 'ok?'
console.log(n) //{ a: 3, b: 4, c: { eat: 'ok?' } }
那么要是想实现一个深拷贝,怎么实现呢?其实就是遍历属性如果属性是一个普通值就赋值,不是普通值就递归知道是普通值为止,然后赋值,代码如下:
// 实现深拷贝 保留继承关系 可以实现各种类型的拷贝 实现递归拷贝
function deepClone(obj) {
if (typeof obj !== 'object') return obj;
if (obj == null) return null;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
let o = new obj.constructor(); // 保留类的继承关系
// for (let key in obj) {
// // console.log(obj.hasOwnProperty === Object.prototype.hasOwnProperty)
// if ( obj.hasOwnProperty(key) ) { //只有自身属性才赋值
// if(typeof (obj[key]) == 'object'){
// o[key] = deepClone(obj[key])
// }else{
// // console.log(obj[key])
// o[key] = obj[key]
// }
// }
// }
Object.keys(obj).forEach((key, index) => {
if(typeof (obj[key]) == 'object'){
o[key] = deepClone(obj[key])
}else{
// console.log(obj[key])
o[key] = obj[key]
}
})
return o;
}
let o = { a: { a: 1 }, b: function(){
console.log(this.a)
} }
let newObj = deepClone(o);
o.a.a = 2;
console.log( newObj.b());
六,数组常用方法
// 1)map返回值 返回值是一个新数组
Array.prototype.map = function (fn) {
let arr = [];
for (let i = 0; i < this.length; i++) {
arr.push(fn(this[i], i));
}
return arr;
};
let arr = [1, 2, 3].map(item => {
return item * 2;
});
console.log(arr);
// 2)filter 过滤 如果返回true表示留下 返回false表示删除
let arr = [1, 2, 3];
let filterArr = arr.filter(item => {
return item > 2;
});
console.log(filterArr);
// 3)some找到后返回true,找false可以用every
let r = [2, 1, 3].some(item => {
return item > 2;
});
console.log(r); //true
// 4)every 检测数组 ages 的所有元素是否都符合条件 :
var ages = [2, 1, 3];
let r = ages.every((item) => {
return item > 2
})
console.log(r) //false
// 5)Array.from(); 将类数组转为数组
七,es6的class
先复习一下es5中的几个名词:
- 成员属性(方法)| 实例属性(方法) :在构造函数中通过this.属性声明的
- 静态属性(方法):通过类来声明的 类.xxx
- 私有属性(方法):只有在类的内部可以使用,其他任何地方都不可以使用的
- 公有属性(方法)|原型属性(方法):在原型上声明的属性或者方法 xx.prototype.xxx 敲代码:
function Parent(name) {
this.name = name; //成员属性|实例属性
this.say = function() { //成员方法
console.log(this.name)
}
}
Parent.smoking = 'no' //静态属性
Parent.prototype.up = function() { //公有方法|原型方法
console.log('ok')
}
再来说说es6中的class(es6中不考虑私有属性和方法):
class Parent{
constructor(x, y){
this.x = x; //成员属性|实例属性 可遍历 打印实例可直接打印出来, // 与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
this.y = y;
return this.x //如果不返回 默认返回实例对象 this
}
static b(){ // 属于类上的方法 也称静态方法
return 2;
}
eat(){ //原型上的方法 | 公有方法 并且都是不可枚举的 打印实例不能显示的打印出来
console.log(this.x);
return this.x
}
// Object.assign(Parent.prototype, {
// eat(){},
// });
}
class Child extends Parent{ //
constructor(x, y, z){
super(x, y); // Parent.call(this); 返回的是子类的实例,
this.age = z; // 成员属性|实例属性
}
static a(){ // 属于类上的方法
return 1;
}
smoking(){ // 原型上的方法
return super.eat() + this.age //需要说明的是 super不仅可以调用父类的原型方法还可以调用父类的静态方法,方法内部的this指向当前的子类,而不是子类的实例
// console.log(this.age)
}
}
let child = new Child(2, 3, 4);
// console.log(child);
console.log(child.smoking())
class Foo {
constructor() { //constructor函数默认返回this, 这里返回一个全新的对象,结果导致实例对象不是Foo类的实例
return Object.create(null);
}
}
new Foo() instanceof Foo
// false
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
console.log(point)
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
以上就是ES6常用的几个新特性,动手敲一遍,你就记住了!当然以上肯定会存在很多不足的地方,欢迎各位提出宝贵的意见或建议,也希望能帮助到你从中获得一些知识!