天天躁日日躁狠狠躁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ā)。 這里有一篇文章詳細介紹了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"    

 

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

  • 子類從父類繼承的代碼必須在子類和父類都定義好之后進行,并且必須在子類原型方法定義之前進行。
  • 雖然子類方法體中可以調(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進行截斷(因為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ù)前面的分析,個人覺得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)進行編程。
不過就我個人而言,在復(fù)雜的場景中如果有面向?qū)ο蟮臋C制會方便的多。
但誰有能擔(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)系我們修改或刪除,多謝。

主站蜘蛛池模板: 97草碰在线视频免费 | 99亚洲精品 | 国产欧美在线亚洲一区刘亦菲 | 午夜噜噜噜私人影院在线播放 | 日本理论片午午伦夜理片2021 | 506070老熟肥妇bbwxx视频 4虎最新网址 | 黑丝袜论坛 | 饥渴的新婚女教师 | 娇小老少配xxxxx | 牛牛自拍国产免费视频 | 99热.com| 97资源站超碰在线视频 | 精品一品国产午夜福利视频 | 果冻传媒在线观看视频 | 国产99视频精品一区 | 日本久久久 | 成人在线视频免费 | 无码天堂亚洲内射精品课堂 | 国产午夜精品理论片 | 欧美gay69| 亚洲国产成人精品青青草原100 | 好男人视频免费高清在线观看www | 永久免费看A片无码网站四虎 | 欧美特黄99久久毛片免费 | 老子午夜伦不卡电影院 | 日韩高清毛片 | 麻豆成人AV久久无码精品 | 熟女理发厅 | 色偷偷成人网免费视频男人的天堂 | 日本精品在线观看视频 | 古装性艳史电影在线看 | caoporn 超碰免费视频 | 亚洲AV久久无码精品蜜桃 | 伊人亚洲综合网色 | 无人在线观看免费高清视频播放 | 8X拨牐拨牐X8免费视频8 | 国产 在线 亚洲 欧美 动漫 | 久久中文字幕免费高清 | 2017最新伦理伦理片67 | 精品国产人成亚洲区 | 国产91专区 |