js 继承小结

本文深入探讨了JavaScript中面向对象的实现方式,包括原型链继承、组合继承等,并介绍了ES5提供的新API Object.create()的应用。同时,文章还提供了一些扩展内容,例如如何在JavaScript中实现数组的继承。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

js的是利用原型链实现面向对象的类行为,和oo语言中的类有这巨大的不同。

下面讲述几种继承的方式以及一些扩展。

我对js的原型继承的一些理解:

  • js中只有函数存在prototype这个属性,代表原型,object中只有__proto__属性
  • js中函数也是object的一种,所以函数同时存在prototype和__proto__属性,但是这是两个完全不同的属性
  • js中所有的object都是继承于底层的Object.prototype
  • js中所有函数的构造函数是Function
  • Function.prototype是函数(这就是解决原型链循环的关键),正常函数的prototype属性都是一个object
  • js中实例的__proto__总是指向它构造函数的prototype(这个也是原型链的重点)
// 父类
function Animal() {
  this.name = 'animal';
  this.type = 'animal';
}
Animal.prototype.say = function () {
  console.log(this.name);
}
复制代码

原型链继承, 通过子类的prototype是父类的一个实例,从而实现一条原型链,如下:(Sub代表子类,sub代表子类的一个实例,Super代表父类,super代表父类的实例)

sub.__proto__ = Sub.prototype = super, super.__proto__ = Super.prototype
复制代码

缺点:父类的数据对象处于子类的prototype中,prototype是所有子类实例所共有的,所以对于引用类型的数据存在一改全改的问题

function Dog() {
  this.name = 'dog'
}
Dog.prototype = new Animal();

var dog = new Dog();
dog.say();
复制代码

dog的详细结构

为了解决上面的原型链缺点,利用构造函数的优点(组合继承)

function Cat(data) {
  Animal.call(this, data); // 将父类的数据类型在子类复制一份
  this.name = 'cat';
}
Cat.prototype = new Animal();

var cat = new Cat(); // 构造函数再次存储了一份父类的数据类型
cat.say();
复制代码

cat详细结构,可以发现有个缺点就是父类的数据类型被存储了2遍

ES5中有个api:

Object.create(object1, object2): 返回一个object,object的prototype = object1,object2代表prototype中新增或者覆盖的属性
eg:
var cat = Object.create(new Animal(), {
    name: {
        value: 'cat'
    }
})
复制代码

上述cat详细结构

参考红宝书(js高级程序设计):这种方式称为原型式继承

function object(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
复制代码

结合原型式继承和构造函数,可以有如下的继承方式

function Bird(data) {
  Animal.call(this, data);
  this.name = 'bird';
}
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;

var bird = new Bird();
bird.say();
复制代码

bird的详细结构:解决了原型链继承和组合继承的问题

构造函数有个特点,就是return的是一个对象的时候new的时候生成的就是这个对象,否则将按照正常的原型链生成对象。eg:

function Test() {
    var arr = [1, 2, 3];
    this.arr = arr;
    return arr;
}
Test.prototype.say = function() {
    console.log(this.arr);
}
var test = new Test();
test.say // undefined
复制代码

这就是传说中的寄生继承,寄生继承返回的对象跟原型链基本保持一致,唯一的问题就是丢失了子类的构造函数吧,以及第一层prototype

function Horse() {
  var o = Object.create(new Animal());
  o.name = 'horse';
  return o;
}
var horse = new Horse();
horse.say();
复制代码

horse详细结构:

扩展题目: 如何继承数组?

// 实现数组继承
var push = [].push;
function myArray() {
  var array = Array.apply(this, arguments);
  array.__proto__ = myArray.prototype;
  return array;
}
myArray.prototype = Object.create(Array.prototype)
myArray.prototype.constructor = myArray;
myArray.prototype.push = function(value) {
  console.log('push:', value);
  push.call(this, value);
}
var list = new myArray(1, 2, 3);
list.push(4);
复制代码

因为数组的独特性所以利用了寄生继承以及object的__proto__属性,以及原型式继承

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值