ECMAScript makaman girmek mekanizmesi amaliyoti
- Tsaɗan Farin neman ƙarfin ƙaɗa
- Dindindin JavaScript yuqori darajali tarzimi
Anan kuma ana kara kara kara fannan fannan kuma kuma kuma ana kara kara kara fannan.
Kuma ana kara kara kara fannan fannan kuma kuma kuma ana kara kara kara fannan.
Bayan a ta fannan bazin, ana kara kara kara fannan fannan. Kuma ana kara kara kara fannan fannan kuma kuma kuma ana kara kara kara fannan.
Ina hanyar ECMAScript taka fannan kuma ana kara kara kara fannan fannan, anan kuma a zamanin ake kara kara kara fannan fannan. Anan kuma ana kara kara kara fannan fannan.
An tashi da tashin fannan zaiwa kara jirin fannan, kuma ana kara kara kara jirin fannan. Tashi, dukin fannan da kuma kuma kuma ana kara kara kara jirin fannan. Kuma ana kara kara kara fannan fannan kuma kuma kuma ana kara kara kara fannan. Kuma ana kara kara kara fannan fannan kuma kuma kuma ana kara kara kara fannan.
继承的方式
和其他功能一样,ECMAScript 实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。
A cikin haka, za a bayar da rahoton rahoton na kusan nasaba.
Object masquerading
Kamar yadda ake gudanar da ECMAScript a farko, ana kirki a cikin kira object masquerading. Ita ce bayan ana fahimtawa da cikakken aikin function, kamar yadda ake amfani da keyword this a cikin muhimmancin hanyoyin.
Principiyar haka: Kwarin kwarin amfani da keyword this domin kama ga duk abin da zai iya zama abin kula da abin da zai iya zama abin kula (kamar yadda ake amfani da kwarin kwarin na kaci). Kuma kuma, kwarin kwarin shine kawai function, kuma zai iya amfani da kwarin kwarin ClassA domin kwarin kwarin ClassB, kuma an kawo amfani da ita. ClassB za a iya samun abin kula da abin kula na kwarin kwarin ClassA. Misali, amfani da haka:
function ClassA(sColor) { this.color = sColor; this.sayColor = function () { alert(this.color); }; } function ClassB(sColor) { }
Kuma kuma? Keyword this shine kuma yana nuna wanda ke amfani da shi a cikin kwarin kwarin. Amma a cikin haka, this shine kuma yana nuna wanda ke nuna. Haka kuma, wannan kimiyya shine amfani da ClassA a matsayin function na kwarin kwarin domin samun nasaba, kuma ba a matsayin kwarin kwarin. Bugu da ƙari, a cikin haka, amfani da kwarin kwarin ClassB za a iya samun nasaba:
function ClassB(sColor) { this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod; }
A cikin shirin haka, za a ba ClassA da method newMethod (kamar yadda ake kira, sunan function na nuna shine nafin nuna). Kuma an kawo amfani da shi, an kawo gudanarwa ga sabon parameters na ClassB. Bugu da ƙari, a cikin ƙasa na code, an kawo kira ga ClassA. Kuma a cikin haka, ba za a iya amfani da shi ne daga baya.
Duk abin da zai iya zama abin kula da abin da zai iya zama abin kula na kaci suna da wajibcin zama bayan kama na sabon method. Haka kuma, amma zai iya zama cewa zai iya kashe abin kula da abin kula na manyan kaci:
function ClassB(sColor, sName) { this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod; this.name = sName; this.sayName = function () { alert(this.name); }; }
domin tasirin code na farko, za a iya gudanar da shirin haka:
var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); //bada "blue" objB.sayColor(); //bada "red" objB.sayName(); // kafa "John"
Object masquerading ya iya samun nasaba da yawa
Kamar yadda ake kira, kuma ake amfani da object masquerading domin samun nasaba da yawa. Haka kuma, wani kaci ya iya samun nasaba daga cikin manyan kaci da yawa. Manhada UML domin nasaba da yawa a cikin manyan kaci a cikin haka:

Tare da a cikin da ana ceke da koyi, amma wanda zai kari cikin ClassX da ClassY, ClassZ ya iya samun nasaba daga cikin wa'adun haka:
function ClassZ() { this.newMethod = ClassX; this.newMethod(); delete this.newMethod; this.newMethod = ClassY; this.newMethod(); delete this.newMethod; }
这里存在一个弊端,如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。
由于这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即 call() 和 apply()。
call() 方法学
call() 方法学是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。例如:
function sayColor(sPrefix,sSuffix) { alert(sPrefix + this.color + sSuffix); }; var obj = new Object(); obj.color = "blue"; sayColor.call(obj, "The color is ", "a very nice color indeed.");
在这个例子中,函数 sayColor() 在对象外定义,即使它不属于任何对象,也可以引用关键字 this。对象 obj 的 color 属性等于 blue。调用 call() 方法时,第一个参数是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。第二个和第三个参数是字符串。它们与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,最后生成的消息 "The color is blue, a very nice color indeed." 将被显示出来。
要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值、调用和删除代码替换即可:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.call(this, sColor); this.name = sName; this.sayName = function () { alert(this.name); }; }
在这个地方,我们需要让 ClassA 中的关键字 this 等于新创建的 ClassB 对象,因此 this 是第一个参数。第二个参数 sColor 对两个类来说都是唯一的参数。
apply() 方法学
apply() 方法学有两个参数,用作 this 的对象和要传递给函数的参数的数组。例如:
function sayColor(sPrefix,sSuffix) { alert(sPrefix + this.color + sSuffix); }; var obj = new Object(); obj.color = "blue"; sayColor.apply(obj, new Array("The color is ", "a very nice color indeed."));
Zhege lianli xiang yu qianmian de lianli xiangshi xiangshi, zhi jiu xianzai diao zhao shi apply() fangfa. Diao zhao apply() fangfa shi, diyi ge canshu rengshi obj, shuo ming ying zhen fu yu sayColor() fangfa zhong de this guanjianzi zhi shi obj. Didi er ge canshu shi you liang ge zifuhao zhi gou cheng de zuhe, yu sayColor() fangfa zhong de canshu sPrefix he sSuffix peihe, zui hou sheng cheng de xiaoxi shi "The color is blue, a very nice color indeed.", bei xianshi chulai.
Zhege fangfa ye yongyu tihuan san ge xian xing de fuzhi, diao diao he shanchu xin fangfa de dai ma:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply(this, new Array(sColor)); this.name = sName; this.sayName = function () { alert(this.name); }; }
Tong de, diyi ge canshu rengshi this, didi er ge canshu shi you yi ge zhi color de zuhe. Kei ba ClassB de quan ge arguments duixiang zhi wei didi er ge canshu chuanrang gei apply() fangfa:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply(this, arguments); this.name = sName; this.sayName = function () { alert(this.name); }; }
Dangran, zhiyou chao lei zhong de canshu xunhao yu zi lei zhong de canshu xunhao wande quan yi yi ge xiangshi cai kai tong canshu duixiang. Ru guo bu shi, zhi hao chuangjian yi ge danliu, anzhao zhengque de xunhao fangshi zhi fang canshu. Cunzai, hai keyi shiyong call() fangfa.
Yuanxian lian (prototype chaining)
Chengji zhe zhong xingshi zai ECMAScript zhong benlai shi yongyu yuanxian lian de. Shangyi zhang jieshao le dingshi lei de yuanxingtai fangshi. Yuanxian lian kuozhan le zhe zhong fangshi, yi ge youqu de fangshi shi xian chengji jixitong.
Zai shangyi zhang xuexi, prototype duixiang shi ge moBan, yao shixian de duixiang dou yi zhege moBan jiuji. Zongzhishi, prototype duixiang de renhe shuxing he fangfa dou bei chuanbo gei na ge lei de suoyou shi lian. Yuanxian lian liyong zhe zhong gongneng shi xian chengji xitong.
Idan kaiyayi kada kada, wadannan dake yong xianxingtai fangshi zhongding yige leibie, tamen jiang zhenwei xiaoxing fangshi:
function ClassA() { } ClassA.prototype.color = "blue"; ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB() { } ClassB.prototype = new ClassA();
原型方式的神奇之处在于突出显示的蓝色代码行。这里,把 ClassB 的 prototype 属性设置成 ClassA 的实例。这很有意思,因为想要 ClassA 的所有属性和方法,但又不想逐个将它们 ClassB 的 prototype 属性。还有比把 ClassA 的实例赋予 prototype 属性更好的方法吗?
注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。为什么?因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为 ClassB 类添加 name 属性和 sayName() 方法的代码如下:
function ClassB() { } ClassB.prototype = new ClassA(); ClassB.prototype.name = ""; ClassB.prototype.sayName = function () { alert(this.name); };
可通过运行下面的例子测试这段代码:
var objA = new ClassA(); var objB = new ClassB(); objA.color = "blue"; objB.color = "red"; objB.name = "John"; objA.sayColor(); objB.sayColor(); objB.sayName();
此外,在原型链中,instanceof 运算符的运行方式也很独特。对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。例如:
var objB = new ClassB(); alert(objB instanceof ClassA); //输出 "true" alert(objB instanceof ClassB); //输出 "true"
在 ECMAScript 的弱类型世界中,这是极其有用的工具,不过使用对象冒充时不能使用它。
原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
混合方式
这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。
在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。用这两种方式重写前面的例子,代码如下:
function ClassA(sColor) { this.color = sColor; } ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB(sColor, sName) { ClassA.call(this, sColor); this.name = sName; } ClassB.prototype = new ClassA(); ClassB.prototype.sayName = function () { alert(this.name); };
在此例子中,继承机制由两行突出显示的蓝色代码实现。在第一行突出显示的代码中,在 ClassB 构造函数中,用对象冒充继承 ClassA 类的 sColor 属性。在第二行突出显示的代码中,用原型链继承 ClassA 类的方法。由于这种混合方式使用了原型链,所以 instanceof 运算符仍能正确运行。
Babban ƙoƙarin yana ƙarshe ita ƙodin:
var objA = new ClassA("blue"); var objB = new ClassB("red", "John"); objA.sayColor(); //bada "blue" objB.sayColor(); //bada "red" objB.sayName(); //bada "John"
- Tsaɗan Farin neman ƙarfin ƙaɗa
- Dindindin JavaScript yuqori darajali tarzimi