René's URL Explorer Experiment


Title: 从underscore源码看如何实现map函数(一) · Issue #13 · webproblem/Blog · GitHub

Open Graph Title: 从underscore源码看如何实现map函数(一) · Issue #13 · webproblem/Blog

X Title: 从underscore源码看如何实现map函数(一) · Issue #13 · webproblem/Blog

Description: 前言 经常会看到这样的面试题,让面试者手动实现一个 map 函数之类的,嗯,貌似并没有什么实际意义。但是对于知识探索的步伐不能停止,现在就来分析下如何实现 map 函数。 PS: 关于 underscore 源码解读注释,详见:underscore 源码解读。 Array.prototype.map 先来了解下原生 map 函数。 map 函数用于对数组元素进行迭代遍历,返回一个新函数并不影响原函数的值。map 函数接受一个 callback 函数以及执行上下文参数,c...

Open Graph Description: 前言 经常会看到这样的面试题,让面试者手动实现一个 map 函数之类的,嗯,貌似并没有什么实际意义。但是对于知识探索的步伐不能停止,现在就来分析下如何实现 map 函数。 PS: 关于 underscore 源码解读注释,详见:underscore 源码解读。 Array.prototype.map 先来了解下原生 map 函数。 map 函数用于对数组元素进行迭代遍历,返回一个新函数并不影...

X Description: 前言 经常会看到这样的面试题,让面试者手动实现一个 map 函数之类的,嗯,貌似并没有什么实际意义。但是对于知识探索的步伐不能停止,现在就来分析下如何实现 map 函数。 PS: 关于 underscore 源码解读注释,详见:underscore 源码解读。 Array.prototype.map 先来了解下原生 map 函数。 map 函数用于对数组元素进行迭代遍历,返回一个新函数并不影...

Opengraph URL: https://github.com/webproblem/Blog/issues/13

X: @github

direct link

Domain: patch-diff.githubusercontent.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"从underscore源码看如何实现map函数(一)","articleBody":"### 前言\r\n\r\n经常会看到这样的面试题,让面试者手动实现一个 map 函数之类的,嗯,貌似并没有什么实际意义。但是对于知识探索的步伐不能停止,现在就来分析下如何实现 map 函数。\r\n\r\nPS: 关于 underscore 源码解读注释,详见:[underscore 源码解读](https://github.com/webproblem/Blog/blob/master/源码解读/underscore/Underscore.1.8.3.analysis.js)。\r\n\r\n### Array.prototype.map\r\n\r\n先来了解下原生 map 函数。\r\n\r\nmap 函数用于对数组元素进行迭代遍历,返回一个新函数并不影响原函数的值。map 函数接受一个 callback 函数以及执行上下文参数,callback 函数带有三个参数,分别是迭代的当前值,迭代当前值的索引下标以及迭代数组自身。map 函数会给数组中的每一个元素按照顺序执行一次 callback 函数。\r\n\r\n```javascript\r\nvar arr = [1,2,3];\r\nvar newArr = arr.map(function(item, index){\r\n    if(index == 1) return item * 3;\r\n    return item;\r\n})\r\nconsole.log(newArr); // [1, 6, 3]\r\n```\r\n\r\n### 实现\r\n\r\n#### for 循环\r\n\r\n实现思路其实挺简单,使用 for 循环对原数组进行遍历,每个元素都执行一遍回调函数,同时将值赋值给一个新数组,遍历结束将新数组返回。\r\n\r\n将自定义的 _map 函数依附在 Array 的原型上,省去了对迭代数组类型的检查等步骤。\r\n\r\n```javascript\r\nArray.prototype._map = function(iteratee, context) {\r\n    var arr = this;\r\n    var newArr = [];\r\n    for(var i=0; i\u003carr.length; i++) {\r\n        newArr[i] = iteratee.call(context, arr[i], i, arr);\r\n    }\r\n    return newArr;\r\n}\r\n```\r\n\r\n测试如下:\r\n\r\n```javascript\r\nvar arr = [1,2,3];\r\nvar newArr = arr._map(function(item, index){\r\n    if(index == 1) return item * 3;\r\n    return item;\r\n})\r\nconsole.log(newArr); // [1, 6, 3]\r\n```\r\n\r\n好吧,其实重点不在于自己如何实现 map 函数,而是解读 underscore 中是如何实现 map 函数的。\r\n\r\n### underscore 中的 map 函数\r\n\r\n_.map 相对于 Array.prototype.map 来说,功能更加完善和健壮。 _.map 源码:\r\n\r\n```javascript\r\n  /**\r\n   * @param obj 对象\r\n   * @param iteratee 迭代回调\r\n   * @param context 执行上下文\r\n   * _.map 的强大之处在于 iteratee 迭代回调的参数可以是函数,对象,字符串,甚至不传参\r\n   * _.map 会根据不同类型的 iteratee 参数进行不同的处理\r\n   * _.map([1,2,3], function(num){ return num * 3; }); // [3, 6, 9]\r\n   * _.map([{name: 'Kevin'}, {name: 'Daisy'}], 'name'); // [\"Kevin\", \"Daisy\"]\r\n   */\r\n  _.map = _.collect = function(obj, iteratee, context) {\r\n    // 针对不同类型的 iteratee 进行处理\r\n    iteratee = cb(iteratee, context);\r\n    var keys = !isArrayLike(obj) \u0026\u0026 _.keys(obj),\r\n        length = (keys || obj).length,\r\n        results = Array(length);\r\n    for (var index = 0; index \u003c length; index++) {\r\n      var currentKey = keys ? keys[index] : index;\r\n      results[index] = iteratee(obj[currentKey], currentKey, obj);\r\n    }\r\n    return results;\r\n  };\r\n```\r\n\r\n可以看到,_.map 接受 3 个参数,分别是迭代对象,迭代回调和执行上下文。iteratee 迭代回调在函数内部进行了特殊处理,为什么要这么做,原因是因为iteratee 迭代回调的参数可以是函数,对象,字符串,甚至不传参。\r\n\r\n```javascript\r\n// 传入一个函数\r\n_.map([1,2,3], function(num){ return num * 3; }); // [3, 6, 9]\r\n\r\n// 什么也不传\r\n_.map([1,2,3]); // [1, 2, 3]\r\n\r\n// 传入一个对象\r\n_.map([{name:'Kevin'}, {name: 'Daisy', age: 18}], {name: 'Daisy'}); // [false, true]\r\n\r\n// 传入一个字符串\r\n_.map([{name:'Kevin'}, {name: 'Daisy', age: 18}], 'name'); // [\"Kevin\", \"Daisy\"]\r\n```\r\n\r\n先来分析下 _.map 函数内部是如何针对不同类型的 iteratee 进行处理的。\r\n\r\n### cb\r\n\r\ncb 函数源码如下(PS: 所有的注释都是个人见解):\r\n\r\n```javascript\r\nvar cb = function(value, context, argCount) {\r\n    // 是否使用自定义的 iteratee 迭代器,外部可以自定义 iteratee 迭代器\r\n    if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);\r\n    // 处理不传入 iteratee 迭代器的情况,直接返回迭代集合\r\n    // _.map([1,2,3]); // [1,2,3]\r\n    if (value == null) return _.identity;\r\n    // 优化 iteratee 迭代器是函数的情况\r\n    if (_.isFunction(value)) return optimizeCb(value, context, argCount);\r\n    // 处理 iteratee 迭代器是对象的情况\r\n    if (_.isObject(value) \u0026\u0026 !_.isArray(value)) return _.matcher(value);\r\n    // 其他情况的处理,数组或者基本数据类型的情况\r\n    return _.property(value);\r\n};\r\n```\r\n\r\ncb 函数内部针对 value 类型(也就是 iteratee 迭代器)的不同做了相应的处理。\r\n\r\nunderscore 中允许我们自定义 _.iteratee 函数的,也就是可以自定义迭代回调。\r\n\r\n```javascript\r\nif (_.iteratee !== builtinIteratee) return _.iteratee(value, context);\r\n```\r\n\r\n正常情况下,这个判断语句应该为 false,因为在 underscore 内部中已经定义了 _.iteratee 就是与 builtinIteratee 相等。\r\n\r\n```javascript\r\n_.iteratee = builtinIteratee = function(value, context) {\r\n    return cb(value, context, Infinity);\r\n};\r\n```\r\n\r\n这样做的目的是为了区分是否有自定义 _.iteratee 函数,如果有重写了 _.iteratee 函数,就使用自定义的函数。\r\n\r\n那么为什么会允许我们去修改 _.iteratee 函数呢?试想如果场景中只是需要 _.map 函数的 iteratee 参数是函数的话,就用该函数处理数组元素,如果不是函数,就直接返回当前元素,而不是将 iteratee 进行针对性处理。\r\n\r\n```javascript\r\n_.iteratee = function(value, context) {\r\n    if(typeof value === 'function') {\r\n        return function(...rest) {\r\n            return value.call(context, ...rest)\r\n        };\r\n    }\r\n    return function(value) {\r\n        return value;\r\n    }\r\n}\r\n```\r\n\r\n测试如下:\r\n\r\n```javascript\r\n_.map([{name:'Kevin'}, {name: 'Daisy', age: 18}], 'name');\r\n```\r\n\r\n![image](https://user-images.githubusercontent.com/20440496/49081260-3b09c880-f281-11e8-9468-4503d1e20466.png)\r\n\r\n需要注意的是,很多迭代函数都依赖于 _.iteratee 函数,所以要谨慎使用自定义 _.iteratee。\r\n\r\n当然了,如果没有 iteratee 迭代器的情况下,也是直接返回迭代集合。\r\n\r\n正常使用情况下,传入的 iteratee 迭代器应该都会是函数的,为了提升性能,在 cb 函数内部针对 iteratee 迭代器是函数的情况做了性能处理,也就是 optimizeCb 函数。\r\n\r\n### optimizeCb \r\n\r\noptimizeCb 函数源码如下:\r\n\r\n```javascript\r\n  /**\r\n   * 优化迭代器回调\r\n   * @param func 迭代器回调 \r\n   * @param context 执行上下文\r\n   * @param argCount 指定迭代器回调接受参数个数\r\n   */\r\n  var optimizeCb = function(func, context, argCount) {\r\n    // 如果没有传入上下文,直接返回\r\n    if (context === void 0) return func;\r\n    // 根据指定接受参数进行处理\r\n    switch (argCount) {\r\n      case 1: return function(value) {\r\n        // value: 当前迭代元素\r\n        return func.call(context, value);\r\n      };\r\n      // The 2-parameter case has been omitted only because no current consumers\r\n      // made use of it.\r\n      case null:\r\n      case 3: return function(value, index, collection) {\r\n        // value: 当前迭代元素,index: 迭代元素索引,collection: 迭代集合\r\n        return func.call(context, value, index, collection);\r\n      };\r\n      case 4: return function(accumulator, value, index, collection) {\r\n        // accumulator: 累加器,value: 当前迭代元素,index: 迭代元素索引,collection: 迭代集合\r\n        return func.call(context, accumulator, value, index, collection);\r\n      };\r\n    }\r\n    // 当指定迭代器回调接受参数的个数超过4个,就用 arguments 代替\r\n    // 为什么不直接使用这段代码而是在上面根据 argCount 处理接受的参数\r\n    // 1. arguments 存在性能问题\r\n    // 2. call 比 apply 速度更快\r\n    return function() {\r\n      return func.apply(context, arguments);\r\n    };\r\n  };\r\n```\r\n\r\noptimizeCb 函数内部主要是针对 iteratee 迭代器接受的参数进行性能优化。当指定迭代器回调接受参数的个数超过4个,就用 arguments 代替。为什么要这样处理?原因是因为 arguments 存在性能问题,且 call 比 apply 速度更快。具体分析会在下一篇给出解释,这里不做过多的分析。\r\n\r\n### _.matcher \r\n\r\n回到前面对 iteratee 迭代器类型做处理的话题,如果 iteratee 迭代器是对象的情况,又该如何处理?也就是这样:\r\n\r\n```javascript\r\n_.map([{name:'Kevin'}, {name: 'Daisy', age: 18}], {name: 'Daisy'}); // [false, true]\r\n```\r\n\r\n在 cb 函数内部使用了 _.matcher 函数处理这种情况,来分析下 _.matcher 函数都做了哪些事情。 _.matcher 源码如下:\r\n\r\n```javascript\r\n  /**\r\n   * 传入一个属性对象,返回一个属性检测函数,检测对象是否具有指定属性\r\n   * var matcher = _.matcher({name: '白展堂'});\r\n    var obj = {name: '白展堂', age: 25};\r\n    matcher(obj); // true\r\n   */\r\n  _.matcher = _.matches = function(attrs) {\r\n    // 合并复制对象,attrs 必须是 Objdect 类型\r\n    // arrts 的值为空或者其他数据类型,都能保证 attrs 是 Object 类型\r\n    attrs = _.extendOwn({}, attrs);\r\n    // 返回属性检测函数\r\n    return function(obj) {\r\n      // 检测 obj 对象是否具有指定属性 attrs\r\n      return _.isMatch(obj, attrs);\r\n    };\r\n  };\r\n```\r\n\r\n_.matcher 的主要作用就是检测 obj 对象是否具有指定属性 attrs,例如:\r\n\r\n```javascript\r\nvar matcher = _.matcher({name: '白展堂'});\r\nvar obj = {name: '白展堂', age: 25};\r\nvar obj2 = {name: '吕秀才', age: 25};\r\n\r\nmatcher(obj); // true\r\nmatcher(obj2); // false\r\n```\r\n\r\n具体的检测是使用了 _.isMatch 函数, _.isMatch 源码如下:\r\n\r\n```javascript\r\n  /**\r\n   * 检测对象中是否包含指定属性\r\n   * var obj = {name: '白展堂', age: 25}; \r\n   * var attrs = {name: '白展堂'}; \r\n   * _.isMatch(obj, attrs); // true\r\n   */\r\n  _.isMatch = function(object, attrs) {\r\n    var keys = _.keys(attrs), length = keys.length;\r\n    if (object == null) return !length;\r\n    var obj = Object(object);\r\n    for (var i = 0; i \u003c length; i++) {\r\n      var key = keys[i];\r\n      if (attrs[key] !== obj[key] || !(key in obj)) return false;\r\n    }\r\n    return true;\r\n  };\r\n```\r\n\r\n核心部分就梳理清楚了,回到 _.map 函数,可以看到,也是使用了 for 循环来实现 map 功能,和我们自己实现了思路一致,有一点不同的是, _.map 函数的第一个参数,不仅限于数组,还可以是对象和字符串。\r\n\r\n```javascript\r\n_.map('name'); // [\"n\", \"a\", \"m\", \"e\"]\r\n\r\n_.map({name: '白展堂', age: 25}); // [\"白展堂\", 25]\r\n```\r\n\r\n在 _.map 函数内部,对类数组的对象也进行了处理。\r\n\r\n### 遗留问题\r\n\r\n到这里就梳理清楚了在 underscore 中是如何实现 map 函数的,以及优化性能方案。可以说在 underscore 中每行代码都很精炼,值得反复揣摩。\r\n\r\n同时在梳理过程中,遗留了两个问题:\r\n\r\n* arguments 存在性能问题\r\n* call 比 apply 速度更快\r\n\r\n这两个问题将会在下一篇中进行详细的分析。\r\n\r\n### 参考\r\n\r\n* https://blog.fundebug.com/2017/07/26/master_map_filter_by_hand_written/\r\n\r\n* https://github.com/mqyqingfeng/Blog/issues/58","author":{"url":"https://github.com/webproblem","@type":"Person","name":"webproblem"},"datePublished":"2018-11-27T13:16:55.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/13/Blog/issues/13"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:59a7c042-a0f7-466a-c794-9f153eb2ffb5
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-idC2E8:18A62A:8788113:AF6D9F7:6975DBCF
html-safe-noncef6b6a372888aff6299b7afb7ab4f4015e9296ef1b2cb11231e48b5dd2593ed16
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDMkU4OjE4QTYyQTo4Nzg4MTEzOkFGNkQ5Rjc6Njk3NURCQ0YiLCJ2aXNpdG9yX2lkIjoiNTk2NjcxNTQ1NzI1NDA1NDg2MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9
visitor-hmac4872706e600a424e0288a6a541998ebe748b3e64d8ea0a7e41cfa96096c1a468
hovercard-subject-tagissue:384790168
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/webproblem/Blog/13/issue_layout
twitter:imagehttps://opengraph.githubassets.com/57b1da2c730c75a05a29b3e035d8b0d375834b1cd5e66eeaafaaef119e8c00c6/webproblem/Blog/issues/13
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/57b1da2c730c75a05a29b3e035d8b0d375834b1cd5e66eeaafaaef119e8c00c6/webproblem/Blog/issues/13
og:image:alt前言 经常会看到这样的面试题,让面试者手动实现一个 map 函数之类的,嗯,貌似并没有什么实际意义。但是对于知识探索的步伐不能停止,现在就来分析下如何实现 map 函数。 PS: 关于 underscore 源码解读注释,详见:underscore 源码解读。 Array.prototype.map 先来了解下原生 map 函数。 map 函数用于对数组元素进行迭代遍历,返回一个新函数并不影...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernamewebproblem
hostnamegithub.com
expected-hostnamegithub.com
None2bce766e7450b03e00b2fc5badd417927ce33a860e78cda3e4ecb9bbd1374cc6
turbo-cache-controlno-preview
go-importgithub.com/webproblem/Blog git https://github.com/webproblem/Blog.git
octolytics-dimension-user_id20440496
octolytics-dimension-user_loginwebproblem
octolytics-dimension-repository_id115346710
octolytics-dimension-repository_nwowebproblem/Blog
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id115346710
octolytics-dimension-repository_network_root_nwowebproblem/Blog
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
releasefcca2b8ef702b5f7f91427a6e920fa44446fe312
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/13#start-of-content
https://patch-diff.githubusercontent.com/
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2Fwebproblem%2FBlog%2Fissues%2F13
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub SparkBuild and deploy intelligent appshttps://github.com/features/spark
GitHub ModelsManage and compare promptshttps://github.com/features/models
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
GitHub SponsorsFund open source developershttps://github.com/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/accelerator
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2Fwebproblem%2FBlog%2Fissues%2F13
Sign up https://patch-diff.githubusercontent.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=webproblem%2FBlog
Reloadhttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/13
Reloadhttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/13
Reloadhttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/13
webproblem https://patch-diff.githubusercontent.com/webproblem
Bloghttps://patch-diff.githubusercontent.com/webproblem/Blog
Notifications https://patch-diff.githubusercontent.com/login?return_to=%2Fwebproblem%2FBlog
Fork 15 https://patch-diff.githubusercontent.com/login?return_to=%2Fwebproblem%2FBlog
Star 113 https://patch-diff.githubusercontent.com/login?return_to=%2Fwebproblem%2FBlog
Code https://patch-diff.githubusercontent.com/webproblem/Blog
Issues 10 https://patch-diff.githubusercontent.com/webproblem/Blog/issues
Pull requests 0 https://patch-diff.githubusercontent.com/webproblem/Blog/pulls
Actions https://patch-diff.githubusercontent.com/webproblem/Blog/actions
Projects 0 https://patch-diff.githubusercontent.com/webproblem/Blog/projects
Security 0 https://patch-diff.githubusercontent.com/webproblem/Blog/security
Insights https://patch-diff.githubusercontent.com/webproblem/Blog/pulse
Code https://patch-diff.githubusercontent.com/webproblem/Blog
Issues https://patch-diff.githubusercontent.com/webproblem/Blog/issues
Pull requests https://patch-diff.githubusercontent.com/webproblem/Blog/pulls
Actions https://patch-diff.githubusercontent.com/webproblem/Blog/actions
Projects https://patch-diff.githubusercontent.com/webproblem/Blog/projects
Security https://patch-diff.githubusercontent.com/webproblem/Blog/security
Insights https://patch-diff.githubusercontent.com/webproblem/Blog/pulse
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/webproblem/Blog/issues/13
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/webproblem/Blog/issues/13
从underscore源码看如何实现map函数(一)https://patch-diff.githubusercontent.com/webproblem/Blog/issues/13#top
JavaScripthttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22JavaScript%22
underscorehttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22underscore%22
https://github.com/webproblem
https://github.com/webproblem
webproblemhttps://github.com/webproblem
on Nov 27, 2018https://github.com/webproblem/Blog/issues/13#issue-384790168
underscore 源码解读https://github.com/webproblem/Blog/blob/master/%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/underscore/Underscore.1.8.3.analysis.js
https://user-images.githubusercontent.com/20440496/49081260-3b09c880-f281-11e8-9468-4503d1e20466.png
https://blog.fundebug.com/2017/07/26/master_map_filter_by_hand_written/https://blog.fundebug.com/2017/07/26/master_map_filter_by_hand_written/
underscore 系列之内部函数 cb 和 optimizeCb mqyqingfeng/Blog#58https://github.com/mqyqingfeng/Blog/issues/58
JavaScripthttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22JavaScript%22
underscorehttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22underscore%22
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.