javascript中的一些核心知识点(二)原型链

最初javascript没有class的概念,我们使用的类是以function模拟,继承的实现手段一般依靠原型链,继承的使用也是评价一个jser的重要指标。每个函数都会包含一个原型对象prototype。原型对象prototype包含一个指向构造函数的指针constructor。实例对象包含一个内部属性__proto__指针指向原型对象prototype。

这是他们之间的三角关系:

(function () {
    var Person = function (name) {
        this.name = name;
    };
    //Person.prototype = {};//这句将影响十分具有constructor属性
    Person.prototype.getName = function () {
        return this.name;
    };

    var Student = function (name, sex, id) {
        this.name = name || '无名氏';
        this.sex = sex || '不明';
        this.id = id || '未填'; //学号
    };
    //相当于将其prototype复制了一次,若是包含constructor的话将指向Person
    Student.prototype = new Person();
    Student.prototype.getId = function () {
        return this.id;
    }
    var y = new Person();
    var s = new Student;
    var s1 = y instanceof Person;
    var s2 = s instanceof Student;
    var s3 = s instanceof Person;
    var s4 = Student.prototype.constructor === Person;
    var s5 = Student.constructor === Person;
    var s6 = Student.constructor === Function;

    var s = '';
})();

一般形式的继承方式如上,偶尔我们会这样干:
Student.prototype = {}

但是这样会导致prototype对象的constructor对象丢失,所以需要找回来,另外一个问题是,这里继承需要执行父类的构造方法,这样是有问题的

比如,父类的构造函数中有一些事件绑定什么的与子类无关,便会导致该类继承无用,所以很多时候我们需要自己实现继承,比较优雅的是prototype的做法,我这里对其进行了一定改造。

var arr = [];
var slice = arr.slice;

function create() {
  if (arguments.length == 0 || arguments.length > 2) throw '参数错误';

  var parent = null;
  //将参数转换为数组
  var properties = slice.call(arguments);

  //如果第一个参数为类(function),那么就将之取出
  if (typeof properties[0] === 'function')
    parent = properties.shift();
  properties = properties[0];

  function klass() {
    this.initialize.apply(this, arguments);
  }

  klass.superclass = parent;
  klass.subclasses = [];

  if (parent) {
    var subclass = function () { };
    subclass.prototype = parent.prototype;
    klass.prototype = new subclass;
    parent.subclasses.push(klass);
  }

  var ancestor = klass.superclass && klass.superclass.prototype;
  for (var k in properties) {
    var value = properties[k];

    //满足条件就重写
    if (ancestor && typeof value == 'function') {
      var argslist = /^\s*function\s*\(([^\(\)]*?)\)\s*?\{/i.exec(value.toString())[1].replace(/\s/i, '').split(',');
      //只有在第一个参数为$super情况下才需要处理(是否具有重复方法需要用户自己决定)
      if (argslist[0] === '$super' && ancestor[k]) {
        value = (function (methodName, fn) {
          return function () {
            var scope = this;
            var args = [function () {
              return ancestor[methodName].apply(scope, arguments);
            } ];
            return fn.apply(this, args.concat(slice.call(arguments)));
          };
        })(k, value);
      }
    }

    klass.prototype[k] = value;
  }

  if (!klass.prototype.initialize)
    klass.prototype.initialize = function () { };

  klass.prototype.constructor = klass;

  return klass;
}

首先,继承时使用一个空构造函数实现,这样不会执行原构造函数的实例方法,再规范化必须实现initialize方法,保留构造函数的入口,这类实现比较优雅,建议各位试试。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值