简体   繁体   English

在各种浏览器中得到广泛支持的最安全的创建原型链的方法是什么?

[英]What is the safest way, broadly supported across browsers, to create prototype chains?

So I'm still learning JavaScript, and I'm working with prototypes right now. 因此,我仍在学习JavaScript,并且现在正在使用原型。 The lesson I just completed showed me how to use __proto__ to create prototype inheritance chains. 我刚刚完成的课程向我展示了如何使用__proto__创建原型继承链。 Here's an example of what I mean: 这是我的意思的示例:

function Person(firstName,lastName,dob){
  this.firstName = firstName;
  this.lastName = lastName;
  this.dob = new Date(dob);
}
Person.prototype = {
  constructor: Person,
  getFullName: function(){
    return this.firstName + " " + this.lastName;
  },
  getAge: function(){
    var ageDiff = Date.now() - this.dob;
    var ageDiffDate = new Date(ageDiff);
    return Math.abs(ageDiffDate.getUTCFullYear() - 1970);
  }
}

function Employee(firstName,lastName,dob,position,dept){
  this.firstName = firstName;
  this.lastName = lastName;
  this.dob = new Date(dob);
  this.position = position;
  this.dept = dept;
  this.isFired = false;
}
Employee.prototype = {
  constructor: Employee,
  __proto__: Person.prototype,
  doWork: function(){
    console.log(this.getFullName() + " is doing work");
  }
}

function Manager(firstName,lastName,dob,dept){
  this.firstName = firstName;
  this.lastName = lastName;
  this.dob = new Date(dob);
  this.position = "Manager";
  this.dept = dept;
}
Manager.prototype = {
  constructor: Manager,
  __proto__: Employee.prototype,
  fireEmployee: function(emp){
    emp.isFired = true;
    console.log(this.getFullName() + " has fired " + emp.getFullName());
  }
}

var per = new Person("Bob","Saget","1990-02-05");
var emp = new Employee("Jane","Doe","1980-05-02","Clerk","Sales");
var mgr = new Manager("Jim","Smith","1970-09-10","Sales");

Employee inherits from Person.prototype , and Manager inherits from Employee.prototype . EmployeePerson.prototype继承,而ManagerEmployee.prototype继承。 Nice and simple. 漂亮又简单。

However, I've read that the __proto__ property isn't guaranteed across all web browsers, since ES6 hasn't been widely adopted yet. 但是,我已经读到并不能在所有Web浏览器中保证__proto__属性,因为ES6尚未得到广泛采用。 I've been scanning the internet, trying to find a clear explanation of what to do instead, and I'm getting a little bit lost. 我一直在浏览互联网,试图找到关于该怎么做的明确解释,但我却迷失了一些。

What is the safe, broadly supported way of setting prototype inheritance chains in ES5, other than using __proto__ ? 除了使用__proto__之外,在ES5中设置原型继承链的安全且受到广泛支持的方法是什么?

The safest way is using standard ES5 and above approaches. 最安全的方法是使用标准 ES5及以上方法。

function A() {}

function B() {}
B.prototype = Object.create(A.prototype);

Quoting from MDN : MDN报价:

The use of __proto__ is controversial, and has been discouraged. __proto__的使用是有争议的,因此不建议使用。 It was never originally included in the EcmaScript language spec, but modern browsers decided to implement it anyway. 它最初从未包含在EcmaScript语言规范中,但是现代的浏览器决定还是要实现它。 Only recently, the __proto__ property has been standardized in the ECMAScript 6 language specification for web browsers to ensure compatibility, so will be supported into the future. 仅在最近,ECproScript 6语言规范中针对Web浏览器的__proto__属性已经标准化,以确保兼容性,因此将来会支持该属性。 It is deprecated in favor of Object.getPrototypeOf / Reflect.getPrototypeOf and Object.setPrototypeOf / Reflect.setPrototypeOf (though still, setting the [[Prototype]] of an object is a slow operation that should be avoided if performance is a concern). 不推荐使用此方法,而推荐使用Object.getPrototypeOf / Reflect.getPrototypeOfObject.setPrototypeOf / Reflect.setPrototypeOf (尽管如此,设置对象的[[Prototype]]是一项缓慢的操作,如果出于性能考虑,应该避免这样做)。

Please also consider the warning concerning performance 请同时考虑有关性能的警告

Warning : Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. 警告 :根据现代JavaScript引擎如何优化属性访问的性质,更改对象的[[Prototype]]在每个浏览器和JavaScript引擎中的操作都非常缓慢。 (...) (...)

If you don't mind the performance implications or just want to experiment with prototypes, the article Inheritance and the prototype chain gives an excellent introduction on how the prototype chain in JS works. 如果您不介意性能影响,或者只是想尝试使用原型,那么“ 继承和原型链”一文将很好地介绍JS中的原型链如何工作。 I'll quote the part that mentions the three different ways to create custom prototype chains here: 我将在此处引用提到创建自定义原型链的三种不同方式的部分:

With a constructor 与构造函数

A "constructor" in JavaScript is "just" a function that happens to be called with the new operator . JavaScript中的“构造函数”就是“恰好”被new运算符调用的函数。

 function Graph() { this.vertices = []; this.edges = []; } Graph.prototype = { addVertex: function(v){ this.vertices.push(v); } }; var g = new Graph(); console.log("g:", Object.keys(g)) console.log("g.prototype:", Object.keys(Object.getPrototypeOf(g))) 

With Object.create 使用Object.create

ECMAScript 5 introduced a new method: Object.create(). ECMAScript 5引入了一种新方法:Object.create()。 Calling this method creates a new object. 调用此方法将创建一个新对象。 The prototype of this object is the first argument of the function: 该对象的原型是该函数的第一个参数:

 var a = {a: 1}; // a ---> Object.prototype ---> null var b = Object.create(a); // b ---> a ---> Object.prototype ---> null console.log(ba); // 1 (inherited) var c = Object.create(b); // c ---> b ---> a ---> Object.prototype ---> null var d = Object.create(null); // d ---> null console.log(d.hasOwnProperty); // undefined, because d doesn't inherit from Object.prototype 

With the class keyword class关键字

ECMAScript 6 introduced a new set of keywords implementing classes. ECMAScript 6引入了一组新的关键字来实现类。 Although these constructs look like those familiar to developers of class-based languages, they are not the same. 尽管这些构造看起来像是基于类的语言的开发人员所熟悉的构造,但是它们并不相同。 JavaScript remains prototype-based. JavaScript仍然基于原型。 The new keywords include class, constructor, static, extends, and super. 新的关键字包括类,构造函数,静态,扩展和超级。

 "use strict"; class Polygon { constructor(height, width) { this.height = height; this.width = width; } } class Square extends Polygon { constructor(sideLength) { super(sideLength, sideLength); } get area() { return this.height * this.width; } set sideLength(newLength) { this.height = newLength; this.width = newLength; } } var square = new Square(2); 

Conclusion 结论

I'd agree with Matias' answer and recommend using Object.create , because it does not hide the prototypal nature of JavaScript - in contrast to constructors or ES6 classes. 我同意Matias的回答,并建议使用Object.create ,因为与构造函数或ES6类相比,它不会隐藏JavaScript的原型性质。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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