[ES6] 对象

新增对象字面量语法

1. 成员速写

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

function person(userName, password, nickName) {
    return {
        userName: userName,    // 原本
        password,              // 简写
        nickName
    }
}
2. 方法速写

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

const obj = {
    name : "abc",
    age : 20,
    //简写前
    sayHello: function() {
        console.log(this.name)
    }
    //简写后
    sayHello(){
        console.log(this.name)
    }
}
3. 计算属性名

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

let name = "name", age = "age";

const obj = {
    [name]: "abc",
    [age]: 20
}

// 调用
console.log(obj[name])

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: "1",
    b: "2",
    c: "3"
}

const obj2 = {
    a: "a",
    b: "b",
    d: "d"
}

const obj3 = {
    ...obj1,
    ...obj2
}

const obj4 = Object.assign({}, obj1, obj2)
3. Object.getOwnPropertyNames 的枚举顺序

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

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

  • 先排数字,按照升序排序
  • 再排其他,按照书写顺序排序
const obj = {
    d: "1",
    b: "2",
    c: "3",
    0: "A",
    10: "B",
    5: "C"
}
console.log(Object.getOwnPropertyNames(obj))  // ["0", "5", "10", "d", "b", "c"]
4. Object.setPrototypeOf

该方法用于设置某个对象的隐式原型
比如:Object.setPrototypeOf(obj1, obj2) == obj1.__proto__ = obj2

const obj1 = {
    a: "1"
}

const obj2 = {
    b: "2"
}

const obj3 = Object.setPrototypeOf(obj1, obj2)

console.log(obj1 === obj3)  // true

面向对象简介

面向对象:一种编程思想,跟具体的语言

对比面向过程:

  • 面向过程:思考的切入点是功能的步骤
// 大象关进冰箱
// 打开门
function openFridge (params) {
    
}
openFridge()
// 把大象装进去
function putIn() {

}
putIn()
// 把门关上
function closeFridge() {

}
closeFridge()
  • 面向对象:思考的切入点是对象的划分
// 一个冰箱原型
function Fridge() {

}
// 一个大象原型
function Elephant () {
    // 大小,体重,等等
}

// 给冰箱原型增加三个方法
Fridge.prototype.openFridge = function() {
    // 打开冰箱
}

Fridge.prototype.closeFridge = function () {
    // 把冰箱关上
}

Fridge.prototype.putIn = function(ele) {
    // 把什么东西放进去
    
    // -----
    // this.openFridge()      // 打开冰箱
    // this.closeFridge()      // 把冰箱门关上
}

// 调用冰箱原型上的方法

//打开冰箱
let fridge = new Fridge();
fridge.openFridge();

//把大象装进去
let elephant = new Elephant();
fridge.putIn(elephant)

//把冰箱门关上
fridge.closeFridge()
//putIn方法里面的参数可以随意组合,往冰箱里放什么东西都可以,这体现了面向对象写法的好处

面向对象的写法更适合多人开发的大型项目,模块化开发,

类:构造函数的语法糖

传统构造函数的问题
  1. 属性和原型方法定义分离,降低了可读性
  2. 原型成员可以被枚举
  3. 默认情况下,构造函数仍然可以被当作普通函数使用
// 传统写法
function Animal (type, name, age, sex) {
    this.type = type;
    this.name = name;
    this.age = age;
    this.sex = sex;
}
// 给构造函数Animal增加打印方法
Animal.prototype.print = function () {
    console.log(`【种类】:${this.type}`)
    console.log(`【名字】:${this.name}`)
    console.log(`【年龄】:${this.age}`)
    console.log(`【性别】:${this.sex}`)
}

let dog = new Animal("狗", "柴", "3岁", "公")

dog.print()  // 调用原型上的方法
类的特点
  1. 类声明不会被提升,与letconst一样,存在暂时性死区
  2. 类中的所有代码均在严格模式下执行
  3. 类的所有方法都是不可枚举的
  4. 类的所有方法内部都无法被当作构造函数使用
  5. 类的构造器必须使用new使用
// ES6类的写法
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}`)
    }
}

let dog = new Animal("狗", "柴", "3岁", "公")

dog.print()

类的其他书写方式

1. 可计算的成员名
const newProp = "newProp"

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

    [newProp]() { // 声明
        console.log(`【种类】:${this.type}`)
        console.log(`【名字】:${this.name}`)
        console.log(`【年龄】:${this.age}`)
        console.log(`【性别】:${this.sex}`)
    }
}

let dog = new Animal("狗", "柴", "3岁", "公")

dog[newProp]()   // 调用
2. getter和setter

使用gettersetter定义的属性不在原型上

const newProp = "newProp"

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

    get age() {  // 获取属性 get
        return this._age
    }

    set age(age) {  // 设置属性 set
        if(age < 0) {
            age = "0"
        } else if(age > 1000) {
            age = "1000"
        }
        this._age = age
    }

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

let dog = new Animal("狗", "柴", "10岁", "公")

dog[newProp]()
3. 静态成员

构造函数本身的成员
使用static关键字定义成员,即静态成员

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

    static width = 100;

    static height = 100;

    static fn() {
        console.log("这是方法")
    }
}

console.log(box.width)  // 100
console.log(box.height)  // 100

box.fn()  // 调用静态方法
4. 字段初始化器 [ES7]

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

class Test {
    static a = 1
    b = 2
    c = 3
    constructor (){
        // b = 2,  c = 3 相当于
        // this.b = 2
        // this.c = 3
        this.d = this.c + this.b       // 5
    }
}

const t = new Test()

console.log(t)   //Test {b: 2, c: 3}
5. 类表达式

用法和之前的相同

// 匿名类,类表达式
const A = class {  
    b = 2
    c = 3
}

const a = new A()
console.log(a)
6. 装饰器 [ES7]

类的继承

新的关键字:

  • extends:继承,用于类的定义
  • super
    • 直接当做函数调用,表示父类构造函数

      ES6要求,如果定义constructor,并且该类是子类,则必须在constructor的第一行手动调用父类的构造函数

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

    • 如果当作对象使用,则表示父类的原型

【冷知识】

  • 用JS制作抽象类
    • 抽象类:一般是父类,不能通过该类创建对象
  • 正常情况下this的指向始终指向具体的类的对象
// ES6类的写法
// 父类
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}`)
    }
}

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

    print () {
        super.print()    // 调用父类上的方法
        console.log(`【爱好】:${this.hobby}`)  // 给父类增加一个子类特有方法
    }
}

// let dog = new Animal("柴", "3岁", "公")  // 抛出错误,throw new TypeError("不能直接创建Animal对象,应该通过子类创建")
let dog = new Dog("柴", "3岁", "公")

dog.print()  // 如果子类有这个方法就执行子类的方法,如果子类没有就执行父类的方法。

你可能感兴趣的:([ES6] 对象)