中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

JS面向對象編程詳解
來源:易賢網 閱讀:771 次 日期:2016-08-02 14:51:10
溫馨提示:易賢網小編為您整理了“JS面向對象編程詳解”,方便廣大網友查閱!

序言

在JavaScript的大世界里討論面向對象,都要提到兩點:1.JavaScript是一門基于原型的面向對象語言 2.模擬類語言的面向對象方式。對于為什么要模擬類語言的面向對象,我個人認為:某些情況下,原型模式能夠提供一定的便利,但在復雜的應用中,基于原型的面向對象系統在抽象性與繼承性方面差強人意。由于JavaScript是唯一一個被各大瀏覽器支持的腳本語言,所以各路高手不得不使用各種方法來提高語言的便利性,優化的結果就是其編寫的代碼越來越像類語言中的面向對象方式,從而也掩蓋了JavaScript原型系統的本質。

基于原型的面向對象語言

原型模式如類模式一樣,都是是一種編程泛型,即編程的方法論。另外最近大紅大紫的函數編程也是一種編程泛型。JavaScript之父Brendan Eich在設計JavaScript時,從一開始就沒打算為其加入類的概念,而是借鑒了另外兩門基于原型的的語言:Self和Smalltalk。

既然同為面向對象語言,那就得有創建對象的方法。在類語言中,對象基于模板來創建,首先定義一個類作為對現實世界的抽象,然后由類來實例化對象;而在原型語言中,對象以克隆另一個對象的方式創建,被克隆的母體稱為原型對象。

克隆的關鍵在于語言本身是否為我們提供了原生的克隆方法。在ECMAScript5中,Object.create可以用來克隆對象。

var person = {

  name: "tree",

  age: 25,

  say: function(){

    console.log("I'm tree.")

  }

};

var cloneTree = Object.create(person);

console.log(cloneTree);

原型模式的目的并不在于得到一個一模一樣的對象,而提供了一種便捷的方式去創建對象(出自《JavaScript設計模式與開發實踐》)。但是由于語言設計的問題,JavaScript的原型存在著諸多矛盾,它的某些復雜的語法看起來就那些基于類的語言,這些語法問題掩蓋了它的原型機制(出自《JavaScript語言精粹》)。如:

function Person(name, age){

  this.name = name;

  this.age = age;      

}

var p = new Person('tree', 25)

實際上,當一個函數對象唄創建時,Function構造器產生的函數對象會運行類似這樣的一些代碼:

this.prototype = {constructor: this}

新的函數對象被賦予一個prototype屬性,它的值是一個包含constructor屬性且屬性值為該新函數的對象。當對一個函數使用new運算符時,函數的prototype的屬性的值被作為原型對象來克隆出新對象。如果new運算符是一個方法,它的執行過程如下:

Function.prorotype.new = function() {

  //以prototype屬性值作為原型對象來克隆出一個新對象

  var that = Object.create(this.prorotype);

   

  //改變函數中this關鍵指向這個新克隆的對象

  var other = this.apply(that, arguments);

   

  //如果返回值不是一個對象,則返回這個新克隆對象

  return (other && typeof other === 'object') ? other : that;

}

從上面可以看出,雖然使用new運算符調用函數看起來像是使用模板實例化的方式來創建對象,但本質還是以原型對象來克隆出新對象。

由于新克隆的對象能否訪問到原型對象的一切方法和屬性,加上new運算符的特性,這便成了利用原型模擬類式語言的基石。 

利用原型模擬類式語言

抽象

用原型模式來模擬類,首先是抽象方式。根據JavaScript語言的特點,通常一個類(實際上是偽類)通常是將字段放置于構造函數(實際上是new 運算符調用的函數,JavaScript本身并沒有構造函數的概念)中,而將方法放置于函數的prototype屬性里。

function Person(name, age) {

  this.name = name;

  this.age = age;

};

Person.prototype.say = function(){

  console.log("Hello, I'm " + this.name);

};

繼承

繼承是OO語言中的一個最為人津津樂道的概念。許多OO語言都支持兩種繼承方式:接口繼承和實現繼承。接口繼承之繼承方法簽名,而實現繼承則繼承實際的方法。但是ECMAScript中無法實現接口繼承,只支持實現繼承,而且其實現繼承主要是依靠原型鏈來實現的。(出自《JavaScript高級程序設計》 6.3節——繼承)在高三中作者探索了各種關于繼承的模擬,如:組合繼承、原型繼承、寄生繼承、寄生組合繼承,最終寄生組合式成為所有模擬類式繼承的基礎。

function Person(name, age) {

  this.name = name;

  this.age = age;

};

Person.prototype.say = function(){

  console.log("Hello, I'm " + this.name);

};

function Employee(name, age, major) {

  Person.apply(this, arguments);

  this.major = major;

};

Employee.prototype = Object.create(Person.prototype);

Employee.prorotype.constructor = Employee;

Employee.prorotype.sayMajor = function(){

  console.log(this.major);

}

高三中只給出了單繼承的解決方案,關于多繼承的模擬我們還得自己想辦法。由于多繼承有其本身的困難:面向對象語言如果支持了多繼承的話,都會遇到著名的菱形問題(DiamondProblem)。假設存在一個如左圖所示的繼承關系,O中有一個方法foo,被A類和B類覆寫,但是沒有被C類覆寫。那么C在調用foo方法的時候,究竟是調用A中的foo,還是調用B中的foo?

名單

所以大多數語言并不支持多繼承,如Java支持單繼承+接口的形式。JavaScript并不支持接口,要在一個不支持接口的語言上去模擬接口怎么辦?答案是著名的鴨式辨型。放到實際代碼中就是混入(mixin)。原理很簡單:

function mixin(t, s) {

   for (var p in s) {

     t[p] = s[p];

   }

 }

值得一提的是dojo利用MRO(方法解析順序(Method Resolution Order),即查找被調用的方法所在類時的搜索順序)方式解決了多繼承的問題。

到此,我們已經清楚了模擬類語言的基本原理。作為一個愛折騰的程序員,我希望擁有自己的方式來簡化類的創建:

提供一種便利的方式去創建類,而不暴露函數的prototype屬性

在子類中覆蓋父類方法時,能夠像Java一樣提供super函數,來直接訪問父類同名方法

以更方便的方式添加靜態變量和方法而不去關心prototype

像C#那樣支持Attribute

最終,在借鑒各位大牛的知識總結,我編寫了自己的類創建工具O.js:

(function(global) {

  var define = global.define;

  if (define && define.amd) {

    define([], function(){

      return O;

    });

  } else {

    global.O = O;

  }

  function O(){};

  O.derive = function(sub) {

    debugger;

    var parent = this;

    sub = sub ? sub : {};

    var o = create(parent);

    var ctor = sub.constructor || function(){};//如何調用父類的構造函數?

    var statics = sub.statics || {};

    var ms = sub.mixins || [];

    var attrs = sub.attributes || {};

    delete sub.constructor;

    delete sub.mixins;

    delete sub.statics;

    delete sub.attributes;

    //處理繼承關系

    ctor.prototype = o;

    ctor.prototype.constructor = ctor;

    ctor.superClass = parent;

    //利用DefineProperties方法處理Attributes

    //for (var p in attrs) {

      Object.defineProperties(ctor.prototype, attrs);

    //}

    //靜態屬性

    mixin(ctor, statics);

    //混入其他屬性和方法,注意這里的屬性是所有實例對象都能夠訪問并且修改的

    mixin(ctor.prototype, sub);

    //以mixin的方式模擬多繼承

    for (var i = 0, len = ms.length; i < len; i++) {

      mixin(ctor.prototype, ms[i] || {});

    }

    ctor.derive = parent.derive;

    //_super函數

    ctor.prototype._super = function(f) {

      debugger;

      return parent.prototype[f].apply(this, Array.prototype.slice.call(arguments, 1));

    }

    return ctor;

  }

  function create(clazz) {

    var F = function(){};

    F.prototype = clazz.prototype;

    //F.prototype.constructor = F; //不需要

    return new F();

  };

  function mixin(t, s) {

    for (var p in s) {

      t[p] = s[p];

    }

  }

})(window);

類創建方式如下:

var Person = O.derive({

  constructor: function(name) {//構造函數

    this.setInfo(name);

  },

  statics: {//靜態變量

    declaredClass: "Person"

  },

  attributes: {//模擬C#中的屬性

    Name: {

      set: function(n) {

        this.name = n;

        console.log(this.name);

      },

      get: function() {

        return this.name + "Attribute";

      }

    }

  },

  share: "asdsaf",//變量位于原型對象上,對所有對象共享

  setInfo: function(name) {//方法

    this.name = name;

  }

});

var p = new Person('lzz');

console.log(p.Name);//lzzAttribute

console.log(Person);

繼承:

var Employee = Person.derive({//子類有父類派生

  constructor: function(name, age) {

    this.setInfo(name, age);

  },

  statics: {

    declaredClass: "Employee"

  },

  setInfo: function(name, age) {

    this._super('setInfo', name);//調用父類同名方法

    this.age = age;

  }

});

var e = new Employee('lll', 25);

console.log(e.Name);//lllAttribute

console.log(Employee);

以上就是本文的全部內容,希望對大家的學習有所幫助。

更多信息請查看網絡編程
易賢網手機網站地址:JS面向對象編程詳解
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
主站蜘蛛池模板: 宝应县| 同德县| 佛冈县| 嘉禾县| 正宁县| 思茅市| 张家港市| 宁晋县| 东兴市| 宣汉县| 和政县| 山阴县| 宁城县| 奉化市| 久治县| 丰顺县| 冷水江市| 吉水县| 甘德县| 庆云县| 平泉县| 宜良县| 沛县| 阜平县| 四平市| 涞源县| 西华县| 娄底市| 永泰县| 句容市| 阳新县| 永清县| 崇左市| 东丽区| 忻州市| 东莞市| 民丰县| 青海省| 桓仁| 当涂县| 通山县|