ES6知识点(模块化、解构、箭头函数、拓展运算符、类、继承、symbol)

模块化导入与导出

ES6导入与导出:

1、列表导入导出

//列表导出
exports.firstName = firstName;
exports.lastName = lastName;
//列表导入
import {firstName,lastName} from '路径';

2、重命名导入导出

//重命名导出
exports.first = firstName;
exports.last = lastName;
//重命名导入
import {first as f,last as l} from './3-modules';

3、单个属性导出导入

//单个属性导出
var a = exports.a = 1;
//单个属性导入
import {a} from './3-modules';

4、方法导入导出

//方法导出
exports.get = get;
function get() {
  console.log('modules3导出');
};
//方法导入
import {get} from './3-modules';

5、默认导入导出

//默认导出
exports.default = {
  firstName: firstName,
  lastName: lastName,
  b: '默认导出'
};
//默认导入
import person from './3-modules';
console.log(person,'默认导入');

**注意:**一个模块只能有一个默认导出

ES5导入与导出:

commonjs模块化导出

let firstName='ren';
let lastName='terry';
// module表示当前模块对象
// console.log(module,'当前模块对象');

module.exports={
	firstName,
	lastName
}

commonjs模块化导入

let {firstName,lastName} =require('./5-modules');
console.log(firstName,lastName,'modules6打印');

ES6和ES5模块化导入导出的区别:

1、commonjs在运行时加载,es6在编译时加载
2、commonjs输出的是值的复制,而es6输出的是一个值的引用。

let、const、var的区别

  • 块级作用域:let、const具有块级作用域,var不具有块级作用域。
  • 给全局添加属性: 浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。
  • 变量声明:var声明变量,可以重复声明,后声明的变量覆盖前声明的变量,let、const不可以重复声明。
  • 初始值设置:在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值,常用于规定值,如PI。
  • 变量提升: var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否在会报错。
  • 暂时性死区: 在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区。
  • 指针指向: let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。

解构

定义:按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
**注意:**解构的本质属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值就等于undefined。

数组解构

  • 第一种:完全解构
let [a,b,c]=[1,2,3];
console.log(a,b,c);//1 2 3

let [a,b,c]=[1,2,3];
console.log(a,b,c,d);//1 2 3 undefined 

let [a,b,c,d,e]=[1,2,3,[4,5],6];
console.log(a,b,c,d,e);//1 2 3 [ 4, 5 ] 6
  • 第二种:不完全解构
let [a,b,c,[d],e]=[1,2,3,[4,5,6],7];
	console.log(a,b,c,d,e);//1 2 3 4 7
  • 第三种:默认值解构
//默认值生效条件 当右侧匹配严格模式为undefiend
let [a=1,b=2,c=3]=[4,5,6];
console.log(a,b,c);//4 5 6

// 默认值也可以是一个函数
let test=()=>{
	console.log('我是箭头函数');
	return 1
}
let [a=test()]=[];
console.log(a);//我是箭头函数 1
  • 第四种:集合解构 拓展运算符
let [a,...b]=[1,2,3,4];
console.log(a,b);//1 [ 2, 3, 4 ]
  • 第五种:拓展运算符
let a=[1,2,3,4,5];
let [...arr]=a;
console.log(arr);//[ 1, 2, 3, 4, 5 ]
console.log(arr===a);//false

对象解构

  • 属性名必须和变量名一致才能取到正确的值
let {name,age}={name:'zhangsan',age:12};
console.log(name,age);//zhangsan 12
  • 重命名解构
// 2.属性名和变量名不一致 给属性名重命名
let {name:a,age:b}={name:'zhangsan',age:12};
console.log(a,b);//zhangsan 12
  • 嵌套解构
let obj={p:['hello',{y:"world"}]};// a b取到hello world
let {p:[a,{y:b}]}=obj;
console.log(a,b);//hello world
  • 对象默认值结构
let {x:y=8}={};
console.log(y);//8

字符串解构

  • 使用数组进行字符串解构
let [a,b,c,d,e]='hello';
console.log(a,b,c,d,e);//h e l l o
  • 使用拓展运算符 解构字符串
let [...arr]='world';
console.log(arr);//[ 'w', 'o', 'r', 'l', 'd' ]
  • 使用对象解构字符串
//相当于把‘hello’当成String基本包装器类型
let {toString,valueOf,length}='hello';
console.log(toString,valueOf,length)//[Function: toString] [Function: valueOf] 5

箭头函数

概念:在es6种允许使用箭头函数,箭头函数提供了更加简洁的函数书写方式,箭头函数多用于匿名函数的定义;

箭头函数的注意点:

1、如果形参只有一个,则小括号可以省略。
2、函数体如果只有一条语句,则花括号可以省略,并省略return,函数的返回值为该条件语句的执行结果。
3、箭头函数this指向声明时所在作用域下this的值。
4、箭头函数不能作为构造函数实例化;
5、不能使用argument

特性

1、箭头函数的this时静态的,始终指向函数声明所在作用域下的this的值
2、不能作为构造实例化对象
3、不能使用argument变量,要使用reat参数。

函数的写法
  • es5函数
sayName:function(){
		函数体
	}
  • es6函数简写
sayName(){
		console.log(this.name);
	}
  • es6箭头函数
sayName:()=>{
		console.log('111');//undefined
	} 

reat参数

返回一个保存实参的数组,搭配拓展运算符使用。

看下面的例子:

let test=(a,...b)=>{
	console.log(a,b); //1 [2,3]
	// console.log(arguments,'222');
	// es6 箭头函数 arguments不再保存实参列表
}
test(1,2,3)

箭头函数和普通函数的区别?

  • 语法更加简洁、清晰
  • 箭头函数是匿名函数,不能作为构造方法,不能使用new关键字
  • 箭头函数不能使用argument,而用reat参数
  • 箭头函数没有自己的this,会捕获上下文的this,并且不能通过call()、apply()来改变其this指向
  • 箭头函数没有原型

拓展运算符

对象的扩展运算符

拓展运算符用到左侧是聚合,右侧是展开。
对象中拓展运算符用于去除参数对象中所有可遍历属性,拷贝到当前对象中

看以下的例子就能明白。

  • 在右侧时,是实现对象的合并。其实就是实现了Object.assign方法,如果有重复的属性值,会被覆盖
let obj={name:'zhangsan',age:12};
let obj1={gender:"male"};
let temp={
	...obj,
	...obj1,
}
temp.width='100px';
console.log(temp);//{ name: 'zhangsan', age: 12, gender: 'male', width: '100px' }

let obj={name:'zhangsan',age:12};
let obj1={gender:"male"};
let temp=Object.assign(obj,obj1,{name:'lisi'})//{ name: 'lisi', age: 12, gender: 'male' }
  • 在左侧时,拓展运算符实现了深拷贝,修改obj4中的属性值,不会导致obj3中的属性值改变,因为拓展运算符实现的是值的引用。
let obj3 = {
	name:'zhangsan',
	age:18,
	gender:'male'
}
let {...obj4} = obj3

obj3.name='sintop'
console.log(obj4,obj3);//{ name: 'zhangsan', age: 18, gender: 'male' } { name: 'sintop', age: 18, gender: 'male' }

数组的拓展运算符

  • 可以将数组转换为参数序列
function Add(a,b){
	return a+b
}
let number = [4,6]
console.log(Add(...number));//10
  • 可以复制数组,直接复制数组是实现了浅拷贝,会导致第一个数组的值发生改变,第二个数组的值也会被同时改变。所以利用运算符来实现深拷贝数组。
let arr=[1,2,3,4];
let [...a]=arr;
console.log(a);//[1,2,3,4]
  • 扩展运算符可以与解构赋值结合起来,用于生成数组
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest);  // [2, 3, 4, 5]

注意:如果将拓展运算符用于数组赋值,只能放在参数的最后一位,否则会报错

  • 扩展运算符还可以将字符串转为真正的数组
let str = 'hello'
let res = [...str]
console.log(res);//[ 'h', 'e', 'l', 'l', 'o' ] 

对象api拓展

静态方法

  • is 比较两个数是否相等 返回值:true 或者是false
console.log(Object.is(+1,-1));//false
console.log(Object.is(+0,-0));//false
console.log(+0===-0);//true
console.log(NaN===NaN);//false
console.log(Object.is(NaN,NaN));//true

-assign
两个参数 复制/拷贝 返回值:返回第一个参数
使用场景 :
深拷贝 指得是被复制得对象里是基本数据类型 实现的是深拷贝
半深拷贝 指得是被复制得对象里面有引用数据类型 实现得就是半深拷贝

在例子中,对象的名字属性属于基本能数据类型,实现的是深拷贝,而在对象中的clazz属于引用数据类型,实现的是半深拷贝。

let obj={};
let obj1={
	name:'zhangsan',
	age:12,
	clazz:{
		number:"web"
	}
}
let res=Object.assign(obj,obj1);
console.log(res,obj);
//{ name: 'zhangsan', age: 12, clazz: { number: 'web' } } 
//{ name: 'zhangsan', age: 12, clazz: { number: 'web' } }
console.log(res===obj);//true
obj.name='lisi';
obj.clazz.number='web1';
console.log(obj,obj1);
//{ name: 'lisi', age: 12, clazz: { number: 'web1' } }
//{ name: 'zhangsan', age: 12, clazz: { number: 'web1' } }

三个参数 合并对象 ,返回值:返回第一个参数

let obj={};
let obj1={name:"hangsan",age:12};
let obj2={gender:'male'};
let res=Object.assign(obj,obj1,obj2);
console.log(res,obj);//{ name: 'hangsan', age: 12, gender: 'male' }
console.log(res===obj);//true
  • 获取原型对象得方法 getPrototypeOf
let obj={
	name:"zhangsan"
};
console.log(obj.__proto__);//[Object: null prototype] {}
console.log(obj.constructor.prototype);//[Object: null prototype] {}
console.log(Object.getPrototypeOf(obj));//[Object: null prototype] {}
  • 设置原型对象方法setPrototypeOf
let obj={};//Object.prototype
let obj1={
	name:"lisi"
};
Object.setPrototypeOf(obj,obj1);//将obj得原型对象设置成obj1
console.log(obj.__proto__);//{ name: 'lisi' }
console.log(obj.constructor.prototype);//[Object: null prototype] {}
console.log(Object.getPrototypeOf(obj));//{ name: 'lisi' }
  • keys values entries
    keys 返回键值组成得数组
    values 返回属性值组成得数组
    entries 返回键值对组成得数组

数组api拓展

  • Array.from(); 将类数组转数组
console.log(Array.from('hello'));//[ 'h', 'e', 'l', 'l', 'o' ]
  • Array.of(); 创建数组实例
var arr=new Array(10);
var arr1=Array.of(10);
console.log(arr,arr1);//[ <10 empty items> ] [ 10 ]
  • Array.prototype.find 查找满足条件数组元素
    参数:回调函数(item,index,arr)
    返回值:返回第一个符合条件得数组元素或者undefiend
var arr=[1,2,3,4,5];
let res=arr.find((item,index,arr)=>{
	return item>2
});
console.log(res);//3
  • Array.prototype.findIndex
    参数:回调函数 (item,index,arr)
    返回值:返回符合条件得第一个数组元素索引或者-1
var arr=[1,2,3,4,5];
let res=arr.findIndex((item,index,arr)=>{
	return item>2
});
console.log(res);//2
  • keys values entries Array.prototype
    返回值:返回一个迭代器对象
var arr=[1,2,3,4,5];
console.log(arr.keys());//Object [Array Iterator] {}
console.log(arr.values());//Object [Array Iterator] {}
console.log(arr.entries());//Object [Array Iterator] {}
  • Array.prototype.flat();展平数组
    参数不写,默认为1
var arr=[1,2,3,[4,5,[6,7,[8,[9,10]]]]];
console.log(arr.flat(Infinity));//[1,2,3,4,5,[6,7,8]]

类 Class

es5

es5中并没有产生类这个概念,而在es5中如果想要生成一个对象实例,需要定义一个构造函数,然后通过new操作符来完成

function Person(name,age){
    this.name = name
    this.age = age
}
Person.prototype.sayName = function(){
    console.log('my name is ' + this.name);
}
var p1 = new Person('siantop',18)
p1.sayName()

es6中的类

es6中引入了类这个概念,通过class关键字可以定义一个特定的对象,使得js中在对象的写法上更加清晰,更像是一种面向对象编程。

class Person{
    // 每个类里面都会有构造方法,用来接收参数,不写也会自动生成
    //constructor方法是类的构造函数的默认方法,通过new命令生成对象实例时,自动调用该方法
    constructor(name,age){
        this.name = name//this指向实例对象
        this.age = age
    }
    // 这是类的方法 不需要加function
    say(){
        console.log('my name is ' + this.name);
    }
}
var p1 = new Person('sintop',19)
p1.say()

注意:

1、类自身指向就是构造函数,可以认为ES6中的类其实就是构造函数的另外一种写法!
2、constructor定义的属性可以称为实例属性(即定义在this对象上),constructor外声明的属性都是定义在原型上的,可以称为原型属性。
3、class不存在变量提升,所以需要先定义再使用。

console.log(Person.prototype);//{}
// 说明构造函数的prototype属性,在es6的类中依然存在

继承

es5的继承

实例使用方法和属性
1、从实例对象本身查找属性或方法
2、如果实例没有,从构造函数的原型对象中找
3、如果还没有,从父构造函数的原型对象中找

原型链继承

父类的实例作为子类的原型

function Person(name,age,type){
    this.name = name
    this.age = age
    this.type = type
    this.say = function(){
        console.log('my type is ' + this.type + '静态方法');
    }
}

Person.prototype.sayName = function(){
    console.log('my name is ' + this.name +'原型方法');
} 

function student(){}


// 将子类的原型变成构造函数的实例
student.prototype = new Person('sintop',18,'student')

var s1 = new student()
s1.sayName()//my name is sintop原型方法
s1.say()//my type is student静态方法

借用构造函数继承

在子类中,使用call()调用父类的方法,并将this修改为子类的this,相当于把父类的实例属性复制了一份放到子类中。

function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayHi = function (){
        console.log('hi! '+ this.name);
    }
}

Person.prototype.sayName = function(){
    console.log('my name is ' + this.name);
}

// 定义子类
function student(name,age){
    Person.call(this,name,age)
}

var s = new student('sintop',19)
var s1 = new student('lays',10)
// s.sayName()//报错,不能继承原型上的方法
s.sayHi();//hi! sintop
组合继承(借用构造函数+原型链继承)

既能调用父类实例属性,又能调用父类原型属性

function Animal(type,age,weight,length){
    this.type = type
    this.age = age
    this.weight = weight
    this.length = length
}
Animal.prototype = {
    constructor:Animal,
    sayType:function(){
        console.log(this.type);
    }
}
function Dog(type,age,weight,length,name,color){
    // 经典继承又称为构造函数继承
    Animal.call(this.type,age,weight,length)
    this.name = name
    this.color = color
}
Dog.prototype = new Animal()
Dog.prototype.costructor = Dog
Dog.prototype.sayColor = function(){
    console.log(this.color);
}
var d1 = new Dog('狗',1,'10kg','40cm','可乐','白色')
console.log(d1);
d1.sayType()
d1.sayColor()

Es6中的类继承

1、class 相当于es5中的构造函数
2、class中定义方法时,前后不能加function,全部定义在class的prototype属性中
3、class中定义的所有方法是不可枚举的
4、class中只能定义方法,不能定义对象,变量等
5、class和方法内默认都是严格模式
es5中的constructor为隐式属性

class Animal{
    // 静态属性
    static animalAttr = 'Animal的静态属性'
    constructor(name,age,weight){
        this.name = name;
        this.age = age;
        this.weight = weight;
    }
    // 实例方法
    sayName(){
        console.log('实例方法');
    }
    // 静态方法
    static animalMethod(){
        console.log('Animal静态方法');
    }
}
// 要实现继承
class Dog extends Animal {
    constructor(name,age,weight,type){
        super(name,age,weight)
        this.type = type
        console.log('Dog的构造器');
    }
}
let dog = new Dog('豆豆',11,30,'dog')
dog.sayName()

symbol

es6引入的一种新的原始数据类型symbol,表示独一无二的值。symbol函数可以接收参数,表示对于这个唯一值的描述,属于基本数据类型,symbol()函数会返回symbo类型的值。

  • 创建一个symbol值
const a = Symbol()
console.log(a);//Symbol
//或者,你也可以在调用Symbol()函数时传入一个可选的字符串参数,相当于给你创建的Symbol实例一个描述信息:
let s2 = Symbol('another symbol')
//使用typeof判断symbol值的类型为symbol
console.log( typeof a);//Symbol
//判断两个类型为symbol,值为一样的,返回的结果会是false
const a=Symbol("name");
const b=Symbol("name");
console.log(a===b) //false

symbol的使用场景

  • 使用symbol作为对象属性名
const name=Symbol();
const age=Symbol();
let obj={
     [name]:"已经代码"
 }
obj[age]=18;
console.log(obj[name]);//已经代码
console.log(obj[age]);//18

*注意:*当使用了symbol作为对象的属性key后不能使用枚举

 const name=Symbol();
 const age=Symbol();
 const obj={
      [name]:"大师",
      [age]:16,
      sex:"男"
    }
console.log(obj)
console.log(Object.keys(obj));//["sex"]  使用symbol定义的属性,不能使用枚举遍历
for(let p in obj){
     console.log(p); // sex
  } 
  // 使用Object的API
    console.log(Object.getOwnPropertyNames(obj));// ["sex"] 得到符号类型代替的属性名,并且为数组
    console.log(Object.getOwnPropertySymbols(obj));// [Symbol(), Symbol()]
    const sybs=Object.getOwnPropertySymbols(obj);
    console.log(sybs[0]===name) //true 引用会相等
    
    //补充:
	1.Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
  2.Object.getOwnPropertySymbols()方法返回一个给定对象自身的所有 Symbol 属性的数组。
  • 使用symbol定义类的私有属性/方法
    在javaScript中,没有如同java等面向对象语言的定义私有属性的private方法,类上所有定义的属性或者方法都是可以公开访问的。有了Symbol以及模块化机制,类的私有属性和方法变得可能。

a.js

  const PASSWORD = Symbol()
 
class Login {
    constructor(username,password){
        this.username = username;
        this[PASSWORD] = password
    }
 
    checkPassword(pwd){
        return this[PASSWORD] === pwd
    }
}
 
export default Login;

b.js

import Login from "./a";
 
const login = new Login("admin", "123456");
 
login.checkPassword("123456"); // true
 
login.PASSWORD; // undefined
login[PASSWORD]; // undefined
login["PASSWORD"]; // undefined

由于Symbol常量PASSWORD被定义在a.js模块中,外面模块b.js无法获取此Symbol(Symbol是唯一的),因此PASSWORD只能被限定在a.js中使用,使用它来定义类属性外部模块无法访问,达到了私有化的目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值