广州凡科互联网科技有限公司

营业时间
MON-SAT 9:00-18:00

全国服务热线
18720358503

公司门店地址
广州市海珠区工业大道北67号凤凰创意园

JavaScript 朝向目标编程设计-封裝

日期:2021-02-20 浏览:
JavaScript 朝向目标编程设计-封裝JavaScript 朝向目标编程设计-承继与多态

文中写的十分精彩纷呈,因此转截回来强烈推荐大伙儿阅读文章。


JavaScript 是一种十分灵便的朝向目标编程设计語言,它与传统式的强种类的朝向目标编程设计語言(如 C++,Java,C# 等)有非常大不一样,因此要完成如 C++、java、C# 之中的一些特点就必须换一种思索方法来处理。今日关键探讨怎样在 JavaScript 脚本制作中完成数据信息的封裝(encapsulation)。

数据信息封裝说的简易点便是把不期待启用者看到的內容掩藏起來。它是朝向目标编程设计的三因素之首,其他2个是承继和多态,有关他们的內容在后边再探讨。

有关数据信息封裝的完成,在 C++、Java、C# 等語言中是根据 public、private、static 等重要字完成的。在 JavaScript 则选用了此外一种迥然不一样的方式。在探讨怎样实际完成某类方法的数据信息封裝前,大家先说好多个简易的,大伙儿所熟识却又非常容易忽视的 JavaScript 的定义。

1 好多个基本要素 1.1 自变量界定

在 JavaScript 語言中,是根据 var 重要字而定义自变量的。

可是假如大家立即给一个沒有应用 var 界定的自变量取值,那麼这一自变量便会变成全局性自变量。

一般状况下,大家应当防止应用沒有用 var 界定的自变量,关键缘故是它会危害程序的实行高效率,由于存储全局性自变量速率比部分自变量要慢很多。

可是这类使用方法能够确保大家的自变量一定是全局性自变量。

此外,以便确保速率,大家在应用全局性自变量时,能够根据 var 界定一个部分自变量,随后将全局性自变量授予之,从而能够获得一个全局性自变量的部分引入。

1.2 自变量种类

沒有界定的自变量,种类为 undefined。

自变量的值能够是涵数。

涵数在 JavaScript 中能够当做类的人物角色。

1.3 自变量功效域

自变量功效域就是指自变量存活周期时间的合理范畴。

单纯性用 { } 建立的块不可以建立功效域。

with 将它包括的目标功效域加上到当今功效域链中,但 with 不建立新的功效域。with 块完毕后,会将目标功效域从当今功效域链中删掉。

try-catch 中,catch 的不正确目标只在 catch 块中合理,但 catch 块中界定的自变量归属于当今功效域。

其他如 if、for、for-in、while、do-while、switch 等操纵句子建立的块不可以建立功效域。

用 function 建立的涵数,会建立一个新的功效域加上到当今功效域中。

下边大家就来探讨实际的封裝。最先说一下大伙儿最了解的几类封裝:独享案例组员、公有制案例组员和公有制静态数据组员。最终会探讨一下大伙儿所不太熟悉的独享静态数据组员和静态数据类的封裝方法。由于下边要探讨的是朝向目标程序编写,全部当涵数做为类而定义和应用时,大家姑且将其变成类。

2.1 独享案例组员

独享案例组员在 JavaScript 中具体上能够用涵数内的部分自变量来完成,它非常于类的独享案例组员。比如:


    var method2 = function() {         alert(m_second);     }     // constructor     {         method1();         method2();     } var o = new class1(); // error alert(o.m_first); o.method1();

这儿 m_first 和 m_second 是 class1 的2个独享案例字段名,method1 和 method2 是2个独享案例方式。她们只有在该类的目标內部被应用,在目标外没法应用。

这儿大伙儿会发觉建立独享方式有二种方法,一种是立即在类中界定方式,另外一种是先界定一个部分自变量(独享案例字段名),随后界定一个密名方式取值给它。

立即在类中界定方式,则该方式的功效域便是这一类,因而这一方式在该类外不可以够被浏览,而它又能够存储类中常有的独享案例字段名,这就确保了它是个独享案例方式。

第二种建立独享案例方式的方法跟第一种方法的实际效果是一样的,可是第二种方法更灵便一些。

你应当还会继续留意到,class1 中把结构器编码用 { } 括起來了,那样做尽管沒有必需,可是编码看起来更为清楚。

有关这一段结构器编码,也有二点必须表明的地区:

1、结构器编码务必放到全部类界定的最终,那样做是以便确保在它之中被启用的方式早已经被界定了。由于 JavaScript 是表述型語言,因此,它会依照从上到下的次序实行,因而,假如结构器编码放到其他方式界定的前边,则实行到启用句子时找不着要启用的方式,便会错误。

2、大家早已了解 { } 建立的块不容易更改功效域,因而假如在这里样的结构器编码中建立部分自变量,具体上是在全部类中建立独享案例组员,因此,假如必须采用部分自变量,理应界定一个独享案例方式,比如能够取名为 constructor(),在 constructor() 这一独享案例方式中界定部分自变量和原先 { } 结构器时要实行的编码,随后在类的最终立即启用它便可以了。因此更强的书写是那样的:


    var method2 = function() {         alert(m_second);     }     constructor(); var o = new class1(); // error alert(o.m_first); o.method1();

最终,你可以能还会继续发觉 class1 的界定大家沒有用 var,那样做大家便可以确保它是个全局性的类了。

2.2 公有制案例组员

公有制案例组员能够根据二种方法来建立,大家先看来下边这一事例:


    var method2 = function() {         alert(m_second);     }     // public fields     this.first = "first";     this.second = ['s','e','c','o','n','d'];     // public methods     this.method1 = method2;     this.method2 = function() {         alert(this.second);     }     // constructor     {         method1();         method2();     } // public method class1.prototype.method3 = function() {     alert(this.first); var o = new class2(); o.method1(); o.method2(); o.method3(); alert(o.first);

大家发觉这一事例是在 class1 的事例上干了一些填补。给它加上了公有制案例字段名和公有制案例方式,大家把他们统称为公有制案例组员。

大家应当早已发觉,建立公有制案例组员实际上非常简单,一种方法是根据在类中给 this.memberName 来取值,假如值是涵数以外的种类,那么就是个公有制案例字段名,假如值是涵数种类,那么就是公有制案例方式。此外一种方法则是根据给 className.prototype.memberName 取值,可取值的种类跟 this.memberName 是同样的。

究竟是根据 this 方法界定好呢,還是根据 prototype 方法界定好呢?

实际上他们都有各的主要用途,他们中间并不是谁比谁更强的关联。在一些状况下,大家只有用在其中特殊的一种方法而定义公有制案例组员,而不可以够应用另外一种方法。缘故取决于他们具体上是有差别的:

1、prototype 方法只应当在类外界定。this 方法只有在类中界定。

2、prototype 方法假如在类中界定时,则存储独享案例组员时,一直存储最终一个目标案例中的独享案例组员。

3、prototype 方法界定的公有制案例组员是建立在类的原形以上的组员。this 方法界定的公有制案例组员,是立即建立在类的案例目标上的组员。

根据前二点差别,大家能够获得那样的结果:假如要在公有制案例方式中存储独享案例组员,那麼务必用 this 方法界定。

有关第三点差别,大家后边在探讨承继时再对它开展更加深入入的分析。这儿要是了解有这一差别便可以了。

大家还会继续发觉,公有制案例组员和独享案例组员姓名是能够同样的,那样不容易有矛盾吗?

自然不容易。缘故取决于他们的存储方法不一样,公有制案例组员在类中存储时,务必要用 this. 作为前缀来引入。而独享案例组员在类中存储时,不应用都不可以应用 this. 作为前缀来存储。而在类外存储时,仅有公有制组员是能够根据类的案例目标存储的,独享组员没法存储。

2.3 公有制静态数据组员

公有制静态数据组员的界定非常简单,比如:


    var method2 = function() {         alert(m_second);     }     // constructor     {         method1();         method2();     } // public static field class3.field1 = 1; // public static method class3.method1 = function() {     alert(class3.field1); class3.method1();

这一事例的 class3 跟 class1 很像。不一样的是 class3 的外边,大家又给 class3 界定了一个静态数据字段名和静态数据方式。

界定的方法便是给 className.memberName 立即取值。

这儿界定的静态数据字段名和静态数据方式全是能够被立即根据类名引入来存储的,而不用建立目标。因而他们是公有制静态数据组员。

但是有点儿要记牢,一定不必将公有制静态数据组员界定在它所属的类的內部,不然你能获得非你所期待的結果。大家能看下边这一事例:


    var method2 = function() {         alert(m_second);     }     class4.method1 = function() {         s_second++;     }     class4.method2 = function() {         alert(s_second);     } var o1 = new class4(); class4.method2();          // 2 class4.method1(); class4.method2();          // 3 var o2 = new class4(); class4.method2();          // 2 class4.method1(); class4.method2();          // 3

这一事例中,大家期待 s_second 可以饰演一个独享静态数据组员的人物角色,可是輸出結果却并不是大家所期待的。大家会发觉 s_second 具体上是 class4 的一个独享案例组员,而并不是独享静态数据组员。而 class4 的 method1 和 method2 所存储的独享组员一直类的最终一个案例目标中的这一独享案例组员。

难题出在哪儿儿呢?

难题出在每一次根据 new class4() 建立一个目标案例时,class4 中的全部句子都是再次实行,因而,s_second 被重设,并变成新目标中的一个独享案例组员。而 class4.method1 和 class4.method2 也被再次界定了,而这一界定也将他们的自变量功效域转换来到最终一个目标上去。这与把根据 prototype 方法建立的公有制案例方式界定在类的內部而造成的不正确是一样的。

因此,一定不必将公有制静态数据组员界定在它所属的类的內部!都不要把根据 prototype 方法建立的公有制案例方式界定在类的內部!

那怎样界定一个独享静态数据组员呢?

2.4 独享静态数据组员

前边在基本要素里大家早已清晰了,仅有用 function 建立涵数,才可以建立一个新的功效域,想要建立独享组员(无论是静态数据组员,還是案例组员),都必须根据建立新的功效域才可以够具有数据信息掩藏的目地。下边所选用的方式便是根据这一点来完成的。

完成独享静态数据组员是根据建立一个密名涵数涵数来建立一个新的功效域来完成的。

一般大家应用密名涵数时全是将它取值给一个自变量,随后根据这一自变量引入该密名涵数。这类状况下,该密名涵数能够被不断启用或是做为类去建立目标。而这儿,大家建立的密名涵数不取值给一切自变量,在它建立后马上实行,或是马上案例化作一个目标,而且该目标都不取值给一切自变量,这类状况下,该涵数自身或是它案例化后的目标也不可以被再度存储,因而它唯一的功效便是建立了一个新的功效域,并防护了它內部的全部部分自变量和涵数。因而,这种部分自变量和涵数就变成大家需要要的独享静态数据组员。而这一马上实行的密名涵数或是马上案例化的密名涵数大家称它为静态数据封裝自然环境。

下边大家先看来根据立即启用密名涵数方法来建立含有独享静态数据组员的类的事例:


    function constructor() {         // private fields         var m_first = 1;         var m_second = 2;         // private methods         function method1() {             alert(m_first);         }         var method2 = function() {             alert(m_second);         }         // public fields         this.first = "first";         this.second = ['s','e','c','o','n','d'];         // public methods         this.method1 = function() {             s_second--;         }         this.method2 = function() {             alert(this.second);         }         // constructor         {             s_method1();             this.method1();         }     }     // public static methods     constructor.method1 = function() {         s_first++;         alert(s_first);     }     constructor.method2 = function() {         alert(s_second);     }     return constructor; })(); var o1 = new class5(); class5.method1(); class5.method2(); o1.method2(); var o2 = new class5(); class5.method1(); class5.method2(); o2.method2();

这一事例中,根据


})();

来建立了一个静态数据封裝自然环境,具体的类是在这里个自然环境中界定的,而且在最终根据 return 句子将最终的类回到帮我们的全局性自变量 class5,随后大家便可以根据 class5 来引入这一含有静态数据独享组员的类了。

以便区别独享静态数据组员和独享案例组员,大家在独享静态数据组员前边用了 s_ 作为前缀,在独享案例组员前边加了 m_ 作为前缀,那样防止了重名,因而在目标中一直能够存储独享静态数据组员的。

可是这类取名方法并不是务必的,仅仅强烈推荐的,独享静态数据组员能够跟独享案例组员同名的,在重名的状况下,在类结构器与在类中界定的案例方式中存储的全是独享案例组员,在静态数据方式(无论是公有制静态数据方式還是独享静态数据方式)中存储的全是独享静态数据组员。

在类外而且在静态数据封裝自然环境中通快递过 prototype 方法界定的公有制案例方式存储的是独享静态数据组员。

在静态数据封裝自然环境外界定的公有制静态数据方式和根据 prototype 方法界定的公有制案例方式没法立即存储独享静态数据组员。

此外一种方法根据立即案例化密名涵数方法来建立含有独享静态数据组员的类的事例紧跟面的事例很类似:


    class6 = function() {         // private fields         var m_first = 1;         var m_second = 2;         // private methods         function method1() {             alert(m_first);         }         var method2 = function() {             alert(m_second);         }         // public fields         this.first = "first";         this.second = ['s','e','c','o','n','d'];         // public methods         this.method1 = function() {             s_second--;         }         this.method2 = function() {             alert(this.second);         }         // constructor         {             s_method1();             this.method1();         }     }     // public static methods     class6.method1 = function() {         s_first++;         alert(s_first);     }     class6.method2 = function() {         alert(s_second);     } var o1 = new class6(); class6.method1(); class6.method2(); o1.method2(); var o2 = new class6(); class6.method1(); class6.method2(); o2.method2();

这一事例的結果跟根据第一种方法建立的事例是同样的。只不过是它的静态数据封裝自然环境是那样的:


在这里里,该涵数沒有回到值,而且针对 class5 的界定是立即在静态数据封裝自然环境內部根据给一个沒有用 var 界定的自变量取值的方法完成的。

自然,也彻底能够在


})();

这类方法中,不给该涵数界定回到值,而立即在静态数据封裝自然环境內部根据给一个沒有用 var 界定的自变量取值的方法来完成含有独享静态数据组员的类的界定。

这二种方法在这里里是等额的的。

2.5 静态数据类

说白了的静态数据类,是一种不可以够被案例化,而且只包括有静态数据组员的类。

在 JavaScript 中大家根据立即案例化一个密名涵数的目标,便可以完成静态数据类了。比如:


class7.method1();

大伙儿会发觉,class7 实际上便是个目标,只不过是这一目标隶属的是密名类,该类在建立完 class7 这一目标后,也不能再被应用了。而 class7 并不是一个 function,因此不可以够做为一个类被案例化,因而,这儿它就非常于一个静态数据类了。

JavaScript 朝向目标编程设计-封裝JavaScript 朝向目标编程设计-承继与多态


网站知识

联系方式丨CONTACT

  • 全国热线:18720358503
  • 传真热线:18720358503
  • Q Q咨询:2639601583
  • 企业邮箱:2639601583@qq.com

首页
电话
短信
联系