JS中的面向对象

最近在复习JS基础,对于JS中的面向对象写法在此总结一下。

第一种:TS写法(ES6写法)

这种写法是在做项目里经常遇到的。特别是最近我参与的一个NG4的项目,全程TS,爽的不要不要的。

  • 先声明一个Car类(为了保证在ES6环境也可以运行,我没写TS的类型注解)
//ES6,使用传统的类、继承、多态和构造函数
class Car {
    constructor(name) {
        this.name = name;
        this.gear = 0;
        this.speed = 0;
    }

    drive() {
        clearInterval(this.driving);
        this.gear++;
        this.driving = setInterval(() => {
            this.speed += this.gear * 10;
            console.log(`老司机的${this.name}车速到了${this.speed}`);
            if (this.speed >= 200) {
                this.stop();
            }
        }, 100);
    }

    stop() {
        console.log("翻车了!");
        this.gear = 0;
        clearInterval(this.driving);
    }
}
let car = new Car("五菱宏光");
car.drive();
  • 这种风格和后端语言的风格非常接近,构造函数+自有方法。
  • 里面使用的模板字符串和箭头函数都是ES6的新特性,有兴趣的可以去看文档。
  • 接下来我们声明一个YunNanCar类,并实例化它。
class YunNanCar extends Car {
    constructor(name, personName) {
        super(name);
        this.personName = personName;
    }

    drive() {
        clearInterval(this.driving);
        this.gear++;
        this.driving = setInterval(() => {
            this.speed += this.gear * 10;
            console.log(`${this.personName}的${this.name}车速到了${this.speed}`);
            if (this.speed >= 300) {
                this.stop();
            }
        }, 100);
    }
}
let kunmingCar = new YunNanCar("昆明车", "樛木");
kunmingCar.drive();
  • 运行代码,毫无违和感。

第二种:ES5写法

第二种就是传统的ES5实现OOP,高级程序设计那本书推崇的方法。

//ES5,(高级程序设计书)使用原型链+构造函数
function Car(name) {
    this.name = name;
    this.gear = 0;
    this.speed = 0;
}
Car.prototype.drive = function () {
    clearInterval(this.driving);
    this.gear++;
    this.driving = setInterval(function () {
        //这里可以用self,但是不好
        this.speed += this.gear * 10;
        console.log("老司机的" + this.name + "车速到了" + this.speed);
        if (this.speed >= 200) {
            this.stop();
        }
    }.bind(this), 100);
};
Car.prototype.stop = function () {
    console.log("翻车了!");
    this.gear = 0;
    clearInterval(this.driving);
};
// var car = new Car("五菱宏光");
// car.drive();
function YunNanCar(name, personName) {
    //继承
    Car.call(this, name);
    this.personName = personName;
}
YunNanCar.prototype = Object.create(Car.prototype);
// 高程上的,会有意想不到的bug
// YunNanCar.prototype = new Car();
// YunNanCar.prototype.constructor = Car;
YunNanCar.prototype.drive = function () {
    clearInterval(this.driving);
    this.gear++;
    this.driving = setInterval(function () {
        //这里可以用self,但是不好
        this.speed += this.gear * 10;
        console.log(this.personName + this.name + "车速到了" + this.speed);
        if (this.speed >= 300) {
            this.stop();
        }
    }.bind(this), 100);
}
var kunmingCar = new YunNanCar("昆明车", "樛木");
kunmingCar.drive();
  • 这是前端们在艰难探索后找到的模仿传统类式OOP的方法,构造+原型链方法。
  • 和属性有关的用构造,和方法有关的添在原型上。目的是防止只用构造函数的时候不能复用函数,和只用原型链的时候会共享引用类型属性。
  • 没有箭头函数的时候,this会有问题,优雅的方法是采用bind强绑定,还有一种方法是使用self变量存放this。
  • 在设置原型链关联的时候,我没有使用高程的用法,原来需要指定YunNanCar的prototype为Car的实例,还要指定YunNanCar的prototype的constructor为Car,但其一那样关联原型链如果Car出了事YunNanCar也会跟着倒霉,其二是constructor根本不靠谱。所以使用更加靠谱的Object.create,如果要兼容旧式浏览器,就写段Polyfill代码。

第三种:纯面向对象写法

第三种方法是为JS量身定做的,和传统的OOP思想完全不一样,没有类,也没有继承,这种模式里没有父类,子类继承父类的概念。只有对象之间互相关联的关系。
比如说,传统OOP:我要一辆车,肯定是从车的基类继承,我要滑板鞋 肯定是从鞋的基类继承。
而行为委托根本不需要基类,在只有车和滑板鞋的情况下,滑板鞋也想飙车怎么办?于是滑板鞋和云南车关联起来,借用它的drive方法就可以了。

//JS中的纯面向对象,这里的三个方法可以分开写(ES5语法)比如init:function(name){..}
let Car = {
    init(name) {
        this.name = name;
        this.gear = 0;
        this.speed = 0;
    },
    drive() {
        clearInterval(this.driving);
        this.gear++;
        this.driving = setInterval(() => {
            this.speed += this.gear * 10;
            console.log(`老司机的${this.name}车速到了${this.speed}`);
            if (this.speed >= 200) {
                this.stop();
            }
        }, 100);
    },
    stop() {
        console.log("翻车了!");
        this.gear = 0;
        clearInterval(this.driving);
    }
}
let Shoe = Object.create(Car);
Shoe.product = function (name, personName) {
    this.init(name);
    this.personName = personName;
}
//独特的飙车方法
Shoe.racing = function () {
    clearInterval(this.driving);
    this.gear++;
    this.driving = setInterval(() => {
        this.speed += this.gear * 10;
        console.log(`${this.personName}的${this.name}滑板鞋速度到了${this.speed}`);
        if (this.speed >= 300) {
            this.stop();
        }
    }, 100);
}
let kunmingShoe = Object.create(Shoe);
kunmingShoe.product("滑板鞋", "樛木");
kunmingShoe.racing();
  • 这里我为了节省力气用了es6语法,es5语法使用传统的方法声明就好了,像init:function(name){..}这样。
  • Car对象里面有三个方法。是特有的。
  • 让滑板鞋关联这个车,接着给滑板鞋对象添加两个方法。
  • produce和racing方法和车毛关系都没有,但是它们的实现借用了车的三个方法,所以达到了滑板鞋也能飙车的目的。

你可能感兴趣的:(JS中的面向对象)