皮皮网
皮皮网

【日内指标源码】【网络留言系统源码】【易语言 传奇源码】原型继承源码

时间:2024-12-28 18:22:01 来源:西城阁源码

1.prototype的含义
2.js原生语法之prototype,原型源码__proto__和constructor
3.请问babel能将es5转成es6吗?

原型继承源码

prototype的含义

       æˆ‘们知道JScript中对象的prototype属性,是用来返回对象类型原型的引用的。我们使用prototype属性提供对象的类的一组基本功能。并且对象的新实例会"继承"赋予该对象原型的操作。但是这个prototype到底是怎么实现和被管理的呢?

       å¯¹äºŽå¯¹è±¡çš„prototype属性的说明,JScript手册上如是说:所有 JScript 内部对象都有只读的 prototype 属性。可以向其原型中动态添加功能(属性和方法),但该对象不能被赋予不同的原型。然而,用户定义的对象可以被赋给新的原型。

       ä¸‹é¢æˆ‘们看三个经典的prototype属性的使用示例。

       1、为脚本环境内建对象添加方法:

       ç¨‹åºä»£ç 

       Array.prototype.max = function()

       {

       var i, max = this[0];

       for (i = 1; i < this.length; i++)

       {

       if (max < this[i])

       max = this[i];

       }

       return max;

       };

       2、为用户自定义类添加方法:

       ç¨‹åºä»£ç 

       function TestObject(name)

       {

       this.m_Name = name;

       }

       TestObject.prototype.ShowName = function()

       {

       alert(this.m_Name);

       };

       3、更新自定义类的prototype:

       ç¨‹åºä»£ç 

       function TestObjectA()

       {

       this.MethodA = function()

       {

       alert('TestObjectA.MethodA()');

       }

       }

       function TestObjectB()

       {

       this.MethodB = function()

       {

       alert('TestObjectB.MethodB()');

       }

       }

       TestObjectB.prototype = new TestObjectA();

       ç¬¬ä¸‰ä¸ªå¾ˆçœ¼ç†Ÿå§ï¼Ÿå¯¹å•Šï¼Œå®ƒå°±æ˜¯æˆ‘们前面介绍的原型继承法呀~~ 不过今天我们不是研究"继承",之所以可以这样来实现一种继承,只是利用了prototype属性的一个副作用而已。

       prototype还有一个默认的属性:constructor,是用来表示创建对象的函数的(即我们OOP里说的构造函数)。constructor属性是所有具有prototype属性的对象的成员。它们包括除Global和Math对象以外的所有JScript内部对象。constructor属性保存了对构造特定对象实例的函数的引用。

       å¼„清楚了JScript中prototype属性怎么使用后,下面我们再来深入的研究它。

       ä¸Šé¢çš„文章中我罗列了一下prototype属性在JScript中的各种用法,但是prototype这个东西却不是JScript创造出来的,JScript实际上是使用了我们设计模式中prototype pattern的一种衍生形式。下面我先简单的说一下prototype pattern,然后再来看到底JScript中的prototype是怎么回事?!

       What's prototype pattern?

       Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

       ç”¨åŽŸåž‹å®žä¾‹æŒ‡å®šåˆ›å»ºå¯¹è±¡çš„种类,并且通过拷贝这些原型创建新的对象。

       åŽŸåž‹æ¨¡å¼å…è®¸ä¸€ä¸ªå¯¹è±¡å†åˆ›å»ºå¦å¤–一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

       ç»§ç»­äº†è§£åˆ°åº•ä»€ä¹ˆæ˜¯prototype pattern,可以参看'设计模式之Prototype(原型)'这篇文章,即使不懂Java也没有关系,把它的代码都当C#看就行了。

       æžæ¸…楚什么是原型了吧?反正记着一点,prototype pattern是的实现是依赖于clone这个操作的,当然要shallow copy还是deep copy的clone看自己的需要了。

       ä¸‹é¢æˆ‘们继续说JScript里的prototype,为什么我们说它和prototype pattern里的prototype不一样呢?! 这个不是我说就说出来的,也不是我吹出来的,看看这个示例,你就能大概糊涂:

       ç¨‹åºä»£ç 

       <script language="javascript">

       function RP()

       {

       RP.PropertyA = 1;

       RP.MethodA = function()

       {

       alert("RP.MethodA ");

       };

       this.PropertyA = ;

       this.MethodA = function()

       {

       alert("this.MethodA");

       };

       }

       RP.prototype.PropertyA = ;

       RP.prototype.MethodA = function()

       {

       alert("RP.prototype.MethodA");

       };

       </script>

       ä¸è¦ç€æ€¥ï¼Œè¿˜æ²¡æœ‰å¼€å§‹åšç¤ºä¾‹ï¼Œåªæ˜¯ç»™å‡ºäº†æˆ‘们用来演示的一个类。RP是什么?rpwt吗?当然不是了,RP是ResearchPrototype了。好了不废话了,看示例及结果分析。

       ç¨‹åºä»£ç 

       <script language="javascript">

       rp = new RP();

       alert(RP.PropertyA);

       RP.MethodA();

       alert(rp.PropertyA);

       rp.MethodA();

       </script>

       è¿è¡Œç»“果闪亮登场:

       1

       RP.MethodA

       

       this.MethodA

       è¿™ä¸ª%$@#^$%&^...,不要着急,继续看哦!

       ç¨‹åºä»£ç 

       <script language="javascript">

       rp = new RP();

       delete RP.PropertyA;

       alert(RP.PropertyA);

       delete RP.MethodA;

       RP.MethodA();

       delete rp.PropertyA;

       alert(rp.PropertyA);

       delete rp.MethodA;

       rp.MethodA();

       </script>

       è¿è¡Œç»“果再次登场:

       ç¨‹åºä»£ç 

       undefined

       A Runtime Error has occurred.

       Do you wish to Debug?

       Line:

       Error: Object doesn't support this property or method

       

       RP.prototype.MethodA

       å¥½çŽ©å§ï¼Œçœ‹å‡ºæ¥ä»€ä¹ˆåå ‚了吗?这里的RP.PropertyA和RP.MethodA只是用来做参照的,可是怎么把this.PropertyA和this.MethodA都delete了,还能出来结果,而且还是prototype导入的属性和方法呢?

       è¿™å°±æ˜¯JScript的prototype和prototype pattern中prototype最大的不同了,JScript中的这个所谓的prototype属性其实是个语言本身支持的特性,这里没有发生任何的copy,不管shallow还是deep的。对于JScript的解释引擎,它在处理"."或"[keyName]"引用的对象的属性和方法时,先在对象本身的实例(this)中查找,如果找到就返回或执行。如果没有查找到,就查找对象的prototype(this.constructor.prototype)里是否定义了被查找的对象和方法,如果找到就返回或执行,如果没有查找到,就返回undefined(对于属性)或runtime error(对于方法)。

       æ­£å› ä¸ºprototype导入类实例的属性或方法是动态查找的,所以我们才能对系统内部对象添加prototype属性和方法,比如给String对象添加trim方法:

       ç¨‹åºä»£ç 

       <script lanuage="javascript">

       String.prototype.trim()

       {

       return this.replace(/(^\s+)|(\s+$)/g, "");

       }

       </scritp>

       æ˜¾ç„¶JScript中的这种用法也是prototype pattern中的prototype不能解释和支持的。

       è¿™ä¸‹å¯¹äºŽJScript OOP中原型继承法的理解因该没有任何的障碍了吧?同时也应该明白为什么原型继承法有那么大的天生缺陷了吧?当然如果有任何问题,欢迎继续讨论。

       é™„演示示例源代码:

       ç¨‹åºä»£ç 

       <html>

       <head>

       <meta name="author" content="birdshome@博客园">

       <title>JScript Prototype Research</title>

       </head>

       <body>

       <script language="javascript">

       function RP()

       {

       RP.PropertyA = 1;

       RP.MethodA = function()

       {

       alert("RP.MethodA ");

       };

       this.PropertyA = ;

       this.MethodA = function()

       {

       alert("this.MethodA");

       };

       }

       RP.prototype.PropertyA = ;

       RP.prototype.MethodA = function()

       {

       alert("RP.prototype.MethodA");

       };

       </script>

       <script language="javascript">

       rp = new RP();

       delete RP.PropertyA;

       alert(RP.PropertyA);

       delete RP.MethodA;

       RP.MethodA();

       delete rp.PropertyA;

       alert(rp.PropertyA);

       delete rp.MethodA;

       rp.MethodA();

       </script>

       </body>

       </html>

js原生语法之prototype,__proto__和constructor

       1前言

       写了几篇vue的源码注释(并不算解析...),感觉到了对原型的理解是不够的,在js中,原型是非常重要的,只要你想在js这座山上往上爬,它就会嘲笑你,你把我搞会了么?如果没有,它就给你加个十倍重力.如果搞懂了,那肯定是能月薪过万,赢取白富美,走向人生巅峰的啦~~~

       这篇文章讲的都是我自己的理解,应该是原创的(我有%把握,除非是我之前看过文章记到脑子里了,没法给到引用了,联系我可以加上),但是如果有人借鉴我的这篇文章,希望给到一个这篇文章的链接.其实我只是想我的文章能有更多的阅读量,我想月薪过万,赢取白富美,走向人生巅峰~~~

2前置知识点2.1数据类型

       js共有7种数据类型

       从可不可以读取属性,可以分为两类

       可以读取属性:

       自身可以有属性:object

       自身不可以有属性:string,number,boolean,symbol

       不可以读取属性:null,undefined

       null,undefined类型,读取和设置属性都是非法的,直接报错.

       只有object能有自有属性,可以读取属性和设置属性

       string,number,boolean,symbol类型可以读取属性,其实是先构造成包装对象,再读取属性,设置属性也是一样,可以理解设置到了会立即销毁的包装对象上,就是可以设置,但是没有任何实质效果.

2.2判断是否是自身属性(hasOwnProperty)

       hasOwnProperty方法是继承来的,用来判断该对象自身上是否有这个属性,有就行,不管是什么值

constobj={ a:1}consto=Object.create(obj)o.b=1o.c=void0console.log('a',o.a,o.hasOwnProperty('a'))//可以读取到值,继承而来,但不是自身属性console.log('b',o.b,o.hasOwnProperty('b'))//可以读取到值,自身属性console.log('c',o.c,o.hasOwnProperty('c'))//读取到undefined,自身属性console.log('d',o.d,o.hasOwnProperty('d'))//读取到undefined,不是自身属性,也没有继承到这个属性3一点小思考

       程序就是数据结构与算法,好的程序最好是使用最小的内存存储数据,使用最快的时间完成运行得到结果.

       复用数据可以达到减少内存使用的目的,例如a和b需要完成一样的功能,就可以复用同一个方法(属性).

       那么就需要解决一个问题,这个复用的方法存在哪里,a和b怎样能找到它.

       在js中的解决方案是,a和b都由函数(这里先叫Function吧)构造而来,复用的方法存放在函数身上(prototype属性里).

       (因为只有构造函数身上需要存放复用的方法,所以prototype只有可构造的函数上才有,箭头函数不是用来构造的,它就没有,其它对象,如果连函数都不是,就更不会有这个属性了)

       那么需要给a,b和Function建立起联系,因为a,b需要到Function身上找它们可以用的复用方法

       在js中的实现是通过constructor属性,即a.constructor,b.constructor可以找到Function

       所以通过a.constructor.prototype可以找到它可以复用的方法的存放地址,为了快速找到js提供了一种快捷方法a.__proto__一步到位找到,即a.constructor.prototype和a.__proto__找到的是同一个对象,当然它俩是全等的啦.

//它俩都不是自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false

       (所以,如果手动修改了constructor,prototype,__proto__的指向,那么你得清楚你在干什么)

       (我不知道js的设计者是不是这样想的,哈哈,我就这样认为,这样好理解多了)

       (这个过程称之为继承,而且是一个链式过程,即可以a.constructor.prototype.constructor.prototype.constructor.prototype这样查找,直到找到最顶端,这个过程可以由a.__proto__.__proto__.__proto__加速,这个就叫做原型链,js的继承只有这一种实现方式.)

       (上面只是引导思考过程,其实查找原型对象并不会通过a.constructor.prototype去找,而是直接通过__proto__查找)

3.1修改constructorconstDog=function(){ }constdog=newDog()dog.constructor=0console.log(dog.hasOwnProperty('constructor'))//trueconsole.log(dog.constructor)//0console.log(dog.__proto__.constructor)//[Function:Dog]

       总结,修改了这个属性,增加了找到构造它的构造函数的难度,不能直接获取了,需要到原型对象上去读取.

       如果它自身的这个属性和原型上的这个属性都被修改了,那么也只是找不到它的构造函数了而已,不会有别的影响.

3.1.1instanceof

       instanceof关心的是原型链,跟constructor没有关系

       印证上面的点,修改constructor属性,除了让实例找不到构造它的构造函数,没有别的影响了.如果需要通过实例找到它的构造函数,就需要维护好它俩的关系.

//语法是//ainstanceofb//这个操作符是判断a的原型链上是否有b.prototype,因为要判断b.prototype所以b必需是一个可构造的函数,否则会报错constfn=function(){ }consto=Object.create(fn.prototype)//此时o的原型链上有fn.prototype,因为o.__proto__===fn.prototypeconsole.log(oinstanceoffn)//trueconstemptyObj={ }fn.prototype=emptyObj//此时o的原型链上已经没有fn.prototype了,因为此时o.__proto__已经不再和fn.prototype相等了console.log(oinstanceoffn)//falseo.__proto__=emptyObj//修正了o.__proto__就好了console.log(oinstanceoffn)//true3.1.2isPrototypeOf

       现在有个新的api,实现的功能和instanceof一致,但是更加语义化一些,直接判断对象是否在另一个对象的原型链上

constfn=function(){ }consto=Object.create(fn.prototype)console.log(fn.prototype.isPrototypeOf(o))//true3.2修改__proto__|prototype

       先说一个总结,在构造实例的时候,会将这个实例的__proto__指向此时的构造函数的prototype,然后实例实际是继承的是__proto__.(为什么强调此时,因为构造函数的prototype可能会被修改指向,修改之后只会影响修改之后构造的实例,修改之前构造的实例还会使用修改之前的prototype)

       所以,就可以理解到修改__proto__和prototype会有哪些影响了

       修改__proto__的指向

       只会影响它自己的继承

constDog=function(){ }constdog=newDog()constd=newDog()Dog.prototype.name='Dog'dog.__proto__={ name:'__proto__',}console.log(d.name)//Dogconsole.log(dog.name)//__proto__

       修改__proto__的属性

       会影响这一波段构造的实例

constDog=function(){ }constdog=newDog()constd=newDog()Dog.prototype.name='Dog'console.log(d.name)//Dogconsole.log(dog.name)//DogDog.prototype={ name:'after',}constdog1=newDog()constd1=newDog()console.log(d1.name)//afterconsole.log(dog1.name)//afterdog1.__proto__.name='__proto__'//可以看到只影响了当前这一段构造的实例,之前和之后的都不会被影响到,因为这一段内的是同一个Dog.prototype,它们的__proto__都是指向它的console.log(d1.name)//__proto__console.log(dog1.name)//__proto__Dog.prototype={ name:'new',}constdog2=newDog()constd2=newDog()console.log(d2.name)//newconsole.log(dog2.name)//new

       修改prototype的指向

       会影响这一波段构造的实例

       修改prototype的属性

       会影响这一波段构造的实例,同修改__proto__的属性

4修改和获取原型对象的方式4.1修改

       上面已经讲了修改prototype和__proto__

4.1.1Object.createconstobj={ name:'objName',}consto=Object.create(obj)//它相当于o.__proto__=obj,但是推荐使用`Object.create`console.log(o.name)//objNameconsole.log(o.__proto__===obj)//true4.1.2Object.setPrototypeOfconstobj={ name:'objName',}consto={ }Object.setPrototypeOf(o,obj)//它相当于o.__proto__=obj,但是推荐使用`Object.setPrototypeOf`constproto=Object.getPrototypeOf(o)console.log(proto===obj&&proto===o.__proto__)//trueconstobj1={ }o.__proto__=obj1constproto1=Object.getPrototypeOf(o)console.log(proto1===obj1&&proto1===o.__proto__)//true

       总结,在什么时候使用Object.create,在什么时候使用Object.setPrototypeOf呢,首先它俩都是标准api,都是建议使用的,在创建对象的时候就要指定原型时使用Object.create,需要动态修改原型对象时,使用Object.setPrototypeOf

4.2获取

       之前已经讲了,通过constructor.prototype和__proto__获取了

4.2.1Object.getPrototypeOfconstobj={ name:'objName',}consto={ }Object.setPrototypeOf(o,obj)constproto=Object.getPrototypeOf(o)console.log(proto===obj&&proto===o.__proto__)//true5js内置原生构造函数

       这些原生的构造函数的prototype属性是不可写,不可枚举,不可配置的

//它俩都不是自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false.1js继承的最顶端是什么

       null,必须是这家伙,不然只能无限套娃了

       然后其它所有对象都是从Object构造而来,所以所有的对象都可以继承到Object.prototype.

//它俩都不是自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false.2js继承的二等公民(Function)

       在上面的小思考中,说到,js对象都是函数构造而来,所以包括Object也是由Function构造来的,甚至它自己都是由自己构造而来

//它俩都不是自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false2

       我再来一点小理解,可能是在js内部做了小处理,第一个Function是凭空变出来的....然后这个Function构造出了Object,然后这个Object构造出了第一个原型对象Object.prototype,然后再去修改一些引用关系.

       其实最复杂的是Object和Function的关系

//它俩都不是自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false.3js继承的三等公民(内置的其他构造函数)//它俩都不是自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false用户定义的特定公民构造函数

       这个才是重点,根据上面的理解,我会再开一篇文章写一下我理解的js的继承,这里就先留个坑

7.总结

       这篇文章跟网上大多讲constructor,prototype,__proto__的文章都有所不同,我的立足点是从给定的一个可以读取属性的值开始,在js中,除了null和undefined,其它所有的值都可以成为立足点.从这个立足点开始,它的__proto__属性记录了它的原型对象,这个原型对象是构造它时,它的构造函数的prototype属性的值。

//它俩都不是继承自有属性,我也不知道怎么从这俩属性上找到原型对象的了,肯定是魔法.....constobj={ }console.log(obj.hasOwnProperty('__proto__'))//falseconsole.log(obj.hasOwnProperty('constructor'))//false5

       读取一个值的属性的值时,如果它自身有这个属性,那么直接返回这个属性的值,否则就会到它的__proto__对象上去找,一直递归下去,直到找到顶部null,找到就返回它的值,没找到就返回undefined

       这篇文章有三个理解点,让我茅塞顿开,都是在我试验了好久突然得到的结论:

       以一个值为立足点开始分析

       在构造实例的时候,会将这个实例__proto__指向此时的构造函数的prototype

       查找原型对象时,以__proto__为准

请问babel能将es5转成es6吗?

       反转技能在前端圈中大放异彩,Deno 的原型源码诞生即是对 Node 的一次正面反转。别忘了,继承Babel 本名 6to5,原型源码逆向运行即成为 5to6,继承日内指标源码满足了问题的原型源码全部需求。

       在前端工程师的继承技能库中,Babel 的原型源码编译原理是人尽皆知的知识点。作为 AST 结构转换工具,继承Babel 的原型源码输出标准并非固定,可以灵活调整以适应不同版本的继承代码需求。此领域代表项目包括 jscodeshift、原型源码网络留言系统源码recast 等。继承通过 Babel,原型源码可以自动优化老项目中的 lodash 的 require,替换为按需 import,并且替换 let 和箭头函数等。其核心功能在于对源码进行自动化优化。易语言 传奇源码

       这些优化基本上在保持语言表达力的基础上进行,主要涉及语法结构的转换,如从 prototype 转向 class。尽管 prototype 继承的动态性很强,但通过静态分析在编译期确定原型链的难度较大,难以自动化迁移到 ES6 的类似草料网站源码 class 语法。

       转换 prototype 到 class 难以实现,反映了类式继承(classical inheritance)和原型继承(prototypal inheritance)的内在差异。前者在编译期即可确定继承链,后者则在运行时动态组装。原型继承的灵活性虽强,但也带来复杂的源码论坛 公然侵权语法结构,难以通过反向生成更高层的抽象。

       经验表明,从高级抽象到低级抽象的转换相对容易,反之则困难重重。现今,"可视化自动生成代码"领域虽有进展,但将修改过的逻辑代码重新进行可视化编辑仍非易事。

       5to6 并未成为热门话题,ES5 时代已逝,各大公司自然无需从 ES5 升级至 ES6。不过,这种技能的未来仍然充满希望。比如,可以将 ES6 中的每个 VariableDeclaration 加上 "any",实现从 ES6 平滑升级至 AnyScript(夸张表述)。

       总而言之,反转技能虽然实际用途有限,但其独特的实用价值不容忽视。在适当情况下,敢于并善于反转,能为生活增添无尽乐趣。

更多内容请点击【焦点】专栏