`this`引用在原型链中丢失了

时间:2017-04-27 19:52:10

标签: javascript

这是非常广泛的,但有趣而详细。

我使用原型的标准JavaScript方法定义了两个“类”:

来源

function Source() {
  this._sourceGuid = "";
  this._periodGuid = "";
  this._eventName = "";
  this._eventKind = 0;

  if (arguments.length > 0) {
    if (arguments[0].__proto__ === this.__proto__) {
      this.sourceGuid(arguments[0].sourceGuid());
      this.periodGuid(arguments[0].periodGuid());
      this.eventName(arguments[0].eventName());
      this.eventKind(arguments[0].eventKind());
    } else {
      this.sourceGuid(arguments[0].sourceGuid);
      this.periodGuid(arguments[0].periodGuid);
      this.eventName(arguments[0].eventName);
      this.eventKind(arguments[0].eventKind);
    }
  }
};

Source.prototype.sourceGuid = function (value) {
  if (arguments.length > 0) {
    this._sourceGuid = value
  } else {
    return this._sourceGuid;
  }
};

Source.prototype.periodGuid = function (value) {
  if (arguments.length > 0) {
    this._periodGuid = value
  } else {
    return this._periodGuid;
  }
};

Source.prototype.eventName = function (value) {
  if (arguments.length > 0) {
    this._eventName = value
  } else {
    return this._eventName;
  }
};

Source.prototype.eventKind = function (value) {
  if (arguments.length > 0) {
    this._eventKind = value
  } else {
    return this._eventKind;
  }
};

Source.prototype.toJSON = function() {
  return {
    sourceGuid: this.sourceGuid(),
    periodGuid: this.periodGuid(),
    eventName: this.eventName(),
    eventKind: this._eventKind()
  };
};

AnalogCamerasSource扩展了Source

function AnalogCamerasSource() {

  this.__proto__.apply(this, arguments);

  this._serverGuid = "";
  this._cameraId = 0;
  this._waitingTime = 0;

  if (arguments.length > 0) {
    if (arguments[0].__proto__ === this.__proto__) {
      this.serverGuid(arguments[0].serverGuid());
      this.cameraId(arguments[0].cameraId());
      this.waitingTime(arguments[0].waitingTime());
    } else {
      this.serverGuid(arguments[0].serverGuid);
      this.cameraId(arguments[0].cameraId);
      this.waitingTime(arguments[0].waitingTime);
    }
  }
};

AnalogCamerasSource.prototype = Source;

AnalogCamerasSource.prototype.serverGuid = function (value) {
  if (arguments.length > 0) {
    this._serverGuid = value
  } else {
    return this._serverGuid;
  }
};

AnalogCamerasSource.prototype.cameraId = function (value) {
  if (arguments.length > 0) {
    this._cameraId = value
  } else {
    return this._cameraId;
  }
};

AnalogCamerasSource.prototype.waitingTime = function (value) {
  if (arguments.length > 0) {
    this._waitingTime = value
  } else {
    return this._waitingTime;
  }
};

AnalogCamerasSource.prototype.toJSON = function() {
  var json = this.__proto__.toJSON();

  json.serverGuid = this.serverGuid();
  json.cameraId = this.cameraId();
  json.waitingTime = this.waitingTime();

  return json;
};

现在我需要一个AnalogCamerasSource的实例,我正在努力创建它:

var data = {"sourceGuid":"{05A00E05-F30D-497D-A272-156F135E1486}","periodGuid":"{8A071454-B473-4937-9C54-4899F866D7FA}","eventName":"signal-lost","eventKind":3,"serverGuid":"{9976B57D-486B-4BCA-8432-78D7C8EDB52B}","cameraId":4,"waitingTime":5};

var c = new AnalogCamerasSource(data);

现在,行this.__proto__.apply(this, arguments);负责调用父的构造函数,它看起来应该没问题,但是现在它应该在父的构造函数中调用父函数,抛出以下错误:

TypeError: this.sourceGuid is not a function
    at Function.Source (http://localhost:8081/js/app/events/model/0-Source.js:14:12)
    at AnalogCamerasSource (http://localhost:8081/js/app/events/model/AnalogCamerasSource.js:3:33)

现在,这是来自Chrome调试器的图片,显示属性在this.__proto__.prototype this.__proto__.apply(this, arguments) AnalogCamerasSource下{{1}}下方的原型链中。

enter image description here

那么,为什么this.sourceGuid不是函数?我该如何调用父的构造函数使这个链正常工作?

这是一个小提琴:https://jsfiddle.net/98bp8pvh/

4 个答案:

答案 0 :(得分:1)

重构代码(避免在代码中使用__proto__

function Source() {
  var args = arguments[0] || {};
  this._sourceGuid = args.sourceGuid || '';
  this._periodGuid = args.periodGuid || '';
  this._eventName = args.eventName || '';
  this._eventKind = args.eventKind || 0;
};

Source.prototype.sourceGuid = function(value) {
  if (arguments.length > 0) {
    this._sourceGuid = value || '';
  } else {
    return this._sourceGuid;
  }
};

Source.prototype.periodGuid = function(value) {
  if (arguments.length > 0) {
    this._periodGuid = value || '';
  } else {
    return this._periodGuid;
  }
};

Source.prototype.eventName = function(value) {
  if (arguments.length > 0) {
    this._eventName = value || '';
  } else {
    return this._eventName;
  }
};

Source.prototype.eventKind = function(value) {
  if (arguments.length > 0) {
    this._eventKind = value || 0;
  } else {
    return this._eventKind;
  }
};

Source.prototype.toJSON = function() {
  return {
    sourceGuid: this.sourceGuid(),
    periodGuid: this.periodGuid(),
    eventName: this.eventName(),
    eventKind: this.eventKind()
  };
};

function AnalogCamerasSource() {
  var args = arguments[0] || {};
  this._serverGuid = args.serverGuid || '';
  this._cameraId = args.cameraId || 0;
  this._waitingTime = args.waitingTime || 0;
  
  this.sourceGuid(args.sourceGuid);
  this.periodGuid(args.periodGuid);
  this.eventName(args.eventName);
  this.eventKind(args.eventKind);
};

AnalogCamerasSource.prototype = Object.create(Source.prototype);

AnalogCamerasSource.prototype.serverGuid = function(value) {
  if (arguments.length > 0) {
    this._serverGuid = value || '';
  } else {
    return this._serverGuid;
  }
};

AnalogCamerasSource.prototype.cameraId = function(value) {
  if (arguments.length > 0) {
    this._cameraId = value || 0;
  } else {
    return this._cameraId;
  }
};

AnalogCamerasSource.prototype.waitingTime = function(value) {
  if (arguments.length > 0) {
    this._waitingTime = value || 0;
  } else {
    return this._waitingTime;
  }
};

AnalogCamerasSource.prototype.toJSON = function() {
  var json = Source.prototype.toJSON.call(this);

  json.serverGuid = this.serverGuid();
  json.cameraId = this.cameraId();
  json.waitingTime = this.waitingTime();

  return json;
};

var data = {
  "sourceGuid": "{05A00E05-F30D-497D-A272-156F135E1486}",
  "periodGuid": "{8A071454-B473-4937-9C54-4899F866D7FA}",
  "eventName": "signal-lost",
  "eventKind": 3,
  "serverGuid": "{9976B57D-486B-4BCA-8432-78D7C8EDB52B}",
  "cameraId": 4,
  "waitingTime": 5
};

var c = new AnalogCamerasSource(data);
console.log(c);

答案 1 :(得分:0)

我通过这种解决方法解决了我的问题,如果有人可以发布更正确的答案,我可以接受这是正确的答案:

我更改了原型定义:

AnalogCamerasSource.prototype = new Source();

然后我将以下功能添加到AnalogCamerasSource

AnalogCamerasSource.prototype.super = function() {
  Source.apply(this, arguments);
};

然后在构造函数中我称之为:

function AnalogCamerasSource() {
  this.super.apply(this, arguments);
  ...
};

像魅力一样。

答案 2 :(得分:0)

保持简单,做这样的继承:

AnalogCamerasSource.prototype = Source.prototype;

...只是apply子类构造函数中父类的构造函数:

function AnalogCamerasSource() {
  Source.apply(this, arguments);
  ...
}

通常无需直接引用__proto__

答案 3 :(得分:0)

尝试将AnalogCamerasSource.prototype = Source;更改为AnalogCamerasSource.prototype = new Source;,将this.__proto__.apply(this, arguments);更改为Source.apply(this, arguments);

问题在于,您的方法AnalogCameraSource.prototype设置为函数(Source对象的构造函数),而不是对象。此函数本身没有在其原型上定义的方法。如果您将AnalogCameraSource.prototype设置为新的Source对象(使用new Source创建),则AnalogCameraSource.prototype对象,这应该是应该的。这将在Source原型上定义的所有方法都放在AnalogCameraSource的原型链中,并且Source构造函数能够顺利运行。