类与构造函数的区别

138 阅读4分钟

一、类的写法

ES6才有类,和构造函数一样都是为了生产对象的

class Phone {
    // 构造器
    /**
     * 实例属性,new出来的实例对象的属性
     * @param {*} name 
     * @param {*} price 
     */
    constructor(name, price){
        this.name = name
        this.price = price
    }
    // 实例方法,new出来的实例对象的方法
    showPrice(){
        console.log(`这台${this.name}手机售价为${this.price}元`);
    }
    // 静态方法,直接通过类名调用
    static foo(){
        console.log('这是Phone类的静态方法');
    }
}
let xiaomi = new Phone('小米', 3999)
let huawei = new Phone('华为', 4999)
console.log(xiaomi.name); // 小米
console.log(huawei.price); // 4999
xiaomi.showPrice() // 这台小米手机售价为3999元
huawei.showPrice() // 这台华为手机售价为4999元
Phone.foo() // 这是Phone类的静态方法

二、构造函数的写法

ES6之前,通过构造函数来(模拟类)创建对象

构造函数的实例成员和静态成员区别:

  • 构造函数内部添加给this的成员,必须通过new创建实例对象,然后通过实例对象调用
  • 构造函数也是对象,直接添加在构造函数上面的方法,只能通过构造函数调用,实例对象无法调用
function Phone(name, price){
    // 实例对象的属性
    this.name = name
    this.price = price
}
// 实例对象的方法通过挂载到原型对象的方式来实现
Phone.prototype.showPrice = function(){
    console.log(`这台${this.name}手机售价为${this.price}元`);
}
// 静态方法直接挂载到构造函数上
Phone.foo = function(){
    console.log('这是静态方法');
}
let xiaomi = new Phone('小米', 3999)
let huawei = new Phone('华为', 4999)
console.log(xiaomi.name); // 小米
console.log(huawei.price); // 4999
xiaomi.showPrice() // 这台小米手机售价为3999元
huawei.showPrice() // 这台华为手机售价为4999元
Phone.foo() // 这是静态方法

三、类与构造函数的区别

1. 构造函数本质也是函数,不必非要使用new调用,可以直接调用,类名加()直接调用会报错

function Foo(){}
let i = Foo()
console.log(i); // undefined

2.class类中实例方法,在遍历实例对象的键名时不会被遍历出来(class中的原型方法(就是实例方法)不可被枚举)

class Phone1 {
    constructor(name, price){
        this.name = name
        this.price = price
    }
    showPrice(){
        console.log(`这台${this.name}手机售价为${this.price}元`);
    }
}
function Phone2(name, price){
    this.name = name
    this.price = price
}
Phone2.prototype.showPrice = function(){
    console.log(`这台${this.name}手机售价为${this.price}元`);
}
let xiaomi = new Phone1('xiaomi', 3999)
let huawei = new Phone2('huawei', 4999)
for (const key in xiaomi) {
    console.log(key);  // name、price
}
console.log('------');
for (const key in huawei) {
    console.log(key); // name、price、showPrice
}

3. class由于使用了严格模式,其中方法参数不能重复(两个参数名不能相同),构造函数可以

4. class中的实例方法不能new(原型上的方法不能通过new来调用),构造函数可以

let xiaomi = new Phone1('xiaomi', 3999)
let huawei = new Phone2('huawei', 4999)
console.log(new xiaomi.showPrice()); // 报错
console.log(new huawei.showPrice()); // 先执行showPrice方法:这台undefined手机售价为undefined元,并通过new产生一个空对象{},输出{}

四、如何通过构造函数实现类(ES6的类通过babel转化为ES5的构造函数)

// 通过 ES6 的 class 语法来创建一个类
class Computer1{
    // 构造器
    constructor(name, price){
        // 实例属性
        this.name = name;
        this.price = price;
    }
    // 实例方法
    showPrice(){
        console.log(`这台${this.name}电脑的价格为${this.price}元。`);
    }
    // 静态方法
    static staticFunc(){
        console.log("这是 Computer1 类的静态方法");
    }
}

//如何通过ES5的构造函数来实现ES6的class
"use strict";
// 核对 class 类的调用方法,如果是以普通函数的形式调用的,就会抛出错误
function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

// 对原型和静态方法做特殊处理,设置其特性
function _defineProperties(target, props) {

    // console.log("target:::",target);
    // console.log("props:::",props);
    // target::: {}
    // props::: [ { key: 'showSth', value: [Function: showSth] } ]
    // target::: [Function: Computer]
    // props::: [ { key: 'comStruct', value: [Function: comStruct] } ]

    // 遍历原型方法和静态方法
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor)
            descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}

// 调用前面的函数,对原型方法和静态方法进行特性设置
function _createClass(Constructor, protoProps, staticProps) {

    console.log("Constructor:::",Constructor);
    console.log("protoProps:::",protoProps);
    console.log("staticProps:::",staticProps);
    // Constructor::: [Function: Computer]
    // protoProps::: [ { key: 'showSth', value: [Function: showSth] } ]
    // staticProps::: [ { key: 'comStruct', value: [Function: comStruct] } ]

    if (protoProps)
        _defineProperties(Constructor.prototype, protoProps);
    if (staticProps)
        _defineProperties(Constructor, staticProps);
    return Constructor;
}

var Computer = /*#__PURE__*/function () {
    // 构造器
    function Computer(name, price) {
        // 1. 核对你是如何进行调用的
        _classCallCheck(this, Computer);

        this.name = name;
        this.price = price;
    } 


    _createClass(Computer, [{
        key: "showSth",
        value: function showSth() {
            console.log("\u8FD9\u662F\u4E00\u53F0".concat(this.name, "\u7535\u8111"));
        } // 原型方法

    }], [{
        key: "comStruct",
        value: function comStruct() {
            console.log("电脑由显示器,主机,键鼠组成");
        } // 静态方法
    }]);

    return Computer;
}();


var apple = new Computer("苹果",15000);