JavaScript手寫代碼

1.手寫promise

// exector 執(zhí)行器
function Promise1(exector) {
    var that = this;
    this.status = "pedding";      //設(shè)置狀態(tài)
    this.resolveParams = "";    //resolve返回的值
    this.rejectParams = "";      //存儲reject 返回的值
    this.resolveFn = [];          //存儲then中成功的回調(diào)函數(shù)
    this.rejectFn = [];         //存儲then中失敗的回調(diào)函數(shù)
    function resolve(value) {
        //只有在pedding狀態(tài)才執(zhí)行  防止多次點擊
        if (that.status == "pedding") {
            that.status = "resolved";
            that.resolveParams = value;
            that.resolveFn.forEach(fn => fn(value))
        }
    }

    function reject(value) {
        //只有在pedding狀態(tài)才執(zhí)行  防止多次點擊
        if (that.status == "pedding") {
            that.status = "rejected";
            that.rejectParams = value;
            that.rejectFn.forEach(fn => fn(value))
        }
    }

    //執(zhí)行器捕獲異常
    try {
        exector(resolve, reject);
    } catch (e) {
        reject(e)
    }
}

Promise1.prototype.then = function (resolve1, reject1) {
    var that = this;

    //同步執(zhí)行成功回調(diào)函數(shù)
    if (this.status == "resolved") {
        resolve1(that.resolveParams)
    }
    //同步執(zhí)行失敗回調(diào)函數(shù)
    if (this.status == "rejected") {
        reject1(that.rejectParams)
    }

    //異步情況時   保存回調(diào)函數(shù)
    if (this.status == "pedding") {
        this.resolveFn.push((val) => {
            resolve1(val)
        })
        this.rejectFn.push((val) => {
            reject1(val)
        })
    }
}


//測試
function test() {
    return new Promise1((resolve, reject) => {
        setTimeout(() => {
            let val = Math.random();
            if (val > 0.5) {
                resolve('成功')
            } else {
                reject('失敗')
            }
        }, 100)
    })
}

test().then(res => {
    console.log(res)
}, (err) => {
    console.log(err)
})

2.數(shù)組和對象深拷貝

1.JSON.parse(JSON.stringify())
2.手寫簡易版

function deepCopy(obj) {
    if (typeof obj !== "object"||!obj) {
        return obj;
    }
    const result= Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        result[key] = typeof obj[key] !== "object" ? obj[key] : deepCopy(obj[key]);
    }
    return result;
}

3.完整版

/**
 * deep clone
 * @param  {[type]} parent object 需要進行克隆的對象
 * @return {[type]}        深克隆后的對象
 */
const clone = parent => {
  // 判斷類型
  const isType = (obj, type) => {
    if (typeof obj !== "object") return false;
    const typeString = Object.prototype.toString.call(obj);
    let flag;
    switch (type) {
      case "Array":
        flag = typeString === "[object Array]";
        break;
      case "Date":
        flag = typeString === "[object Date]";
        break;
      case "RegExp":
        flag = typeString === "[object RegExp]";
        break;
      default:
        flag = false;
    }
    return flag;
  };

  // 處理正則
  const getRegExp = re => {
    var flags = "";
    if (re.global) flags += "g";
    if (re.ignoreCase) flags += "i";
    if (re.multiline) flags += "m";
    return flags;
  };
  // 維護兩個儲存循環(huán)引用的數(shù)組
  const parents = [];
  const children = [];

  const _clone = parent => {
    if (parent === null) return null;
    if (typeof parent !== "object") return parent;

    let child, proto;

    if (isType(parent, "Array")) {
      // 對數(shù)組做特殊處理
      child = [];
    } else if (isType(parent, "RegExp")) {
      // 對正則對象做特殊處理
      child = new RegExp(parent.source, getRegExp(parent));
      if (parent.lastIndex) child.lastIndex = parent.lastIndex;
    } else if (isType(parent, "Date")) {
      // 對Date對象做特殊處理
      child = new Date(parent.getTime());
    } else {
      // 處理對象原型
      proto = Object.getPrototypeOf(parent);
      // 利用Object.create切斷原型鏈
      child = Object.create(proto);
    }

    // 處理循環(huán)引用
    const index = parents.indexOf(parent);

    if (index != -1) {
      // 如果父數(shù)組存在本對象,說明之前已經(jīng)被引用過,直接返回此對象
      return children[index];
    }
    parents.push(parent);
    children.push(child);

    for (let i in parent) {
      // 遞歸
      child[i] = _clone(parent[i]);
    }

    return child;
  };
  return _clone(parent);
};


3.繼承的實現(xiàn) 原型鏈繼承

子類實例化出來的對象擁有父類的屬性和方法
子類實例化出來的對象屬于子類,也屬于父類
原型鏈繼承金三句:

  • 讓子類實例化出來的對象擁有父類的屬性 Person.apply(this,arguments)
  • 讓子類擁有父類的所有方法Student.prototype=Object.create(Person.prototype)谨读;
  • 找回丟失的構(gòu)造器Student.prototype.constructor=Student;
//定義一個父類
function Person(name,age){
    this.name=name;
    this.age=age;
}
Person.prototype.run=function(){
    console.log(this.name+'正在散步')
}
//定義一個子類
function Student(name,age,score){
   this.score=score;
   //讓子類實例化出來的對象擁有父類的屬性  apply 和call都可以
   Person.apply(this,arguments) 
}
//讓子類擁有父類的所有方法
Student.prototype=Object.create(Person.prototype);
//找回丟失的構(gòu)造器
Student.prototype.constructor=Student;
Student.prototype.read=function(){
    console.log(this.name+'正在看書')
}

let student1 = new Student('張三',20,100);
console.dir(student1 );
console.log(student1 instanceof Student); //true
console.log(student1 instanceof Person);  //true

Object.create 原理

function create(proto) {
    function F(){}
    F.prototype = proto;
    return new F();
}

4.new 操作符實現(xiàn)

  • 它創(chuàng)建了一個全新的對象拳氢。
  • 它會被執(zhí)行[[Prototype]](也就是proto)鏈接蒋譬。
  • 它使this指向新創(chuàng)建的對象徐裸。羊初。
  • 通過new創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個函數(shù)的prototype對象上。
    如果函數(shù)沒有返回對象類型Object(包含F(xiàn)unctoin, Array, Date, RegExg, Error)舶衬,那么new表達式中的函數(shù)調(diào)用將返回該對象引用埠通。
function New(Fn) {
    let obj = {}
    let arg = Array.prototype.slice.call(arguments, 1)
    obj.__proto__ = Fn.prototype
    obj.__proto__.constructor = Fn
    Fn.apply(obj, arg)
    return obj
}

5.實現(xiàn)instanceOf

function instance_of(left, R) {
  //L 表示左表達式,R 表示右表達式
  var O = R.prototype; // 取 R 的顯示原型
  left= left.__proto__; // 取left 的隱式原型
  while (true) {
    if (left === null) return false;
    if (O === left){
      // 這里重點:當(dāng) O 嚴(yán)格等于left 時逛犹,返回 true
      return true;
    }
   left= left.__proto__;
  }
}

6.解析 URL Params 為對象

function parseParam(url) {
  const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 將 ? 后面的字符串取出來
  const paramsArr = paramsStr.split('&'); // 將字符串以 & 分割后存到數(shù)組中
  let paramsObj = {};
  // 將 params 存到對象中
  paramsArr.forEach(param => {
    if (/=/.test(param)) { // 處理有 value 的參數(shù)
      let [key, val] = param.split('='); // 分割 key 和 value
      val = decodeURIComponent(val); // 解碼
      val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判斷是否轉(zhuǎn)為數(shù)字

      if (paramsObj.hasOwnProperty(key)) { // 如果對象有 key植阴,則添加一個值
        paramsObj[key] = [].concat(paramsObj[key], val);
      } else { // 如果對象沒有這個 key,創(chuàng)建 key 并設(shè)置值
        paramsObj[key] = val;
      }
    } else { // 處理沒有 value 的參數(shù)
      paramsObj[param] = true;
    }
  })

  return paramsObj;
}

7.實現(xiàn)一個call

// 模擬 call bar.mycall(null);
//實現(xiàn)一個call方法:
Function.prototype.myCall = function(context) {
  //此處沒有考慮context非object情況
  context.fn = this;
  let args = [];
  for (let i = 1, len = arguments.length; i < len; i++) {
    args.push(arguments[i]);
  }
  context.fn(...args);
  let result = context.fn(...args);
  delete context.fn;
  return result;
};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末圾浅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子憾朴,更是在濱河造成了極大的恐慌狸捕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件众雷,死亡現(xiàn)場離奇詭異灸拍,居然都是意外死亡,警方通過查閱死者的電腦和手機砾省,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門鸡岗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人编兄,你說我怎么就攤上這事轩性。” “怎么了狠鸳?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵揣苏,是天一觀的道長。 經(jīng)常有香客問我件舵,道長卸察,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任铅祸,我火速辦了婚禮坑质,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘临梗。我一直安慰自己涡扼,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布夜焦。 她就那樣靜靜地躺著壳澳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茫经。 梳的紋絲不亂的頭發(fā)上巷波,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天萎津,我揣著相機與錄音,去河邊找鬼抹镊。 笑死锉屈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垮耳。 我是一名探鬼主播颈渊,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼终佛!你這毒婦竟也來了俊嗽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤铃彰,失蹤者是張志新(化名)和其女友劉穎绍豁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牙捉,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡竹揍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了邪铲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芬位。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖带到,靈堂內(nèi)的尸體忽然破棺而出昧碉,到底是詐尸還是另有隱情,我是刑警寧澤阴孟,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布晌纫,位于F島的核電站,受9級特大地震影響永丝,放射性物質(zhì)發(fā)生泄漏锹漱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一慕嚷、第九天 我趴在偏房一處隱蔽的房頂上張望哥牍。 院中可真熱鬧,春花似錦喝检、人聲如沸嗅辣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澡谭。三九已至,卻和暖如春损俭,著一層夾襖步出監(jiān)牢的瞬間蛙奖,已是汗流浹背潘酗。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雁仲,地道東北人仔夺。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像攒砖,于是被迫代替她去往敵國和親缸兔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353