摘要:來自朋友去某信用卡管家的做的一道面試題,用原生模擬的方法,不準用和方法。他們的用途相同,都是在特定的作用域中調用函數。不同之處在于,方法傳遞給調用函數的參數是逐個列出的,而則是要寫在數組中。
本文首發我的個人博客:前端小密圈,評論交流送1024邀請碼,嘿嘿嘿?。
來自朋友去某信用卡管家的做的一道面試題,用原生JavaScript模擬ES5的bind方法,不準用call和bind方法。
至于結果嘛。。。那個人當然是沒寫出來,我就自己嘗試研究了一番,其實早就寫了,一直沒有組織好語言發出來。
額。。。這個題有點刁鉆,這是對JavaScript基本功很好的一個檢測,看你JavaScript掌握的怎么樣以及平時有沒有去深入研究一些方法的實現,簡而言之,就是有沒有折騰精神。
不準用不用call和apply方法,這個沒啥好說的,不準用我們就用原生JavaScript先來模擬一個apply方法,感興趣的童鞋也可以看看chrome的v8怎么實現這個方法的,這里我只按照自己的思維實現,在模擬之前我們先要明白和了解原生call和apply方法是什么。
簡單粗暴地來說,call,apply,bind是用于綁定this指向的。(如果你還不了解JS中this的指向問題,以及執行環境上下文的奧秘,這篇文章暫時就不太適合閱讀)。
什么是call和apply方法我們多帶帶看看ECMAScript規范對apply的定義,看個大概就行:
15.3.4.3 Function.prototype.apply (thisArg, argArray)
順便貼一貼中文版,免得翻譯一下,中文版地址:
通過定義簡單說一下call和apply方法,他們就是參數不同,作用基本相同。
1、每個函數都包含兩個非繼承而來的方法:apply()和call()。
2、他們的用途相同,都是在特定的作用域中調用函數。
3、接收參數方面不同,apply()接收兩個參數,一個是函數運行的作用域(this),另一個是參數數組。
4、call()方法第一個參數與apply()方法相同,但傳遞給函數的參數必須列舉出來。
知道定義然后,直接看個簡單的demo
var jawil = { name: "jawil", sayHello: function (age) { console.log("hello, i am ", this.name + " " + age + " years old"); } }; var lulin = { name: "lulin", }; jawil.sayHello(24); // hello, i am jawil 24 years old
然后看看使用apply和call之后的輸出:
jawil.sayHello.call(lulin, 24);// hello, i am lulin 24 years old jawil.sayHello.apply(lulin, [24]);// hello, i am lulin 24 years old
結果都相同。從寫法上我們就能看出二者之間的異同。相同之處在于,第一個參數都是要綁定的上下文,后面的參數是要傳遞給調用該方法的函數的。不同之處在于,call方法傳遞給調用函數的參數是逐個列出的,而apply則是要寫在數組中。
總結一句話介紹call和apply
分析call和apply的原理call()方法在使用一個指定的this值和若干個指定的參數值的前提下調用某個函數或方法。
apply()方法在使用一個指定的this值和參數值必須是數組類型的前提下調用某個函數或方法。
上面代碼,我們注意到了兩點:
call和apply改變了this的指向,指向到lulin
sayHello函數執行了
這里默認大家都對this有一個基本的了解,知道什么時候this該指向誰,我們結合這兩句話來分析這個通用函數:f.apply(o),我們直接看一本書對其中原理的解讀,具體什么書,我也不知道,參數我們先不管,先了解其中的大致原理。
正好可以打印lulin而不是之前的jawil了,哎,不容易啊!?
模擬實現第二步最一開始也講了,apply函數還能給定參數執行函數。舉個例子:
var jawil = { name: "jawil", sayHello: function (age) { console.log(this.name,age); } }; var lulin = { name: "lulin", }; jawil.sayHello.apply(lulin,[24])//lulin 24
注意:傳入的參數就是一個數組,很簡單,我們可以從Arguments對象中取值,Arguments不知道是何物,趕緊補習,此文也不太適合初學者,第二個參數就是數組對象,但是執行的時候要把數組數值傳遞給函數當參數,然后執行,這就需要一點小技巧。
參數問題其實很簡單,我們先偷個懶,我們接著要把這個參數數組放到要執行的函數的參數里面去。
Function.prototype.applyTwo = function(context) { // 首先要獲取調用call的函數,用this可以獲取 context.fn = this; var args = arguments[1] //獲取傳入的數組參數 context.fn(args.join(","); delete context.fn; }
很簡單是不是,那你就錯了,數組join方法返回的是啥?
typeof [1,2,3,4].join(",")//string
Too young,too simple啊,最后是一個 "1,2,3,4" 的字符串,其實就是一個參數,肯定不行啦。
也許有人會想到用ES6的一些奇淫方法,不過apply是ES3的方法,我們為了模擬實現一個ES3的方法,要用到ES6的方法,反正面試官也沒說不準這樣。但是我們這次用eval方法拼成一個函數,類似于這樣:
eval("context.fn(" + args +")")
先簡單了解一下eval函數吧
定義和用法
eval() 函數可計算某個字符串,并執行其中的的 JavaScript 代碼。
語法:
eval(string)
string必需。要計算的字符串,其中含有要計算的 JavaScript 表達式或要執行的語句。該方法只接受原始字符串作為參數,如果 string 參數不是原始字符串,那么該方法將不作任何改變地返回。因此請不要為 eval() 函數傳遞 String 對象來作為參數。
簡單來說吧,就是用JavaScript的解析引擎來解析這一堆字符串里面的內容,這么說吧,你可以這么理解,你把eval看成是標簽。
eval("function Test(a,b,c,d){console.log(a,b,c,d)};Test(1,2,3,4)")
就是相當于這樣
第二版代碼大致如下:
Function.prototype.applyTwo = function(context) { var args = arguments[1]; //獲取傳入的數組參數 context.fn = this; //假想context對象預先不存在名為fn的屬性 var fnStr = "context.fn("; for (var i = 0; i < args.length; i++) { fnStr += i == args.length - 1 ? args[i] : args[i] + ","; } fnStr += ")";//得到"context.fn(arg1,arg2,arg3...)"這個字符串在,最后用eval執行 eval(fnStr); //還是eval強大 delete context.fn; //執行完畢之后刪除這個屬性 } //測試一下 var jawil = { name: "jawil", sayHello: function (age) { console.log(this.name,age); } }; var lulin = { name: "lulin", }; jawil.sayHello.applyTwo(lulin,[24])//lulin 24
好像就行了是不是,其實這只是最粗糙的版本,能用,但是不完善,完成了大約百分之六七十了。
模擬實現第三步其實還有幾個小地方需要注意:
1.this參數可以傳null或者不傳,當為null的時候,視為指向window
舉個兩個簡單栗子栗子?:
demo1:
var name = "jawil"; function sayHello() { console.log(this.name); } sayHello.apply(null); // "jawil"
demo2:
var name = "jawil"; function sayHello() { console.log(this.name); } sayHello.apply(); // "jawil"
2.函數是可以有返回值的.
舉個簡單栗子?:
var obj = { name: "jawil" } function sayHello(age) { return { name: this.name, age: age } } console.log(sayHello.apply(obj,[24]));// {name: "jawil", age: 24}
這些都是小問題,想到了,就很好解決。我們來看看此時的第三版apply模擬方法。
//原生JavaScript封裝apply方法,第三版 Function.prototype.applyThree = function(context) { var context = context || window var args = arguments[1] //獲取傳入的數組參數 context.fn = this //假想context對象預先不存在名為fn的屬性 if (args == void 0) { //沒有傳入參數直接執行 return context.fn() } var fnStr = "context.fn(" for (var i = 0; i < args.length; i++) { //得到"context.fn(arg1,arg2,arg3...)"這個字符串在,最后用eval執行 fnStr += i == args.length - 1 ? args[i] : args[i] + "," } fnStr += ")" var returnValue = eval(fnStr) //還是eval強大 delete context.fn //執行完畢之后刪除這個屬性 return returnValue }
好緊張,再來做個小測試,demo,應該不會出問題:
var obj = { name: "jawil" } function sayHello(age) { return { name: this.name, age: age } } console.log(sayHello.applyThree(obj,[24]));// 完美輸出{name: "jawil", age: 24}
完美?perfact?這就好了,不存在的,我們來看看第四步的實現。
模擬實現第四步其實一開始就埋下了一個隱患,我們看看這段代碼:
Function.prototype.applyThree = function(context) { var context = context || window var args = arguments[1] //獲取傳入的數組參數 context.fn = this //假想context對象預先不存在名為fn的屬性 ...... }
就是這句話, context.fn = this //假想context對象預先不存在名為fn的屬性,這就是一開始的隱患,我們只是假設,但是并不能防止contenx對象一開始就沒有這個屬性,要想做到完美,就要保證這個context.fn中的fn的唯一性。
于是我自然而然的想到了強大的ES6,這玩意還是好用啊,幸好早就了解并一直在使用ES6,還沒有學習過ES6的童鞋趕緊學習一下,沒有壞處的。
重新復習下新知識:
基本數據類型有6種:Undefined、Null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。
ES5對象屬性名都是字符串容易造成屬性名的沖突。
舉個栗子?:
var a = { name: "jawil"}; a.name = "lulin"; //這樣就會重寫屬性
ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。
注意,Symbol函數前不能使用new命令,否則會報錯。這是因為生成的Symbol是一個原始類型的值,不是對象
Symbol函數可以接受一個字符串作為參數,表示對Symbol實例的描述,主要是為了在控制臺顯示,或者轉為字符串時,比較容易區分。
// 沒有參數的情況 var s1 = Symbol(); var s2 = Symbol(); s1 === s2 // false // 有參數的情況 var s1 = Symbol("foo"); var s2 = Symbol("foo"); s1 === s2 // false
注意:Symbol值不能與其他類型的值進行運算。
作為屬性名的Symbol
var mySymbol = Symbol(); // 第一種寫法 var a = {}; a[mySymbol] = "Hello!"; // 第二種寫法 var a = { [mySymbol]: "Hello!" }; // 第三種寫法 var a = {}; Object.defineProperty(a, mySymbol, { value: "Hello!" }); // 以上寫法都得到同樣結果 a[mySymbol] // "Hello!"
注意,Symbol值作為對象屬性名時,不能用點運算符。
看看下面這個栗子?:
var a = {}; var name = Symbol(); a.name = "jawil"; a[name] = "lulin"; console.log(a.name,a[name]); //jawil,lulin
Symbol值作為屬性名時,該屬性還是公開屬性,不是私有屬性。
這個有點類似于java中的protected屬性(protected和private的區別:在類的外部都是不可以訪問的,在類內的子類可以繼承protected不可以繼承private)
但是這里的Symbol在類外部也是可以訪問的,只是不會出現在for...in、for...of循環中,也不會被Object.keys()、Object.getOwnPropertyNames()返回。但有一個Object.getOwnPropertySymbols方法,可以獲取指定對象的所有Symbol屬性名。
看看第四版的實現demo,想必大家了解上面知識已經猜得到怎么寫了,很簡單。
直接加個var fn = Symbol()就行了,,,
//原生JavaScript封裝apply方法,第四版 Function.prototype.applyFour = function(context) { var context = context || window var args = arguments[1] //獲取傳入的數組參數 var fn = Symbol() context[fn] = this //假想context對象預先不存在名為fn的屬性 if (args == void 0) { //沒有傳入參數直接執行 return context[fn]() } var fnStr = "context[fn](" for (var i = 0; i < args.length; i++) { //得到"context.fn(arg1,arg2,arg3...)"這個字符串在,最后用eval執行 fnStr += i == args.length - 1 ? args[i] : args[i] + "," } fnStr += ")" var returnValue = eval(fnStr) //還是eval強大 delete context[fn] //執行完畢之后刪除這個屬性 return returnValue }模擬實現第五步
呃呃呃額額,慢著,ES3就出現的方法,你用ES6來實現,你好意思么?你可能會說,不管黑貓白貓,只要能抓住老鼠的貓就是好貓,面試官直說不準用call和apply方法但是沒說不準用ES6語法啊。
反正公說公有理婆說婆有理,這里還是不用Symbol方法實現一下,我們知道,ES6其實都是語法糖,ES6能寫的,咋們ES5都能實現,這就導致了babel這類把ES6語法轉化成ES5的代碼了。
至于babel把Symbol屬性轉換成啥代碼了,我也沒去看,有興趣的可以看一下稍微研究一下,這里我說一下簡單的模擬。
ES5 沒有 Sybmol,屬性名稱只可能是一個字符串,如果我們能做到這個字符串不可預料,那么就基本達到目標。要達到不可預期,一個隨機數基本上就解決了。
//簡單模擬Symbol屬性 function jawilSymbol(obj) { var unique_proper = "00" + Math.random(); if (obj.hasOwnProperty(unique_proper)) { arguments.callee(obj)//如果obj已經有了這個屬性,遞歸調用,直到沒有這個屬性 } else { return unique_proper; } } //原生JavaScript封裝apply方法,第五版 Function.prototype.applyFive = function(context) { var context = context || window var args = arguments[1] //獲取傳入的數組參數 var fn = jawilSymbol(context); context[fn] = this //假想context對象預先不存在名為fn的屬性 if (args == void 0) { //沒有傳入參數直接執行 return context[fn]() } var fnStr = "context[fn](" for (var i = 0; i < args.length; i++) { //得到"context.fn(arg1,arg2,arg3...)"這個字符串在,最后用eval執行 fnStr += i == args.length - 1 ? args[i] : args[i] + "," } fnStr += ")" var returnValue = eval(fnStr) //還是eval強大 delete context[fn] //執行完畢之后刪除這個屬性 return returnValue }
好緊張,再來做個小測試,demo,應該不會出問題:
var obj = { name: "jawil" } function sayHello(age) { return { name: this.name, age: age } } console.log(sayHello.applyFive(obj,[24]));// 完美輸出{name: "jawil", age: 24}
到此,我們完成了apply的模擬實現,給自己一個贊 b( ̄▽ ̄)d
實現Call方法這個不需要講了吧,道理都一樣,就是參數一樣,這里我給出我實現的一種方式,看不懂,自己寫一個去。
//原生JavaScript封裝call方法 Function.prototype.callOne = function(context) { return this.applyFive(([].shift.applyFive(arguments), arguments) //巧妙地運用上面已經實現的applyFive函數 }
看不太明白也不能怪我咯,我就不細講了,看個demo證明一下,這個寫法沒問題。
Function.prototype.applyFive = function(context) {//剛才寫的一大串} Function.prototype.callOne = function(context) { return this.applyFive(([].shift.applyFive(arguments)), arguments) //巧妙地運用上面已經實現的applyFive函數 } //測試一下 var obj = { name: "jawil" } function sayHello(age) { return { name: this.name, age: age } } console.log(sayHello.callOne(obj,24));// 完美輸出{name: "jawil", age: 24}實現bind方法
養兵千日,用兵一時。
什么是bind函數如果掌握了上面實現apply的方法,我想理解起來模擬實現bind方法也是輕而易舉,原理都差不多,我們還是來看看bind方法的定義。
我們還是簡單的看下ECMAScript規范對bind方法的定義,暫時看不懂不要緊,獲取幾個關鍵信息就行。
15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]])
注意一點,ECMAScript規范提到: Function.prototype.bind 創建的函數對象不包含 prototype 屬性或 [[Code]], [[FormalParameters]], [[Scope]] 內部屬性。
bind() 方法會創建一個新函數,當這個新函數被調用時,它的 this 值是傳遞給 bind() 的第一個參數, 它的參數是 bind() 的其他參數和其原本的參數,bind返回的綁定函數也能使用new操作符創建對象:這種行為就像把原函數當成構造器。提供的this值被忽略,同時調用時的參數被提供給模擬函數。。
語法是這樣樣子的:fun.bind(thisArg[, arg1[, arg2[, ...]]])
呃呃呃,是不是似曾相識,這不是call方法的語法一個樣子么,,,但它們是一樣的嗎?
bind方法傳遞給調用函數的參數可以逐個列出,也可以寫在數組中。bind方法與call、apply最大的不同就是前者返回一個綁定上下文的函數,而后兩者是直接執行了函數。由于這個原因,上面的代碼也可以這樣寫:
jawil.sayHello.bind(lulin)(24); //hello, i am lulin 24 years old jawil.sayHello.bind(lulin)([24]); //hello, i am lulin 24 years old
bind方法還可以這樣寫 fn.bind(obj, arg1)(arg2).
用一句話總結bind的用法:該方法創建一個新函數,稱為綁定函數,綁定函數會以創建它時傳入bind方法的第一個參數作為this,傳入bind方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。
bind在實際中的應用實際使用中我們經常會碰到這樣的問題:
function Person(name){ this.nickname = name; this.distractedGreeting = function() { setTimeout(function(){ console.log("Hello, my name is " + this.nickname); }, 500); } } var alice = new Person("jawil"); alice.distractedGreeting(); //Hello, my name is undefined
這個時候輸出的this.nickname是undefined,原因是this指向是在運行函數時確定的,而不是定義函數時候確定的,再因為setTimeout在全局環境下執行,所以this指向setTimeout的上下文:window。關于this指向問題,這里就不細扯
以前解決這個問題的辦法通常是緩存this,例如:
function Person(name){ this.nickname = name; this.distractedGreeting = function() { var self = this; // <-- 注意這一行! setTimeout(function(){ console.log("Hello, my name is " + self.nickname); // <-- 還有這一行! }, 500); } } var alice = new Person("jawil"); alice.distractedGreeting(); // after 500ms logs "Hello, my name is jawil"
這樣就解決了這個問題,非常方便,因為它使得setTimeout函數中可以訪問Person的上下文。但是看起來稍微一種蛋蛋的憂傷。
但是現在有一個更好的辦法!您可以使用bind。上面的例子中被更新為:
function Person(name){ this.nickname = name; this.distractedGreeting = function() { setTimeout(function(){ console.log("Hello, my name is " + this.nickname); }.bind(this), 500); // <-- this line! } } var alice = new Person("jawil"); alice.distractedGreeting(); // after 500ms logs "Hello, my name is jawil"
bind() 最簡單的用法是創建一個函數,使這個函數不論怎么調用都有同樣的 this 值。JavaScript新手經常犯的一個錯誤是將一個方法從對象中拿出來,然后再調用,希望方法中的 this 是原來的對象。(比如在回調中傳入這個方法。)如果不做特殊處理的話,一般會丟失原來的對象。從原來的函數和原來的對象創建一個綁定函數,則能很漂亮地解決這個問題:
this.x = 9; var module = { x: 81, getX: function() { return this.x; } }; module.getX(); // 81 var getX = module.getX; getX(); // 9, 因為在這個例子中,"this"指向全局對象 // 創建一個"this"綁定到module的函數 var boundGetX = getX.bind(module); boundGetX(); // 81
很不幸,Function.prototype.bind 在IE8及以下的版本中不被支持,所以如果你沒有一個備用方案的話,可能在運行時會出現問題。bind 函數在 ECMA-262 第五版才被加入;它可能無法在所有瀏覽器上運行。你可以部份地在腳本開頭加入以下代碼,就能使它運作,讓不支持的瀏覽器也能使用 bind() 功能。
幸運的是,我們可以自己來模擬bind功能:
初級實現了解了以上內容,我們來實現一個初級的bind函數Polyfill:
Function.prototype.bind = function (context) { var me = this; var argsArray = Array.prototype.slice.callOne(arguments); return function () { return me.applyFive(context, argsArray.slice(1)) } }
我們先簡要解讀一下:
基本原理是使用apply進行模擬。函數體內的this,就是需要綁定this的實例函數,或者說是原函數。最后我們使用apply來進行參數(context)綁定,并返回。
同時,將第一個參數(context)以外的其他參數,作為提供給原函數的預設參數,這也是基本的“顆?;╟urring)”基礎。
上面的實現(包括后面的實現),其實是一個典型的“Monkey patching(猴子補丁)”,即“給內置對象擴展方法”。所以,如果面試者能進行一下“嗅探”,進行兼容處理,就是錦上添花了。
Function.prototype.bind = Function.prototype.bind || function (context) { ... }顆?;╟urring)實現
對于函數的柯里化不太了解的童鞋,可以先嘗試讀讀這篇文章:前端基礎進階(八):深入詳解函數的柯里化。
上述的實現方式中,我們返回的參數列表里包含:atgsArray.slice(1),他的問題在于存在預置參數功能丟失的現象。
想象我們返回的綁定函數中,如果想實現預設傳參(就像bind所實現的那樣),就面臨尷尬的局面。真正實現顆粒化的“完美方式”是:
Function.prototype.bind = Function.prototype.bind || function (context) { var me = this; var args = Array.prototype.slice.callOne(arguments, 1); return function () { var innerArgs = Array.prototype.slice.callOne(arguments); var finalArgs = args.concat(innerArgs); return me.applyFive(context, finalArgs); } }
上面什么是bind函數還介紹到:bind返回的函數如果作為構造函數,搭配new關鍵字出現的話,我們的綁定this就需要“被忽略”。
構造函數場景下的兼容有了上邊的講解,不難理解需要兼容構造函數場景的實現:
Function.prototype.bind = Function.prototype.bind || function (context) { var me = this; var args = Array.prototype.slice.callOne(arguments, 1); var F = function () {}; F.prototype = this.prototype; var bound = function () { var innerArgs = Array.prototype.slice.callOne(arguments); var finalArgs = args.concat(innerArgs); return me.apply(this instanceof F ? this : context || this, finalArgs); } bound.prototype = new F(); return bound; }更嚴謹的做法
我們需要調用bind方法的一定要是一個函數,所以可以在函數體內做一個判斷:
if (typeof this !== "function") { throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); }
做到所有這一切,基本算是完成了。其實MDN上有個自己實現的polyfill,就是如此實現的。
另外,《JavaScript Web Application》一書中對bind()的實現,也是如此。
//簡單模擬Symbol屬性 function jawilSymbol(obj) { var unique_proper = "00" + Math.random(); if (obj.hasOwnProperty(unique_proper)) { arguments.callee(obj)//如果obj已經有了這個屬性,遞歸調用,直到沒有這個屬性 } else { return unique_proper; } } //原生JavaScript封裝apply方法,第五版 Function.prototype.applyFive = function(context) { var context = context || window var args = arguments[1] //獲取傳入的數組參數 var fn = jawilSymbol(context); context[fn] = this //假想context對象預先不存在名為fn的屬性 if (args == void 0) { //沒有傳入參數直接執行 return context[fn]() } var fnStr = "context[fn](" for (var i = 0; i < args.length; i++) { //得到"context.fn(arg1,arg2,arg3...)"這個字符串在,最后用eval執行 fnStr += i == args.length - 1 ? args[i] : args[i] + "," } fnStr += ")" var returnValue = eval(fnStr) //還是eval強大 delete context[fn] //執行完畢之后刪除這個屬性 return returnValue } //簡單模擬call函數 Function.prototype.callOne = function(context) { return this.applyFive(([].shift.applyFive(arguments)), arguments) //巧妙地運用上面已經實現的applyFive函數 } //簡單模擬bind函數 Function.prototype.bind = Function.prototype.bind || function (context) { var me = this; var args = Array.prototype.slice.callOne(arguments, 1); var F = function () {}; F.prototype = this.prototype; var bound = function () { var innerArgs = Array.prototype.slice.callOne(arguments); var finalArgs = args.concat(innerArgs); return me.applyFive(this instanceof F ? this : context || this, finalArgs); } bound.prototype = new F(); return bound; }
好緊張,最后來做個小測試,demo,應該不會出問題:
var obj = { name: "jawil" } function sayHello(age) { return { name: this.name, age: age } } console.log(sayHello.bind(obj,24)());// 完美輸出{name: "jawil", age: 24}
看了這篇文章,以后再遇到類似的問題,應該能夠順利通過吧~
參考文章ES6入門之Symbol
ECMAScript 5.1(英文版)
從一道面試題,到“我可能看了假源碼”
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91681.html
摘要:來自朋友去某信用卡管家的做的一道面試題,用原生模擬的方法,不準用和方法。他們的用途相同,都是在特定的作用域中調用函數。不同之處在于,方法傳遞給調用函數的參數是逐個列出的,而則是要寫在數組中。 本文首發我的個人博客:前端小密圈,評論交流送1024邀請碼,嘿嘿嘿?。 來自朋友去某信用卡管家的做的一道面試題,用原生JavaScript模擬ES5的bind方法,不準用call和bind方法。 ...
摘要:跨域請求詳解從繁至簡前端掘金什么是為什么要用是的一種使用模式,可用于解決主流瀏覽器的跨域數據訪問的問題。異步編程入門道典型的面試題前端掘金在界中,開發人員的需求量一直居高不下。 jsonp 跨域請求詳解——從繁至簡 - 前端 - 掘金什么是jsonp?為什么要用jsonp?JSONP(JSON with Padding)是JSON的一種使用模式,可用于解決主流瀏覽器的跨域數據訪問的問題...
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器。同時,將第一個參數以外的其他參數,作為提供給原函數的預設參數,這也是基本的顆?;A。 今天想談談一道前端面試題,我做面試官的時候經常喜歡用它來考察面試者的基礎是否扎實,以及邏輯、思維能力和臨場表現,題目是:模擬實現ES5中原生bind函數。也許這道題目已經不再新鮮,部分讀者也會有思路來解答。社區上關于原生bind的研...
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器。同時,將第一個參數以外的其他參數,作為提供給原函數的預設參數,這也是基本的顆?;A。 今天想談談一道前端面試題,我做面試官的時候經常喜歡用它來考察面試者的基礎是否扎實,以及邏輯、思維能力和臨場表現,題目是:模擬實現ES5中原生bind函數。也許這道題目已經不再新鮮,部分讀者也會有思路來解答。社區上關于原生bind的研...
閱讀 3712·2023-04-25 17:45
閱讀 3426·2021-09-04 16:40
閱讀 999·2019-08-30 13:54
閱讀 2126·2019-08-29 12:59
閱讀 1396·2019-08-26 12:11
閱讀 3273·2019-08-23 15:17
閱讀 1516·2019-08-23 12:07
閱讀 3878·2019-08-22 18:00