简体   繁体   中英

forcing __proto__ equality

I want the prototype of these instances to be the same, but the following equality check evaluates to false.

var emp1 = new(EmployeeScope())("John");
var emp2 = new(EmployeeScope())("Amit");
var mgr1 = new(ManagerScope())("Robert", "Data");
var mgr2 = new(ManagerScope())("Alex", "Science");
emp1.getName() // John
emp2.getName() // Amit
mgr1.getDept() // Data
mgr2.getDept() // Science
mgr1.getName() // Robert
mgr2.getName() // Alex

emp1.__proto__ === emp2.__proto__ //false
mgr1.__proto__ === mgr2.__proto__ //false

function EmployeeScope() {
  var name;

  function Employee(newName) {
    name = newName;
  }
  Employee.prototype.getName = function() {
    return name
  };
  Employee.prototype.setName = function(newName) {
    name = newName
  };
  return Employee;
}

function ManagerScope() {
  var Employee = EmployeeScope();
  var dept;

  function Manager(newName, newDept) {
    new Employee(newName);
    dept = newDept;
  }
  Manager.prototype = Object.create(Employee.prototype);
  Manager.prototype.constructor = Manager;
  Manager.prototype.getDept = function() {
    return dept
  };
  Manager.prototype.setDept = function(newDept) {
    dept = newDept
  };
  return Manager;
}

The reason the two objects have different prototypes is that the constructor functions Employee and Manager are created again at each call of the wrapper functions you put them in. So they represent different constructors when called in different calls of the wrapper functions.

A common solution to let the object methods access private members, is by defining them not on the prototype, but on the instances. That way you can define them in the constructor scope:

 function Employee(newName) { var name = newName; this.getName = function() { return name }; this.setName = function(newName) { name = newName }; } function Manager(newName, newDept) { var dept = newDept; // Inherit from Employee Employee.call(this, newName); this.getDept = function() { return dept }; this.setDept = function(newDept) { dept = newDept }; } var emp1 = new Employee("John"); var emp2 = new Employee("Amit"); var mgr1 = new Manager("Robert", "Data"); var mgr2 = new Manager("Alex", "Science"); console.log(emp1.getName()) // John console.log(emp2.getName()) // Amit console.log(mgr1.getDept()) // Data console.log(mgr2.getDept()) // Science console.log(mgr1.getName()) // Robert console.log(mgr2.getName()) // Alex console.log(Object.getPrototypeOf(emp1) === Object.getPrototypeOf(emp2)); console.log(Object.getPrototypeOf(mgr1) === Object.getPrototypeOf(mgr2)); 

Note that it is advised to use Object.getPrototypeOf() instead of __proto__ .

Secondly, you should declare local variables with var (or let , const ), because otherwise the variable is silently declared as a global variable, and you would get the same name for every employee.

Maybe it's easier to understand why they don't share the same prototype when you write the code as following:

var EmployeeA = EmployeeScope();
var EmployeeB = EmployeeScope();
EmployeeA === EmployeeB // false
EmployeeA.prototype === EmployeeB.prototype // false
var emp1 = new EmployeeA("John");
var emp2 = new EmployeeB("Amit");
Object.getPrototypeOf(emp1) === EmployeeA.prototype // true
Object.getPrototypeOf(emp2) === EmployeeB.prototype // true

Having your EmployeeScope create a new class (constructor + prototype) on every new call isn't the best idea. Also you can only use it for a single instance, given that name is statically stored:

var emp3 = new EmployeeB("Dirk");
Object.getPrototypeOf(emp2) === Object.getPrototypeOf(emp3) // true
emp2.getName() // Dirk - oops

Your Manager class suffers from the same problem of course. So drop those "scope" functions and make them standard classes:

function Employee(newName) {
  this.name = newName;
}
Employee.prototype.getName = function() {
  return this.name
};
Employee.prototype.setName = function(newName) {
  this.name = newName
};


function Manager(newName, newDept) {
  Employee.call(this, newName);
  this.dept = newDept;
}
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.getDept = function() {
  return this.dept
};
Manager.prototype.setDept = function(newDept) {
  this.dept = newDept
};

var emp1 = new Employee("John");
var emp2 = new Employee("Amit");
var emp3 = new Employee("Dirk");
var mgr1 = new Manager("Robert", "Data");
var mgr2 = new Manager("Alex", "Science");
Object.getPrototypeOf(emp1) === Employee.prototype // true
Object.getPrototypeOf(emp2) === Employee.prototype // true
Object.getPrototypeOf(emp3) === Employee.prototype // true
Object.getPrototypeOf(mgr1) === Manager.prototype // true
Object.getPrototypeOf(mgr2) === Manager.prototype // true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM