Prototypal inheritance
JavaScript Prototypal inheritance (JavaScript原型继承)
In programming, it is often necessary to take something and extend it. (在编程中,通常需要采取一些东西并进行扩展。)
For example, there is a user object with its methods and properties. You intend to make admin and guest as pretty modified variants of it. So you wish to reuse what you have in the user, building a new object on top of it. (例如,有一个用户对象及其方法和属性。您打算将admin和guest设置为它的漂亮修改变体。因此,您希望重用用户中的内容,并在其上构建新对象。)
The prototypal inheritance feature is there to help you. (原型继承功能可以为您提供帮助。)
[[Prototype]]
[[Prototype]] (原型)
JavaScript objects have a unique hidden property [[Prototype]]. It is either null or references another object. The object is named “a prototype.” (JavaScript对象具有唯一的隐藏属性[[Prototype]]。它要么为null ,要么引用另一个对象。该对象被命名为“原型”。)
The prototype is a super-useful thing. When one wants to read a property from the object, and it’s missing, JavaScript takes it from the prototype. This action is called “prototypal inheritance” in programming. (原型是一个非常有用的东西。当想要从对象中读取属性,但缺少该属性时, JavaScript会从原型中获取该属性。这个动作在编程中被称为“原型继承”。)
The property [[Prototype]] can be internal and hidden. There is a variety of ways to set it. (属性[[Prototype]]可以是内部的,也可以是隐藏的。设置方法多种多样。)
One such way is using the unique name proto. (一种方法是使用独特的名称__ proto __。)
For instance:
let animal = {
speaks: true
};
let dog = {
runs: true
};
dog.__proto__ = animal;
Please, take into account that proto is not the same as [[Prototype]]: it’s a getter/setter for it. The proto might only be supported by browsers, but all the environments, including the server-side, support it.
If you search for a property in the dog, and it’s missing, JavaScript takes it from the animal:
let animal = {
speaks: true
};
let dog = {
runs: true
};
dog.__proto__ = animal; // (*
// we can find both properties in dog now:
console.log(dog.speaks); // true (**)
console.log(dog.runs); // true
In the example above, the line () sets the animal to be a prototype of the dog. (在上面的示例中,行()将动物设置为狗的原型。)
So, we can note that the animal is the prototype of the dog. If the first has many valuable properties and methods, they become automatically available in the second one. Properties, like this, are known as “inherited.” (因此,我们可以注意到,动物是狗的原型。如果前者具有许多有价值的属性和方法,则它们在第二个属性和方法中自动可用。像这样的属性被称为“继承”。)
In case you have a method in the animal, you can call it on the dog. (如果您在动物身上有一种方法,您可以在狗身上调用它。)
For instance:
let animal = {
speaks: true,
walk() {
console.log("Animal walks");
}
};
let dog = {
runs: true,
__proto__: animal
};
dog.walk(); // Animal walks,walk is taken from the prototype
For example:
let animal = {
speaks: true,
walk() {
console.log("Animal walks");
}
};
let dog = {
runs: true,
__proto__: animal
};
let animalWeight = {
weight: 30,
__proto__: dog
};
animalWeight.walk(); // Animal walks, walk is taken from the prototype chain
console.log(animalWeight.runs); // true (from dog)
Only two limitations can be distinguished:
It is not possible to implement the references in circles. An error will occur, in case you try to assign proto in a circle. The value of proto might be either null or an object. Any other type is ignored. (无法在圈子中实现引用。 如果您尝试在圆圈中分配__ proto __ ,则会出现错误。 __ proto __的值可以是null或对象。 任何其他类型都将被忽略。)
Writing Doesn’t Use Prototype
Writing Doesn’t Use Prototype (写作不使用原型)
You can use prototype only for reading properties. The operations like write or delete operate directly with the object. (只能将原型用于读取属性。像写入或删除这样的操作直接与对象一起操作。)
Let’s see the following example:
let animal = {
speaks: true,
walk() {
/* this method doesn’t be used by dog */
(/*此方法不被狗使用*/)
}
};
let dog = {
__proto__: animal
};
dog.walk = function () {
console.log("Dog starts run!");
};
dog.walk(); // Dog starts run!
The dog.walk() call finds the method in the object at once and executes it, not using prototype. (Dog.walk ()调用会立即在对象中找到并执行该方法,而不是使用原型。)
To write such property is nearly the same as to call a function. (编写此类属性几乎与调用函数相同。)
That’s why message.fullMessage works in the example below:
let site = {
siteName: "w3cdoc",
bookName: "Javascript",
set fullMessage(value) {
[this.siteName, this.bookName] = value.split(" ");
},
get fullMessage() {
return `Welcome to ${this.siteName}'s ${this.bookName} book`;
}
};
let message = {
__proto__: site,
showMessage: true
};
console.log(message.fullMessage); // Welcome to w3cdoc's Javascript book
message.fullMessage = "Welcome to w3cdoc's Git book"; // setter triggers
The Value of “this”
The Value of “this” (“this”的价值)
It doesn’t matter whether the method is found in the object or its prototype. In a method call, this should also be before the dot. Hence, the setter call message.fullMessage= uses message as this, not site. (无论方法是在对象中还是在其原型中找到,都无关紧要。在方法调用中,这也应该在点之前。因此, setter调用message.fullMessage =使用message作为this ,而不是site。)
It is an essential thing, as, at times, you may have a large object with a lot of methods, and have objects that inherit from it. While the inheriting objects run the inherited methods, they can modify merely their states, but never the state of the large object. (这是一件必不可少的事情,因为有时,你可能有一个包含很多方法的大对象,并且有从中继承的对象。虽然继承对象运行继承的方法,但它们只能修改其状态,而不能修改大对象的状态。)
The for …in loop
The for …in loop (For… in循环)
The for..in loop also iterates over the inherited properties. (For.. in循环也会迭代继承的属性。)
Here is an example:
let animal = {
speaks: true
};
let dog = {
runs: true,
__proto__: animal
};
console.log(Object.keys(dog)); // runs, Object.keys only returns own keys
// for..in loops over both own and inherited keys
for (let prop in dog) console.log(prop); // runs, then speaks
If it’s not what you want, and you intend to exclude the inherited properties, you can use a built-in method obj.hasOwnProperty(key): it may return true in case the obj has a property named key that is not inherited.
You can either filter out the inherited properties or do anything else with them. (您可以过滤掉继承的属性,也可以对它们执行其他任何操作。)
For example:
let animal = {
speaks: true
};
let dog = {
runs: true,
__proto__: animal
};
for (let prop in dog) {
let isOwn = dog.hasOwnProperty(prop);
if (isOwn) {
console.log(`Our: ${prop}`); // Our: runs
} else {
console.log(`Inherited: ${prop}`); // Inherited: speaks
}
}
So, the inheritance chain looks like this: the dog inherits from the animal , which inherits from Object.prototype, and then null above it.
So, you may wonder where the method dog.hasOwnProperty comes from. If you look at the chain carefully, you can notice that it is provided by Object.prototype.hasOwnProperty . So, it is inherited. (因此,您可能想知道dog.hasOwnProperty方法的来源。如果仔细查看链,可以看到它是由Object.prototype.hasOwnProperty提供的。因此,它是继承的。)
Also note that all other key/value-getting methods (for example, Object.keys and Object.values) ignore the properties that were inherited. They work on the object itself. But, the prototype properties are not taken into account. (另请注意,所有其他键/值获取方法(例如, Object.keys和Object.values )都会忽略继承的属性。它们处理对象本身。但是,不考虑原型属性。)