【问题标题】:TypeError while retriving prototype properties检索原型属性时出现 TypeError
【发布时间】:2016-10-24 05:21:38
【问题描述】:

我有以下代码:

function inheritPrototype (sup, sub) {
  var proto = Object.create(sup.prototype);
  Object.defineProperty(proto, "constructor", {value : sub});
  sub.prototype = proto;
}

function Person (name, age) {
  this.name = name;
  this.age = age;

  if (!Person.prototype.getName) {
    Person.prototype.getName = function () { return this.name; }
    Person.prototype.getAge = function () { return this.age; }
  }
}

function Employee (name, age, skills) {
  Person.call(this, name, age);
  this.skills = skills;

  if (!Employee.prototype.getSkills) {
    inheritPrototype(Person, Employee);
    Employee.prototype.getSkills = function () { return this.skills; }
  }
}

var person = new Person ("Dave", 21);
var employee = new Employee ("David", 22, ["C", "C++", "Java", "Python", "PHP"]);

console.log(employee.getSkills());

inheritPrototype 只是为了防止父 (Person) 构造函数的双重调用而定义的。为了清楚起见,我在构造函数中分配原型属性并防止每次创建新实例时发生这种情况,我正在检查原型属性是否存在。如果是这样,那么我们不想重新分配属性,否则我们会这样做。问题是,我收到一个 TypeError 说“employee.getName is not a function”。仅当我尝试使用 Employee 实例访问 Employee 的原型属性时才会发生这种情况。 person 构造函数具有相同的分配 Prototype 属性的方法,但它工作正常。

console.log(person.getName()); // "Dave"
console.log(employee.getSkills()); // or getName or anything, TypeError

我想我在那里做了一些愚蠢的事情,但无法发现它。那么,怎么了?

【问题讨论】:

  • 为什么需要inheritPrototype方法?你能详细说明一下吗? “为了清楚起见,我在构造函数中分配原型属性并防止每次创建新实例时发生这种情况,我正在检查原型属性是否存在。”
  • @Sreekanth 我不想调用 Person 构造函数两次。相反,如果我一直这样做Employee.prototype = new Person (),我会调用构造函数两次。我使用的模式是Parasitic Combination Inheritance
  • 大家有什么建议吗?
  • 我需要先查看寄生组合继承,然后才能发表评论。但是,您在 Employee 上看到错误但在 Person 上没有看到错误的原因是对 Employee 上的 inheritPrototype 进行了调用。

标签: javascript object constructor prototype-programming


【解决方案1】:

在外面打个inheritPrototype怎么样?

这对我有用:

function inheritPrototype (sup, sub) {
  var proto = Object.create(sup.prototype);
  Object.defineProperty(proto, "constructor", {value : sub});
  sub.prototype = proto;
}

function Person (name, age) {
  this.name = name;
  this.age = age;

  if (!Person.prototype.getName) {
    Person.prototype.getName = function () { return this.name; }
    Person.prototype.getAge = function () { return this.age; }
  }
}

function Employee (name, age, skills) {
  Person.call(this, name, age);
  this.skills = skills;

  if (!Employee.prototype.getSkills) {
    Employee.prototype.getSkills = function () { return this.skills; }
  }
}

inheritPrototype(Person, Employee); // <= FIX

var person = new Person ("Dave", 21);
var employee = new Employee ("David", 22, ["C", "C++", "Java", "Python", "PHP"]);

console.log(person.getName()); // returns "Dave"
console.log(employee.getSkills()); // returns ["C", "C++", "Java", "Python", "PHP"]
console.log(employee.getName());  // returns David

【讨论】:

  • 它也适用于我。但是我想知道为什么这样写它不起作用的原因。
  • 因为如果您在 function Employee () 定义中执行此操作,则仅在定义 Employee 时才会发生继承。这意味着,如果您使用原始代码并连续两次执行var employee = new Employee,它就可以工作。因为继承发生在第一次构造之后。
  • 如果你想让它在function Employee()中工作,你可能需要继承实例而不是函数,可能使用inheritPrototype(Person, this)但不确定是否可行。
【解决方案2】:

这个问题主要是由于调用了 inheritPrototype 方法后原型引用不匹配造成的。

在 inheritPrototype 方法中,您有 Object.create(sup.prototype),它试图从原型中创建一个新实例,该实例与创建 Employee 对象时使用的对象引用不同。

这可以在为 Employee 原型打印的控制台日志中看到,其中为原型创建了一个新引用,其中不调用 inheritPrototype 方法的 EmployeeOne 具有相同的引用。

所以,您看到异常的原因是参考不匹配。即使您引用的是原型,在 inheritMethod 调用之前和之后的引用也是不同的。

我没有文档来支持我的理论,但是,我相信由于原型引用在 inheritPrototype 方法调用调用的情况下发生了变化,这就是为什么新添加的方法 getSkills 在原型链查找中不可见的原因那个对象。

但是,一旦原型值在第一次员工调用期间更新,后续员工对象就能够看到新的 getSkills,因为原型引用现在指向早期调用的原型引用。

function inheritPrototype(sup, sub) {
  var proto = Object.create(sup.prototype);
  Object.defineProperty(proto, "constructor", {
    value: sub
  });
  sub.prototype = proto;
}

function Person(name, age) {
  this.name = name;
  this.age = age;

  if (!Person.prototype.getName) {
    Person.prototype.getName = function () {
      return this.name;
    }
    Person.prototype.getAge = function () {
      return this.age;
    }
  }
}

function Employee(name, age, skills) {
  Person.call(this, name, age);
  this.skills = skills;

  var p = Employee.prototype;
  if (!Employee.prototype.getSkills) {
    inheritPrototype(Person, Employee);

    Employee.prototype.getSkills = function () {
      return this.skills;
    }
  }
  console.log("Employee with inheritPrototype invocation : " + (p === Employee.prototype));
}


function EmployeeOne(name, age, skills) {
  Person.call(this, name, age);
  this.skills = skills;

  var p = EmployeeOne.prototype;
  if (!EmployeeOne.prototype.getSkills) {
    EmployeeOne.prototype.getSkills = function () {
      return this.skills;
    }
  }
  console.log("EmployeeOne without inheritPrototype invocation : " + (p === EmployeeOne.prototype));
}


var person = new Person("Dave", 21);
var employee = new Employee("David", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);

var employeeOne = new EmployeeOne("DavidOne", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);

var employeeTwo = new Employee("David", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);

console.log(employeeTwo.getSkills());

我尝试在inheritPrototype方法之后查找Employee构造函数的引用,我上面对原型的新引用的解释结果是正确的。

function inheritPrototype(sup, sub) {
  var proto = Object.create(sup.prototype);
  Object.defineProperty(proto, "constructor", {
    value: sub
  });
  sub.prototype = proto;
}

function Person(name, age) {
  this.name = name;
  this.age = age;

  if (!Person.prototype.getName) {
    Person.prototype.getName = function() {
      return this.name;
    }
    Person.prototype.getAge = function() {
      return this.age;
    }
  }
}

function Employee(name, age, skills) {
  Person.call(this, name, age);
  this.skills = skills;

  var p = Employee.prototype;
  if (!Employee.prototype.getSkills) {
    inheritPrototype(Person, Employee);
    Employee.prototype.getSkills = function() {
      return this.skills;
    }
  } else {
    inheritPrototype(Person, Employee);

  }
  if (employeeTwoPrototype !== undefined) {
    console.log("Employee with 2nd inheritPrototype invocation : " + (p === employeeTwoPrototype));

    console.log("Employee with 2nd inheritPrototype invocation : " + (p === Employee.prototype));
  } else {
    console.log("Employee with inheritPrototype invocation : " + (p === Employee.prototype));
  }
}



function EmployeeOne(name, age, skills) {
  Person.call(this, name, age);
  this.skills = skills;

  var p = EmployeeOne.prototype;
  if (!EmployeeOne.prototype.getSkills) {
    EmployeeOne.prototype.getSkills = function() {
      return this.skills;
    }
  }
  console.log("EmployeeOne without inheritPrototype invocation : " + (p === EmployeeOne.prototype));
}


var person = new Person("Dave", 21);
var employee = new Employee("David", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);

var employeeOne = new EmployeeOne("DavidOne", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);

var employeeTwo = new Employee("David", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);

var employeeTwoPrototype = Employee.prototype;
var employeeThree = new Employee("David", 22, [
  "C",
  "C++",
  "Java",
  "Python",
  "PHP"
]);


console.log(employeeTwo.getSkills());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2018-08-08
    • 1970-01-01
    相关资源
    最近更新 更多