<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      深入理解JavaScript系列(46):代碼復(fù)用模式(推薦篇)

      2012-04-24 08:38  湯姆大叔  閱讀(22279)  評論(19)    收藏  舉報

      介紹

      本文介紹的四種代碼復(fù)用模式都是最佳實踐,推薦大家在編程的過程中使用。

      模式1:原型繼承

      原型繼承是讓父對象作為子對象的原型,從而達到繼承的目的:

      function object(o) {
      function F() {
      }

      F.prototype = o;
      return new F();
      }

      // 要繼承的父對象
      var parent = {
      name: "Papa"
      };

      // 新對象
      var child = object(parent);

      // 測試
      console.log(child.name); // "Papa"


      // 父構(gòu)造函數(shù)
      function Person() {
      // an "own" property
      this.name = "Adam";
      }
      // 給原型添加新屬性
      Person.prototype.getName = function () {
      return this.name;
      };
      // 創(chuàng)建新person
      var papa = new Person();
      // 繼承
      var kid = object(papa);
      console.log(kid.getName()); // "Adam"


      // 父構(gòu)造函數(shù)
      function Person() {
      // an "own" property
      this.name = "Adam";
      }
      // 給原型添加新屬性
      Person.prototype.getName = function () {
      return this.name;
      };
      // 繼承
      var kid = object(Person.prototype);
      console.log(typeof kid.getName); // "function",因為是在原型里定義的
      console.log(typeof kid.name); // "undefined", 因為只繼承了原型

      同時,ECMAScript5也提供了類似的一個方法叫做Object.create用于繼承對象,用法如下:

      /* 使用新版的ECMAScript 5提供的功能 */
      var child = Object.create(parent);

      var child = Object.create(parent, {
      age: { value: 2} // ECMA5 descriptor
      });
      console.log(child.hasOwnProperty("age")); // true

      而且,也可以更細粒度地在第二個參數(shù)上定義屬性:

      // 首先,定義一個新對象man
      var man = Object.create(null);

      // 接著,創(chuàng)建包含屬性的配置設(shè)置
      //
      屬性設(shè)置為可寫,可枚舉,可配置
      var config = {
      writable: true,
      enumerable: true,
      configurable: true
      };

      // 通常使用Object.defineProperty()來添加新屬性(ECMAScript5支持)
      //
      現(xiàn)在,為了方便,我們自定義一個封裝函數(shù)
      var defineProp = function (obj, key, value) {
      config.value = value;
      Object.defineProperty(obj, key, config);
      }

      defineProp(man, 'car', 'Delorean');
      defineProp(man, 'dob', '1981');
      defineProp(man, 'beard', false);

      所以,繼承就這么可以做了:

      var driver = Object.create( man );
      defineProp (driver, 'topSpeed', '100mph');
      driver.topSpeed // 100mph

      但是有個地方需要注意,就是Object.create(null)創(chuàng)建的對象的原型為undefined,也就是沒有toStringvalueOf方法,所以alert(man);的時候會出錯,但alert(man.car);是沒問題的。

      模式2:復(fù)制所有屬性進行繼承

      這種方式的繼承就是將父對象里所有的屬性都復(fù)制到子對象上,一般子對象可以使用父對象的數(shù)據(jù)。

      先來看一個淺拷貝的例子:

      /* 淺拷貝 */
      function extend(parent, child) {
      var i;
      child = child || {};
      for (i in parent) {
      if (parent.hasOwnProperty(i)) {
      child[i] = parent[i];
      }
      }
      return child;
      }

      var dad = { name: "Adam" };
      var kid = extend(dad);
      console.log(kid.name); // "Adam"

      var dad = {
      counts: [1, 2, 3],
      reads: { paper: true }
      };
      var kid = extend(dad);
      kid.counts.push(4);
      console.log(dad.counts.toString()); // "1,2,3,4"
      console.log(dad.reads === kid.reads); // true

      代碼的最后一行,你可以發(fā)現(xiàn)dad和kid的reads是一樣的,也就是他們使用的是同一個引用,這也就是淺拷貝帶來的問題。

      我們再來看一下深拷貝:

      /* 深拷貝 */
      function extendDeep(parent, child) {
      var i,
      toStr = Object.prototype.toString,
      astr = "[object Array]";

      child = child || {};

      for (i in parent) {
      if (parent.hasOwnProperty(i)) {
      if (typeof parent[i] === 'object') {
      child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
      extendDeep(parent[i], child[i]);
      } else {
      child[i] = parent[i];
      }
      }
      }
      return child;
      }

      var dad = {
      counts: [1, 2, 3],
      reads: { paper: true }
      };
      var kid = extendDeep(dad);

      kid.counts.push(4);
      console.log(kid.counts.toString()); // "1,2,3,4"
      console.log(dad.counts.toString()); // "1,2,3"

      console.log(dad.reads === kid.reads); // false
      kid.reads.paper = false;

      深拷貝以后,兩個值就不相等了,bingo!

      模式3:混合(mix-in)

      混入就是將一個對象的一個或多個(或全部)屬性(或方法)復(fù)制到另外一個對象,我們舉一個例子:

      function mix() {
      var arg, prop, child = {};
      for (arg = 0; arg < arguments.length; arg += 1) {
      for (prop in arguments[arg]) {
      if (arguments[arg].hasOwnProperty(prop)) {
      child[prop] = arguments[arg][prop];
      }
      }
      }
      return child;
      }

      var cake = mix(
      { eggs: 2, large: true },
      { butter: 1, salted: true },
      { flour: '3 cups' },
      { sugar: 'sure!' }
      );

      console.dir(cake);

      mix函數(shù)將所傳入的所有參數(shù)的子屬性都復(fù)制到child對象里,以便產(chǎn)生一個新對象。

      那如何我們只想混入部分屬性呢?該個如何做?其實我們可以使用多余的參數(shù)來定義需要混入的屬性,例如mix(child,parent,method1,method2)這樣就可以只將parent里的method1和method2混入到child里。上代碼:

      // Car 
      var Car = function (settings) {
      this.model = settings.model || 'no model provided';
      this.colour = settings.colour || 'no colour provided';
      };

      // Mixin
      var Mixin = function () { };
      Mixin.prototype = {
      driveForward: function () {
      console.log('drive forward');
      },
      driveBackward: function () {
      console.log('drive backward');
      }
      };


      // 定義的2個參數(shù)分別是被混入的對象(reciving)和從哪里混入的對象(giving)
      function augment(receivingObj, givingObj) {
      // 如果提供了指定的方法名稱的話,也就是參數(shù)多余3個
      if (arguments[2]) {
      for (var i = 2, len = arguments.length; i < len; i++) {
      receivingObj.prototype[arguments[i]] = givingObj.prototype[arguments[i]];
      }
      }
      // 如果不指定第3個參數(shù),或者更多參數(shù),就混入所有的方法
      else {
      for (var methodName in givingObj.prototype) {
      // 檢查receiving對象內(nèi)部不包含要混入的名字,如何包含就不混入了
      if (!receivingObj.prototype[methodName]) {
      receivingObj.prototype[methodName] = givingObj.prototype[methodName];
      }
      }
      }
      }

      // 給Car混入屬性,但是值混入'driveForward' 和 'driveBackward'*/
      augment(Car, Mixin, 'driveForward', 'driveBackward');

      // 創(chuàng)建新對象Car
      var vehicle = new Car({ model: 'Ford Escort', colour: 'blue' });

      // 測試是否成功得到混入的方法
      vehicle.driveForward();
      vehicle.driveBackward();

      該方法使用起來就比較靈活了。

      模式4:借用方法

      一個對象借用另外一個對象的一個或兩個方法,而這兩個對象之間不會有什么直接聯(lián)系。不用多解釋,直接用代碼解釋吧:

      var one = {
      name: 'object',
      say: function (greet) {
      return greet + ', ' + this.name;
      }
      };

      // 測試
      console.log(one.say('hi')); // "hi, object"

      var two = {
      name: 'another object'
      };

      console.log(one.say.apply(two, ['hello'])); // "hello, another object"

      // 將say賦值給一個變量,this將指向到全局變量
      var say = one.say;
      console.log(say('hoho')); // "hoho, undefined"

      // 傳入一個回調(diào)函數(shù)callback
      var yetanother = {
      name: 'Yet another object',
      method: function (callback) {
      return callback('Hola');
      }
      };
      console.log(yetanother.method(one.say)); // "Holla, undefined"

      function bind(o, m) {
      return function () {
      return m.apply(o, [].slice.call(arguments));
      };
      }

      var twosay = bind(two, one.say);
      console.log(twosay('yo')); // "yo, another object"


      // ECMAScript 5給Function.prototype添加了一個bind()方法,以便很容易使用apply()和call()。

      if (typeof Function.prototype.bind === 'undefined') {
      Function.prototype.bind = function (thisArg) {
      var fn = this,
      slice = Array.prototype.slice,
      args = slice.call(arguments, 1);
      return function () {
      return fn.apply(thisArg, args.concat(slice.call(arguments)));
      };
      };
      }

      var twosay2 = one.say.bind(two);
      console.log(twosay2('Bonjour')); // "Bonjour, another object"

      var twosay3 = one.say.bind(two, 'Enchanté');
      console.log(twosay3()); // "Enchanté, another object"

      總結(jié)

      就不用總結(jié)了吧。

      同步與推薦

      本文已同步至目錄索引:深入理解JavaScript系列

      深入理解JavaScript系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載等各類型的文章,如果對你有用,請推薦支持一把,給大叔寫作的動力。

      主站蜘蛛池模板: 国产深夜福利在线免费观看| 日韩有码中文在线观看| 亚洲精品国产综合久久一线| 亚洲国产日韩一区三区| 国产成人精品午夜在线观看| www免费视频com| 欧美深度肠交惨叫| 久久se精品一区精品二区国产 | 在线日韩日本国产亚洲| 97成人碰碰久久人人超级碰oo| 成人免费无遮挡在线播放| 亚洲性无码av在线| 亚洲深深色噜噜狠狠网站| 国产AV影片麻豆精品传媒| 国产不卡一区不卡二区| h动态图男女啪啪27报gif| 国内不卡一区二区三区| 欧日韩无套内射变态| 亚洲开心婷婷中文字幕| 亚洲区中文字幕日韩精品| 国产精品无码无在线观看| 久久精品网站免费观看| 亚洲av一本二本三本| 色偷偷久久一区二区三区| 伊大人香蕉久久网欧美| 花莲县| 久久精品蜜芽亚洲国产AV| 国产精品一区二区三区91| 日韩在线视频线观看一区| 无码任你躁久久久久久老妇| 久久久精品人妻一区二区三区| 高清精品视频一区二区三区| 欧美亚洲国产一区二区三区| 美乳丰满人妻无码视频| 办公室强奷漂亮少妇视频| 中文字幕99国产精品| 丰满熟妇人妻av无码区| 日韩有码中文字幕av| 国产精品一区二区传媒蜜臀| 亚洲国产精品人人做人人爱| 成人亚欧欧美激情在线观看|