国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript專題之模擬實現call和apply

ky0ncheng / 2356人閱讀

摘要:函數可計算某個字符串,并執行其中的的代碼男男成功啦實現了函數參數的傳遞,那么函數返回值怎么處理呢。而且,如果傳入的對象是,又該如何處理所以還需要再做一些工作處理返回值返回返回值男男判斷傳入對象的類型,如果為就指向對象。

本文共 1320 字,讀完只需  5 分鐘
概述

JS 函數 call 和 apply 用來手動改變 this 的指向,call 和 apply 唯一的區別就在于函數參數的傳遞方式不同,call 是以逗號的形式,apply 是以數組的形式:

let person1 = {
    name: "person1",
    say: function(age, sex) {
        console.log(this.name + " age: " + age + " sex: " + sex);
    }
}

let person2 = {
    name: "person"
}

person1.say.call(person2, 20, "男");

person1.say.apply(person2, [20, "男"]);

本文就嘗試用其他方式來模擬實現 call 和 apply。

首先觀察 call 和 apply 有什么特點?

被函數調用(函數也是對象),相當于 call 和 apply 是函數的屬性

如果沒有傳入需要 this 指向對象,那么 this 指向全局對象

函數執行了

最后都改變了 this 的指向

一、初步實現

基于 call 函數是調用函數的屬性的特點,call 的 this 指向調用函數,我們可以嘗試把調用函數的作為傳入的新對象的一個屬性,執行后,再刪除這個屬性就好了。

Function.prototype.newCall = function (context) {
    context.fn = this;  // this 指的是 say 函數
    context.fn();
    delete context.fn;
}

var person = {
    name: "jayChou"
};

var say = function() {
    console.log(this.name);
}

say.newCall(person);  // jayChou

是不是就初步模擬實現了 call 函數呢,由于 call 還涉及到傳參的問題,所以我們進入到下一環節。

二、eval 方式

在給對象臨時一個函數,并執行時,傳入的參數是除了 context 其余的參數。那么我們可以截取 arguments 參數數組的第一個后,將剩余的參數傳入臨時數組。

在前面我有講過函數 arguments 類數組對象的特點,arguments 是不支持數組的大多數方法, 但是支持for 循環來遍歷數組。

Function.prototype.newCall = function (context) {
    context.fn = this;
    
    let args = [];
    
    for(let i=1; i< arguments.length; i++) {
        args.push("arguments[" + i + "]");
    }
    // args => [arguments[1], arguments[2], arguments[3], ...]
    
    context.fn(args.join(","));  // ???
    delete context.fn;
}

var person = {
    name: "jayChou"
};

var say = function(age, sex) {
    console.log(`name: ${this.name},age: ${age}, sex: ${sex}`);
}

say.newCall(person);

上面傳遞參數的方式最后肯定是失敗的,我們可以嘗試 eval 的方式,將參數添加子函數的作用域中。

eval() 函數可計算某個字符串,并執行其中的的 JavaScript 代碼
Function.prototype.newCall = function (context) {
    context.fn = this;
    
    let args = [];
    
    for(var i=1; i< arguments.length; i++) {
        args.push("arguments[" + i + "]");
    }

    // args => [arguments[1], arguments[2], arguments[3], ...]
    
    eval("context.fn(" + args + ")");
    delete context.fn;
}

var person = {
    name: "jayChou"
};

function say(age, sex) {
    console.log(`name: ${this.name},age: ${age}, sex: ${sex}`);
}

say.newCall(person, 18, "男");  // name: jayChou,age: 18, sex: 男

成功啦!
實現了函數參數的傳遞,那么函數返回值怎么處理呢。而且,如果傳入的對象是 null,又該如何處理?所以還需要再做一些工作:

Function.prototype.newCall = function (context) {
    if (typeof context === "object") {
        context = context || window
    } else {
        context = Object.create(null);
    }
    
    context.fn = this;
    
    let args = [];
    
    for(var i=1; i< arguments.length; i++) {
        args.push("arguments[" + i + "]");
    }

    // args => [arguments[1], arguments[2], arguments[3], ...]
    
    var result = eval("context.fn(" + args + ")");  // 處理返回值
    delete context.fn;
    return result;  // 返回返回值
}

var person = {
    name: "jayChou"
};

function say(age, sex) {
    console.log(`name: ${this.name},age: ${age}, sex: ${sex}`);
    return age + sex;
}

var check = say.newCall(person, 18, "男");
console.log(check); // 18男

判斷傳入對象的類型,如果為 null 就指向 window 對象。利用 eval 來執行字符串代碼,并返回字符串代碼執行的結果,就完成了模擬 call。
大功告成!

三、ES 6 實現

前面我們用的 eval 方式可以用 ES6 的解決還存在的一些問題,有沒有注意到,這段代碼是有問題的。

context.fn = this;

假如對象在被 call 調用前,已經有 fn 屬性怎么辦?

ES6 中提供了一種新的基本數據類型,Symbol,表示獨一無二的值,另外,Symbol 作為屬性的時候,不能使用點運算符。所以再加上 ES 的 rest 剩余參數替代 arguments 遍歷的工作就有:

Function.prototype.newCall = function (context,...params) {
    if (typeof context === "object") {
        context = context || window
    } else {
        context = Object.create(null);
    }
    let fn = Symbol();
    context[fn] = this
    var result = context[fn](...params);
    
    delete context.fn;
    return result;
}

var person = {
    name: "jayChou"
};

function say(age, sex) {
    console.log(`name: ${this.name},age: ${age}, sex: ${sex}`);
    return age + sex;
}

var check = say.newCall(person, 18, "男");
console.log(check); // 18男
四、apply

apply 和 call 的實現原理,基本類似,區別在于 apply 的參數是以數組的形式傳入。

Function.prototype.newApply = function (context, arr) {
    if (typeof context === "object") {
        context = context || window
    } else {
        context = Object.create(null);
    }
    context.fn = this;

    var result;
    if (!arr) {  // 判斷函數參數是否為空
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0; i < arr.length; i++) {
            args.push("arr[" + i + "]");
        }
        result = eval("context.fn(" + args + ")");
    }

    delete context.fn;
    return result;
}

es6 實現

Function.prototype.newApply = function(context, parameter) {
  if (typeof context === "object") {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context[fn] = this;
  var result = context[fn](...parameter);
  delete context[fn];
  return result;
}
總結

本文通過原生 JS 的 ES5 的方法和 ES 6 的方法模擬實現了 call 和 apply 的原理,旨在深入了解這兩個方法的用法和區別,希望你能有所收獲。

歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98832.html

相關文章

  • JavaScript專題模擬實現bind

    摘要:但是三作為構造函數時函數其實還有一個非常重要的特點返回的函數如果作為構造函數,搭配關鍵字出現的話,我們的綁定就需要被忽略。其次,當返回的函數作為構造函數時,之前綁定的會失效。 本文共 1100 字,讀完只需 4 分鐘 概述 前一篇文章我們嘗試模擬實現了 call 和 apply 方法,其實 bind 函數也可以用來改變 this 的指向。bind 和 call和 apply 兩者的區別...

    劉明 評論0 收藏0
  • JavaScript專題模擬實現new

    摘要:模擬實現操作符構造函數返回結果創建一個空對象取傳入的第一個參數,即構造函數,并刪除第一個參數。二處理返回值構造函數也是函數,有不同類型返回值。有時候構造函數會返回指定的對象內容,所以要對這部分進行處理。 本文共 1230 字,讀完只需 5 分鐘 寫在前面 最近工作太忙,快接近兩周沒更新博客,總感覺有一些事情等著自己去做,雖然工作內容對自己提升挺大,但我總覺得,一直埋著頭走路,偶爾也...

    pingink 評論0 收藏0
  • JavaScript深入系列15篇正式完結!

    摘要:寫在前面深入系列共計篇已經正式完結,這是一個旨在幫助大家,其實也是幫助自己捋順底層知識的系列。深入系列自月日發布第一篇文章,到月日發布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 深入系列共計 15 篇已經正式完結,這是一個旨在幫助大家,其實也是幫助自己捋順 JavaScript 底層知識的系列。重點講解了如原型、作用域、執行上下文、變量對象、this、...

    fxp 評論0 收藏0
  • JS專題數組去重

    摘要:將元素作為對象的鍵,默認鍵對應的值為如果對象中沒有這個鍵,則將這個元素放入結果數組中去。 前言 數組去重在日常開發中的使用頻率還是較高的,也是網上隨便一抓一大把的話題,所以,我寫這篇文章目的在于歸納和總結,既然很多人都在提的數組去重,自己到底了解多少呢。又或者是如果自己在開發中遇到了去重的需求,自己能想到更好的解決方案嗎。 這次我們來理一理怎么做數組去重才能做得最合適,既要考慮兼容性,...

    only_do 評論0 收藏0
  • JavaScript專題遞歸

    摘要:專題系列第十八篇,講解遞歸和尾遞歸定義程序調用自身的編程技巧稱為遞歸。然而非尾調用函數,就會創建多個執行上下文壓入執行上下文棧。所以我們只用把階乘函數改造成一個尾遞歸形式,就可以避免創建那么多的執行上下文。 JavaScript 專題系列第十八篇,講解遞歸和尾遞歸 定義 程序調用自身的編程技巧稱為遞歸(recursion)。 階乘 以階乘為例: function factorial(n...

    asoren 評論0 收藏0

發表評論

0條評論

ky0ncheng

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<