ES6 课程概述③

5-1. 新增的对象字面量语法

  1. 成员速写

如果对象字面量初始化时,成员的名称来自于一个变量,并且和变量的名称相同,则可以进行简写

function createUser(loginId, loginPwd, nickName) {
  const sayHello = function () {
    console.log("loginId", this.loginId, "nickname", this.nickName);
  };
  return {
    loginId,
    loginPwd,
    nickName,
    sayHello,
    id: Math.random(),
  };
}
const u = createUser("abc", "123", "aaa");
  1. 方法速写

对象字面初始化时,方法可以省略冒号和 function 关键字

const user = {
  name: "姬成",
  age: 100,
  sayHello() {
    console.log(this.name, this.age);
  },
};

user.sayHello();
  1. 计算属性名

有的时候,初始化对象时,某些属性名可能来自于某个表达式的值,在 ES6,可以使用中括号来表示该属性名是通过计算得到的。

const prop1 = "name2";
const prop2 = "age2";
const prop3 = "sayHello2";

const user = {
  [prop1]: "姬成",
  [prop2]: 100,
  [prop3]() {
    console.log(this[prop1], this[prop2]);
  },
};

user[prop3]();

console.log(user);

5-2. Object 的新增 API

  1. Object.is

用于判断两个数据是否相等,基本上跟严格相等(===)是一致的,除了以下两点:

1). NaN 和 NaN 相等
2). +0 和-0 不相等

console.log(NaN === NaN); // false
console.log(+0 === -0);  // true

console.log(Object.is(NaN, NaN))  // true
console.log(Object.is(+0, -0))  // false

2 Object.assign

用于混合对象

const obj1 = {
    a: 123,
    b: 456,
    c: "abc"
}

const obj2 = {
    a: 789,
    d: "kkk"
}

/*
{
    a: 789,
    b: 456,
    c: "abc",
    d: "kkk"
} 
*/

//将obj2的数据,覆盖到obj1,并且会对obj1产生改动,然后返回obj1
// const obj = Object.assign(obj1, obj2);


const obj = Object.assign({}, obj1, obj2);

console.log(obj)  
//{a: 789, b: 456, c: 'abc', d: 'kkk'}
  
console.log(obj===obj1)  //false

console.log(obj1)  //{a: 123, b: 456, c: 'abc'}

console.log(obj2)   //{a: 789, d: 'kkk'}
  1. Object.getOwnPropertyNames 的枚举顺序

Object.getOwnPropertyNames 方法之前就存在,只不过,官方没有明确要求,对属性的顺序如何排序,如何排序,完全由浏览器厂商决定。

ES6 规定了该方法返回的数组的排序方式如下:

  • 先排数字,并按照升序排序
  • 再排其他,按照书写顺序排序
const obj = {
  d: 1,
  b: 2,
  a: 3,
  0: 6,
  5: 2,
  4: 1,
};
const props = Object.getOwnPropertyNames(obj);
console.log(props);
//['0', '4', '5', 'd', 'b', 'a']
  1. Object.setPrototypeOf

该函数用于设置某个对象的隐式原型

比如: Object.setPrototypeOf(obj1, obj2),
相当于: ` obj1.__proto__ = obj2 `

const obj1 = {
    a: 1
}

const obj2 = {
    b: 2
}

// obj1.__proto__ = obj2

Object.setPrototypeOf(obj1, obj2)

console.log(obj1) 

在这里插入图片描述

5-4 类:构造函数的语法糖

传统的构造函数的问题

  1. 属性和原型方法定义分离,降低了可读性
  2. 原型成员可以被枚举
  3. 默认情况下,构造函数仍然可以被当作普通函数使用
// 构造函数  构造器
function Animal(type, name, age, sex) {
  this.type = type;
  this.name = name;
  this.age = age;
  this.sex = sex;
}

// 定义实例方法(原型方法)
Animal.prototype.print = function () {
  console.log(`【种类】:${this.type}`);
  console.log(`【名字】:${this.name}`);
  console.log(`【年龄】:${this.age}`);
  console.log(`【性别】:${this.sex}`);
};

const a = new Animal("狗", "旺财", 3, "男");
a.print();

for (const prop in a) {
  console.log(prop); //原型成员可以被枚举
}

在这里插入图片描述

// 类对照写法
class Animal {
  constructor(type, name, age, sex) {
    this.type = type;
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  print() {
    console.log(`【种类】:${this.type}`);
    console.log(`【名字】:${this.name}`);
    console.log(`【年龄】:${this.age}`);
    console.log(`【性别】:${this.sex}`);
  }
}

类的特点

  1. 类声明不会被提升,与 let 和 const 一样,存在暂时性死区
  2. 类中的所有代码均在严格模式下执行
  3. 类的所有方法都是不可枚举的
  4. 类的所有方法都无法被当作构造函数使用
  5. 类的构造器必须使用 new 来调用

5-5. 类的其他书写方式

匿名类,类表达式

const A = class { 
    a = 1;
    b = 2;
}

const a = new A();
console.log(a)
class Test {

    constructor() {
        this.a = 123;
    }

    print = () => {
        console.log(this.a)
    }
}

const t1 = new Test();
const t2 = new Test();
console.log(t1.print === t2.print)
//false
class Test {
    static a = 1;
    b = 2;
    c = 3;

    constructor() {
        this.d = this.b + this.c;
    }
}

const t = new Test();
console.log(t)

//Test {b: 2, c: 3, d: 5}
  1. 可计算的成员名
const printName = "print"; //可计算的成员名

class Animal {
  constructor(type, name, age, sex) {
    this.type = type;
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  //创建一个age属性,并给它加上getter,读取该属性时,会运行该函数
  get age() {
    return this._age + "岁";
  }

  //创建一个age属性,并给它加上setter,给该属性赋值时,会运行该函数
  set age(age) {
    if (typeof age !== "number") {
      throw new TypeError("age property must be a number");
    }
    if (age < 0) {
      age = 0;
    } else if (age > 1000) {
      age = 1000;
    }
    this._age = age;
  }

  [printName]() {
    //可计算的成员名
    console.log(`【种类】:${this.type}`);
    console.log(`【名字】:${this.name}`);
    console.log(`【年龄】:${this.age}`);
    console.log(`【性别】:${this.sex}`);
  }
}

var a = new Animal("狗", "旺财", 3, "男");
a[printName](); //可计算的成员名

Animal.abc = 123;
  1. getter 和 setter

Object.defineProperty 可定义某个对象成员属性的读取和设置

使用 getter 和 setter 控制的属性,不在原型上

  1. 静态成员

构造函数本身的成员

//静态成员与实例成员的区别
Animal.abc = 123;

const a = new Ainmal(“狗”, “旺财”, 3, “男”);

//abc 不能通过 a 来访问,只能通过构造函数的本身访问
//a 只能访问本的实例成员和原型的实例成员

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

使用 static 关键字定义的成员即静态成员

class Chess {
  constructor(name) {
    this.name = name;
  }

  static width = 50;

  static height = 50;

  static method() {}
}
//静态成员
console.dir(Chess);
Chess.method();
//实例成员
const chess = new Chess();
console.dir(chess);

在这里插入图片描述

  1. 字段初始化器(ES7)

注意:

1). 使用 static 的字段初始化器,添加的是静态成员
2). 没有使用 static 的字段初始化器,添加的成员位于对象上
3). 箭头函数在字段初始化器位置上,指向当前对象

  1. 类表达式

  2. [扩展]装饰器(ES7)(Decorator)

横切关注点

装饰器的本质是一个函数

5-6. 类的继承
如果两个类 A 和 B,如果可以描述为:B 是 A,则,A 和 B 形成继承关系

如果 B 是 A,则:

B 继承自 A
A 派生 B
B 是 A 的子类
A 是 B 的父类
如果 A 是 B 的父类,则 B 会自动拥有 A 中的所有实例成员。

新的关键字:

extends:继承,用于类的定义
super
直接当作函数调用,表示父类构造函数
如果当作对象使用,则表示父类的原型
注意:ES6 要求,如果定义了 constructor,并且该类是子类,则必须在 constructor 的第一行手动调用父类的构造函数

如果子类不写 constructor,则会有默认的构造器,该构造器需要的参数和父类一致,并且自动调用父类构造器

class Animal {
    constructor(type, name, age, sex) {
        this.type = type;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    print() {
        console.log(`【种类】:${this.type}`);
        console.log(`【名字】:${this.name}`);
        console.log(`【年龄】:${this.age}`);
        console.log(`【性别】:${this.sex}`);
    }

    jiao(){
        throw new Error("动物怎么叫的?");
    }
}

class Dog extends Animal {
    constructor(name, age, sex) {
        super("犬类", name, age, sex);
        // 子类特有的属性
        this.loves = "吃骨头";
    }

    print(){
        //调用父类的print
        super.print();
        //自己特有的代码
        console.log(`【爱好】:${this.loves}`);
    }


    //同名方法,会覆盖父类
    jiao(){
        console.log("旺旺!");
    }
}

const d = new Dog("旺财", 3, "公");
d.print();

//【种类】:犬类  【名字】:旺财 【年龄】:3  【性别】:公  【爱好】:吃骨头

console.log(d)

//Dog {type: '犬类', name: '旺财', age: 3, sex: '公', loves: '吃骨头'}

d.jiao(); //旺旺!
class Animal {
    constructor(type, name, age, sex) {
        if (new.target === Animal) {
            throw new TypeError("你不能直接创建Animal的对象,应该通过子类创建")
        }
        this.type = type;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    print() {
        console.log(`【种类】:${this.type}`);
        console.log(`【名字】:${this.name}`);
        console.log(`【年龄】:${this.age}`);
        console.log(`【性别】:${this.sex}`);
    }

    jiao() {
        throw new Error("动物怎么叫的?");
    }
}

class Dog extends Animal {
    constructor(name, age, sex) {
        super("犬类", name, age, sex);
        // 子类特有的属性
        this.loves = "吃骨头";
    }

    print() {
        //调用父类的print
        super.print();
        //自己特有的代码
        console.log(`【爱好】:${this.loves}`);
    }


    //同名方法,会覆盖父类
    jiao() {
        console.log("旺旺!");
    }
}

//下面的代码逻辑有误
const a = new Dog("旺财", 3, "公")
a.print();

【冷知识】

用 JS 制作抽象类
抽象类:一般是父类,不能通过该类创建对象
正常情况下,this 的指向,this 始终指向具体的类的对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值