ES6(超详细)4—最终篇!

105 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

ES6专题所有文章:

ES6-1(let、const、解构赋值、模板字符串、对象简化写法、箭头函数) ES6-2(函数默认参数、扩展运算符、rest参数、Symbol) ES6-3(迭代器、生成器、Promise、Set、Map) ES6-4(Class、数值扩展、对象方法扩展、模块化)

15. Class

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

  • 如果对C++等后端语言有一定基础的同学,相信对class并不陌生,哪怕是没有学习过后端语言,也应该能够经常听到这个说法:面向对象编程。
  • 那么这个“对象”跟我们的Object类型有什么关系吗?其实他们的核心思想都是一样的,那就是封装。将多个属性或方法,封装进一个对象中。
  • 如果是将属性或方法封装进一个Object对象中,那么你就创建了一个实例对象,你可以通过他的对象名.xxx的形式去访问其内部属性和方法。
  • 如果是将属性或方法封装进一个Class中,那么你就相当于创建了一个类别,你可以通过new 类名(参数)去根据你所传入的参数不同而创建不同的实例对象,并且各个对象的属性是互不影响的。(这里可以类比工厂函数,可能会方便理解)
class shouji {
  constructor(brand,price) {
    this.brand=brand;
    this.price=price
  }
  
  call(){
    console.log('打电话')
  }
}

let A = new shouji('1+',1999);
console.log(A)

通过控制台的输出,我们发现,该对象的方法并不在它自身身上,当需要调用该方法的时候,它会去他的Class中寻找,也就是说,这个方法是所有实例对象共用的

  • 静态成员
class Person{
  static name='手机'
}
let nokia = new Person();
console.log(nokia.name);  //undefined
console.log(Person.name);  //手机

利用static关键字可以定义静态属性和静态方法,而拥有static关键字的属性和方法,只有通过类本身调用,而无法在实例对象中调用

  • 构造函数继承
function Phone(brand,price){
  this.brand=brand;
  this.price=price;
}
Phone.prototype.call=function (){
  console.log("打电话");
}
function SmartPhone(brand,price,color,size){
  Phone.call(this,brand,price);
  this.color=color;
  this.size=size;
}

//设置子级构造函数原型
SmartPhone.prototype=new Phone;
SmartPhone.prototype.constructor=SmartPhone;

//声明子类方法
SmartPhone.prototype.photo = function (){
  console.log('我可以玩游戏');
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch')
console.log(chuizi);

注意: 这里设置子级构造函数原型时,记得要将子级原型的构造函数重新指向自身

  • Class的类继承

class也支持继承,即子类可以继承父类的属性及方法,关键字是extends,这个单词本身有扩展的意思,意为在原有的基础上可以添加属于自己的一些属性和方法;

同时一个父类可以对应多个子类,当子类调用方法或属性时,会先在自身寻找,如果没有就到父类身上去寻找,有点类似原型链

class Phone{
  constructor(brand,price) {
    this.brand=brand;
    this.price=price;
    
  }
  //父类的成员属性
  call(){
    console.log('我可以打电话')
  }
}
class SmartPhone extends Phone{
  constructor(brand,price,color,size) {
    super(brand,price);
    this.color=color;
    this.size=size;
  }
  photo(){
    console.log('拍照');
  }
  
  playGame(){
    console.log('打游戏');
  }
}
const xiaomi=new SmartPhone('小米',1999,'黑色','4.7inch')
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
  • 子类对父类方法的重写

在子类中可以对父类的方法进行重写,当子类再次调用这个方法的时候,就不会去父类中寻找,并且重写的方法不会影响到父类身上的方法

class Phone{
  constructor(brand,price) {
    this.brand=brand;
    this.price=price;
    
  }
  //父类的成员属性
  call(){
    console.log('我可以打电话')
  }
}
class SmartPhone extends Phone{
  constructor(brand,price,color,size) {
    super(brand,price);
    this.color=color;
    this.size=size;
  }
  photo(){
    console.log('拍照');
  }
  
  playGame(){
    console.log('打游戏');
  }
  
  //重写
  call(){
    console.log('我可以进行视频通话')
  }
}
const xiaomi=new SmartPhone('小米',1999,'黑色','4.7inch')
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
  • get和set设置

对于getset,如果小伙伴有接触过Vue的watch监听属性,应该能够很快理解,简单来说就是定义两个函数,get定义的函数当用户访问对应属性时调用,而set则是修改属性时调用

注意: 切忌在get中访问对应属性或在set中为该属性赋值,否则将会进入死循环!!!

class Phone{
  get price(){
    console.log("价格被读取了")
    return 'I LOVE YOU'
  }
  
  set price(val){
    console.log('价格被修改了')
    return val;
  }
}

//实例化对象
let s = new Phone();
s.price=12  
// console.log(s.price)   //其实是调用price方法

16. 数值扩展

  • Number.EPSILON是 JavaScript的最小精度,属性的值接近于 2.22044...E-16

这个可以用于适当降低js评判的精度

相信小伙伴们都知道,js中进行两个小数的运算时,并不是百分百准确的,因为底层是利用二进制进行运算,存在一定的偏差,但是这个偏差微乎其微,所以就可以通过这个最小精度去解决

function equal(a, b) {
    if (Math.abs(a - b) < Number.EPSILON) {
        return true;
    } else {
        return false;
    }
}
console.log(0.3 == 0.1 + 0.2);
console.log(equal(0.3, 0.1 + 0.2));

  • 不同进制数的表示
let b = 0b1010; //2进制
let o = 0o777;  //8进制
let d = 100;    //10进制
let x = 0xff;   //16进制
console.log(x)   //255

注意输出的都是按十进制输出

  • isFinite()

可用于检测一个数是否为有限数

console.log(Number.isFinite(100));  //true
console.log(Number.isFinite(100/0));  //false
console.log(Number.isFinite(Infinity));  //false
  • isNaN()

可用于检测一个数是否为NaN

console.log(Number.isNaN(123))  //false
  • 字符串转换为数值
console.log(Number.parseInt('5213123love')); //5213123
console.log(Number.parseFloat('5.123123神器')); //5.123123

注意这里只会转换开头的数字,如果数字中间穿插了字符,那么后面的数字也会被忽略掉

  • 判断数值是否为整数
console.log(Number.isInteger(5));  //true
console.log(Number.isInteger(2.5)); //false
  • 将小数部分抹除
console.log(Math.trunc(3.45345345345)) //3

当然抹除小数除了利用Math.trunc之外,还可以利用上面讲到的parseInt(),效果也是一样滴

  • 检测一个数是正数、负数、还是0
console.log(Math.sign(100)) //1
console.log(Math.sign(0))  //0
console.log(Math.sign(-123)) //-1

通过上面的输出可以看出:返回值为1时表示正数,-1时表示负数,0时表示为0

17. 对象方法扩展

  • Object.is()

用于判断两个值是否完全相等

console.log(Object.is(120,120))  //true
console.log(Object.is(NaN,NaN))  //false
let a = {
  value:1
}
let b = {
  value:1
}
console.log(Object.is(a,b))  //false

注意: 除了判断普通的数值,还可以用来判断两个对象是否完全相等,注意这里a对象和b对象虽然内部的属性和值完全一模一样,但是他们是存储在不同地址的对象,所以两者并不一样!

  • Object.assign()

用于将对象进行合并

const a = {
    name:'小明',
    age:12,
    pass:'456'
}
const b = {
    pass:'123'
}
console.log(Object.assign(a,b))

注意: 这个方法并不会返回一个新的数组,而是将第一个参数后面的对象组合并到第一个对象中,所以如果在上面的例子中输出a,返回值也是图中所示。

另外,如果后面要被合并的对象中,存在与目标对象中同名的属性,会对原对象中的属性进行覆盖

  • Object.setPrototypeOf()、Object.getPrototypeOf()

用于设置和读取原型对象

    const person = {
        name:'小明'
    }
    const girlfriends = {
        gf:['小红','小美']
    }
    Object.setPrototypeOf(person,girfriends)
    console.log(Object.getPrototypeOf(person))
    console.log(person)

18. 模块化

  • 模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

  • 模块化的好处:

    • 防止命名冲突
    • 代码复用
    • 高维护性
  • 模块化规范产品
    ES6之前的模块化规范有:

    • CommonJS ==> NodeJS、Browserify
    • AMD ==> requireJS
    • CMD ==> seaJS
  • 模块功能主要有两个命令构成:export和import

    • export命令用于规定模块的对外接口
    • import命令用于输入其他模块提供的功能
export let person = '小明'
export function talk(){
    console.log('说话')
}
import * as m1 from "./src/js/m1.js";
console.log(m1);
  • 暴露语法汇总

    • 统一暴露
let person = '小明';
function talk(){
    console.log('说话');
}
export {person,talk}
-   默认暴露
export default {
    name:'小明',
    talk:function(){
        console.log('说话')
    }
}
  • 引入语法汇总
  1. 通用导入方式
import * as m1 from "./src/js/m1.js"
import * as m2 from "./src/js/m2.js"
import * as m3 from "./src/js/m3.js"

这种方式相当于将导入的文件中所有向外暴露的对象整合到一个默认对象中,并且进行命名,如图:

  1. 解构赋值方式
import {person,talk} from "./src/js/m1.js"
import {person as p,talk} from "./src/js/m2.js"
import {default as m3 } from "./src/js/m3.js"

哈喽!这里是Crizz的前端之旅~

ES6专题到此完结!后会有期~