js如何实现继承

对象冒充

对象冒充是通过利用构造函数使用this关键字给所有属性和方法赋值来实现继承,临时属性、call()、apply()、bind()都可以实现对象冒充。对象冒充可以支持多重继承,也就是说一个类可以继承多个类。

function Person(name) {
    this.name = name;
    this.say = function() {
        console.log(this.name);
    }
}
function F2E(name, id) {
     // 临时属性方式
     this.temp = Person;
     this.temp(name);
     this.temp = null;

    // call()/apply()/bind()方式实质上是改变了this指针的指向
    // Person.apply(this, [name]);
    // Person.call(this, name);
    // Person.bind(this)(name);

    this.id = id;
    this.showId = function() {
        console.log(this.id);
    }
}
var simon = new F2E("Simon", 9527);
simon.say();
simon.showId();

通过对象冒充方式继承时,所有的成员方法都是指向this的,也就是说new之后,每个实例将都会拥有这个成员方法,并不是共用的,这会造成大量的内存浪费。并且通过对象冒充的方式,无法继承通过prototype方式定义的变量和方法。

原型链方式

JavaScript中每个对象都有一个隐藏的__proto__属性,一个实例化对象的__proto__属性指向其类的prototype方法,而这个prototype方法又可以被赋值成另一个实例化对象,这个对象的__proto__又需要指向其类,由此形成一条链,这就是原型链。

原型链继承是JavaScript中实现继承最简单的方法,只需要将子类型的原型指向父类型的实例就行了。

JavaScript对象在读取某个属性时,会先查找自身属性,没有则再去依次查找原型链上对象的属性。也就是说原型链的方法是可以共用的,这样就解决了对象冒充浪费内存的缺点。

function Person(name) {
    this.name = name;
    this.say = function() {
        console.log(this.name);
    }
}
function F2E(name, id) {
    this.id = id;
    this.showId = function() {
        console.log(this.id);
    }
}

F2E.prototype = new Person();

var simon = new F2E("Simon", 9527);
simon.say();  // undefined
simon.showId();  // 9527

通过原型链实现继承在实例化子类时不能将参数传给父类,因此将两种继承方式结合起来使用会更好。

function Person(name) {
    this.name = name;
    this.say = function() {
        console.log(this.name);
    }
}
function F2E(name, id) {
    // 成员变量采用对象冒充方式
    this.temp = Person;
    this.temp(name);
    this.temp = null;
    // Person.apply(this, [name]);
    // Person.call(this, name);
    // Person.bind(this)(name);

    this.id = id;
    this.showId = function() {
        console.log(this.id);
    }
}

F2E.prototype = new Person(); // 成员方法采用原型链方式
F2E.prototype.constructor = F2E; // 替换prototype对象之后需要把constructor属性指回原来的构造函数

var simon = new F2E("Simon", 9527);
simon.say(); 
simon.showId();

ES6继承(class, extends, super)

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂。

class Animal {
    // 构造方法
    constructor(){ 
        // this关键字代表实例对象
        this.type = "animal";
    }
    // constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实例对象可以共享的
    says(say){
        console.log(this.type + " says " + say)
    }
}

// Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。
class Cat extends Animal {
    constructor(){
        // super关键字指代父类的实例(即父类的this对象)
        super(); // 子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。所以子类必须在constructor方法中调用super方法,否则将获取不到this对象。
        this.type = "cat";
    }
}

let cat = new Cat();
cat.says("hello"); //cat says hello

ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值