亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JavaScript繼承的特性與實踐應用深入詳解

2024-05-06 16:47:20
字體:
來源:轉載
供稿:網友

本文詳細講述了JavaScript繼承的特性與實踐應用。分享給大家供大家參考,具體如下:

繼承是代碼重用的模式。JavaScript 可以模擬基于類的模式,還支持其它更具表現力的模式。但保持簡單通常是最好的策略。

JavaScript 是基于原型的語言,也就是說它可以直接繼承其他對象。

1 偽類

JavaScript 的原型不是直接讓對象從其他對象繼承,而是插入一個多余的間接層:通過構造函數來產生對象。

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

this.prototype = {constructor : this};

新的函數對象新增了一個 prototype 屬性,它是一個包含了 constructor 屬性且屬性值為該新函數的對象。

當采用構造器調用模式,即用 new 去調用一個函數時,它會這樣執行:

Function.method('new', function (){  var that = Object.create(this.prototype);//創建一個繼承了構造器函數的原型對象的新對象  var other = this.apply(that, arguments);//調用構造器函數,綁定 this 到新對象  return (typeof other === 'object' && other) || that;//如果構造器函數的返回值不是對象,就直接返回這個新對象});

我們可以定義一個構造器,然后擴充它的原型:

//定義構造器并擴充原型var Mammal = function (name) {  this.name = name;};Mammal.prototype.get_name = function () {  return this.name;};Mammal.prototype.says = function () {  return this.saying || '';};

然后構造實例:

var myMammal = new Mammal('Herb the mammal');console.log(myMammal.get_name());//Herb the mammal

構造另一個偽類來繼承 Mammal(定義構造器函數并替換它的 prototype):

var Cat = function (name) {  this.name = name;  this.saying = 'meow';};Cat.prototype = new Mammal();

擴充原型:

Cat.prototype.purr = function (n) {  var i, s = '';  for (i = 0; i < n; i += 1) {    if (s) {      s += '-';    }    s += 'r';  }  return s;};Cat.prototype.get_name = function () {  return this.says() + ' ' + this.name + ' ' + this.says();};var myCat = new Cat('Henrietta');console.log(myCat.says());//meowconsole.log(myCat.purr(5));//r-r-r-r-rconsole.log(myCat.get_name());//meow Henrietta meow

我們使用 method 方法定義了 inherits 方法,來隱藏上面這些丑陋的細節:

/** * 為 Function.prototype 新增 method 方法 * @param name 方法名稱 * @param func 函數 * @returns {Function} */Function.prototype.method = function (name, func) {  if (!this.prototype[name])//沒有該方法時,才添加    this.prototype[name] = func;  return this;};Function.method('inherits', function (Parent) {  this.prototype = new Parent();  return this;});

這兩個方法都返回 this,這樣我們就可以以級聯的方式編程啦O(∩_∩)O~

var Cat = function (name) {  this.name = name;  this.saying = 'meow';}.inherits(Mammal).method('purr', function (n) {    var i, s = '';    for (i = 0; i < n; i += 1) {      if (s) {        s += '-';      }      s += 'r';    }    return s;  }).method('get_name', function () {    return this.says() + ' ' + this.name + ' ' + this.says();  });var myCat = new Cat('Henrietta');console.log(myCat.says());//meowconsole.log(myCat.purr(5));//r-r-r-r-rconsole.log(myCat.get_name());//meow Henrietta meow

雖然我們有了行為很像“類”的構造器函數,但沒有私有環境,所有的屬性都是公開的,而且不能訪問父類的方法。

如果在調用構造函數時忘記加上 new 前綴,那么 this 就不會被綁定到新對象上,而是被綁定到了全局變量?。。∵@樣我們不但沒有擴充新對象,還破壞了全局變量環境。

這是一個嚴重的語言設計錯誤!為了降低出現這個問題的概率,所有的構造器函數都約定以首字母大寫的形式來命名。這樣當我們看到首字母大寫的形式的函數,就知道它是構造器函數啦O(∩_∩)O~

當然,更好的策略是根本不使用構造器函數。

2 對象說明符

有時候,構造器需要接受一大堆參數,這很麻煩。所以在編寫構造器時,讓它接受一個簡單的對象說明符會更好:

var myObject = maker({ first: f, middle: m, last: l});

現在這些參數可以按照任意的順序排列咯,而且構造器還能夠聰明地為那些沒有傳入的參數使用默認值,代碼也變得更易閱讀啦O(∩_∩)O~

3 原型

基于原型的繼承指的是,一個新對象可以繼承一個舊對象的屬性。首先構造出一個有用的對象,然后就可以構造出更多與那個對象類似的對象。

/** * 原型 */var myMammal = {  name: 'Herb the mammal',  get_name: function () {    return this.name;  },  says: function () {    return this.saying || '';  }};//創建新實例var myCat = Object.create(myMammal);myCat.name = 'Henrietta';myCat.saying = 'meow';myCat.purr = function (n) {  var i, s = '';  for (i = 0; i < n; i += 1) {    if (s) {      s += '-';    }    s += 'r';  }  return s;};myCat.get_name = function () {  return this.says() + ' ' + this.name + ' ' + this.says();};console.log(myCat.says());//meowconsole.log(myCat.purr(5));//r-r-r-r-rconsole.log(myCat.get_name());//meow Henrietta meow

這里用到了 create 方法來創建新的實例:

Object.create = function (o) {    var F = function () {    };    F.prototype = o;    return new F(); }

4 函數化

目前為止看到的繼承模式的問題是:無法保護隱私,對象的所有屬性都是可見的。有一些無知的程序員會使用偽裝私有的模式,即給一個需要私有的屬性起一個古怪的名字,并希望其他使用代碼的程序員假裝看不到它們!

其實有更好的方法:應用模塊模式。

我們先構造一個生成對象的函數,它有這些步驟:
①. 創建新對象。這有四種方式:
【1】構造一個對象字面量。
【2】調用一個構造器函數。
【3】構造一個已存在對象的新實例。
【4】調用任意一個會返回對象的函數。
②. 定義私有實例變量與方法。
③. 為這個新對象擴充方法,這些方法擁有特權去訪問這些參數。
④. 返回這個新對象。

函數化構造器的偽代碼如下:

var constructor = function (spec, my){  var that, 其他私有變量;  my = my || {}; //把共享的變量和函數添加到 my 中 that = 一個新對象 //添加給 that 的特權方法 return that;};

spec 對象包含了需要構造一個新實例的所有信息,它可以被用到到私有變量或者其他函數中。
my 對象為在一個繼承鏈中的構造器提供了共享的容器,如果沒有傳入,那么會創建一個 my 對象。

創建特權方法的方式是:把函數定義為私有方法,然后再把它們分配給 that:

var methodical = function (){ ...};that.methodical = methodical;

這樣分兩步定義的好處是:私有的 methodical 不受這個實例被改變的影響。

現在,我們把這個模式應用到 mammal 示例中:

var mammal = function (spec) {  var that = {};  that.get_name = function () {    return spec.name;  };  that.says = function () {    return spec.saying || '';  };  return that;};var myMammal = mammal({name: 'Herb'});console.log(myMammal.get_name());//Herbvar cat = function (spec) {  spec.saying = spec.saying || 'meow';  var that = mammal(spec);  that.purr = function (n) {    var i, s = '';    for (i = 0; i < n; i += 1) {      if (s) {        s += '-';      }      s += 'r';    }    return s;  };  that.get_name = function () {    return that.says() + ' ' + spec.name + ' ' + that.says();  };  return that;};var myCat = cat({name: 'Henrietta'});console.log(myCat.says());//meowconsole.log(myCat.purr(5));//r-r-r-r-rconsole.log(myCat.get_name());//meow Henrietta meow

函數化模式還能調用父類的方法。這里我們構造一個 superior 方法,它會返回調用某個方法名的函數:

//返回調用某個方法名的函數Object.method('superior', function (name) {  var that = this,    method = that[name];  return function () {    return method.apply(that, arguments);  };});

現在創建一個 coolcat,它擁有一個可以調用父類方法的 get_name:

var coolcat = function (spec) {  var that = cat(spec),    super_get_name = that.superior('get_name');  that.get_name = function (n) {    return 'like ' + super_get_name() + ' baby';  };  return that;};var myCoolCat = coolcat({name: 'Bix'});console.log(myCoolCat.get_name());//like meow Bix meow baby

函數化模式有很大的靈活性,而且可以更好地實現封裝、信息隱藏以及訪問父類方法的能力。

如果對象所有的狀態都是私有的,那么就稱為防偽對象。這個對象的屬性可以被替換或刪除,但這個對象的狀態不受影響。如果用函數化模式來創建對象,并且這個對象的所有方法都不使用 this 或 that,那么這個對象就是持久性的,它不會被入侵。除非存在特權方法,否則不能訪問這個持久性對象的內部狀態。

5 事件處理函數

可以構造一個能夠給任何對象添加簡單事件處理特性的函數。這里,我們給這個對象添加一個 on 方法,fire 方法和私有的事件注冊對象:

var eventuality = function (that) {  var registry = {};  /**   * 觸發事件   *   * 使用 'on' 方法注冊的事件處理程序將被調用   * @param 可以是包含事件名稱的字符串,或者是一個擁有 type 屬性(值為事件名稱)的對象。   */  that.fire = function (event) {    var array,      func,      handler,      i,      type = typeof event === 'string' ? event : event.type;    //如果這個事件已被注冊,則遍歷并依序執行    if (registry.hasOwnProperty(type)) {      array = registry[type];      for (i = 0; i < array.length; i += 1) {        handler = array[i];//處理程序包含一個方法和一組可選的參數        func = handler.method;        if (typeof func === 'string') {//如果方法是字符串形式的名稱,則尋找它          func = this[func];        }        //調用它。如果處理程序包含參數,則傳遞過去,否則就傳遞事件對象        func.apply(this, handler.parameters || [event]);      }    }    return this;  };  /**   * 注冊一個事件   * @param type   * @param method   * @param parameters   */  that.on = function (type, method, parameters) {    var handler = {      method: method,      parameters: parameters    };    if (registry.hasOwnProperty(type)) {//如果已存在,就新增數組項      registry[type].push(handler);    } else {//新增      registry[type] = [handler];    }    return this;  };  return that;};

可以在任何單獨對象上調用 eventuality,授予它事件處理方法。也可以在 that 被返回前,在構造函數中調用它:

eventuality(that);

JavaScript 弱類型的特性在此是一個巨大的優勢,因為我們無須處理對象繼承關系中的類型O(∩_∩)O~

希望本文所述對大家JavaScript程序設計有所幫助。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国内精品久久久久| 成人在线激情视频| 亚洲精品视频在线观看视频| 久久久久久久香蕉网| 欧美日韩国产在线| 日韩欧美国产黄色| 亚洲视频在线观看免费| 亲爱的老师9免费观看全集电视剧| 精品国偷自产在线视频| 久久亚洲精品视频| 九九热这里只有精品6| 国产亚洲欧美日韩美女| 色综合导航网站| 91色中文字幕| 亚洲高清一二三区| 日韩在线视频中文字幕| 日韩av一区二区在线观看| 成人网欧美在线视频| 欧美成年人在线观看| 欧美日韩精品中文字幕| 性色av一区二区三区| 亚洲男人天堂网| 欧美日韩国产va另类| 欧美www视频在线观看| 欧美国产精品人人做人人爱| 欧美激情精品久久久久久| 久久99热精品| 亚洲国产精品电影在线观看| 国模叶桐国产精品一区| 日韩久久免费视频| 欧美日韩国产在线播放| 亚洲国产99精品国自产| 日韩精品中文在线观看| 九九久久精品一区| 7m精品福利视频导航| 蜜臀久久99精品久久久久久宅男| 日本在线观看天堂男亚洲| 国产男女猛烈无遮挡91| 91在线观看免费| 欧美极度另类性三渗透| 久久久精品在线观看| 国产精品久久久久久五月尺| 美女扒开尿口让男人操亚洲视频网站| 国产精品天天狠天天看| 国产三级精品网站| 久久久人成影片一区二区三区观看| 欧美乱人伦中文字幕在线| 岛国av一区二区在线在线观看| 亚洲国产精品va在线看黑人| 亚洲男人天堂网站| 69**夜色精品国产69乱| 57pao成人国产永久免费| 最近2019中文字幕mv免费看| 精品国产老师黑色丝袜高跟鞋| 伊是香蕉大人久久| 中文在线不卡视频| 91国产视频在线| 日韩在线观看免费网站| 欧美亚洲在线视频| 91精品久久久久| 91网站在线免费观看| 一区二区亚洲欧洲国产日韩| 黑人狂躁日本妞一区二区三区| 国产亚洲精品美女久久久久| 亚洲国产又黄又爽女人高潮的| 97久久精品人人澡人人爽缅北| 欧美激情视频一区二区| 亚洲国产精品久久久| 色综合久久精品亚洲国产| 在线播放国产精品| 91人成网站www| 日韩欧美在线视频免费观看| 亚洲激情自拍图| 亚洲片在线观看| 亚洲变态欧美另类捆绑| 国产精品亚洲片夜色在线| 成人网在线视频| 亚洲精品91美女久久久久久久| 亚洲激情小视频| 精品国产欧美一区二区五十路| 久久精品国产亚洲| 日韩毛片在线观看| 久久九九有精品国产23| 4438全国成人免费| 在线观看欧美成人| 欧美日韩在线视频观看| 性欧美暴力猛交69hd| 国产成人精品电影久久久| 78m国产成人精品视频| 欧美激情综合亚洲一二区| 中文字幕国产亚洲| 亚洲精选在线观看| 成人亚洲综合色就1024| 国产精品久久久久久亚洲调教| 久久国产精品久久精品| 国产成人精品一区二区在线| 欧美激情在线观看视频| 成人观看高清在线观看免费| 青青久久av北条麻妃海外网| 九九视频这里只有精品| 美女扒开尿口让男人操亚洲视频网站| 欧美日韩国产综合新一区| 色综合伊人色综合网| 91久久综合亚洲鲁鲁五月天| 亚洲国产高潮在线观看| 亚洲香蕉成视频在线观看| 亚洲国产精品悠悠久久琪琪| 98午夜经典影视| 欧美日韩亚洲国产一区| 亚洲精品国产精品久久清纯直播| 久久综合电影一区| 日韩欧美国产免费播放| 日韩欧美在线网址| 26uuu久久噜噜噜噜| 欧美三级欧美成人高清www| 国产精品女人久久久久久| 欧洲一区二区视频| 精品国产福利视频| 日韩欧美福利视频| 欧美电影在线播放| 在线播放日韩专区| 美日韩精品视频免费看| 久久免费精品日本久久中文字幕| 欧美日韩黄色大片| 亚洲精品福利视频| 欧美激情久久久久| 国产精品久久久久一区二区| 亚洲男人的天堂在线| 国产精品久久久久久久美男| 性欧美xxxx| 欧美wwwwww| 韩剧1988免费观看全集| 91影视免费在线观看| 最近2019年中文视频免费在线观看| 97国产在线观看| 亚洲成人av在线| xvideos成人免费中文版| 国产午夜精品理论片a级探花| 黑人巨大精品欧美一区二区一视频| 亚洲国产成人精品久久久国产成人一区| 成人伊人精品色xxxx视频| 亚洲经典中文字幕| 久久影院免费观看| 国产一区二区激情| 黄色一区二区在线| 91精品国产高清自在线| 亚洲视频一区二区三区| 中文字幕综合在线| 日本高清视频一区| 欧美色图在线视频| 黑人巨大精品欧美一区免费视频| 亚洲精品国产综合区久久久久久久| 精品国产欧美一区二区三区成人| 欧美高清视频免费观看| 国产欧美日韩综合精品| 欧美尤物巨大精品爽| 亚洲新声在线观看| 国产精品视频久久久| 亚洲精品一区久久久久久| 日韩欧美精品中文字幕| 亚洲福利视频免费观看| 欧美日韩免费在线| 最近2019好看的中文字幕免费| 亚洲国产高潮在线观看|