[js] 原型 继承 委托

本文探讨JavaScript中的原型、继承和委托概念。每个函数都有prototype属性,指向原型对象,而实例的[[Prototype]]指向构造函数的原型。继承在JS中通过原型链实现,包括组合继承、原型式继承、寄生组合式继承等。委托是一种利用Object.create实现的多态方式,不同于传统的继承思考。文章还提到了常见的继承实现和《你不知道的js》中的相关讨论。

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

每个函数都有prototype属性,prototype是一个指向原型对象的指针
例外:通过Function.prototype.bind方法构造出来的函数没有prototype属性

function Point(x, y) {
  this.x = x;
  this.y = y;
}
var Y = Point.bind(null, 0, 3);

Point.prototype // Object {}
Y.prototype // undefined

每个原型对象默认取得一个constructor属性,constructor是指向对应函数的指针
每个实例也会有constructor属性,指向创建当前对象的函数
通过构造函数产生的实例对象会有一个[[prototype]]属性,指向创建这个对象的函数的原型函数(to the value of its constructor’s “prototype”),在ES5中可使用Object.getPrototypeOf()获取
- 函数的[[prototype]]指向的是Function.prototype,为一个空函数
- 原型对象的[[prototype]]指向Object.prototype
- 不能通过对象实例 重写 原型对象中的值

function a(){}
a.__proto__ == Function.prototype // true
a.prototype.__proto__ == Object.prototype // true

这里写图片描述

typeof instanceof
typeof用来检测一个变量是不是基本数据类型的变量
instanceof用来检测引用类型

if(typeof a != "undefined"){} // 判断a是否存在
if(!a){} // 若a未定义会报错

继承


my git
js中的继承与其他语言不太一致

  1. js中没有类的概念(es6后的类是语法糖,本质是函数),所有都是对象
  2. js的继承采用原型链实现

继承应当实现继承与多态两个功能

继承

采用key复制实现

var extend = function extend(source, target) {
  for (var key in source) {
    if (!(key in target)) {
      target[key] = source[key];
    }
  }
  // actually needn't...
  return target;
};

采用原型链实现

function Super(){}
function Sub(){}
Sub.prototype = new Super(); 
var instance = new Sub(); // instance.__proto__.__proto__ == Sub.prototype.__proto__ == Super.prototype
  • Super中的实例属性变成了Sub的原型属性,若是引用值会造成问题
  • 无法在所有instance都不影响的情况下给Super的构造函数传递参数

多态

采用实现

常用实现

组合继承

function Super(super){
    this.superProperty = super;
}
Super.prototype.doSup = function(){}
function Sub(super, sub){
    Super.call(this, super); // 构造函数继承实例属性
    this.subProperty = sub;
}
Sub.prototype = new Super(); // 原型链继承原型方法
Sub.prototype.doSome = function(){}
Sub.prototype.constructor = Sub;
var instance = new Sub(); // instance和instance.__proto__都有superProperty

原型式继承(Prototypal Inheritance)

Prototypal Inheritance
Classical Inheritance

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

var person = {
    name: 'ab',
    friend: ['a', 'b']
}

var onePerson = object(person); // onePerson.__proto__ == person person被所有的instance共享
  • ES5中可使用Object.create()
  • 引用类型会共享相应的值
  • 原型式继承是没有显著的构造函数的,相当于是直接对对象o进行继承(对象对对象的继承)

寄生组合式继承

  • 与组合式继承相比,利用原型式继承方式减少一次调用Super函数的过程
  • 原型链上不会有额外的属性
  • 结果本质和组合式继承一样

    function inherit(sub, super){
    var prototype = Object.create(super.prototype); // 创建一个super的实例,实际上调用了一个prototype和Super.prototype相同的匿名构造函数
    prototype.constructor = sub;
    sub.prototype = prototype;
    }

    function Super(super){
    this.superProperty = super;
    }
    Super.prototype.doSup = function(){}
    function Sub(super, sub){
    Super.call(this, super); // 构造函数继承实例属性
    this.subProperty = sub;
    }
    inherit(Sub, Super);
    var instance = new Sub();

函数式的继承方法

// js the good parts p53
var constructor = function (spec, my) {
    var that;
    my = my || {}; // 共享的方法

    that = {};
    // 通过spec给that添加私有方法
    return that;
}

委托


my git
《你不知道的js》
委托是一种利用Object.create与对象方式实现的js类多态方式
与继承的思考方式不同,委托采用proto链,但是不追求方法的复写和多态

var Base = {
  baseFunc: function () {
    console.log(this);
  }
};

// 令 Delegate.__proto__ === Base
var Delegate = Object.create(Base);

Delegate.delegateFunc = function delegateFunc() {
  // 通过这种方式不需要使用函数调用的硬绑定,用这种方式也可以保护愿型链方法
  this.baseFunc();
};

Delegate.selfFunc = function selfFunc() {
  console.log(this);
};

从设计思想上,委托与继承并不相同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值