1、判断一个对象的数据类型,使用带有闭包的Object.prototype.toString,通过传入不同的判断类型,返回不同的判断函数。一行代码简洁优雅灵活(注意传入类型参数时首字母大写)不推荐使用该函数检测可能生成包装类型的基本数据类型,因为call会将第一个参数2框起来。ES5实现了数组映射的方法。值得一提的是,map的第二个参数是第一个参数回调中的this点,如果第一个参数是箭头函数,那么设置第二个this会因为箭头函数的词法绑定而失效。另外稀疏数组的处理是通过hasOwnProperty判断下标元素是否存在于数组中(感谢评论区的小伙伴)3.使用reduce实现数组map方法4.ES5实现数组过滤方法5.使用reduce实现数组过滤方法6.ES5实现数组的some方法执行some方法如果数组是空数组,最后总是返回false,如果数组在另一个的every方法中array是一个空数组,它总是返回true7。ES5实现了数组的reduce方法。当初值不存在时,下标从1开始计算,当初值存在时,下标从0开始计算8.使用reduce实现数组的flat方法因为selfFlat依赖于这一点,所以需要reduce遍历时指定selfFlat的this点,否则默认指向window所以错误原理是通过reduce遍历数组,当数组的某个元素还是数组时,通过的展开运算符进行降维ES6(ES5可以使用concat方法),而这个数组元素内部也可能有一个嵌套数组,所以需要递归调用selfFlat,并且原生的flat方法支持一个depth参数来表示降维的深度。默认为1,即对数组进行降维,传入Inifity,会将传入的数组变成一维数组。原理是每次递归时将深度参数减1。如果深度参数为0,则直接返回原数组。9、实现ES6类语法ES6类内部是基于寄生组合继承,这是目前最理想的继承方式,通过Object.create方法创建一个空对象,并从Object.create方法的参数中继承这个空对象,然后让子类的原型对象(subType)等于这个空对象,这样子类实例的原型就等于这个空对象,原型这个空对象等于父类原型对象(superType.prototype)和Object.create的继承关系,支持第二个参数,即为生成的空对象定义属性和属性描述符/访问器描述符。我们可以为这个空对象定义一个constructor属性来更符合默认的继承行为,它是一个不可枚举的内部属性(enumerable:false),ES6类允许子类继承类的静态方法和静态属性父类,而普通的寄生组合继承只能实现instance和instance类之间的继承,类之间的继承需要定义额外的方法。这里使用Object.setPrototypeOf将superType设置为subType的原型,这样就可以继承父类的静态方法和静态属性。10.函数柯里化方法:柯里化是函数式编程中的一项重要技能。它将使用多个参数的函数转换为一系列使用一个参数的函数。函数式编程的另一个重要功能是compose,可以组合函数,组合函数。函数只接受一个参数,所以如果需要接受多个函数,需要使用compose进行函数组合,就需要使用currying对要组合的函数进行部分求值,使其始终只接受一个参数。Yu博客中的示例11.如何使用函数柯里化(支持占位符):占位符可以使柯里化更加灵活。思路是先填好每一轮传递的参数。如果当前回合参数包含占位符,它将被放置在内部保存的数组的末尾。本轮的元素不会填充当前轮参数的占位符,而只会填充之前传递的占位符12。如何使用偏函数:偏函数和柯里化的概念是相似的。个人觉得它们的区别在于,partialfunctions会固定你传入的几个参数,然后一次性接受剩下的参数,而functioncurrying会根据你传入的参数输入参数并返回给函数不断循环,直到参数个数满足柯里化前函数的参数个数。Function.prototype.bind函数是偏函数的典型代表。它接受第二个参数,这个参数是预先添加到绑定函数的参数列表中的参数,与bind不同的是,上面的函数还支持占位符。13.斐波那契数列及其优化使用函数内存来保存之前运算的结果计算能力依赖于之前的结果可以节省很多时间,比如斐波那契数列。缺点是闭包中的obj对象会占用额外的内存。14.实现函数绑定方法。当函数被new作为构造函数调用时,绑定值将失效,变为new指定的对象,定义绑定函数的length属性和name属性(不可枚举属性)。绑定函数的原型需要指向原来的15.实现函数调用方法的原理是将函数作为传入的上下文参数(context)的属性来执行。这里使用ES6Symbol类型来防止属性冲突。16、简单的CO模块使用方法:run函数接受一个生成的生成器函数,run函数包裹的生成器函数每当遇到yield关键字就会停止。当yield后面的promise解析成功后,会自动调用next方法执行到下一个yield关键字,最后每当一个promise解析成功,就会解析下一个promise。当所有解析成功后,将打印所有解析结果,演变成最常用的async/await语法。事件触发后是否再触发一次,原理是利用定时器,如果在规定时间内再次触发事件,最后的定时器会被清零,即函数不会执行,重新触发一个新的定时器定时器会被重置,直到超过指定的时间,定时器中的函数才会自动触发。同时通过闭包对外暴露了一个取消函数,使得外部可以直接清空内部计数器。判断,如果一段时间内没有触发事件,则允许触发下一个事件删除,***所有图片加载完成后,需要解除绑定拦截事件intersectionObserver的实现,实例化一个IntersectionObserver,并使它观察所有img标签。当img标签进入可见区域时,会执行实例化回调,同时给回调传递一个entries参数,里面保存了实例观察到的所有元素的一些状态,比如每个元素的边界信息信息,当前元素对应的DOM节点,当前元素进入可见区域的比例,每当有元素进入可见区域,将真实图片赋值给当前img标签,并释放其观察值20.new关键字21.实现Object.assign22。instanceof的原理是递归遍历正确参数的原型链。每次和左边的参数比较,遍历到原型链的末尾就返回false,找到就返回true。变量,这样它们就不能被外部访问。私有变量以闭包的形式存储。缺点是类的所有实例都访问同一个私有变量。另一种闭包实现解决了上述闭包的缺点。每个实例都有自己的私有变量。缺点是舍弃了类语法的简洁性,所有特权方法(访问私有变量的方法)都通过WeakMap和闭包存储在构造函数中,在每次实例化时保存当前实例和所有私有变量组成的对象。闭包中的WeakMap不能被外部访问。使用Wea??kMap的好处是不用担心内存溢出,这会导致数组的乱序并不是真正的乱序,即使最新版的chrome采用了in-place算法让排序成为稳定的算法,乱序的问题依然没有通过shuffling算法来解决才能达到真正的无序。洗牌算法分为原地和非原地。图1显示了就地改组算法。它不需要声明额外的数组来节省内存使用量。原理就是依次遍历数组的元素,随机选择一个当前元素和所有后续元素,并交换它们。25、单例模式是通过ES6的Proxy拦截构造函数的执行方法来实现的。26、promisify的使用方法:promisify函数是将回调函数改成是promise的一个辅助函数,适用于error-first风格的回调函数(nodejs)。其原理是无论error-first风格的回调成功还是失败,执行完成后都会执行最后一个回调函数。我们需要做的就是让这个回调函数控制promise的状态。这里也使用了proxy来代理整个fs模块,拦截get方法,这样就不需要手动为fs模块的所有方法包裹一层promisify函数,更加灵活。27.优雅处理如何使用async/await:不用每次用async/await都包裹一层try/catch,更优雅。这是另一个想法。如果使用webpack,可以写一个loader,分析AST语法树,遇到await语法自动注入try/catch,这样连辅助功能都不用用。28、发布和订阅EventEmitter通过on方法注册事件,trigger方法触发事件,实现事件之间的松散解耦,另外增加once和off辅助函数,注册和只触发一次事件和注销事件29、实现JSON。stringify(附加)使用JSON.stringify将对象转换为JSON字符串时,一些非法数据类型会被扭曲。主要表现如下。如果对象包含toJSON方法,则调用toJSON作为属性的值为NaN,加上或减去Inifinty,就会变成一个字符串null。当数组中存在Undefined/Symbol/Function数据类型时,它将变为null。如果有Infinity/NaN,也会变成null。对象中的属性值是Undefined/Symbol/Function数据类型,属性和值都不会被转换成字符串。属性值为Infinity/NaN,属性值变为null。日期数据类型的值将调用toISOString。不是数组/对象/函数/日期的复杂数据类型会变成一个空对象循环引用会抛出错误。此外,JSON.stringify还可以传入第二个和第三个可选参数。感兴趣的朋友可以详细了解一下
