GithubHelp home page GithubHelp logo

chenhw2017 / blogs Goto Github PK

View Code? Open in Web Editor NEW
0.0 0.0 0.0 4.15 MB

记录自己的前端成长之路,并加以总结以和大家分享交流

Home Page: https://github.com/Chenhw2017/blogs

JavaScript 100.00%

blogs's People

Contributors

chenhw2017 avatar

Watchers

 avatar  avatar

blogs's Issues

vscode插件开发入门

微软出品必属精品,vscode也不例外,微软大佬凭借其强大的开发与架构能力给予electron实现了跨平台的可拓展的轻量级编辑器,其很多强大的功能都是通过其插件拓展实现的

阅读这篇文章你将收获:

  • 如何快速开发一个vscode插件
  • 如何使用webview
  • 插件的生命周期及相关常用api

同时我也需要有以下知识储备

  • 了解TypeScript的使用(开发插件虽然是非必须,但还是建议使用TS)
  • 熟悉es6

开发环境搭建

  • Node
  • vscode最新版本,因为如果不是最新版本可能无法调试,部分mac用户可能把vscode放到download里面导致vscode不能及时更新,请将其放到其他目录再手动更新
  • 安装yeoman脚手架及yo的插件generator-code,npm i -g yo generator-code
  • 执行yo code或者执行yo通过命令行选择相应的代码生成器

我们要做什么

我们今天就做个类型收藏小网站的功能,最终效果图如下:

项目结构

主要目录功能描述

  • provider treeview列表的数据提供者及视图实现
  • webview 实现webview逻辑目录
  • extension.ts 插件的入口
  • package.json 命令及视图定义文件,所有代码中注册的命令都要在这里定义

插件开发可以分为以下几步

1 ��使用yo生成插件模版
2 在package.json配置要用到的插件激活命令、相应的view命令
3 在activate生命钩子黎明定义相应命令对应的处理逻辑
4 实现TreeDataProvider
5 注册webview命令及相应处理逻辑

package.json说明

1 contributes.viewsContainers.activitybar:主要是定义右边tabbar

2 定义treeview,如果key等于上面activitybar的id,则这个view就属于那个bar里

3 如果这个view的id在activationEvents的onview注册了,那么这个view的展示就会促发activate钩子函数

JavaScript手写原理之节流与防抖

节流与防抖这两个概念大家并不陌生,可是你是否真正了解两者的真正区别?是否能够在实际开发中知道什么时候该用防抖?什么用节流?

阅读本文你将收获:

  • 清晰认识防抖与节流之间的区别,并能够正确的应用与实际开发中
  • 多样的代码实现
  • 闭包的特性的应用

什么是防抖

debounce(fn, threshhold)

技术最终都要服务于社会,任何脱离业务(社会)实际的都是耍流氓,防抖当然也不例外,实际生活中对于拍照(人工防抖,不是智能那种:joy:),如果你在自拍,你肯定不会在镜头没稳定之前,按下快门吧(PS:如果你想要这种模糊效果当我没说:no_mouth:),也就是镜头不稳(手抖)你不会按下快门,如果你感觉稳了,才会按下快门,类似:

  1. 防抖函数debounce的功能就相当于帮你判断什么时候该按下快门
  2. fn相当于快门
  3. threshhold(阈值)就相当于人体感知稳定的需要经历的时间阈值
  4. 只有稳定之后才会按下快门即执行fn,也就是说一旦间隔threshhold有一次抖动都会重新判断稳定
  5. 如果threshhold间隔内一直稳定不下来,第一次触发threshholdms之后fn不会被执行,同理一直不稳定,fn永远不会被执行(假入死循环)
// fn => 2
function debounce(fn, threshhold){ // 1
    if(!fn instanceof Function) {
        throw new TypeError('Expected a function')
    }
    let timer = null;
    return function () {
        clearTimeout(timer); // 3
        timer = setTimeout(() => { 
            fn.apply(this) // 4 
        },threshhold)
    };
}

代码浅析:debounce就相当于帮你判断是什么时候该按下快门,要执行的fn相当于快门,人体的感知稳定时间阈值为threshhold,如果连续两次调用(对应拍照抖动)小于threshhold,那么肯定要重新设置稳定间隔的起始点也就是重置clearTimeout(timer),当然如果两次间隔超过threshhold,重置已经无法影响了已经发生的调用了,最后定时器执行fn.apply(this)就是手终于不抖可以按下快门啦:joy:

什么是节流

throttle(fn, threshhold)

实际生活中,节流这一概念其实生活中有很多例子,比如这快过年了,火车站考虑到大家的安全,对进站进行节流(官方应该叫限流,其实表达都是同一个意思)因为单位时间内车站的接待(容纳)人数是有限的,还有大家更加熟悉的例子,王者荣耀或者英雄联盟这类moba游戏,都有攻速上限(攻速2.5),换句话说哦假设程序设定了英雄一秒最多A五下,那么即使你手速再快,1s内也A不出第六下,通过以上例子我们可以得出:

  1. threshhold间隔内函数fn无论触发多少次,第一次触发到threshholdms后都是只执行一次
  2. 第二次触发距离第一次时间超过threshhold,则第二次会立即执行

根据这两点,有两种实现方式

第一种

function throttle(fn, threshhold) {
    if(!fn instanceof Function) {
        throw new TypeError('Expected a function')
    }
    let limited = false;  // 节流阀标志位
    let start = Date.now();
    threshhold = threshhold || 500
    return function (...args) {
        let current = Date.now();
        limited = limited && current- start < threshhold
        if(!limited) {
                fn.apply(this,args);
                limited = true;
                start = Date.now();
        }
    }
}

代码浅析:通过limited节流阀标志位模拟当前是否需要节流(限流),第一次默认fales即首次不限流(车站为空的:joy:),限流之后(limited = true)且只有两次时间间隔(current- start)超过threshhold,才会除去限制,调用fn即车站让旅客进站进入新的周期重置开始时间start

第二种

function throttle2(fun, threshhold) {
    if(!fun instanceof Function) {
        throw new TypeError('Expected a function')
    }
    let limited = false; // 节流阀标志位
    let timer = null;
    let start = Date.now();
    threshhold = threshhold || 500
    return function (...args) {
        let current = Date.now();
        limited = limited && current- start < threshhold
        if (limited) {
            clearTimeout(timer)
            timer = setTimeout(() => {
                limited = true
                start = Date.now()
                fun.apply(this, args)
            }, threshhold)
        }else {
            limited = true
            start = Date.now();
            fun.apply(this,args)
        }
    }
}

代码浅析:第二种使用了setTimeout定时器的方式,多加了如果最后一次触发距离上一次调用fn小于threshhold则这次设置的定时器回调将会在下一个threshhold周期内执行,所以这种方式触发多次fn总共会执行两次,只是第二次会在下一个threshhold周期内执行

节流两种方式对比

  • 第一种,一个threshhold间隔内多次促发,fn只会被执行一次,最后一次并不会进入下一个周期执行,比如连续1秒内平A了5次超过限度(节流)5次,第六次并不会说下一秒自动平A,而是直接舍去
  • 第二种,一个threshhold间隔内多次促发,fn总共会执行两次,注意第二次会进入下一个threshhold周期执行

两者比较

相同点:

  • 其实本质上都是为了节省程序的性能(防止高频函数调用)
  • 借助了闭包的特性来缓存变量(状态)
  • 都可以使用setTimeout实现

区别:

  • 使用防抖,可能n个threshhold时间间隔之后fn也没执行,但是使用节流触发的threshhold间隔内有且只执行一次
  • 同样threshhold间隔内连续触发,防抖只执行一次,而节流会执行两次,只是在不同的threshhold周期内
  • 侧重点不同,防抖侧重于稳定只能执行一次,而节流强调限周期内次数,即执行频率,不限制所有时间内的总次数

应用场景

防抖:

  • 一些表单元素的校验,如手机号,邮箱,用户名等
  • 部分搜索功能的联想结果实现

节流:

  • 一些鼠标的跟随动画实现
  • scroll,resize, touchmove, mousemove等极易持续性促发事件的相关动画问题,降低频率

总结

无论什么技术都有他擅长的地方,技术与实现的优与劣不能单从技术方面去考量,这样是没有意义的,如对于节流函数的两种方式,他们都有适合的场景,比如你的产品需要类似游戏内限制攻速的,显然节流的第一种方案更合适,元芳你怎么看?:laughing:(ps:github源码地址含单测)

HTTP协议学习太枯燥?那我们看图吧~

研究表明知识概念的图形化,相较于文字描述更具有直观性,有助于高效的学习及加深对知识概念的理解

http协议的文章太多了,光掘金就有"几千篇",更别说google了,也有很多优秀的文章,但是本文将尽可能避免过多的使用文字,而是使用图形或者表格来刻画描述http及其相关生态圈概念,以便让大家能够花最少的时间更加高效直观的掌握http以及方便以后查阅,作图作表不易,你的赞就是对作者的最大的鼓励

阅读本文你将收获/了解:

  • 系统的http/https知识体系
  • http缓存机制
  • 实践开发中如何选择缓存策略
  • https及其工作机制
  • 什么是证书及证书的工作机制

http在TCP/IP模型中(发送请求发生了什么)

TCP/IP模型

TCP/IP模型

http知识网络

http概念

http概念

报文

请求方式

请求方式 描述
GET GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据.
HEAD HEAD方法请求一个与GET请求的响应相同的响应,但没有响应体(报文主体),用于确认URI的有效性及资源更新的日期时间等.
POST POST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用.
PUT PUT方法用请求有效载荷替换目标资源的所有当前表示, 由于PUT自身不带验证机制,存在安全问题,一般不用,若配合web程序的验证制或架构设计采用REST标准的同类web网站,可能会开放PUT方法
DELETE DELETE方法删除指定的资源,一般不用,原因PUT
CONNECT CONNECT方法建立一个到由目标资源标识的服务器的隧道.
OPTIONS 查询针对指定请求URI指定的资源支持的方法
TRACE TRACE方法配合Max-forwords沿着到目标资源的路径执行一个消息环回测试,不常用(容易跨站追踪攻击)
LINK 建立和资源之间的联系(HTTP/1.1已弃用)
�UNLINK 断开连接关系(HTTP/1.1已弃用)

常见状态码

状 态 码 描述
1xx Informational(信息性状状态码),接受的请求正在处理
2xx Success(成功状态码),请求正常处理完毕
200 OK:请求正常处理完毕,注意HEAD请求方法不返回报文主体
204 NO CONTENT:成功处理但是返回响应不含任何实体的主体;当然也不允许返回任何实体的主体,一般用于不需要对客户端返回新内容对情况
206 Partial Content:客户端进行了范围请求,而服务器成功执行了这部分GET请求,响应报文中包含由Content-Range指定范围的实体内容
3xx 重定向
301 Moved Permanently:永久性重定向,请求的资源已经被分配新的URI,以后应使用该URI
302 Found:临时性重定向,请求的资源已经被分配新的URI,希望本次应使用该URI
303 See Other:对应当前请求的响应可以在另一个 URI 上被找到,而且客户端应当采用 GET 的方式访问那个资源。与302区别是如果POST方式希望用户能使用GET重定向,303状态码更加合适,虽然功能上是一样的
304 Not Modified:客户端发送带有条件的请求时,服务器允许请求访问资源,但是因发生请求未满条件的情况(即可直接shying客户端未过期缓存)
307 Temporary Redirect:临时性重定向,与302含义相同,尽管302标准禁止POST改为GET,但是实际大家并不遵守,307会遵守标准不会POST改为GET,但是对于处理响应的行为,每种浏览器可能不一样
4xx 客户端错误
400 Bad Request:请求报文中存在语法错误
401 Unauthorized:当前请求需要用户验证,弹出认证用的对话窗口;若之前已经请求过一次,则表示用户认证失败,该响应必须包含一个适用于请求资源的 WWW-Authenticate 信息头用以询问用户信息
403 Forbidden:服务器已经理解请求,但是拒绝执行它
404 Not Found:请求失败,请求所希望得到的资源未被在服务器上发现.也可用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应用的情况
405 Method Not Allowed:请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够受的请求方法的列表
5xx 服务器错误
500 Internal Server Error:服务器在执行请求时发生了错误,也可能是web应用存在bug或者临时故障
502 Bad Gateway:此错误响应表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应。
503 Service Unavailable:服务器没有准备好处理请求。 常见原因是服务器因维护或超负载而停机
504 Gateway Timeout:当服务器作为网关,不能及时得到响应时返回此错误代码

缓存机制

缓存控制相关字段

字段名称 可能值举例 缓存优先级 描述
Cache-Control max-age=3600 高(强缓存) 再次请求3600s内都可以使用缓存
Expires Sat, 10 Jan 2020 09:00:00 GMT 高(强缓存) 2020年1月10日9点之前再次请求都可以使用缓存
If-Modified-Since/Last-Modified Sat, 10 Jan 2020 09:00:00 GMT 第一个时间>第二个(只能精确到秒),返回304,反之,200,读取服务器资源并返回实体结果
If-None-Match/ETag 123xx 若123xx!==ETag,则读取资源并返回实体,反之304,注意:,ETag判断资源是否修改的准确度虽然高于If-Modified-Since,但这是要牺牲服务器的资源的为前提的,因为要根据算法生成ETag需要额外开销服务器资源

注: 1.缓存控制字段同时存在时,会按照优先级由高到低进行控制缓存命中控制,在HTTP/1.0中,同时存在Cache-Control和Expires会忽略Cache-Control,在HTTP/1.1中,则会忽略Expires

Cache-Control指令

缓存请求指令

指令 参数 说明
no-cache 强制向源服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age = [ 秒] 必需 响应的最大Age值
max-stale( = [ 秒]) 可省略 接收已过期的响应
min-fresh = [ 秒] 必需 期望在指定时间内的响应仍有效
no-transform 代理不可更改媒体类型
only-if-cached 从缓存获取资源
cache-extension - 新指令标记(token)

缓存响应指令

指令 参数 说明
public 可向任意方提供响应的缓存
private 可省略 仅向特定用户返回响应
no-cache 可省略 缓存前必须先确认其有效性
no-store 不缓存请求或响应的任何内容
no-transform 代理不可更改媒体类型
must-revalidate 可缓存但必须再向源服务器进行确认
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认
max-age = [ 秒] 必需 响应的最大Age值
s-maxage = [ 秒] 必需 公共缓存服务器响应的最大Age值
cache-extension - 新指令标记(token)

http缓存控制工作原理

http概念

http缓存控制工作流程

实践中如何定制缓存策略

http概念

定制缓存策略

在使用强缓存时,当我们设置了缓存有效时间之后,如果在有效时间静态内资源被修改,但是我们依然会使用缓存(老的),显然生成中这是不被允许的!在单页面实践中,在打包的时候webpack会通过hash的方式修改html引用的静态资源文件名(否者静态资源的URI没变,依然会使用缓存),并将其嵌入html中生产新的html文件,所以我们只需要设置请求html资源为no-cache(即每次请求都会验证缓存的有效性)就可以保证即使缓存有效期内,被引用的静态资源发生了修改,也能获取到最新的改动

�针对http的安全策略

https

https

https

https

https示意图

https工作流程

https

https工作流程

证书机制

证书机制

关于数字签名及其验证

附录

首部字段

首部字段名 说明
Cache-Control 控制缓存的行为
Connection 逐跳首部、连接的管理
Date 创建报文的日期时间
Pragma 报文指令
Trailer 报文末端的首部一览
Transfer-Encoding 指定报文主体的传输编码方式
Upgrade 升级为其他协议
Via 代理服务器的相关信息
Warning 错误通知

请求首部字段

首部字段名 说明
Accept 用户代理可处理的媒体类型
Accept-Charset 优先的字符集
Accept-Encoding 优先的内容编码
Accept-Language 优先的语言(自然语言)
Authorization Web认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求资源所在服务器
If-Match 比较实体标记(ETag)
If-Modified-Since 比较资源的更新时间
If-None-Match 比较实体标记(与 If-Match 相反)
If-Range 资源未更新时发送实体 Byte 的范围请求
If-Unmodified-Since 比较资源的更新时间(与If-Modified-Since相反)
Max-Forwards 最大传输逐跳数
Proxy-Authorization 代理服务器要求客户端的认证信息
Range 实体的字节范围请求
Referer 对请求中 URI 的原始获取方
TE 传输编码的优先级
User-Agent HTTP 客户端程序的信息

响应首部字段

首部字段名 说明
Accept-Ranges 是否接受字节范围请求
Age 推算资源创建经过时间
ETag 资源的匹配信息
Location 令客户端重定向至指定URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Retry-After 对再次发起请求的时机要求
Server HTTP服务器的安装信息
Vary 代理服务器缓存的管理信息
WWW-Authenticate 服务器对客户端的认证信息

实体首部字段

首部字段名 说明
Allow 资源可支持的HTTP方法
Content-Encoding 实体主体适用的编码方式
Content-Language 实体主体的自然语言
Content-Length 实体主体的大小(单位:字节)
Content-Location 替代对应资源的URI
Content-MD5 实体主体的报文摘要
Content-Range 实体主体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体主体过期的日期时间
Last-Modified 资源的最后修改日期时间

�建立TCP连接建立过程

TCP连接建立

常见应用层协议

协议简称 英文全称 中文全称 描述
SMTP Simple Mail Transfer Protocol 简单邮件传输协议 用于邮件发送的基于TCP的应用层协议
POP3 Post Office Protocol - Version 3 邮局协议版本3 用于邮件接收的基于TCP的应用层协议
DNS Domain Name System 域名系统 用于解析域名与IP地址的基于UDP/TCP 应用层协议
DHCP Dynamic Host Configuration Protocol 动态主机配置协议 用于主机动态获取IP地址、缺省网关、DNS服务器等参数的基于UDP 应用层协议
CIFS Common Internet File System 通用网络文件系统 Windows 文件共享的基于TCP的应用层协议
NFS Network File System 网络文件系统 用于Unix / Linux 文件共享,基于UDP/TCP协议
NTP Network Time Protocol 网络时间协议 用于时钟同步的基于UDP的应用层协议
SIP Session Initiation Protocol 会话发起协议 IP电话信令协议,IETF协议标准,基于TCP/UDP应用层协议
H.323 - - IP电话信令协议,国际电信联盟 ITU协议标准,基于TCP/UDP应用层协议
RTP Real-time Transport Protocol 实时传输协议 用于IP多媒体电话的语音、文字、视频等流体的传输,基于UDP的应用层协议

总结

http几乎深透了我们每天的开发实践中,渗透到你对它的存在习以为常而忽略它,,但它真的很重要,因为它是前后端通信的桥梁,也是前端性能优化的一个点,这块知识难点不多,但是很散,如果大家看完这篇文章(图),对http生态有个清晰或者深刻的认识,我的目的就达到了~,本人水平有限,文章如有错误或者建议,还请指教

参考

JavaScript手写原理之call/apply

call/apply在我们日常开发中也是经常会用到的两个api,如何使用它们我们并不陌生,所以今天我们讨论下如何实现它

call

需求分析

用法:function.call(thisArg, arg1, arg2, ...)

它有以下功能与约束:

  1. 参数的兼容处理
  2. 调用function,并且指定function内this指向为thisArg
  3. call没有副作用,调用之后不会对thisArg产生任何影响
  4. 返回值为function调用的返回值

实现

对于第一点

这里需要处理下参数的兼容性及相应的性能优化:

  • thishisArg为null或者undefined,则this为宿主环境全局对象
  • thishisArg 为 null或者undefined且参数只有一个时或者参数为空时,就没必要进行下面逻辑了
  • thisArg如果是部分基本类型需要做处理,call内部会对这些基本类型进行转换相应类型的实例对象
function globalEnv () {
    return this;
}
...
if(typeof thisArg === 'string' || typeof thisArg === 'boolean' || typeof thisArg === 'number') { 
    thisArg = new Object(thisArg);
}else if (!arguments.length || (thisArg === null || thisArg === void 0) && arguments.length === 1) { // call() || call(null)
    return this();
}

thisArg = thisArg || globalEnv();

Tip:基本类型进行转换相应类型的实例对象

var numberObj = new Object(22);
numberObj.constructor === Number // => true
numberObj instanceof Number // => true
numberObj instanceof Object // => true

对于第二点,我们如何实现调用function,并且指定function内this指向为thisArg呢?

我们知道函数调用时,其函数内this指向分为以下四种情况

  1. 由new调用?绑定到新创建的对象。
  2. 由call或者apply(或者bind)调用?绑定到指定的对象。
  3. 由上下文对象调用?绑定到那个上下文对象即obj.fn(),fnthis指向就是obj
  4. 默认:在严格模式下绑定到undefined,否则绑定到全局对象。

首先,function不一定是构造函数所以1行不通,2是我们这次要实现的pass,因为call就是要绑定到指定对象,全局或者undefined只是其中一种情况,所以我们通过3将函数绑定到上下文对象上即thisArg更加符合要求,分析到这里思路就非常明确了,无非就是给绑定对象thisArg加个function方法

var uiqueFn = Date.now();
while (thisArg.hasOwnProperty(uiqueFn)) { // 防止属性重复
    uiqueFn = Date.now();
}
thisArg[uiqueFn] = this; // 1

由于参数是从类数组对象arguments取出,其只支持for遍历,不支持数组其他api

var rest = [],result;
for (var index = 1; index < arguments.length; index++) {
    rest.push("arguments[" + index + "]");
}

函数调用时,是以fn(a,b,c...)的形式调用,考虑兼容问题不实用es6的拓展运算符,改用eval的形式,如果你有更好的方法,欢迎评论👏

 eval('result = thisArg[uiqueFn]('+arr+')');

对于3,4

函数调用获取结果后,将添加的���属性删除即可,并把函数结果返回

    delete  thisArg[uiqueFn]; // 2
    return result;

最后,贴下完整代码:

function globalEnv () {
    return this;
}

Function.prototype._mycall = function (thisArg) {
    if(typeof thisArg === 'string' || typeof thisArg === 'boolean' || typeof thisArg === 'number') { 
        thisArg = new Object(thisArg);
    }else if (!arguments.length || (thisArg === null || thisArg === void 0) && arguments.length === 1) { // call() || call(null)
        return this();
    }
    thisArg = thisArg || globalEnv();
    var uiqueFn = Date.now();
    while (thisArg.hasOwnProperty(uiqueFn)) {
        uiqueFn = Date.now();
    }
    thisArg[uiqueFn] = this; // 1
    var rest = [],result;
    for (var index = 1; index < arguments.length; index++) { 
        rest.push("arguments[" + index + "]");
    }
    eval('result = thisArg[uiqueFn]('+rest+')'); // 3 
    delete  thisArg[uiqueFn]; // 2
    return result;
}

apply

需求分析

用法:func.apply(thisArg, [argsArray])

实现

apply和call两者除了参数不同之外,其他没有任何区别,实现上只有对于第二个参数的错误处理有区别之外,其他几乎没有任何区别,这里我就不再赘述细节直接贴代码

注意⚠️:由于是检测函数类型,所以这里instanceof可以使用typeof替代进行检测,但是需注意typeof对于其他类型如null判断的是object,以及其他引用类型也是object,如ArrayDate

Function.prototype._myapply = function (thisArg) {
    if(!this instanceof Function) {
        throw new Error(`${this}.myapply is not a function`)
    } else if(!arguments.length || (thisArg === null || thisArg === void 0) && arguments.length === 1) {  // 参数全部为空直接调用 没必要执行下面逻辑了
        return this();
    } else if (typeof arguments[1] === 'boolean' || typeof arguments[1] === 'string' || typeof arguments[1] === 'number') { // 兼容处理部分基本类型
        throw new Error(`CreateListFromArrayLike called on non-object`);
    }
    thisArg = thisArg || globalEnv();
    var uiqueFn = Date.now();
    while (thisArg.hasOwnProperty(uiqueFn)) {
        uiqueFn = Date.now();
    }
    var rest = arguments[1] instanceof Array ?  arguments[1] : [], result, arr = [];
    for (var index = 0; index < rest.length; index++) {
        arr[index] = 'rest['+index+']'
    }

    thisArg[uiqueFn] = this; 
    eval('result = thisArg[uiqueFn]('+arr+')'); 
    delete  thisArg[uiqueFn]; 
    return result;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.