成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

前端面試題:Call的用法及實現

開發 前端
手寫 Call,核心在于通過另一種修改 this 指向的方式:Obj.fn() 執行時 This 會指向Obj 對象。

大家好,我是前端西瓜哥。

我之前寫了一篇手寫 bind 的文章,里面直接使用了原生 call 方法。

有讀者說他面試的時候這個 call 也要求自己實現的。

那我們今天來手寫 call。apply 的實現也是一樣,只是調用形式有點區別。

call 的用法

我們先看看 Function.prototype.call() 的用法。

call() 可以修改函數調用時 this 的指向,其余參數則會作為原函數的參數。

call 接收的參數:

  1. 第一個參數 thisArg。代表 this 將會被指向的值。如果不是對象,也會通過 Object() 方法轉換為對象。如果是 null 或 undefined,this 則會指向全局對象(即 window 或 global),或在嚴格模式("use strict;")下,保持 undefined 或 null;
  2. 其余參數。第二個往后的參數則會傳入到原函數中。

例子:

function sum(num1, num2) {
return this.val + num1 + num2;
}
const obj = { val: 1 };
sum.call(obj, 2, 3); // 6

上面代碼中,this 指向了 obj。

Function.prototype.apply 也是類似,但它的參數是以數組的形式存在的。上面的 call 寫法等價于:

sum.call(obj, [2, 3]);

call 的實現

JS 函數中的 this 指向是在運行時決定的,里面的規則比較多,但其中有一條是:

如果是通過 obj.fn() 執行時,this 會指向前面的 obj 對象。

那我們只要將傳入對象和原方法進行拼接,拼成上面這個 對象.方法 的形式,執行時,this 就能乖乖指向我們傳入的 thisArg 了。

實現如下:

Function.prototype.myCall = function(thisArg, ...args) {
const context = Object(thisArg) || window;
// 構造唯一 key
const fn = Symbol();
// 組裝成"對象.方法"形式并調用,來改變 this
context[fn] = this;
const ret = context[fn](...args);
// 刪掉臨時加的 key,復原 thisArg
delete context[fn];
return ret;
}

這里我們用 Symbol() 創建了一個唯一的 key,是為了防止覆蓋掉 thisArg 原有的同名屬性。

執行完后,記得將這個 key 移除掉,防止污染 thisArg 對象。

如果面試官要你用 ES5 實現,那會復雜很多,我這里也給出實現吧。

在這之前,我們先來學點前置知識。

判斷是否為嚴格模式

var strict = (function() { return !this })();

利用了嚴格模式下,如果沒有指定 this(通過 bind、call、前面帶對象等方式),就會得到 undefined 的機制。如果是非嚴格模式,this 會拿到全局變量。

fn(...args) 的 ES5 實現

ES6 的擴展運算符 ... 能夠將數組 args,進行拆分按順序放到函數中。

const args = [4, 5, 6];
fn(...args);
// 等價于
fn(4, 5, 6);

那我們用 ES5,也能將數組拆分成一個參數塞到函數中嗎?

可以,但我們要用一點奇技淫巧:Function 方法。

Function 方法用得比較少。它可以在運行時創建一個函數,最后一個參數是函數體內容,前面的參數則是函數的參數。

const sum = new Function('a', 'b', 'return a + b');
sum(2, 6) // 8

fn(...args) 的 ES5 實現為:

function construct(fn, args) {
var list = [];
for (var i = 0; i < args.length; i++) {
list[i] = 'a[' + i + ']';
}
var f = new Function('fn', 'a', 'return fn(' + list.join(', ') + ')');
return f(fn, args);
}

Function 方法可以根據參數長度,動態生成 new Function('fn', 'a', 'return fn(a[0], a[1])') 形式的函數,來實現類似擴展運算符的效果。

還有種寫法是用 eval,也能根據字符串動態生成可執行代碼。

function construct(fn, a) {
var list = [];
for (var i = 0; i < a.length; i++) {
list[i] = 'a[' + i + ']';
}
return eval('fn(' + list.join(', ') + ')');
}

但這種封裝成一個函數的寫法,會有 this 隱式丟失問題。比如執行 construct(dog.bark, ['bark!']),執行時 this 將不再指向對象 dog。

關于 this 的指向問題還是比較復雜的,以后我會專門寫一篇文章來講解 this。

call 的 ES5 實現

Function.prototype.myCall = function(thisArg/*, ...args */) {
var context = Object(thisArg) || window;
context.fn = this;
// 偷懶用了 Array.prototype.slice + 原生 call
// 請讀者自行實現 slice
var a = Array.prototype.slice.call(arguments, 1);
var list = [];
for (var i = 0; i < a.length; i++) {
list[i] = 'a[' + i + ']';
}
var ret = eval('context.fn(' + list.join(',') + ')');
delete context.fn; // 復原
return ret;
}

為了不被干擾,上面的代碼實現 忽略掉了一些細節。

  • 這里我沒有用前面實現的 construct 方法,因為會丟失 this,所以直接用了 eval。
  • slice 請自行實現,不能用 Array.prototype.slice.call,因為用了原生的 call。
  • 我們用了一個字符串 'fn'來臨時掛載函數,可能會和 thisArg 上的屬性名沖突,但 ES5 又不能用 Symbol,這種情況下。更好的做法是生成一個隨機的長字符串,用hasOwnProperty判斷對象是否存在該屬性,如果不存在就使用它。
  • this 不可調用時(即不是函數時),要拋出錯誤。

另外我的實現,沒有考慮嚴格模式。嚴格模式下,如果 thisArg 是 undefined 或 null,直接執行原函數就行了,不需要拼裝成 obj.fn 形式。

結尾

手寫 call,核心在于通過另一種修改 this 指向的方式:obj.fn() 執行時 this 會指向 obj 對象。

手寫 apply 也是一樣的邏輯,還能少寫一個 slice 方法。

責任編輯:姜華 來源: 今日頭條
相關推薦

2023-08-27 15:57:28

前端開發

2022-01-18 08:16:52

Web 前端JavaScript

2022-07-08 08:21:26

JSbind 方法

2022-02-09 07:40:42

JavaScript前端面試題

2019-02-21 14:12:26

前端面試題Vue

2023-05-19 08:21:40

MarginCSS

2021-02-02 06:12:39

JavaScript 前端面試題

2018-03-08 18:40:47

Java百度面試題

2023-12-12 07:40:52

JavaScript面試題前端

2017-09-06 09:13:24

2015-07-23 14:13:43

前端開發面試題

2020-11-06 09:05:18

前端web開發

2023-04-27 09:08:19

JavaScript隱式類型轉換

2012-06-26 11:09:07

Web

2021-03-15 09:53:37

計算機網絡面試題

2024-02-26 15:35:44

2018-05-10 16:52:03

阿里巴巴前端面試題

2012-02-02 09:45:24

Web

2009-02-16 13:03:43

華為面試

2021-07-04 08:01:30

Synchronize線程安全并發編程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91精品国产99久久 | 亚洲一区二区三区在线播放 | 人操人免费视频 | 动漫www.被爆羞羞av44 | 国产视频h | 夜夜操av | 日本在线免费看最新的电影 | 水蜜桃亚洲一二三四在线 | 天堂一区二区三区四区 | 午夜ww | 午夜性色a√在线视频观看9 | 亚洲一区二区三区四区五区中文 | 一区二区精品 | 日本精品999 | 亚洲一区不卡在线 | 天天拍天天操 | 正在播放国产精品 | 男人的天堂久久 | 成人在线播放 | 久久国产精品99久久久久 | 龙珠z在线观看 | 欧美成人一级 | 高清久久久 | 国产在线精品一区二区 | 日韩国产黄色片 | 久久久久久亚洲欧洲 | 99久久久无码国产精品 | 成人一区二区视频 | 欧美aaaa视频| 欧美精品 在线观看 | 国产精品久久久久久妇女6080 | 成人激情视频在线播放 | 久久国产一区二区三区 | 成人免费在线电影 | 激情福利视频 | 国产中文字幕网 | 欧美性一区二区三区 | 国产免费xxx | h视频在线免费 | 午夜三区 | 亚洲av毛片成人精品 |