深入一点-使用bind的时候发生了什么呢

从规范来看,Function.prototype.bind 是如何工作,以及如何来模拟bind操作。 简单示例如下简单示例,普通对象 testObj 内部有一个b函数,接受一个普通参数,若参数为空则输出 this.a。 const testObj = { a: 3, b: function(args) { console.log(args || this.a); },};testObj.b()testObj.b(23)const c = testObj.bc()c(23)const c1 = testObj.b.bind(testObj, 50)c1(70)查看结果: testObj.b 被重新赋值给 c 后,函数的的执行上下文已经改变,导致输出为 undefined。通过上面例子,如果采用 bind 后,则可以改变 testObj的执行上下文,并可以把默认值传递到参数函数列表. 倘若在 testObj.b内,加入 console.log(arguments), 则可以看到如下输出: 50 70bind 函数bind函数是,Function 原型链上的函数,主要是改变函数执行上下文的同时,可以传入函数参数值,并返回新的函数 如图是mdn上的定义, bind产生的函数就一个偏函数,就是说使用bind可以参数一个函数,然后接受新的参数。 In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.详细可看: https://github.com/mqyqingfeng/Blog/issues/43规范定义在EcmaScript的规范 15.3.4.5 中如下截图: ...

November 5, 2019 · 2 min · jiezi

深入一点-为什么说splice-效率低呢

原文: https://zswfx.com/articles/5da713302ddd022595ff506a我们在使用 Array.prototype.splice 方法的时候,都会提及说它速度慢,效率低。尤其在例如 Vue或者React 框架中也不推荐使用,原因是为什么呢? splice 方法方法介绍如下: 方法也比较明了,就是在数组内删除或者添加元素。如下示例: // 添加一个元素const arr = [1, 2, 3]arr.splice(1, 0, 2, 3)// [1, 2, 3, 2, 3]// 删除元素arr.splice(2, 2)// arr: [1, 2, 3]返回值则是删除元素的数组,若是添加就是空数组. w3c 执行过程在 w3c 中关于 splice 是如何描述过程的呢? Array.prototype.splice 位于ecmascript 规范中 15.4 数组章节下面的 15.4.4.12 点击这了即可下面看关于 splice描述: 下面就用删除和添加两个例子来说明规范的操作过程: 在规范里面共有 17步的数据操作: 第2步中,splice引入了新组数 A,用来存返回数据结果第6,7步中,得到真实开始位置与删除个数,在这里进行边界判断第9步这里判断当前是否是删除,若 actualDeleteCount > 0即为删除,然后得到A的删除数组,这里就获取到了要删除的元素,若删除元素个数为0,则跳过A为空数组,k 为0, 否则 k为删除个数,A 为删除元素集合. actualStart 为传入的数组中某个下标值, actualDeleteCount 为传入某个个数范围是 0-len在12步判断添加元素是否多与删除个数,若少于删除个数,数组长度减少。第13步判断添加元素多余删除元素个数,数组长度增加。见下图示第14步初始化开始位置,也就是变量k第15步中进行元素位置移动,如果添加则会不断把元素添加到元素内第16步中计算length,元素长度是由原始长度减去删除元素加上增加元素的数量。最后一步就是返回在第9步中得到移除的元素A.在 splice 方法中,我们会使用情况如下: 删除元素添加元素删除同时添加元素删除元素在第9步处理删除元素数组,第12步处理元素前移并删除结尾的元素。添加元素在13步内处理元素后移,并在15步在对应下标下放入元素。删除元素同时删除上面每一步都会走到。 关于规范一些内部方法说明: [[HasProperty]](P) 对象上的内部方法,若通过P得到对象结果为undefined则为false,否则为true。[[GET]](P) 对象内部方法,通过属性名P获取结果。[[Put]](P, V, Throw) 设置对象属性P的值为V,Throw若为true,遇到错误则会抛出TypeError。[[Delete]](P, Throw) 删除对象上属性P,若Throw为true,遇到错误则抛出TypeError.图示一个数组删除数量多于添加数量操作数组: ...

October 16, 2019 · 1 min · jiezi

javascript深入理解从作用域链理解闭包

一、概要红宝书(P178)对于闭包的定义:闭包就是有权访问另外一个函数作用域中变量的函数。 MDN,对于闭包的定义:闭包就是指能够访问自由变量的函数。 那么什么是自由变量?自由变量就是在函数中使用,但既不是函数参数arguments,也不是函数的局部变量的变量,就是说另外一个函数作用域中的变量。 闭包组成?闭包 = 函数 + 函数能够访问的变量 文章首发地址于sau交流学习社区:https://www.mwcxs.top/page/57... 二、分析举个栗子: var a = 1;function foo() { console.log(a);}foo();foo函数可以访问到变量a,但是a并不是foo函数的局部变量,也不是foo函数的参数,所以a就是自由变量,那么函数foo+foo函数可以访问自由变量a不就是构成了一个闭包嘛。 我们再来看一个栗子: function getOuter(){ var date = '1127'; function getDate(str){ console.log(str + date); //访问外部的date } return getDate('今天是:'); //"今天是:1127"}getOuter();其中date不是函数getDate的参数,也不是局部变量,所以date是自由变量。 总结起来就是两点: 1、是一个函数(比如:内部函数从父函数中返回) 2、能够访问上级函数作用域中的变量(哪怕上级函数的上下文已经销毁) 然后我们再来看一个栗子(来自《JavaScript权威指南》)来分析: var scope = "global scope";function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f;}var foo = checkscope(); // foo指向函数ffoo();这时候需要我们来分析一下这段代码中执行上下文栈和执行上下文的变化情况。 简要的分析一下执行过程: 1、进入全局代码,创建全局执行上下文,全局执行上下文压入执行上下文栈; 2、全局执行上下文初始化; 3、执行checkscope函数,创建sheckscope函数执行上下文,checkscope执行上下文被压入执行上下文栈; 4、checkscope执行上下文初始化,创建变量对象,作用域链,this等; ...

May 27, 2019 · 2 min · jiezi