最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript繼承的特性與實(shí)踐應(yīng)用深入詳解

 更新時(shí)間:2018年12月30日 12:02:42   作者:deniro_li  
這篇文章主要介紹了JavaScript繼承的特性與實(shí)踐應(yīng)用,結(jié)合實(shí)例形式較為深入的分析了javascript繼承相關(guān)概念、特性、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下

本文詳細(xì)講述了JavaScript繼承的特性與實(shí)踐應(yīng)用。分享給大家供大家參考,具體如下:

繼承是代碼重用的模式。JavaScript 可以模擬基于類(lèi)的模式,還支持其它更具表現(xiàn)力的模式。但保持簡(jiǎn)單通常是最好的策略。

JavaScript 是基于原型的語(yǔ)言,也就是說(shuō)它可以直接繼承其他對(duì)象。

1 偽類(lèi)

JavaScript 的原型不是直接讓對(duì)象從其他對(duì)象繼承,而是插入一個(gè)多余的間接層:通過(guò)構(gòu)造函數(shù)來(lái)產(chǎn)生對(duì)象。

當(dāng)一個(gè)函數(shù)被創(chuàng)建時(shí),F(xiàn)unction 構(gòu)造器產(chǎn)生的函數(shù)對(duì)象會(huì)運(yùn)行這樣類(lèi)似的代碼:

this.prototype = {constructor : this};

新的函數(shù)對(duì)象新增了一個(gè) prototype 屬性,它是一個(gè)包含了 constructor 屬性且屬性值為該新函數(shù)的對(duì)象。

當(dāng)采用構(gòu)造器調(diào)用模式,即用 new 去調(diào)用一個(gè)函數(shù)時(shí),它會(huì)這樣執(zhí)行:

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

我們可以定義一個(gè)構(gòu)造器,然后擴(kuò)充它的原型:

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

然后構(gòu)造實(shí)例:

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

構(gòu)造另一個(gè)偽類(lèi)來(lái)繼承 Mammal(定義構(gòu)造器函數(shù)并替換它的 prototype):

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

擴(kuò)充原型:

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());//meow
console.log(myCat.purr(5));//r-r-r-r-r
console.log(myCat.get_name());//meow Henrietta meow

我們使用 method 方法定義了 inherits 方法,來(lái)隱藏上面這些丑陋的細(xì)節(jié):

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

這兩個(gè)方法都返回 this,這樣我們就可以以級(jí)聯(lián)的方式編程啦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());//meow
console.log(myCat.purr(5));//r-r-r-r-r
console.log(myCat.get_name());//meow Henrietta meow

雖然我們有了行為很像“類(lèi)”的構(gòu)造器函數(shù),但沒(méi)有私有環(huán)境,所有的屬性都是公開(kāi)的,而且不能訪(fǎng)問(wèn)父類(lèi)的方法。

如果在調(diào)用構(gòu)造函數(shù)時(shí)忘記加上 new 前綴,那么 this 就不會(huì)被綁定到新對(duì)象上,而是被綁定到了全局變量?。?!這樣我們不但沒(méi)有擴(kuò)充新對(duì)象,還破壞了全局變量環(huán)境。

這是一個(gè)嚴(yán)重的語(yǔ)言設(shè)計(jì)錯(cuò)誤!為了降低出現(xiàn)這個(gè)問(wèn)題的概率,所有的構(gòu)造器函數(shù)都約定以首字母大寫(xiě)的形式來(lái)命名。這樣當(dāng)我們看到首字母大寫(xiě)的形式的函數(shù),就知道它是構(gòu)造器函數(shù)啦O(∩_∩)O~

當(dāng)然,更好的策略是根本不使用構(gòu)造器函數(shù)。

2 對(duì)象說(shuō)明符

有時(shí)候,構(gòu)造器需要接受一大堆參數(shù),這很麻煩。所以在編寫(xiě)構(gòu)造器時(shí),讓它接受一個(gè)簡(jiǎn)單的對(duì)象說(shuō)明符會(huì)更好:

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

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

3 原型

基于原型的繼承指的是,一個(gè)新對(duì)象可以繼承一個(gè)舊對(duì)象的屬性。首先構(gòu)造出一個(gè)有用的對(duì)象,然后就可以構(gòu)造出更多與那個(gè)對(duì)象類(lèi)似的對(duì)象。

/**
 * 原型
 */
var myMammal = {
  name: 'Herb the mammal',
  get_name: function () {
    return this.name;
  },
  says: function () {
    return this.saying || '';
  }
};
//創(chuàng)建新實(shí)例
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());//meow
console.log(myCat.purr(5));//r-r-r-r-r
console.log(myCat.get_name());//meow Henrietta meow

這里用到了 create 方法來(lái)創(chuàng)建新的實(shí)例:

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

4 函數(shù)化

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

其實(shí)有更好的方法:應(yīng)用模塊模式。

我們先構(gòu)造一個(gè)生成對(duì)象的函數(shù),它有這些步驟:
①. 創(chuàng)建新對(duì)象。這有四種方式:
【1】構(gòu)造一個(gè)對(duì)象字面量。
【2】調(diào)用一個(gè)構(gòu)造器函數(shù)。
【3】構(gòu)造一個(gè)已存在對(duì)象的新實(shí)例。
【4】調(diào)用任意一個(gè)會(huì)返回對(duì)象的函數(shù)。
②. 定義私有實(shí)例變量與方法。
③. 為這個(gè)新對(duì)象擴(kuò)充方法,這些方法擁有特權(quán)去訪(fǎng)問(wèn)這些參數(shù)。
④. 返回這個(gè)新對(duì)象。

函數(shù)化構(gòu)造器的偽代碼如下:

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

spec 對(duì)象包含了需要構(gòu)造一個(gè)新實(shí)例的所有信息,它可以被用到到私有變量或者其他函數(shù)中。
my 對(duì)象為在一個(gè)繼承鏈中的構(gòu)造器提供了共享的容器,如果沒(méi)有傳入,那么會(huì)創(chuàng)建一個(gè) my 對(duì)象。

創(chuàng)建特權(quán)方法的方式是:把函數(shù)定義為私有方法,然后再把它們分配給 that:

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

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

現(xiàn)在,我們把這個(gè)模式應(yīng)用到 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());//Herb
var 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());//meow
console.log(myCat.purr(5));//r-r-r-r-r
console.log(myCat.get_name());//meow Henrietta meow

函數(shù)化模式還能調(diào)用父類(lèi)的方法。這里我們構(gòu)造一個(gè) superior 方法,它會(huì)返回調(diào)用某個(gè)方法名的函數(shù):

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

現(xiàn)在創(chuàng)建一個(gè) coolcat,它擁有一個(gè)可以調(diào)用父類(lèi)方法的 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

函數(shù)化模式有很大的靈活性,而且可以更好地實(shí)現(xiàn)封裝、信息隱藏以及訪(fǎng)問(wèn)父類(lèi)方法的能力。

如果對(duì)象所有的狀態(tài)都是私有的,那么就稱(chēng)為防偽對(duì)象。這個(gè)對(duì)象的屬性可以被替換或刪除,但這個(gè)對(duì)象的狀態(tài)不受影響。如果用函數(shù)化模式來(lái)創(chuàng)建對(duì)象,并且這個(gè)對(duì)象的所有方法都不使用 this 或 that,那么這個(gè)對(duì)象就是持久性的,它不會(huì)被入侵。除非存在特權(quán)方法,否則不能訪(fǎng)問(wèn)這個(gè)持久性對(duì)象的內(nèi)部狀態(tài)。

5 事件處理函數(shù)

可以構(gòu)造一個(gè)能夠給任何對(duì)象添加簡(jiǎn)單事件處理特性的函數(shù)。這里,我們給這個(gè)對(duì)象添加一個(gè) on 方法,fire 方法和私有的事件注冊(cè)對(duì)象:

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

可以在任何單獨(dú)對(duì)象上調(diào)用 eventuality,授予它事件處理方法。也可以在 that 被返回前,在構(gòu)造函數(shù)中調(diào)用它:

eventuality(that);

JavaScript 弱類(lèi)型的特性在此是一個(gè)巨大的優(yōu)勢(shì),因?yàn)槲覀儫o(wú)須處理對(duì)象繼承關(guān)系中的類(lèi)型O(∩_∩)O~

感興趣的朋友還可以使用本站在線(xiàn)HTML/CSS/JavaScript代碼運(yùn)行工具http://tools.jb51.net/code/HtmlJsRun測(cè)試上述代碼運(yùn)行結(jié)果。

更多關(guān)于JavaScript相關(guān)內(nèi)容還可查看本站專(zhuān)題:《javascript面向?qū)ο笕腴T(mén)教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)

希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • JavaScript使用Promise實(shí)現(xiàn)并發(fā)請(qǐng)求數(shù)限制

    JavaScript使用Promise實(shí)現(xiàn)并發(fā)請(qǐng)求數(shù)限制

    本文主要介紹了JavaScript使用Promise實(shí)現(xiàn)并發(fā)請(qǐng)求數(shù)限制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • ECMAScript5中的對(duì)象存取器屬性:getter和setter介紹

    ECMAScript5中的對(duì)象存取器屬性:getter和setter介紹

    這篇文章主要介紹了ECMAScript5中的對(duì)象屬性存取器:getter和setter介紹,事實(shí)上在除ie外最新主流瀏覽器的實(shí)現(xiàn)中,任何一個(gè)對(duì)象的鍵值都可以被getter和setter方法所取代,這被稱(chēng)之為“存取器屬性”,需要的朋友可以參考下
    2014-12-12
  • JS數(shù)組方法join()用法實(shí)例分析

    JS數(shù)組方法join()用法實(shí)例分析

    這篇文章主要介紹了JS數(shù)組方法join()用法,結(jié)合實(shí)例形式分析了JS數(shù)組join()方法具體功能、定義、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2020-01-01
  • JavaScript三大變量聲明詳析

    JavaScript三大變量聲明詳析

    這篇文章主要介紹了JavaScript三大變量聲明詳析,三大變量聲明主要包括var、const和let,下面文章我們就圍繞三者展開(kāi)詳細(xì)內(nèi)容介紹,需要的朋友可以參考一下
    2022-06-06
  • JavaScript實(shí)現(xiàn)文字展開(kāi)和收起效果

    JavaScript實(shí)現(xiàn)文字展開(kāi)和收起效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)文字展開(kāi)和收起效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • JavaScript實(shí)現(xiàn)星星等級(jí)評(píng)價(jià)功能

    JavaScript實(shí)現(xiàn)星星等級(jí)評(píng)價(jià)功能

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)星星等級(jí)評(píng)價(jià)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 小程序webView實(shí)現(xiàn)小程序內(nèi)嵌H5頁(yè)面的全過(guò)程

    小程序webView實(shí)現(xiàn)小程序內(nèi)嵌H5頁(yè)面的全過(guò)程

    在微信小程序中內(nèi)嵌H5頁(yè)面是一種常見(jiàn)的需求,因?yàn)镠5頁(yè)面具有靈活性和跨平臺(tái)性,可以彌補(bǔ)小程序原生代碼的不足,這篇文章主要給大家介紹了關(guān)于小程序webView實(shí)現(xiàn)小程序內(nèi)嵌H5頁(yè)面的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • 詳解PHP中pathinfo()函數(shù)導(dǎo)致的安全問(wèn)題

    詳解PHP中pathinfo()函數(shù)導(dǎo)致的安全問(wèn)題

    這篇文章主要給大家介紹了PHP中pathinfo()函數(shù)導(dǎo)致的安全問(wèn)題,文中給出了詳細(xì)的介紹與示例代碼,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下,下面來(lái)一起看看吧。
    2017-01-01
  • 小程序中監(jiān)聽(tīng)頁(yè)面滾動(dòng)的幾種方法實(shí)例

    小程序中監(jiān)聽(tīng)頁(yè)面滾動(dòng)的幾種方法實(shí)例

    這段時(shí)間接了一個(gè)微信小程序項(xiàng)目,從此打開(kāi)小程序的新世界大門(mén),下面這篇文章主要給大家介紹了關(guān)于小程序中監(jiān)聽(tīng)頁(yè)面滾動(dòng)的幾種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • 簡(jiǎn)單實(shí)現(xiàn)JS上傳圖片預(yù)覽功能

    簡(jiǎn)單實(shí)現(xiàn)JS上傳圖片預(yù)覽功能

    這篇文章主要為大家詳細(xì)介紹了如何簡(jiǎn)單實(shí)現(xiàn)JS上傳圖片預(yù)覽功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04

最新評(píng)論

和政县| 大足县| 东至县| 祥云县| 温泉县| 建平县| 随州市| 灵川县| 榆林市| 剑阁县| 奎屯市| 娄底市| 象州县| 浦县| 长岛县| 克东县| 珲春市| 东安县| 衡山县| 衡阳县| 乌拉特中旗| 阿图什市| 临漳县| 乐业县| 宣武区| 新田县| 南投市| 长汀县| 思茅市| 邵东县| 略阳县| 三河市| 江陵县| 临猗县| 株洲市| 张家口市| 罗山县| 丰台区| 阜阳市| 龙川县| 买车|