JavaScript的继承方式是什么

发布时间:2022-05-11 10:16:32 作者:zzz
来源:亿速云 阅读:157

JavaScript的继承方式是什么

JavaScript是一种基于原型的面向对象编程语言,它的继承机制与传统的基于类的语言(如Java、C++)有所不同。JavaScript的继承方式主要通过原型链来实现,同时也支持一些现代的继承方式,如class语法糖。本文将详细介绍JavaScript中的继承方式。

1. 原型链继承

原型链是JavaScript中最基本的继承方式。每个对象都有一个内部属性[[Prototype]],指向它的原型对象。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到该属性或方法为止。

1.1 原型链继承的实现

function Parent() {
    this.name = 'Parent';
}

Parent.prototype.sayHello = function() {
    console.log('Hello from ' + this.name);
};

function Child() {
    this.name = 'Child';
}

// 将Child的原型指向Parent的实例
Child.prototype = new Parent();

const child = new Child();
child.sayHello(); // 输出: Hello from Child

在这个例子中,Child继承了Parent的属性和方法。Child的原型指向了Parent的实例,因此Child的实例可以访问Parent原型上的方法。

1.2 原型链继承的缺点

2. 构造函数继承

为了解决原型链继承中的问题,JavaScript引入了构造函数继承。通过在子类构造函数中调用父类构造函数,可以实现属性的继承。

2.1 构造函数继承的实现

function Parent(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

function Child(name) {
    // 调用父类构造函数
    Parent.call(this, name);
}

const child1 = new Child('Child1');
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']

const child2 = new Child('Child2');
console.log(child2.colors); // 输出: ['red', 'blue', 'green']

在这个例子中,Child通过调用Parent.call(this, name)继承了Parent的属性。每个Child实例都有自己独立的colors属性,不会相互影响。

2.2 构造函数继承的缺点

3. 组合继承

组合继承结合了原型链继承和构造函数继承的优点,既可以继承父类的属性,也可以继承父类原型上的方法。

3.1 组合继承的实现

function Parent(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.sayHello = function() {
    console.log('Hello from ' + this.name);
};

function Child(name) {
    // 调用父类构造函数
    Parent.call(this, name);
}

// 将Child的原型指向Parent的实例
Child.prototype = new Parent();
Child.prototype.constructor = Child;

const child1 = new Child('Child1');
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child1.sayHello(); // 输出: Hello from Child1

const child2 = new Child('Child2');
console.log(child2.colors); // 输出: ['red', 'blue', 'green']
child2.sayHello(); // 输出: Hello from Child2

在这个例子中,Child通过构造函数继承继承了Parent的属性,并通过原型链继承继承了Parent原型上的方法。

3.2 组合继承的缺点

4. 原型式继承

原型式继承是通过创建一个临时构造函数,并将其原型指向父类对象来实现的。这种方式类似于原型链继承,但更加灵活。

4.1 原型式继承的实现

function createObject(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}

const parent = {
    name: 'Parent',
    colors: ['red', 'blue', 'green'],
    sayHello: function() {
        console.log('Hello from ' + this.name);
    }
};

const child1 = createObject(parent);
child1.name = 'Child1';
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child1.sayHello(); // 输出: Hello from Child1

const child2 = createObject(parent);
child2.name = 'Child2';
console.log(child2.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child2.sayHello(); // 输出: Hello from Child2

在这个例子中,child1child2都继承了parent对象的属性和方法。由于colors是引用类型,child1child2共享这个属性。

4.2 原型式继承的缺点

5. 寄生式继承

寄生式继承是在原型式继承的基础上,增强对象的功能。它通过创建一个新对象,并在新对象上添加额外的属性和方法来实现继承。

5.1 寄生式继承的实现

function createObject(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}

function createChild(parent) {
    const child = createObject(parent);
    child.sayGoodbye = function() {
        console.log('Goodbye from ' + this.name);
    };
    return child;
}

const parent = {
    name: 'Parent',
    colors: ['red', 'blue', 'green'],
    sayHello: function() {
        console.log('Hello from ' + this.name);
    }
};

const child1 = createChild(parent);
child1.name = 'Child1';
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child1.sayHello(); // 输出: Hello from Child1
child1.sayGoodbye(); // 输出: Goodbye from Child1

const child2 = createChild(parent);
child2.name = 'Child2';
console.log(child2.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child2.sayHello(); // 输出: Hello from Child2
child2.sayGoodbye(); // 输出: Goodbye from Child2

在这个例子中,child1child2不仅继承了parent对象的属性和方法,还添加了新的方法sayGoodbye

5.2 寄生式继承的缺点

6. 寄生组合式继承

寄生组合式继承是组合继承的优化版本,它通过借用构造函数来继承属性,并通过原型链来继承方法。这种方式避免了组合继承中父类构造函数被调用两次的问题。

6.1 寄生组合式继承的实现

function inheritPrototype(child, parent) {
    const prototype = Object.create(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}

function Parent(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.sayHello = function() {
    console.log('Hello from ' + this.name);
};

function Child(name) {
    Parent.call(this, name);
}

inheritPrototype(Child, Parent);

const child1 = new Child('Child1');
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child1.sayHello(); // 输出: Hello from Child1

const child2 = new Child('Child2');
console.log(child2.colors); // 输出: ['red', 'blue', 'green']
child2.sayHello(); // 输出: Hello from Child2

在这个例子中,Child通过Parent.call(this, name)继承了Parent的属性,并通过inheritPrototype函数继承了Parent原型上的方法。这种方式避免了父类构造函数被调用两次的问题。

6.2 寄生组合式继承的优点

7. ES6 class 继承

ES6引入了class语法糖,使得JavaScript的继承更加直观和易于理解。class语法糖本质上仍然是基于原型的继承,但它提供了更简洁的语法。

7.1 class 继承的实现

class Parent {
    constructor(name) {
        this.name = name;
        this.colors = ['red', 'blue', 'green'];
    }

    sayHello() {
        console.log('Hello from ' + this.name);
    }
}

class Child extends Parent {
    constructor(name) {
        super(name);
    }
}

const child1 = new Child('Child1');
child1.colors.push('yellow');
console.log(child1.colors); // 输出: ['red', 'blue', 'green', 'yellow']
child1.sayHello(); // 输出: Hello from Child1

const child2 = new Child('Child2');
console.log(child2.colors); // 输出: ['red', 'blue', 'green']
child2.sayHello(); // 输出: Hello from Child2

在这个例子中,Child通过extends关键字继承了Parent的属性和方法。super关键字用于调用父类的构造函数。

7.2 class 继承的优点

总结

JavaScript的继承方式多种多样,每种方式都有其优缺点。原型链继承是最基本的继承方式,但存在共享引用类型属性的问题。构造函数继承解决了共享属性问题,但无法继承父类原型上的方法。组合继承结合了原型链继承和构造函数继承的优点,但存在父类构造函数被调用两次的问题。原型式继承和寄生式继承提供了更灵活的继承方式,但仍然存在共享引用类型属性的问题。寄生组合式继承是组合继承的优化版本,避免了父类构造函数被调用两次的问题。ES6的class语法糖使得继承更加简洁和易于理解。

在实际开发中,应根据具体需求选择合适的继承方式。对于现代JavaScript开发,推荐使用ES6的class语法糖来实现继承。

推荐阅读:
  1. 不同的继承方式(三十八)
  2. 6种JavaScript继承方式及优缺点(小结)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

javascript

上一篇:Java怎么使用反射和动态代理实现一个View注解绑定库

下一篇:Java数组的使用方法实例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》