ECMAScript, being a highly abstract object-oriented programming language, operates on objects. There are also primitives, but they, when required, are also converted into objects. An object is a collection of properties that also has a prototype object associated with it. The prototype is either an object, or null.In JavaScript, there are no familiar classes, but there are constructor functions that spawn objects according to certain algorithms (see Operator new).
var Grandfather = function () {}; // Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; // Father Father.prototype = new Grandfather(); // , var Son = function () {}; // Son Son.prototype = new Father(); // var u = new Grandfather(); // "" Grandfather var f = new Father(); // "" Father var s = new Son(); // "" Son // console.log([u.color, f.color, s.color]); // ["green", "green", "green"] // Grandfather.prototype.color = 'blue'; console.log([u.color, f.color, s.color]); // ["blue", "blue", "blue"] // Father.prototype.color = 'green'; // : // Grandfather.prototype.color = 'green'; console.log([u.color, f.color, s.color]); // ["blue", "green", "green"] // Grandfather.prototype.color = 'blue'; console.log([u.color, f.color, s.color]); // ["blue", "green", "green"] // s.color = 'black'; // , console.log([u.color, f.color, s.color]); // ["blue", "green", "black"] var SonsSon = function () {}; // SonsSon SonsSon.prototype = new Son(); // var ss = new SonsSon(); // "" SonsSon // console.log([u.color, f.color, s.color, ss.color]); // ["blue", "green", "black", "green"] A prototype chain is a finite chain of objects that is used to organize inheritance and shared properties.
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined } var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = {x: 10, __proto__: Point}; // 'x' : /* px */ getProperty(p, 'x'); // 10 // 'y' __proto__ - Point /* py */ getProperty(p, 'y'); // 0 // print __proto__ - Point /* p.print() */ getProperty(p, 'print').call(p); // 10 0 Why I used call , but did not call the received function directly, is described below.Point has another property, yes, this is our reference to the prototype of the parent __proto__ , which in the case of Point points to Object.prototype . /* SonsSon <- Son <---- Father <- Grandfather <-- Object <-- null */ console.log(ss.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ === null); function Point(x, y) { // Point this.x = x; this.y = y; } Point.prototype = { // print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); // p.print(); // 10 20 new F(arguments...) ) and performs the following actions:__proto__ property that refers to F.prototypeF constructor in which this is the previously created objectNew function that emulates the behavior of the new operator: function New (F, args) { /*1*/ var n = {'__proto__': F.prototype}; /*2*/ F.apply(n, args); /*3*/ return n; } function Point(x, y) { // Point this.x = x; this.y = y; } Point.prototype = { // print: function () { console.log(this.x, this.y); } }; var p1 = new Point(10, 20); p1.print(); // 10 20 console.log(p1 instanceof Point); // true // : var p2 = New(Point, [10, 20]); p2.print(); // 10 20 console.log(p2 instanceof Point); // true Father.prototype = new Grandfather() : var Grandfather = function () {}; // Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; // Father Father.prototype = new Grandfather(); // , var Son = function () {}; // Son Son.prototype = new Father(); // new Grandfather() : Father.prototype = { __proto__: { // Grandfather color: 'green', __proto__: Object.prototype } }; new Father() we get the following object (we will immediately expand the object): Son.prototype = { __proto__: { // Father __proto__: { // Grandfather color: 'green', __proto__: Object.prototype } } } { color: 'black', // __proto__: { // Son __proto__: { // Father color: 'green', // __proto__: { // Grandfather color: 'blue', // __proto__: Object.prototype } } } } Father.prototype = new Grandfather() not the best way to build a chain of prototypes?Grandfather constructor, which can mix extra properties and call extra methods, for example alert . To work around this problem, use the fake constructor: function inherit (object, parent) { function F(){}; // F.prototype = parent.prototype; // object.prototype = new F(); // return object; // }; var Grandfather = function () {}; // Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; // Father inherit(Father, Grandfather); // Grandfather Designer will not be executed. If we all need to do the Grandfather constructor, then call it using call or appy. var Father = function () { // Father Grandfather.call(this); }; if (p instanceof Point) { // ... } instanceof operator is very closely related to chained prototypes. It uses exactly the prototype chain for rendering a verdict, and does not check whether the given object “p” is generated by the “Point” constructor. In this moment there is often confusion.instanceof operator operates on two objects — obj and constructor: ( obj instanceof constructor ). Starting from constructor.prototype, it runs through a chain of prototypes and tests the following equality obj.__proto__ === constructor.prototype , if it is true, then it returns true. function isInstanceOf(obj, constructor) { if (obj.__proto__ === constructor.prototype) return true; else if (obj.__proto__ !== null) return isInstanceOf(obj.__proto__, constructor) else return false } function Point(x, y) { // Point this.x = x; this.y = y; } Point.prototype = { // print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); // /* {} instanceof Object */ console.log(isInstanceOf({}, Object)); // true /* p instanceof Point */ console.log(isInstanceOf(p, Point)); // true /* p instanceof Object */ console.log(isInstanceOf(p, Object)); // true , Object (Point.__proto__ === Object.prototype) /* p instanceof Array */ console.log(isInstanceOf(p, Array)); // false , Array Many are used to the fact that the this keyword in programming languages ​​is closely related to object-oriented programming, that is, it points to the current object generated by the constructor. In ECMAScript, this is not limited to the definition of the object being spawned.In JavaScript, the value of this is determined by the caller on the form of the call. The rule that determines what will be in this is (I will explain in simple terms):
new, call, apply, bind, with, try catch ), then the value of this will be the object that stands before the point to the left of the method name. var foo = { bar: function () { console.log(this); } }; var bar = foo.bar; bar(); // this === global (2) foo.bar(); // this === foo (1) (foo.bar)(); // this === foo (1) // - (foo.bar = foo.bar)(); // this === global (3) (false || foo.bar)(); // this === global (3) (foo.bar, foo.bar)(); // this === global (3) function foo() { function bar() { console.log(this); } bar(); // this === global (2) } getProperty(p, 'print').call(p) because of this rule I manually specified the value of this. Otherwise, the print function would receive as this - window.this: new, call, apply, bind, with, try catch (everything is more or less clear with them, I will not touch it).Source: https://habr.com/ru/post/120193/
All Articles