JavaScript實現(xiàn)常用API

一、new運算符

語法
new constructor[([arguments])]

constructor
一個指定對象實例的類型的類或函數(shù)第煮。
arguments
一個用于被 constructor 調(diào)用的參數(shù)列表。

描述

當(dāng)代碼 new Foo(...) 執(zhí)行時,會發(fā)生以下事情:

  1. 一個繼承自 Foo.prototype 的新對象被創(chuàng)建砂竖。
  2. 使用指定的參數(shù)調(diào)用構(gòu)造函數(shù) Foo,并將 this 綁定到新創(chuàng)建的對象秦叛。new Foo 等同于 new Foo()晦溪,也就是沒有指定參數(shù)列表,Foo*不帶任何參數(shù)調(diào)用的情況挣跋。
  3. 由構(gòu)造函數(shù)返回的對象就是 new 表達(dá)式的結(jié)果三圆。如果構(gòu)造函數(shù)沒有顯式返回一個對象,則使用步驟1創(chuàng)建的對象避咆。(一般情況下舟肉,構(gòu)造函數(shù)不返回值,但是用戶可以選擇主動返回對象查库,來覆蓋正常的對象創(chuàng)建步驟)路媚。

根據(jù)上面的條件,我們就可以寫代碼了

 function myNew(constructor, ...args) {
        //以構(gòu)造器原型創(chuàng)建對象
        let instance = Object.create(constructor.prototype);
        //執(zhí)行構(gòu)造器樊销,并把構(gòu)造器內(nèi)部的this指向返回的對象
        let res = constructor.apply(instance, args);
        //如果構(gòu)造器有返回對象,則使用返回的對象整慎,沒有則使用以構(gòu)造器原型創(chuàng)建對象
        return typeof res === "object" ? res : instance;
      }

測試代碼

let mFunc = myNew(Foo, "張三");
      mFunc.work();
      console.log(mFunc.name);

二、call/apply方法

call語法
fun.call(thisArg, arg1, arg2, ...)

thisArg
在 fun 函數(shù)運行時指定的 this 值围苫。
if(thisArg == undefined|null) this = window裤园,
if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()
arg1, arg2, ...
指定的參數(shù)列表。

返回值

使用調(diào)用者提供的 this 值和參數(shù)調(diào)用該函數(shù)的返回值剂府。若該方法沒有返回值拧揽,則返回 undefined

apply語法
func.apply(thisArg, [argsArray])

thisArg
可選的。在 func 函數(shù)運行時使用的 this 值淤袜。請注意痒谴,this可能不是該方法看到的實際值:如果這個函數(shù)處于非嚴(yán)格模式下,則指定為 nullundefined 時會自動替換為指向全局對象铡羡,原始值會被包裝积蔚。
argsArray
可選的。一個數(shù)組或者類數(shù)組對象蓖墅,其中的數(shù)組元素將作為單獨的參數(shù)傳給 func 函數(shù)库倘。如果該參數(shù)的值為 nullundefined,則表示不需要傳入任何參數(shù)论矾。從ECMAScript 5 開始可以使用類數(shù)組對象教翩。
其實call和apply的區(qū)別就是第二個參數(shù),apply第二個參數(shù)是一個數(shù)組或者類數(shù)組贪壳。其他的和call一樣饱亿,性能也一樣。所以闰靴,自定義功能時彪笼,唯一的區(qū)別就是傳遞的參數(shù)。
根據(jù)上面的條件蚂且,我們就可以寫代碼了

      Function.prototype.MyCall = function(context, ...args) {
        //獲取當(dāng)前this(調(diào)用MyCall的函數(shù))配猫,自定義的call方法在函數(shù)的原型對象上,所以typeof this =='function'
        let mFunc = this;
        //創(chuàng)建變量杏死,作為指定this對象(call的第一個參數(shù)context)的屬性名
        let fnKey = "fnKey";
        //把當(dāng)前this(調(diào)用MyCall的函數(shù))作為屬性值保存到指定this對象(call的第一個參數(shù)context)上泵肄,屬性名為上面定義的fnKey
        context[fnKey] = mFunc;
        //調(diào)用指定this對象(call的第一個參數(shù)context)上的當(dāng)前this(調(diào)用MyCall的函數(shù))
        let result = context[fnKey](...args);
        //執(zhí)行結(jié)束,刪除該屬性
        delete context[fnKey];
        return result;
      };
     Function.prototype.MyApply = function(context, args) {
        //獲取當(dāng)前this(調(diào)用MyCall的函數(shù))淑翼,自定義的call方法在函數(shù)的原型對象上腐巢,所以typeof this =='function'
        let mFunc = this;
        //創(chuàng)建變量,作為指定this對象(call的第一個參數(shù)context)的屬性名
        let fnKey = "fnKey";
        //把當(dāng)前this(調(diào)用MyCall的函數(shù))作為屬性值保存到指定this對象(call的第一個參數(shù)context)上玄括,屬性名為上面定義的fnKey
        context[fnKey] = mFunc;
        //調(diào)用指定this對象(call的第一個參數(shù)context)上的當(dāng)前this(調(diào)用MyCall的函數(shù))
        let result = context[fnKey](...args);
        //執(zhí)行結(jié)束冯丙,刪除該屬性
        delete context[fnKey];
        return result;
      };

測試代碼

 let obj = {
        name: "張三",
        id: 1002
      };
      function TestFunc(name, id) {
        this.name = name;
        this.id = id;
        return {
          name: this.name,
          id: this.id
        };
      }
      let resCall = TestFunc.MyCall(obj, "abc", 11111);
      console.log(obj);
      console.log(resCall);
      let resApply = TestFunc.MyApply(obj, ["efg", 2222]);
      console.log(obj);
      console.log(resApply);

三、Object.create()方法

語法
Object.create(proto[, propertiesObject])

proto
新創(chuàng)建對象的原型對象
propertiesObject
可選遭京。如果沒有指定為 undefined胃惜,則是要添加到新創(chuàng)建對象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對象的屬性描述符以及相應(yīng)的屬性名稱哪雕。這些屬性對應(yīng)Object.defineProperties()的第二個參數(shù)船殉。
返回新的對象,帶著指定的原型對象和屬性热监。
這里偷個懶捺弦,給新對象添加屬性就采用Object.defineProperties()饮寞,不熟悉Object.defineProperties()可以點擊上面藍(lán)色部分查看孝扛,里面也有兼容版本polyfill的實現(xiàn)列吼。
根據(jù)上面的條件,我們就可以寫代碼了

 Object.prototype.myCreate = function(proto, propertiesObject) {
        //判斷傳入的原型對象
        if (typeof proto !== "object" && typeof proto !== "function") {
          throw new TypeError("Object prototype may only be an Object");
        } else if (proto === null) {
          throw new Error(" Object.create不支持第一個參數(shù)為null");
        }
        if (propertiesObject === null) {
          throw new Error(" Object.create第二個參數(shù)不能為null");
        }
        //創(chuàng)建一個構(gòu)造函數(shù)
        function F() {}
        //設(shè)置構(gòu)造函數(shù)的原型為新創(chuàng)建對象的原型對象
        F.prototype = proto;
        //構(gòu)造器的原型對象的constructor指向自身苦始,防止原型鏈錯亂
        F.prototype.constructor = F;
        //創(chuàng)建實例對象
        let newObj = new F();
        //加到新創(chuàng)建對象的可枚舉屬性
        if (typeof propertiesObject != "undefined") {
          //這里偷懶,這個API暫時就不自定義
          Object.defineProperties(newObj, propertiesObject);
        }
        return newObj;
      };

測試代碼

     let obj = {};
      let propertiesObj = {
        property1: {
          value: true,
          writable: true
        },
        property2: {
          value: "Hello",
          writable: false
        }
      };
      console.log(Object.create(obj, propertiesObj));
      let myObj = Object.myCreate(obj, propertiesObj);
      console.log(myObj);

四寞钥、數(shù)組的map方法

語法
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
}[, thisArg])

callback
生成新數(shù)組元素的函數(shù),使用三個參數(shù):
currentValue
callback 數(shù)組中正在處理的當(dāng)前元素陌选。
index可選
callback 數(shù)組中正在處理的當(dāng)前元素的索引理郑。
array可選
callback map 方法被調(diào)用的數(shù)組。
thisArg可選
執(zhí)行 callback 函數(shù)時使用的this 值咨油。
返回一個新數(shù)組您炉,每個元素都是回調(diào)函數(shù)的結(jié)果。
根據(jù)上面的條件役电,我們就可以寫代碼了

       Array.prototype.MyMap = function (callBack, context) {
           // 淺拷貝要遍歷的數(shù)組
           var copyArr = Array.prototype.slice.call(this);
            //有就使用赚爵,null或者undefined,設(shè)定為全局對象
            context = context || window;
            //調(diào)函數(shù)的結(jié)果
            var resultArr = [];
            for (let index = 0; index < copyArr.length; index++) {
                //是否是自己的屬性
                if (!copyArr.hasOwnProperty(index)) continue;
                //把回調(diào)結(jié)果放入返回的數(shù)組中法瑟,回調(diào)函數(shù)按照上面設(shè)置為三個參數(shù)
                resultArr.push(callBack.call(context, copyArr[index], index, this));
            }
            return resultArr;
        }

測試代碼

        let arr = [1, 2, { name: '123' }];
        arr.MyMap(function(item,index,context){
            console.log('item:'+item,"index:"+index);
            console.log(this);
        },{id:123});
結(jié)果
        let arr = [1, 2, { name: '123' }];
       let newArr= arr.MyMap(function(item,index,context){
            console.log('item:'+item,"index:"+index);
            console.log(this);
            return {name:item}
        });
        console.log(newArr);
image.png

另外冀膝,map方法中,對于每一項是淺拷貝霎挟。

        let arr = [1, 2, { name: '123' }];
        arr.map(function (item,index) {
            if (typeof item === 'object') {
                item.id = 4555;
            } else {
                item = index;
            }
        });
  console.log(arr);

image.png

所以窝剖,上面采用淺拷貝就行,淺拷貝和深拷貝有疑惑的酥夭,可以閱讀一下這篇文章

五赐纱、數(shù)組的reduce方法

語法
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

callback
執(zhí)行數(shù)組中每個值的函數(shù),包含四個參數(shù):
accumulator
累計器累計回調(diào)的返回值; 它是上一次調(diào)用回調(diào)時返回的累積值采郎,或initialValue(見于下方)千所。
currentValue
數(shù)組中正在處理的元素。
currentIndex可選
數(shù)組中正在處理的當(dāng)前元素的索引蒜埋。 如果提供了initialValue淫痰,則起始索引號為0,否則為1整份。
array可選
調(diào)用reduce()的數(shù)組
initialValue可選
作為第一次調(diào)用 callback函數(shù)時的第一個參數(shù)的值待错。 如果沒有提供初始值,則將使用數(shù)組中的第一個元素烈评。 在沒有初始值的空數(shù)組上調(diào)用 reduce 將報錯火俄。
返回函數(shù)累計處理的結(jié)果。
根據(jù)上面的條件讲冠,我們就可以寫代碼了

        Array.prototype.myReduce = function (callBack, initialValue) {
            // 淺拷貝要遍歷的數(shù)組
            let copyArr = Array.prototype.slice.call(this);
            //提供初始值瓜客,從第一項開始,沒有提供從第二項開始
            let currentIndex = initialValue ? 0 : 1;
            let result = initialValue ? initialValue : copyArr[0];
            for (let index = currentIndex; index < copyArr.length; index++) {
                //調(diào)用回調(diào)函數(shù),按照上面的設(shè)置四個參數(shù)
                result = callBack.call(null, result, copyArr[index], index, this);
            }
            return result;
        }

下面是測試代碼

      let redarr = [1, 2, 3, 4, 5];
        let result = redarr.reduce(function (accumulator, item) {
            return accumulator + item;
        }, 10);
        console.log(result);
        let mResult = redarr.myReduce(function (accumulator, item) {
            return accumulator + item;
            return
        }, 10);
        console.log(mResult);
結(jié)果

bind方法

語法
function.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg
調(diào)用綁定函數(shù)時作為this參數(shù)傳遞給目標(biāo)函數(shù)的值谱仪。 如果使用new運算符構(gòu)造綁定函數(shù)玻熙,則忽略該值。當(dāng)使用bindsetTimeout中創(chuàng)建一個函數(shù)(作為回調(diào)提供)時疯攒,作為thisArg傳遞的任何原始值都將轉(zhuǎn)換為object嗦随。如果bind函數(shù)的參數(shù)列表為空,執(zhí)行作用域的this將被視為新函數(shù)的thisArg敬尺。
arg1, arg2, ...
當(dāng)目標(biāo)函數(shù)被調(diào)用時,預(yù)先添加到綁定函數(shù)的參數(shù)列表中的參數(shù)砂吞。
返回一個原函數(shù)的拷貝,并擁有指定的this值和初始參數(shù)蜻直。
根據(jù)上面的條件,我們就可以寫代碼了

      Function.prototype.myBind = function(context, ...args) {
        //獲取當(dāng)前方法
        let _that = this;
        //創(chuàng)建返回的函數(shù)
        let mNewFunc = function(...argsNew) {
          //把參數(shù)拼接袭蝗,并改變原函數(shù)的this對象,返回原函數(shù)的返回值
          return _that.apply(context || window, [...args, ...argsNew]);
        };
        //保證原函數(shù)的原型對象上的屬性不丟失
        mNewFunc.prototype = Object.create(_that.prototype);
        return mNewFunc;
      };

測試代碼

      var myName = "999";
      let module = {
        myName: "上海"
      };
      function bindFuc(args) {}
      bindFuc.myName = "ABCDE";
      function textFuc(args) {
        console.log("args:", arguments);
        console.log("myName:" + this.myName);
      }
      var boundTextFuc = textFuc.bind(module, "123");
      boundTextFuc("145");
      var boundTextFuc = textFuc.myBind(module, "123");
      boundGetX("145");

instanceof運算符

語法
object instanceof constructor

object
要檢測的對象
constructor
某個構(gòu)造函數(shù)
instanceof 運算符用來檢測 constructor.prototype 是否存在于參數(shù) object 的原型鏈上朵逝。
根據(jù)上面的條件,我們就可以寫代碼了

      Object.prototype.myInstanceof = function(constructor) {
        //獲取要檢測的對象
        let object = this;
        //判斷constructor是否是對象
        if (constructor == null || typeof constructor !== "function") {
          return new Error("第二個參數(shù)必須為構(gòu)造函數(shù)");
        }
        //獲取驗檢測對象的原型
        let objProto = Object.getPrototypeOf(object);
        //循環(huán)在檢測對象的原型鏈上查找是否存在constructor.prototype
        while (true) {
          //排除檢測對象是Object.prototype的原型的情況
          if (objProto == null) return false;
          if (objProto == constructor.prototype) return true;
          objProto = Object.getPrototypeOf(objProto);
        }
      };

測試代碼

      function TestFunc() {}
      let mTestFunc = new TestFunc();
      console.log(mTestFunc.myInstanceof(Number),mTestFunc instanceof Number);
      console.log(mTestFunc.myInstanceof(Function),mTestFunc instanceof Function);
      console.log(mTestFunc.myInstanceof(Object),mTestFunc instanceof Object);
      console.log(Function.myInstanceof(Object),Function instanceof Object);
      console.log(Object.myInstanceof(Function),Object instanceof Function);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末配名,一起剝皮案震驚了整個濱河市渠脉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芋膘,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件为朋,死亡現(xiàn)場離奇詭異,居然都是意外死亡厚脉,警方通過查閱死者的電腦和手機(jī)习寸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來傻工,“玉大人霞溪,你說我怎么就攤上這事孵滞。” “怎么了鸯匹?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵剃斧,是天一觀的道長。 經(jīng)常有香客問我忽你,道長,這世上最難降的妖魔是什么臂容? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任科雳,我火速辦了婚禮,結(jié)果婚禮上脓杉,老公的妹妹穿的比我還像新娘糟秘。我一直安慰自己,他們只是感情好球散,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布尿赚。 她就那樣靜靜地躺著,像睡著了一般蕉堰。 火紅的嫁衣襯著肌膚如雪凌净。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天屋讶,我揣著相機(jī)與錄音冰寻,去河邊找鬼。 笑死皿渗,一個胖子當(dāng)著我的面吹牛斩芭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乐疆,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼划乖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挤土?” 一聲冷哼從身側(cè)響起琴庵,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤细卧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贪庙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翰苫,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡这橙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年导披,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹰晨。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡模蜡,死狀恐怖忍疾,靈堂內(nèi)的尸體忽然破棺而出卤妒,到底是詐尸還是另有隱情字币,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布收叶,位于F島的核電站判没,受9級特大地震影響澄峰,放射性物質(zhì)發(fā)生泄漏辟犀。R本人自食惡果不足惜堂竟,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一出嘹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烦秩,春花似錦、人聲如沸兜蠕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岭皂。三九已至爷绘,卻和暖如春进倍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陶因。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工楷扬, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留烘苹,地道東北人片部。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓廊鸥,卻偏偏與公主長得像辖所,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子助被,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容