Javascript 理解typescript生成的_扩展函数?

Javascript 理解typescript生成的_扩展函数?,javascript,prototype,javascript-objects,proto,javascript-inheritance,Javascript,Prototype,Javascript Objects,Proto,Javascript Inheritance,我正在玩并试图理解编译器生成的已编译Javascript代码 打字脚本代码: class A { } class B extends A { } var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && funct

我正在玩并试图理解编译器生成的已编译Javascript代码

打字脚本代码:

class A { }
class B extends A { }
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));
生成的Javascript代码:

class A { }
class B extends A { }
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));
根据的Javascript继承如下所示:

在Typescript生成的代码中,我不理解的部分如下

一,。这条路线的目的是什么?看起来它正在将A的所有键复制到B中?这是对静态属性的一种攻击吗

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]; };
二,。这是干什么的

function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
我不明白这一部分:
(\uuuuu.prototype=b.prototype,new())

为什么函数B()返回这个值

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

如果有人能逐行向我解释这一点,我将不胜感激。

我自己也对这一点很好奇,但找不到快速的答案,所以这里是我的分类:

它的作用

__extends是一个函数,它模拟面向对象语言中的单类继承,并为派生函数返回一个新的构造函数,该派生函数可以创建从基对象继承的对象

注1:

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
})();
我自己并没有意识到这一点,但是如果你做了如下的事情,其中所有的值都是真的,那么变量就被设置为最后一个测试项目的值,除非其中一个是假的,在这种情况下,变量被设置为假的:

// 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时,这是最让我困惑的事情,它在扩展函数定义中被使用了好几次

注2: 参数d(可能代表派生)和b(可能代表基)都是构造函数,而不是实例对象

注3:

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
})();
prototype
是函数的属性,是“构造函数”函数使用的原型对象(即使用
new()
创建的对象)

使用
new
操作符构造新对象时,新对象的内部
[[PROTOTYPE]]
aka
\uuuu proto\uuu
设置为函数的PROTOTYPE属性

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);
新对象的
\uuu proto\uu
设置为
对象.prototype
(内置对象构造函数)

您可以使用
object.create
将对象的
原型设置为另一个对象

当在当前对象上找不到属性或方法时,将检查对象的
[[PROTOTYPE]]
。如果找不到,则检查该对象的原型。所以它会检查原型,直到它到达最终的原型对象,
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,因为it Person的构造函数指向内置的
函数

您可以在以下位置查看上面的代码:

原件:

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
})();
故障:

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,第一部分(和结尾)创建了一个名为u_extends的变量,其目的是保存一个函数来设置派生类的原型

(this && this.__extends) 
正在做我的注释1解释的事情。如果这是真的,而这是真的,那么变量uu extends已经存在,因此设置为自身的现有实例。如果不是,则设置为| |之后的内容,这是一个iife(立即调用的函数表达式)

现在对于gobbledygook,它是uu的实际定义扩展:

名为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]; };
在注释3中,我讨论了
\uuu proto\uuu
aka
[[PROTOTYPE]]]
以及如何设置它。代码

{ __proto__: [] } instanceof Array
是一种测试,通过将文字对象的
\uuuuu proto\uuu
集与文字数组与数组内置函数进行比较,确定当前环境是否允许设置此属性

(__.prototype = b.prototype, new __()
回到我上面的注释1,请记住javascript instanceof操作符返回true或false(),如果环境对一个对象进行求值,并将其prototype属性设置为内置数组,那么ExtendStatics将设置为

function (d, b) { d.__proto__ = b; })
如果环境没有以这种方式进行评估,则extendStatics设置为:

function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }
之所以这样做,是因为在ECMAScript 2015(以及根据)之前,
\uuuuuuu proto\uuuuuu
从来都不是官方ECMAScript标准的一部分,只是为了向后兼容)。如果受支持,则使用
\uuuu proto\uuu
函数,或者使用“滚动您自己的”版本,该版本将用户定义的属性从对象b复制到对象d

现在已经定义了extendStatics函数变量,将返回一个调用extendStatics内部任何内容(以及其他内容)的函数。请注意,参数“d”是子类(继承的)而“b”是超类(继承的):

调用extendStatics将其分解,第一个参数对象(d)的原型设置为(b)(回想上文注释3):

在下一行中,将声明一个名为“_u”的构造函数,该构造函数将其构造函数指定为派生(d)构造函数:

function __() { this.constructor = d; }
如果基本(b)
构造函数
函数恰好为空,这将确保派生的构造函数将保留其自己的
原型

从,Object.prototype.constructor(所有对象都是javascript中的对象):

返回对创建的对象构造函数的引用 实例对象。请注意,此属性的值是 引用函数本身,而不是字符串
// 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
    }
  }
}
// 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
}