javascript面向对象总结

js面向对象

一.js类的生成方式

1.工厂模式

function Person(options) {
    var obj = new Object();
    obj.name = options.name;
    obj.age = options.age;
    obj.say = function () { console.log("工厂模式"); }
    return obj;
}
var person = Person({ name: 'A', age: 18 });/* 没有new */
console.log(person);/* Object{name: "A", age: 18, say: ƒ} */
person.say();/* 工厂模式 */

缺点:构造函数都为Object,不同类之间区分不方便。
2.构造函数模式

function Person2(options) {
    this.name = options.name;
    this.age = options.age;
    this.say = function () {
        console.log("构造函数");
    }
}
var person2 = new Person2({ name: 'B', age: 16 });
console.log(person2);/* Person2 {name: "B", age: 16, say: ƒ} */
person2.say();/* 构造函数 */
console.log(person2 instanceof Person2);/* true */

缺点:创建每个实例都要创建相同方法,浪费内存。
3.原型模式

function Person3(options) {
    this.name = options.name;
    this.age = options.age;
}
Person3.prototype.say = function () {
    console.log("原型  " + this.name);
}
var person3 = new Person3({ name: 'C', age: 21 });
console.log(person3);/* Person3 {name: "C", age: 21} */
person3.say();/* 原型  C */
console.log(person3.__proto__);/* say: ƒ ()   constructor: ƒ Person3(options) */

原型模式不仅可以防止命名冲突,还可以实现所有实例共用prototype的内容,当函数以构造函数形式调用,所创建的对象会有一个隐含属性__proto__指向该构造函数的原型对象,prototype,proto,constructor的关系如下图:
原型链
当ldh对象实例使用一个本身没有的属性或方法时,会利用__proto__一直往上延申寻找直到null,也就是Object._proto_。

二.继承

1.组合继承
借用构造函数继承属性:在Son构造函数中改变通过改变this指向并传参的方式调用Father实现继承属性。
利用原型继承方法:将Father的实例对象作为Son的原型,并且把Son原型的constructor强制改为Son,Son可以通过__proto__访问父类的方法,实现过程如下图:
注意:不能直接Son.prototype=Father.prototype(因为这种情况下,子类和父类指向同一原型对象,子类独有的方法父类也会拥有,例如父类是不能有exam方法的)。
原型继承

function Father(name, age) {
    this.name = name;
    this.age = age;
}
Father.prototype.money = function () {
    console.log(100000);
}
function Son(name, age) {
    // 借用父类构造函数,改变this指向实现继承属性
    Father.call(this, name, age);
}
/* 将Father的一个实例作为Son的原型 */
Son.prototype = new Father();//或者Object.create(Father());
/* Father实例的constructor是Father,需要强制改为Son */
Son.prototype.constructor = Son;
//Son自己的方法
Son.prototype.exam = function () {
    console.log("100分");
}
console.log(new Son('Mike', 11));/* Son {name: "Mike", age: 11} */

2.ES6中extend关键字继承
与其它语言类似,直接在定义时加关键字,注意的是构造函数里面需要用super传参并且super必须在最前面。

class Father {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    showInfo() { console.log(this.name, this.age); }
}
class Son extends Father {
    constructor(name, age) {
        super(name, age);//传入父类
        this.name = name;
        this.age = age;
    }
}
var son = new Son('zhangsan', 22);
console.log(son);/* Son {name: "zhangsan", age: 22} */
son.showInfo();/* zhangsan 22 */

三.重载

与其他语言不同,js中的重载并不是真正意义上的重载,而是在一个方法内根据传参情况不同做出不同表现。

function count(){
    if(arguments.length%2==1){
        console.log( "奇数个参数");
    }else{
        console.log("偶数个参数");
    }
}

四.重写

继承了父类,但是自己原型上定义了同名方法,在调用时执行自己原型上的方法。

function Father(name, age) {
    this.name = name;
    this.age = age;
}
Father.prototype.money = function () {
    console.log(100000);
}
function Son(name, age) {
    // 借用父类构造函数,改变this指向实现继承属性
    Father.call(this, name, age);
}
/* 将Father的一个实例作为Son的原型 */
Son.prototype = new Father();
/* Father实例的constructor是Father,需要强制改为Son */
Son.prototype.constructor = Son;
/* Son重写方法 */
Son.prototype.money = function () {
    console.log(100);
}
var son = new Son('Mike', 11);
son.money();//100

五.多态

多态的概念是对同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。

function Dog() { };
function Cat() { };
Dog.prototype.sound = function () { console.log("汪!") }
Cat.prototype.sound = function () { console.log('喵!') };
function makeSound(animal) {
    animal.sound();
}
makeSound(new Dog());//汪!
makeSound(new Cat());//喵!
posted @ 2020-04-06 00:09  aeipyuan  阅读(153)  评论(0编辑  收藏  举报