Native Prototypes
JavaScript Native Prototypes (JavaScript原生原型)
The “prototype” property is commonly used by the core of JavaScript. It is used by all the built-in constructor functions. (JavaScript的核心通常使用“prototype”属性。它被所有内置构造函数使用。)
Let’s start at the details. (让我们从细节开始。)
Object.prototype
Object.prototype
Imagine you output an object that is empty:
let obj = {};
console.log(obj); // "[object Object]" ?
Probably, you wonder where the code creating the string “[object Object]” is. It is the built-in toString method. But, in fact, the obj is empty. (您可能想知道创建字符串“[object Object]”的代码在哪里。它是内置的toString方法。但是,实际上,对象是空的。)
Note that short notation obj = {} is equal to obj = new Object(), where Object is a built-in object constructor function along with its prototype referencing an immense object with toString or other methods.
Whenever, a new Object() is invoked, its [[Prototype]] is set to Object.prototype:
As you can see, when you call obj.toString(), the method is taken from Object.prototype. (如您所见,调用obj.toString ()时,方法取自Object.prototype。)
You have the option of checking it, acting like this:
let obj = {};
console.log(obj.__proto__ === Object.prototype); // true
// obj.toString === obj.__proto__.toString == Object.prototype.toString
Please, take into account that the prototype doesn’t exist any more in the chain above Object.prototype. (请考虑原型不再存在于Object.prototype上面的链中。)
It looks like this:
console.log(Object.prototype.__proto__); // null
Other Built-in Prototypes
Other Built-in Prototypes (其他内置原型)
Array, Date, Function, and other built-in objects keep methods in prototypes, as well. (Array、Date、Function和其他内置对象也在原型中保留方法。)
For example, if you create an array [‘a’, ‘b’, ‘c’], the default new Array() constructor is implemented internally. Hence, Array.prototype grows into its prototype providing methods. It is quite efficient for memory. There is Object.prototype on the top of overall built-in prototypes. The popular opinion that “ everything inherits from objects” comes from here. (例如,如果创建数组[‘a’, ‘b’, ‘c’] ,则默认的new Array ()构造函数在内部实现。因此, Array.prototype成长为提供方法的原型。它对记忆非常有效。在整体内置原型的顶部有Object.prototype。“一切都从物体继承”的流行观点来自这里。)
For the manual check of the prototypes, you should act like this:
let arr = ['a', 'b', 'c'];
// it inherits from Array.prototype?
console.log(arr.__proto__ === Array.prototype); // true
// then from Object.prototype?
console.log(arr.__proto__.__proto__ === Object.prototype); // true
// and null on the top.
console.log(arr.__proto__.__proto__.__proto__); // null
Part of the methods in prototype can possibly overlap. For example, the Array.prototype has its toString, which is targeted at listing comma-delimited elements, as follows:
let arr = ['a', 'b', 'c'];
console.log(arr); // a,b,c <-- the result of Array.prototype.toString
Also, the Array.prototype obtains toString, but Array.prototype is nearer in the chain. Hence, the array option is used. (此外, Array.prototype获取toString ,但Array.prototype在链中更接近。因此,使用了数组选项。)
Chrome developer console also shows inheritance. (Chrome开发者控制台也显示继承。)
Other built-in objects operate similarly. The functions, as well, are objects of a built-in Function constructor. Their methods (call , apply, and more) are taken from Function.prototype . Likewise, the functions have toString . (其他内置对象的操作类似。函数也是内置函数构造函数的对象。它们的方法(调用、应用等)取自Function.prototype。同样,函数也有toString。)
function f() {}
console.log(f.__proto__ == Function.prototype); // true
console.log(f.__proto__.__proto__ == Object.prototype); // true, inherit from objects
Primitives
Primitives (原语)
Now, let’s see what happens with strings, booleans, and numbers. As you already know, they are not objects. But when you try to access their properties, temporary wrapper objects are generated using built-in constructors, such as String, Number, and Boolean. After providing methods, they disappear. (现在,让我们看看字符串、布尔值和数字会发生什么。 如你所知,它们不是物体。 但是,当您尝试访问其属性时,会使用内置构造函数(如String、Number和Boolean )生成临时包装器对象。 提供方法后,它们消失了。)
They are created out of your sight, and most of the engines optimize them out. Their methods, as well, reside in prototypes, available as Number.prototype, String.prototype, and Boolean.prototype. (它们是在您视线之外创建的,大多数引擎都会优化它们。它们的方法也驻留在原型中,可用作Number.prototype、String.prototype和Boolean.prototype。)
Special values, such as null and undefined , don’t have wrappers. Therefore, methods and properties are not available to them. Neither they have matching prototypes. (特殊值(如null和undefined )没有包装器。因此,他们无法使用方法和属性。他们都没有匹配的原型。)
Modifying Native Prototypes
Modifying Native Prototypes (修改原生原型)
It is possible to modify native prototypes. Adding a method to String.prototype makes it available to all the strings. (可以修改原生原型。向String.prototype添加方法使其对所有字符串都可用。)
For instance:
String.prototype.welcome = function () {
console.log(this);
};
"Welcome to w3cdoc".welcome(); // Welcome to w3cdoc
It is essential to know that prototypes are global. Hence, there is a high possibility of getting a conflict. For example, if two libraries add a String.prototype.welcome method, one will overwrite the method of the other. So, it is not considered a good idea to modify a native prototype. (重要的是要知道原型是全球性的。因此,发生冲突的可能性很大。例如,如果两个库添加了String.prototype.welcome方法,则其中一个库将覆盖另一个库的方法。因此,修改原生原型并不是一个好主意。)
In nowadays programming, modifying native prototypes can be approved in one case. It’s polyfilling. Polyfilling is used to make a substitute for a method that exists in the JavaScript specification. But it’s not yet supported by a specific JavaScript engine. (在如今的编程中,修改原生原型可以在一种情况下获得批准。它是polyfilling。Polyfilling用于替代JavaScript规范中存在的方法。但尚未获得特定JavaScript引擎的支持。)
It is necessary to implement it manually, populating the built-in prototype with it. (有必要手动实现它,用它填充内置原型。)
Here is an example:
if (!String.prototype.repeat) {
// add it to the prototype, if there's no such method
(//如果没有这种方法,则将其添加到原型)
String.prototype.repeat = function (n) {
// repeat the string n times
(//将字符串重复n次)
//literally, the code can be a bit more complex than that ( find the full
(//从字面上看,代码可能比这复杂一点(找到完整的)
//algorithm in the specification), but even not perfect polyfill may often be
(//规范中的算法) ,但即使不是完美的polyfill也可能经常)
//considered fine
(//被认为是罚款)
return new Array(n + 1).join(this);
};
}
console.log("Ha".repeat(2)); // HaHa
Borrowing from Prototypes
Borrowing from Prototypes (从原型借用)
We have already spoken about method borrowing in the chapter Decorators and Forwarding, Call/Apply. (我们已经在“Decorators and Forwarding, Call/Apply”一章中谈到了方法借用。)
It’s when one takes a method from an object and copies it into another. Often some of the native prototypes’ methods are borrowed. For example, if you are creating an array-like object, you may need to copy several Array methods to it:
let obj = {
0: "Welcome",
1: "w3cdoc!",
length: 2,
};
obj.join = Array.prototype.join;
console.log(obj.join(' to ')); // Welcome to w3cdoc!
Another way of inheriting is to set obj.proto to Array.prototype . Thus, all array methods can be automatically available in obj . But that is impossible when obj inherits from another one. Note that you can inherit from one object only once. (另一种继承方式是将obj.__proto__设置为Array.prototype。因此,所有数组方法都可以在obj中自动使用。但是,当obj从另一个继承时,这是不可能的。请注意,只能从一个对象继承一次。)
Borrowing methods allow the mixing of functionalities from different objects. (借用方法允许混合来自不同对象的功能。)