日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从一道面试题,到“我可能看了假源码[2]

發(fā)布時間:2025/3/21 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从一道面试题,到“我可能看了假源码[2] 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上一篇從一道面試題,到“我可能看了假源碼”中,由淺入深介紹了關(guān)于一篇經(jīng)典面試題的解法。
最后在皆大歡喜的結(jié)尾中,突生變化,懸念又起。這一篇,就是為了解開這個懸念。

如果你還沒有看過前傳,可以參看前情回顧:

回顧1. 題目是模擬實現(xiàn)ES5中原生bind函數(shù);
回顧2. 我們通過4種遞進實現(xiàn)達到了完美狀態(tài);
回顧3. 可是ES5-shim中的實現(xiàn),又讓我們大跌眼鏡...

ES5-shim的懸念

ES5-shim實現(xiàn)方式源碼貼在了最后,我們看看他做了什么奇怪的事情:
1)從結(jié)果上看,返回了bound函數(shù)。
2)bound函數(shù)是這樣子聲明的:

bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);

3)bound使用了系統(tǒng)自己的構(gòu)造函數(shù)Function來聲明,第一個參數(shù)是binder,函數(shù)體內(nèi)又binder.apply(this, arguments)。
我們知道這種動態(tài)創(chuàng)建函數(shù)的方式,類似eval。最好不要使用它,因為用它定義函數(shù)比用傳統(tǒng)方式要慢得多。
4)那么ES5-shim抽風了嗎?

追根問底

答案肯定是沒抽風,他這樣做是有理由的。

神秘的函數(shù)的length屬性

你可能不知道,每個函數(shù)都有l(wèi)ength屬性。對,就像數(shù)組和字符串那樣。函數(shù)的length屬性,用于表示函數(shù)的形參個數(shù)。更重要的是函數(shù)的length屬性值是不可重寫的。我寫了個測試代碼來證明:

function test (){} test.length // 輸出0 test.hasOwnProperty('length') // 輸出true Object.getOwnPropertyDescriptor('test', 'length') // 輸出: // configurable: false, // enumerable: false, // value: 4, // writable: false

撥云見日

說到這里,那就好解釋了。
ES5-shim是為了最大限度的進行兼容,包括對返回函數(shù)length屬性的還原。如果按照我們之前實現(xiàn)的那種方式,length值始終為零。
所以:既然不能修改length的屬性值,那么在初始化時賦值總可以吧!
于是我們可通過eval和new Function的方式動態(tài)定義函數(shù)來。
同時,很有意思的是,源碼里有這樣的注釋:

// XXX Build a dynamic function with desired amount of arguments is the only // way to set the length property of a function. // In environments where Content Security Policies enabled (Chrome extensions, // for ex.) all use of eval or Function costructor throws an exception. // However in all of these environments Function.prototype.bind exists // and so this code will never be executed.

他解釋了為什么要使用動態(tài)函數(shù),就如同我們上邊所講的那樣,是為了保證length屬性的合理值。但是在一些瀏覽器中出于安全考慮,使用eval或者Function構(gòu)造器都會被拋出異常。但是,巧合也就是這些瀏覽器基本上都實現(xiàn)了bind函數(shù),這些異常又不會被觸發(fā)。

So, What a coincidence!

嘆為觀止

我們明白了這些,再看他的進一步實現(xiàn):

if (!isCallable(target)) {throw new TypeError('Function.prototype.bind called on incompatible ' + target); }

這是為了保證調(diào)用的正確性,他使用了isCallable做判斷,isCallable很好實現(xiàn):

isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } }

重設(shè)綁定函數(shù)的length屬性:

var boundLength = max(0, target.length - args.length);

構(gòu)造函數(shù)調(diào)用情況,在binder中也有效兼容。如果你不明白什么是構(gòu)造函數(shù)調(diào)用情況,可以參考上一篇。

if (this instanceof bound) { ... // 構(gòu)造函數(shù)調(diào)用情況 } else {... // 正常方式調(diào)用 }if (target.prototype) {Empty.prototype = target.prototype;bound.prototype = new Empty();// Clean up dangling references.Empty.prototype = null; }

無窮無盡

當然,ES5-shim里還歸納了幾項todo...

// TODO // 18. Set the [[Extensible]] internal property of F to true. // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). // 20. Call the [[DefineOwnProperty]] internal method of F with // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and // false. // 21. Call the [[DefineOwnProperty]] internal method of F with // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, // and false. // 22. Return F.

比較簡單,我就不再翻譯了。

源碼回放

bind: function bind(that) {var target = this;if (!isCallable(target)) {throw new TypeError('Function.prototype.bind called on incompatible ' + target);}var args = array_slice.call(arguments, 1);var bound;var binder = function () {if (this instanceof bound) {var result = target.apply(this,array_concat.call(args, array_slice.call(arguments)));if ($Object(result) === result) {return result;}return this;} else {return target.apply(that,array_concat.call(args, array_slice.call(arguments)));}};var boundLength = max(0, target.length - args.length);var boundArgs = [];for (var i = 0; i < boundLength; i++) {array_push.call(boundArgs, '$' + i);}bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);if (target.prototype) {Empty.prototype = target.prototype;bound.prototype = new Empty();Empty.prototype = null;}return bound; }

總結(jié)

通過學(xué)習(xí)ES5-shim的源碼實現(xiàn)bind方法,結(jié)合前一篇,希望讀者能對bind和JS包括閉包,原型原型鏈,this等一系列知識點能有更深刻的理解。
同時在程序設(shè)計上,尤其是邏輯的嚴密性上,有所積累。

PS:百度知識搜索部大前端繼續(xù)招兵買馬,有意向者火速聯(lián)系。。。

總結(jié)

以上是生活随笔為你收集整理的从一道面试题,到“我可能看了假源码[2]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久55| 黑人3p波多野结衣在线观看 | 妓院一钑片免看黄大片 | 欧美大片在线看 | 欧美性生活一区 | 91福利免费 | 免费日韩精品 | 神马老子午夜 | 另类第一页 | www香蕉视频 | av免费国产 | 国产精品免费视频一区二区三区 | 中文字幕人乱码中文字 | 国产三级久久久久 | 国产一级二级三级精品 | 高清一级片 | 日韩人妻一区二区三区蜜桃视频 | 日本特黄特黄刺激大片 | 国产精品色悠悠 | 91九色国产在线 | 精品亚洲国产成人av制服丝袜 | 男生看的污网站 | www99re| 欧美日韩一区二区在线视频 | 亚洲专区欧美专区 | 精品少妇 | 日本做受 | 欧美日韩一区在线观看 | 深夜福利久久 | 日韩精品一区二区视频 | 涩涩视频免费观看 | 精品777 | 美利坚合众国av | 美日韩免费视频 | 日韩三级一区二区三区 | 久久国产精品无码网站 | 中国黄色网址 | www.黄色片网站 | 性欧美丰满熟妇xxxx性久久久 | 亚洲欧美激情小说另类 | 国内自拍视频在线播放 | 黄色欧美在线观看 | 天天碰视频 | 久久国产视频网站 | av天堂一区二区 | 97视频久久 | 亚洲AV无码成人精品区在线观 | 精品孕妇一区二区三区 | 亚州av免费 | 国产精品国产三级国产aⅴ中文 | 国产精品久久久久久久久岛 | jizz日本18 | 国产免费久久 | 最新国产拍偷乱偷精品 | 亚洲人视频在线观看 | 国产黑丝在线播放 | 成人网站免费观看 | 国产精品 欧美精品 | 99久久精品免费看国产交换 | 国产片91 | 99精品欧美一区二区 | 日韩一卡二卡三卡 | 99re在线精品视频 | 中文字幕国产专区 | 国产一区二区三区在线看 | 国产91亚洲 | 男女在线免费观看 | 欧美日韩999 | 少妇性bbb搡bbb爽爽爽欧美 | 乌克兰做爰xxxⅹ性视频 | 日日碰狠狠躁久久躁蜜桃 | 国产黑丝在线 | 国产乱强伦一区二区三区 | 台湾swag在线播放 | 亚洲中文字幕无码一区二区三区 | 五月天综合婷婷 | 自拍欧美日韩 | 永久中文字幕 | 国产91在线亚洲 | 日批免费在线观看 | 国产精品久久久久久久久久久久久久久久久久 | 婷婷综合色 | 国产v综合v亚洲欧美久久 | 69国产精品视频 | 欧美乱大交xxxxx潮喷 | 三级在线观看网站 | 日日日视频 | 在线观看涩涩视频 | 秋霞av在线 | 国产一区二区三区 | 国产精品第一国产精品 | 奇米狠狠操 | 999久久精品 | 手机在线永久免费观看av片 | 国产无套内射又大又猛又粗又爽 | 神马久久久久久久久久 | 91亚洲精品视频 | 午夜伦理剧场 | 精品视频免费观看 |