摘要:在阅读的过程中,发现了它的一些小技巧,对我们平时的编程很有用。事实上,在上也的确是可以被更改的而在或高版本的中,并不能更改全局的。但是,局部的仍然可以被改变。所以,建议在已知长度的情况下,使用第一种,而不知道长度的情况下,使用第二种。
在阅读 underscore 的过程中,发现了它的一些小技巧,对我们平时的编程很有用。在这里向大家介绍一二
void 0 代替 underfined首先,看源码:
_.isUndefined = function(obj) { return obj === void 0; };
这里为啥要用 obj === void 0, 而不是 obj === undefined 呢?
因为,在 js 中,undefined 并不是类似关键字(js 关键字有 function,return ...),所以,理论上是可以更改的。
事实上,在 IE8 上也的确是可以被更改的,
var undefined = 1; alert(undefined); // 1 -- IE8, undefined --- chrome
而在 chrome 或高版本的 IE 中,并不能更改全局的 undefined 。但是,局部的 undefined 仍然可以被改变。例如:
(function() { var undefined = 1; alert(undefined); // 1 -- chrome })();
所以, undefined 并不十分可靠,所以才需要 void 0 , void 是 js 的保留字,所以不可被更改。
在 MDN 上定义是:The void operator evaluates the given expression and then returns undefined.
翻译:void 操作符会对 void 后面的表达式进行运算,然后返回 undefined
所以,使用void会一直返回 undefined ,所以,可以用void 0替代undefined.
复制数组Array.prototype.slice.call(array); 可用来复制一个数组,或将类数组转换为数组
在 js 中,如果我们想复制一个数组,要如何复制呢?也许你会这样做:
function copy(array) { var copyArray = []; for (var i = 0, len = array.length; i < len; i++) { copyArray.push(array[i]); } return copyArray; }
其实,我们可以利用数组的 slice 和 concat 方法返回新的数组这个特性,来实现复制数组的功能;
var newArray = Array.prototype.slice.call(array); var newArray2 = Array.prototype.concat.call(array);
而且,性能方面, slice 以及 concat 比单纯使用 for 循环还要更加高效
var array = _.range(10000000); //_.range,是undescore一个方法,用于生成一个从0到10000000的数组 console.time("for copy push"); var copyArray1 = []; for (var i = 0, length = array.length; i < length; i++) { copyArray1.push(array[i]); } console.timeEnd("for copy push"); console.time("slice"); var copyArray2 = Array.prototype.slice.call(array); console.timeEnd("slice"); console.time("concat"); var copyArray3 = Array.prototype.concat.call(array); console.timeEnd("concat"); //结果 //for copy push: 379.315ms //slice: 109.300ms //concat: 92.852ms
另外,也是通过 slice , call 将类数组转换为数组
function test() { console.log(Array.prototype.slice.call(arguments)); } test(1, 2, 3); //输出[1, 2, 3]使用 Array[length]=value 代替 push 添加元素
实际业务代码,除非对性能要求极高,否则还是推荐 push,毕竟更符合习惯
首先看源码 _.values()
_.values = function(obj) { var keys = _.keys(obj); var length = keys.length; var values = Array(length); //等同于new Array(length) for (var i = 0; i < length; i++) { values[i] = obj[keys[i]]; } return values; };
一开始看这种写法,并不习惯,我们大多数人可能更习惯这样写(使用 push ):
_.values = function(obj) { var keys = _.keys(obj); var length = keys.length; var values = []; // for (var i = 0; i < length; i++) { values.push(obj[keys[i]]); //使用push } return values; };
实际测试中,第一种写法会比第二种更快。
关键在于,我们事先知道要填充的数组 values 的长度,然后预先生成一个对应长度的数组,之后只需要给对应的位置赋值。而第二种在 push 的时候,除了给对应位置赋值,还需要改变 values 数组的 length。
所以,建议在已知长度的情况下,使用第一种,而不知道长度的情况下,使用第二种。
适当的使用 return function当我们编写两个功能非常相近的函数时,例如,实现复制一个数组的功能,分别是正序和倒序,我们可能会这样子实现(这里只是为了举例子,复制数组推荐第二点提到的使用slice或concat):
function copyArray(array, dir) { var copyArray = []; var i = dir > 0 ? 0 : array.length - 1; for (; i >= 0 && i < array.length; i += dir) { copyArray.push(array[i]); } return copyArray; } var copyDesc = function(array) { return copyArray(array, 1); }; var copyAsce = function(array) { return copyArray(array, -1); };
这样子实现会有什么问题呢?
其实对copyDesc,copyAsce,来说,只有 dir 是不同的而已,但是,这种方式实现,却需要将 array 也作为参数传递给 `copyArray。
而copyDesc,copyAsce其实只是一个转发的作用而已。
我们可以继续优化:
function copyArray(dir) { return function(array) { var copyArray = []; var i = dir > 0 ? 0 : array.length - 1; for (; i >= 0 && i < array.length; i += dir) { copyArray.push(array[i]); } return copyArray; }; } var copyDesc = copyArray(1); var copyAsce = copyArray(-1);
我觉得 return function 这种写法比较优雅一点,你觉得呢?
类型判断,使用 Object.prototype.toString()来判断这里只举两个例子,isString,isArray,其他的例如 isArguments , isFunction , 由于有些浏览器兼容问题需要特殊处理,这里就不细说了。
而像isNull,isUndefined,这些比较简单的,这里也不细说了:)
我们知道:
typeof 可能的返回值有:
类型 | 结果 |
---|---|
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
String | "string" |
Symbol(ES6 新增) | "symbol" |
宿主对象(由 JS 环境提供) | Implementation-dependent |
函数对象( [[Call]]) | "function" |
任何其他对象 | "object" |
但是, typeof 却有下面这种问题
typeof "test" ---> "string" typeof new String("test") ---> "object" typeof 123 -----> "number" typeof new Number(123) --->"object"
跟我们的期望不太一样,Object.prototype.toString 则没有这问题。
Object.prototype.toString.call("test"); //"[object String]" Object.prototype.toString.call(new String("test")); //"[object String]" Object.prototype.toString.call(123); //"[object Number]" Object.prototype.toString.call(new Number(123)); //"[object Number]"
所以,我们可以通过Object.prototype.toString来进行类型判断
function isNumber(obj) { return Object.prototype.toString.call(obj) === "[object Number]"; } function isString(obj) { return Object.prototype.toString.call(obj) === "[object String]"; }待续。。。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/100260.html
摘要:模块化是随着前端技术的发展,前端代码爆炸式增长后,工程化所采取的必然措施。目前模块化的思想分为和。特别指出,事件不等同于异步,回调也不等同于异步。将会讨论安全的类型检测惰性载入函数冻结对象定时器等话题。 Vue.js 前后端同构方案之准备篇——代码优化 目前 Vue.js 的火爆不亚于当初的 React,本人对写代码有洁癖,代码也是艺术。此篇是准备篇,工欲善其事,必先利其器。我们先在代...
摘要:来源于拉丁语,不要与混淆了。本文首先介绍一个简单的使用优化技术的例子,然后解读和库中使用的源码,加深理解。总结是一种优化技术,避免一些不必要的重复计算,可以提高计算速度。 memoization 来源于拉丁语 memorandum (to be remembered),不要与 memorization 混淆了。 首先来看一下维基百科的描述: In computing, memoizat...
摘要:专题系列共计篇,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究专题之函数组合专题系列第十六篇,讲解函数组合,并且使用柯里化和函数组合实现模式需求我们需要写一个函数,输入,返回。 JavaScript 专题之从零实现 jQuery 的 extend JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 ext...
摘要:本文同步自我得博客最近准备折腾一下,在事先了解了之后,我知道了对这个库有着强依赖,正好之前也没使用过,于是我就想先把彻底了解一下,这样之后折腾的时候也少一点阻碍。 本文同步自我得博客:http://www.joeray61.com 最近准备折腾一下backbone.js,在事先了解了backbone之后,我知道了backbone对underscore这个库有着强依赖,正好undersc...
摘要:最近开始看源码,并将源码解读放在了我的计划中。将转为数组同时去掉第一个元素之后便可以调用方法总结数组的扩展方法就解读到这里了,相关源码可以参考这部分。放个预告,下一篇会暂缓下,讲下相关的东西,敬请期待。 Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中。 阅读一些著名框架类库的源码,就好...
阅读 1870·2021-11-25 09:43
阅读 3160·2021-11-15 11:38
阅读 2707·2019-08-30 13:04
阅读 483·2019-08-29 11:07
阅读 1491·2019-08-26 18:37
阅读 2696·2019-08-26 14:07
阅读 581·2019-08-26 13:52
阅读 2277·2019-08-26 12:09