Understanding the __extends function generated by typescript?

I am playing with Typescript and trying to understand the compiled Javascript code generated by the compiler

Typewriter Code:

class A { }
class B extends A { }

Generated Javascript Code:

var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var A = /** @class */ (function () {
    function A() {
    }
    return A;
}());
var B = /** @class */ (function (_super) {
    __extends(B, _super);
    function B() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    return B;
}(A));

The inheritance of Javascript according to the Mozilla Docs is as follows:

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

The parts that I do not understand in the generated Typescript code are

1. What is the purpose of this line? Looks like he is copying all keys A to B? Is this a bit of a hack for static properties?

var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };

2. What does it do?

function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());

I do not understand this part: (__.prototype = b.prototype, new __())

Why does function B () return this?

return _super !== null && _super.apply(this, arguments) || this;

If someone could explain this to me line by line, I would be grateful.

+9
source share
2

, :

__extends - , - , , .

1:

, - , , , , false:

// value1 is a function with the definition function() {}
var value1 = true && true && function() {};

// value2 is false
var value2 = true  && false && function() {};

// value3 is true
var value3 = true && function() {} && true;

, , , javascript, __extends.

2: d (, ) b (, ) , .

3:

prototype -, ( , new <function name>()).

new , [[PROTOTYPE]] aka __proto__ .

function Person() {  
}

// Construct new object 
var p = new Person();

// true
console.log(p.__proto__ === Person.prototype);

// true
console.log(Person.prototype.__proto__ === Object.prototype);

. .

,

var o = {};

// true    
console.log(o.__proto__ === Object.prototype);

__proto__ Object.prototype ( ).

__prototype__ , Object.create.

, [[PROTOTYPE]]. , TH. , -, Object.prototype. , .

4 Javascript " ".

function Girl() {  
}

Girl.prototype = Object.create(Person.prototype);

// true
console.log(Girl.prototype.__proto__ === Person.prototype);

// true
console.log(Girl.constructor === Function);

// Best practices say reset the constructor to be itself
Girl.constructor = Girl;

// points to Girl function
console.log(Girl.constructor);

, Girl, Person Function.

: http://jsbin.com/dutojo/1/edit?js,console

:

var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();

:

var __extends = (this && this.__extends) || (function () {
   // gobbledygook
})();

1 , ( ) __extends, .

(this && this.__extends) 

, 1. .__ extends , __extends . , , || iife ( ).

gobbledygook, __extends:

var extendStatics = Object.setPrototypeOf ||

extendedStatics Object.setPrototypeOf , (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf)

({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };

3 __proto__ [[PROTOTYPE]] .

{ __proto__: [] } instanceof Array

- , , , __proto__, , Array.

1 , instanceof javascript true false (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof), , , extendsStatics

function (d, b) { d.__proto__ = b; })

, extensionStatics :

function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }

, __proto__ ECMAScript, ECMAScript 2015 (, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) ). , __proto__, " " , b d .

, exteStatics, , , exteStatics ( ). , 'd' (), 'b' ( ):

return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };

extendedStatics, (d) (b) (, 3 ):

extendStatics(d, b);

__, (d):

function __() { this.constructor = d; }

base (b) constructor null, , prototype.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor, Object.prototype.constructor ( javascript):

Object . , , , .

. , ( ) , .

, constructor '__' , .

:

d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());

prototype (d) , constructor

//  b is null here so creates {}
Object.create(b)

__ constructor prototype prototype, __(), constructor .

(__.prototype = b.prototype, new __()

, , .

B() ?

return _super !== null && _super.apply(this, arguments) || this;

: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

apply() this, ( , ).

, B - , B.

Person ( ), , Girl ( ) .

// Base constructor function
function Person(n) {
  // Set parameter n to the name property of a Person
  this.name = n;
}

function Girl() {
   // Call the Person function with same arguments passed to new Girl
   Person.apply(this, arguments);
   // Set it so all Girl objects created inherit properties and methods from Person
   Girl.prototype = Object.create(Person.prototype);  
   // Make sure the constructor is not set to Person
   Girl.prototype.constructor =  Girl;
}

var p = new Person("Sally");
var g = new Girl("Trudy");
console.log(p.name);
console.log(g.name);
+11

, TypeScript. , , , .

  • - 'setPrototypeOf'

TypeScript __extends :

// refactored version of __extends for better readability

if(!(this && this.__extends))                      // skip if already exists
{
  var __extends = function(derived_cl, base_cl)    // main function
  {
    // find browser compatible substitute for implementing 'setPrototypeOf'

    if(Object.setPrototypeOf)                      // first try
      Object.setPrototypeOf(derived_cl, base_cl);
    else if ({ __proto__: [] } instanceof Array)   // second try
      derived_cl.__proto__ = base_cl;
    else                                           // third try
      for (var p in base_cl)
        if (base_cl.hasOwnProperty(p)) derived_cl[p] = derived_cl[p];

    // construct the derived class

    if(base_cl === null)
      Object.create(base_cl)                 // create empty base class if null
    else
    {
      var deriver = function(){}             // prepare derived object
      deriver.constructor = derived_cl;      // get constructor from derived class
      deriver.prototype = base_cl.prototype; // get prototype from base class
      derived_cl.prototype = new deriver();  // construct the derived class
    }
  }
}

, , , , "" . , , TypeScript.

// Barebone version of __extends for best comprehension

var __extends = function(derived_cl,base_cl)
{
  Object.setPrototypeOf(derived_cl,base_cl);
  var deriver = function(){}             // prepare derived object
  deriver.constructor = derived_cl;      // get constructor from derived class
  deriver.prototype = base_cl.prototype; // get prototype from base class
  derived_cl.prototype = new deriver();  // construct derived class
}

:

var __extends = function(derived_cl,base_cl)
{
  Object.setPrototypeOf(derived_cl,base_cl);
  var deriver = function(){}		 // prepare derived object
  deriver.constructor = derived_cl;	 // get constructor from derived class
  deriver.prototype = base_cl.prototype; // get prototype from base class
  derived_cl.prototype = new deriver();  // construct derived class
}

// define the base class, and another class that is derived from base

var Base = function()
{
  this.method1 = function() { return "replace the batteries" }
  this.method2 = function() { return "recharge the batteries" }
}

var Derived = function(_super) {
  function Derived() {
    __extends(this, _super); _super.apply(this, arguments);

    this.method3 = function() { return "reverse the batteries" }
    this.method4 = function() { return "read the damn manual" }
  }
  return Derived
}(Base)

// Let do some testing: create the objects and call their methods

var oBase = new Base();             // create the base object
var oDerived = new Derived();       // create the derived object

console.log(oDerived.method2());    // result: 'recharge the batteries'
console.log(oDerived.method4());    // result: 'read the damn manual'

console.log(oBase.method1()) ;      // result: 'replace the batteries'
try{ console.log(oBase.method3()) }
catch(e) {console.log(e.message)};  // result: 'oBase.method3 is not a function'
Hide result

, TypeScript, , __extend , JavaScript 'apply' , .

... , - ?

// Short, readable, explainable, understandable, ...
// probably a 'best practice' for JavaScript inheritance !

var Base = function()
{
  this.method1 = function() { return "replace the batteries" }
  this.method2 = function() { return "recharge the batteries" }
}

var Derived = function(){
    Base.apply(this, arguments);  // Here we inherit all methods from Base!
    this.method3 = function() { return "reverse the batteries" }
    this.method4 = function() { return "read the damn manual" }
}

var oDerived = new Derived();       // create the derived object
console.log(oDerived.method2());    // result: 'recharge the batteries'
Hide result

0

Source: https://habr.com/ru/post/1684724/


All Articles