理解typescript生成的__extends函数? [英] Understanding the __extends function generated by typescript?

查看:189
本文介绍了理解typescript生成的__extends函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

Typescript代码:

Typescript code:

class A { }
class B extends A { }

生成的Javascript代码:

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));

按照 Mozilla docs 就是这样:

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

我在Typescript生成的代码中不理解的部分是这个

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

1。这条线的目的是什么?看起来它正在将A的所有键复制到B中?这是静态属性的某种破解吗?

1. What is the purpose of this line? Looks like it is copying all the keys of A into B? Is this some sort 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。这是做什么的?

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

我不明白这一部分:(__。prototype = b。原型,新__())

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

Why does function B() return this?

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

如果有人可以逐行向我解释,我将不胜感激。

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

推荐答案

我自己很好奇,无法找到快速答案所以这是我的细分:

I was curious about this myself and couldn't find a quick answer so here is my breakdown:

它做什么

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

__extends is a function that simulates single class inheritance in object oriented languages and returns a new constructor function for a derived function that can create objects that inherit from a base object.

注1:

我自己并没有真正意识到这一点,但是如果你做了类似下面的事情,其中​​所有值都是真实的,那么变量被设置为被测试的最后一个项目的值,除非一个是假的在这种情况下,变量设置为false:

I wasn't actually aware of this myself but if you do something like the following where all of the values are truthy the variable is set to the value of last item being tested unless one is falsy in which case the variable is set to 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 函数定义中使用了几次。

I mention this because this is the thing that confused me the most when I saw this javascript and it is used a couple of times in the __extends function defintion.

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

Note 2: Parameter d (probably stands for derived) and b (probably stands for base) are both constructor functions and not instance objects.

注3:

prototype 是函数的一个属性,它是'constructor'函数使用的原型对象(即使用的对象创建的对象) new< function name>())。

prototype is a property of a function and it is a prototype object used by 'constructor' functions (i.e. objects created by using new <function name>()).

使用 new 运算符构造新对象时,新对象的内部 [[PROTOTYPE]] aka __ proto __ 被设置为函数的原型属性。

When you use the new operator to construct a new object, the new object's internal [[PROTOTYPE]] aka __proto__ is set to be the function's prototype property.

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 (内置的Object构造函数)。

the new object's __proto__ is set to Object.prototype (the built-in Object constructor function).

你可以设置一个对象的 __ prototype __ 到另一个对象但是使用 Object.create

You can set an object's __prototype__ to another object however using Object.create.

当在当前对象上找不到属性或方法时,检查对象的 [[PROTOTYPE]] 。如果未找到,则检查该对象的原型。因此它会检查原型,直到它到达最终的原型对象 Object.prototype 。请记住,没有任何内容是副本。

When a property or method isn't found on the current object the object's [[PROTOTYPE]] is checked. If it isn't found then THAT object's prototype is checked. And so it goes checking prototypes until it reaches the final prototype object, Object.prototype. Keep in mind nothing is a copy.

注4
在Javascript中模拟继承时,构造函数函数的原型设置为。

Note 4 When simulating inheritance in Javascript the 'constructor' functions' prototypes are set.

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的构造函数指向内置的功能

Notice how we point the constructor to Girl because it Person's constructor points to the built-in Function.

您可以在以下位置看到上面的代码: http://jsbin.com/dutojo/1/edit?js,console

You can see the code above in action at: 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 的变量,其目的是持有一个函数来设置派生类的原型。

Keeping my Note 1 above in mind, this first part (and end) is creating a variable called __extends that has the intention of holding a function to set the prototype of the derived class.

(this && this.__extends) 

正在做我的注1 解释。如果这个是真的并且这个.__ extends 是真实的,那么变量 __ extends 已经存在,因此设置为它自己的现有实例。如果没有,则设置为||之后的内容这是一个生命(立即调用函数表达式)。

is doing what my Note 1 explains. If this is truthy and this.__extends is truthy then the variable __extends is already exists and so set to the existing instance of itself. If not it is set to what comes after the || which is an iife (immediately invoked function expression).

现在gobbledygook是 __ extends 的实际定义:

Now for the gobbledygook which is the actual definition of __extends:

var extendStatics = Object.setPrototypeOf ||

名为 extendStatics 的变量设置为内置的Object.setPrototypeOf运行脚本的环境的功能( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf

A variable named extendStatics is set to either the built in Object.setPrototypeOf function of the environment that the script is running in (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 __ aka [[PROTOTYPE]] 以及如何设置。代码

In Note 3 I discussed __proto__ aka [[PROTOTYPE]] and how it could be set. The code

{ __proto__: [] } instanceof Array

是一个测试,用于确定当前环境是否允许通过将文字对象的 __ proto __ 设置为文字数组来设置此属性使用Array内置函数。

is a test to determine whether the current environment allows setting this property by comparing a literal object's __proto__ set to a literal array with the Array built-in function.

从上面回到我的 Note 1 ,并记住javascript instanceof运算符返回true或false( https://developer.mozilla.org/en -US / docs / Web / JavaScript / Reference / Operators / instanceof )如果环境评估一个对象,其prototype属性设置为内置数组,则 extendsStatics 设置为

Referring back to my Note 1 from above and keeping in mind that the javascript instanceof operator returns true or false (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) if the environment evaluates an an object with its prototype property set to the built in Array then extendsStatics is set to

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

如果环境没有这样评估,那么extendStatics设置为:

If the environment doesn't evaluate it that way then extendStatics is set to this:

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

这样做是因为 __ proto __ 从未直到ECMAScript 2015的官方ECMAScript标准的一部分(并根据 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto )仅用于向后兼容)。如果支持,则使用 __ proto __ 函数,否则它使用'roll your own'版本',它从对象b到d执行用户定义属性的复制。

It does this because __proto__ was never part of the official ECMAScript standard until ECMAScript 2015 (and according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) is there only for backwards compatibility). If it is supported the __proto__ function is used or else it uses the 'roll your own' version' which does a copy from object b to d for user defined properties.

现在定义了 extendStatics 函数变量,一个调用 extendStatics 内部的函数的函数(以及其他一些东西) )被退回。请注意,参数d是子类(继承的子类),b是超类(继承自的类):

Now that the extendStatics function variable defined, a function that calls whatever is inside extendStatics (as well as some other stuff) is returned. Note that parameter 'd' is the sub-class (the one inheriting) and 'b' is the super-class (the one being inherited from):

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

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

Breaking it down extendStatics is called and the first parameter object (d) has its prototype set to be (b) (recall Note 3 above):

extendStatics(d, b);

在下一行中,声明了一个名为'__'的构造函数,它将其构造函数指定为派生函数(d)构造函数:

In the next line a constructor function named '__' is declared that assigns its constructor to be the derived (d) constructor function:

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

如果基数(b)构造函数函数碰巧为null,这将确保派生将保留自己的原型

if the base (b) constructor function happens to be null this will make sure that the derived will keep its own prototype.

来自 https://developer.mozilla.org/en-US/ docs / Web / JavaScript / Reference / Global_Objects / Object / constructor ,Object.prototype.constructor(所有对象都是javascript中的对象):

From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor, the Object.prototype.constructor (all objects are Objects in javascript):


返回对Object构造函数的引用,该函数创建
实例对象。请注意,此属性的值是对函数本身的
引用,而不是包含
函数名称的字符串。

Returns a reference to the Object constructor function that created the instance object. Note that the value of this property is a reference to the function itself, not a string containing the function's name.


所有对象都有一个构造函数属性。在没有
的情况下创建的对象显式使用构造函数(即对象和数组
literals)将具有一个构造函数属性,该属性指向该对象的
Fundamental Object构造函数类型。

All objects will have a constructor property. Objects created without the explicit use of a constructor function (i.e. the object and array literals) will have a constructor property that points to the Fundamental Object constructor type for that object.

所以如果构造函数函数'__'是新的,就像它会创建的那样派生对象。

So if constructor function '__' was new'd up as is it would create a derived object.

最后有这一行:

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

设置派生的原型( d)如果基本构造函数函数恰好为null,则为新的空对象

which sets the prototype of the derived (d) to be a new empty object if the base constructor function happens to be null

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

OR

设置__ 构造函数函数的原型成为基类 prototype ,然后调用__(),其效果是将派生函数构造函数设置为是派生函数。

sets the __ constructor function's prototype to be the base class prototype and then calls __() which has the effect of setting the derived functions constructor to be the derived function.

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

因此,返回的最终函数基本上创建了一个派生的构造函数,该函数原型继承自基础构造函数。

So basically the final function returned creates a derived constructor function that prototypically inherits from the base constructor function.

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

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

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


apply()方法调用具有给定值的函数,并将
参数作为数组(或类数组对象)提供。

The apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

记住B是一个构造函数,它是B定义中返回的函数。

Remember B is a constructor function and that is what is being returned in B's definition.

如果你有一个Person类(构造函数)函数)接受构造函数中的name参数,然后可以使用girls name作为参数调用派生的Girl类(构造函数)。

If you had a Person class (constructor function) that accepted a name parameter in the constructor function you could then call a derived Girl class (constructor function) with the girls name as a parameter.

// 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);

这篇关于理解typescript生成的__extends函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆