天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

JavaScript 繼承詳解(四)

Classical Inheritance in JavaScript。
Crockford是JavaScript開發(fā)社區(qū)最知名的權(quán)威,是JSON、JSLint、JSMin和ADSafe之父,是《JavaScript: The Good Parts》的作者。
現(xiàn)在是Yahoo的資深JavaScript架構(gòu)師,參與YUI的設(shè)計開發(fā)。 這里有一篇文章詳細(xì)介紹了Crockford的生平和著作。
當(dāng)然Crockford也是我等小輩崇拜的對象。

調(diào)用方式

首先讓我們看下使用Crockford式繼承的調(diào)用方式:
注意:代碼中的method、inherits、uber都是自定義的對象,我們會在后面的代碼分析中詳解。

    // 定義Person類    function Person(name) {      this.name = name;    }    // 定義Person的原型方法    Person.method("getName", function() {      return this.name;    });         // 定義Employee類    function Employee(name, employeeID) {      this.name = name;      this.employeeID = employeeID;    }    // 指定Employee類從Person類繼承    Employee.inherits(Person);    // 定義Employee的原型方法    Employee.method("getEmployeeID", function() {      return this.employeeID;    });    Employee.method("getName", function() {      // 注意,可以在子類中調(diào)用父類的原型方法      return "Employee name: " + this.uber("getName");    });    // 實例化子類    var zhang = new Employee("ZhangSan", "1234");    console.log(zhang.getName());  // "Employee name: ZhangSan"    

 

這里面有幾處不得不提的硬傷:

  • 子類從父類繼承的代碼必須在子類和父類都定義好之后進(jìn)行,并且必須在子類原型方法定義之前進(jìn)行。
  • 雖然子類方法體中可以調(diào)用父類的方法,但是子類的構(gòu)造函數(shù)無法調(diào)用父類的構(gòu)造函數(shù)。
  • 代碼的書寫不夠優(yōu)雅,比如原型方法的定義以及調(diào)用父類的方法(不直觀)。

 

當(dāng)然Crockford的實現(xiàn)還支持子類中的方法調(diào)用帶參數(shù)的父類方法,如下例子:

    function Person(name) {      this.name = name;    }    Person.method("getName", function(prefix) {      return prefix + this.name;    });    function Employee(name, employeeID) {      this.name = name;      this.employeeID = employeeID;    }    Employee.inherits(Person);    Employee.method("getName", function() {      // 注意,uber的第一個參數(shù)是要調(diào)用父類的函數(shù)名稱,后面的參數(shù)都是此函數(shù)的參數(shù)      // 個人覺得這樣方式不如這樣調(diào)用來的直觀:this.uber("Employee name: ")      return this.uber("getName", "Employee name: ");    });    var zhang = new Employee("ZhangSan", "1234");    console.log(zhang.getName());  // "Employee name: ZhangSan"    

 

代碼分析

首先method函數(shù)的定義就很簡單了:

    Function.prototype.method = function(name, func) {      // this指向當(dāng)前函數(shù),也即是typeof(this) === "function"      this.prototype[name] = func;      return this;    };    
要特別注意這里this的指向。當(dāng)我們看到this時,不能僅僅關(guān)注于當(dāng)前函數(shù),而應(yīng)該想到當(dāng)前函數(shù)的調(diào)用方式。 比如這個例子中的method我們不會通過new的方式調(diào)用,所以method中的this指向的是當(dāng)前函數(shù)。

 

inherits函數(shù)的定義有點復(fù)雜:

    Function.method('inherits', function (parent) {      // 關(guān)鍵是這一段:this.prototype = new parent(),這里實現(xiàn)了原型的引用      var d = {}, p = (this.prototype = new parent());            // 只為子類的原型增加uber方法,這里的Closure是為了在調(diào)用uber函數(shù)時知道當(dāng)前類的父類的原型(也即是變量 - v)      this.method('uber', function uber(name) {        // 這里考慮到如果name是存在于Object.prototype中的函數(shù)名的情況        // 比如 "toString" in {} === true        if (!(name in d)) {          // 通過d[name]計數(shù),不理解具體的含義          d[name] = 0;        }            var f, r, t = d[name], v = parent.prototype;        if (t) {          while (t) {            v = v.constructor.prototype;            t -= 1;          }          f = v[name];        } else {          // 個人覺得這段代碼有點繁瑣,既然uber的含義就是父類的函數(shù),那么f直接指向v[name]就可以了          f = p[name];          if (f == this[name]) {            f = v[name];          }        }        d[name] += 1;        // 執(zhí)行父類中的函數(shù)name,但是函數(shù)中this指向當(dāng)前對象        // 同時注意使用Array.prototype.slice.apply的方式對arguments進(jìn)行截斷(因為arguments不是標(biāo)準(zhǔn)的數(shù)組,沒有slice方法)        r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));        d[name] -= 1;        return r;      });      return this;    });    
注意,在inherits函數(shù)中還有一個小小的BUG,那就是沒有重定義constructor的指向,所以會發(fā)生如下的錯誤:
    var zhang = new Employee("ZhangSan", "1234");    console.log(zhang.getName());  // "Employee name: ZhangSan"    console.log(zhang.constructor === Employee);  // false    console.log(zhang.constructor === Person);   // true    

 

改進(jìn)建議

根據(jù)前面的分析,個人覺得method函數(shù)必要性不大,反而容易混淆視線。 而inherits方法可以做一些瘦身(因為Crockford可能考慮更多的情況,原文中介紹了好幾種使用inherits的方式,而我們只關(guān)注其中的一種), 并修正了constructor的指向錯誤。

    Function.prototype.inherits = function(parent) {      this.prototype = new parent();      this.prototype.constructor = this;      this.prototype.uber = function(name) {        f = parent.prototype[name];        return f.apply(this, Array.prototype.slice.call(arguments, 1));      };    };    
調(diào)用方式:
    function Person(name) {      this.name = name;    }    Person.prototype.getName = function(prefix) {      return prefix + this.name;    };    function Employee(name, employeeID) {      this.name = name;      this.employeeID = employeeID;    }    Employee.inherits(Person);    Employee.prototype.getName = function() {      return this.uber("getName", "Employee name: ");    };    var zhang = new Employee("ZhangSan", "1234");    console.log(zhang.getName());  // "Employee name: ZhangSan"    console.log(zhang.constructor === Employee);  // true    

 

有點意思

在文章的結(jié)尾,Crockford居然放出了這樣的話:

I have been writing JavaScript for 8 years now, and I have never once found need to use an uber function. The super idea is fairly important in the classical pattern, but it appears to be unnecessary in the prototypal and functional patterns. I now see my early attempts to support the classical model in JavaScript as a mistake.
可見Crockford對在JavaScript中實現(xiàn)面向?qū)ο蟮木幊滩毁澇桑⑶衣暦QJavaScript應(yīng)該按照原型和函數(shù)的模式(the prototypal and functional patterns)進(jìn)行編程。
不過就我個人而言,在復(fù)雜的場景中如果有面向?qū)ο蟮臋C(jī)制會方便的多。
但誰有能擔(dān)保呢,即使像jQuery UI這樣的項目也沒用到繼承,而另一方面,像Extjs、Qooxdoo則極力倡導(dǎo)一種面向?qū)ο蟮?a href=/itjie/Javajishu/ target=_blank class=infotextkey>JavaScript。 甚至Cappuccino項目還發(fā)明一種Objective-J語言來實踐面向?qū)ο蟮?a href=/itjie/Javajishu/ target=_blank class=infotextkey>JavaScript。

JavaScript技術(shù)JavaScript 繼承詳解(四),轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 成人无码国产AV免费看 | 三级黄在线 | 国产在线观看码高清视频 | 国产www视频| 玖玖爱这里只有精品视频 | 在线AV国产传媒18精品免费 | 亚洲午夜精品久久久久久抢 | 久久香蕉国产免费天天 | 高清bblxx手机在线观看 | 亚洲国产AV一区二区三区四区 | 国产在线播放91 | 姉调无修版ova国语版 | 美女被撕开胸罩狂揉大乳 | 久久精品成人免费看 | 日本一区精品久久久久影院 | 国产欧美精品国产国产专区 | 色悠久久综合 | 久久热免费视频 | 美女坐脸vk | 97伦理电影在线不卡 | 少爷被多个暗卫肉高h | 国产成人免费全部网站 | 小处雏一区二区三区 | yellow日本动漫观看免费 | 精品无码国产自产在线观看水浒传 | 99久久久久精品国产免费麻豆 | 99热精品一区 | 午夜亚洲WWW湿好大 午夜性爽视频男人的天堂在线 | 四虎国产精品永久免费入口 | 麻豆高清免费国产一区 | 亚洲AV无码一区二区色情蜜芽 | 色悠悠电影网 | 国产成人综合在线视频 | 北岛玲手机在线观看视频观看 | 日日噜噜夜夜躁躁狠狠 | 免费的黄直播 | xlxx美女| 久久99re2在线视频精品 | 亚洲精品人成电影网 | 兔费看少妇性L交大片免费 偷偷要色偷偷 | 久拍国产在线观看 |