Underscore-分析
0.Ecmascript的版本重要时间点
Ecmascript262-3 1999年,ie5.5及以后完全支持,ff,chrome等全部支持
Ecmascript262-4 因为跨越太大,废弃
Ecmascript262-3.1 后改名ecmascript5 主流浏览器支持,ie8部分支持,ie9全部支持
1.常用ecmascript5原生方法
1.1 Array.isArray(arg)
如果是数组,放回true
if (!Array.isArray) {
Array.prototype.isArray = function(ar) {
return Object.prototype.toString.call(ar) === “[object Array]”
}
}
1.2 Object.keys(obj)
把obj的所有属性枚举放到数组里返回,顺序取决于for in的顺序,Object.keys不枚举原型链中的属性
if (!Object.keys) {
Object.prototype.keys = function(obj) {
var ar = [];
for (var i in obj) {
if (Object.prototype.hasOwnProperty.call(obj,i) {
ar.push(i);
}
}
return ar;
}
}
1.3 FuncProto.bind
fun.bind(thisArg[, arg1[, arg2[, ...]]])
if (!Function.bind) {
Function.prototype.bind = function(context) {
var fn = this,
arg = [];
for (var i = 1, len = arguments.length; i < len; i++) {
arg[i-1] = arguments[i];
}
return function() {
for (var j = 0, len2 = arguments.length; j < len2; j++) {
arg[i++] = arguments[j];
}
fn.apply(context, arg);
}
}
}
1.4 Object.create
Object.create(prototype, [ propertiesObject ])
创建一个对象并返回,让该对象的prototype对象指向参数的对象
if (!Object.prototype.create) {
Object.prototype.create = (function() {
function fn() {
};
var hasown = Object.prototype.hasOwnProperty;
return function(proto, args) {
var obj;
fn.prototype = proto;
obj = new fn();
fn.prototype = null;
if (args) {
for (var i in args) {
if (hasown.call(args, i)) {
obj[i] = args[i];
}
}
}
return obj;
}
}())
}
2. _
构建UnderScore的安全的构造函数
关键点是安全:
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
如果参数obj是通过构造函数_new出来的对象,那么直接返回
如果this不是_的对象,说明可能不是通过new _的调用,所以执行
return new _(obj);
最终执行this._wrapped = obj;
2.1 new操作符的过程
当new ConstructorFn(...) 执行时:
1.一个新对象被创建。它继承自ConstructorFn.prototype(newobj.prototype=foo.prototype).
2.构造函数 ConstructorFn 被执行。执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例。new ConstructorFn 等同于 new ConstructorFn(), 只能用在不传递任何参数的情况。
3.如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象,ps:一般情况下构造函数不返回任何值,不过用户如果想覆盖这个返回值,可以自己选择返回一个普通对象来覆盖。当然,返回数组也会覆盖,因为数组也是对象。
3.baseCreate
创建一个对象,让它的prototype指向参数对象,多用于子类继承父类
首先判断参数是否为对象或函数,如果不是,返回空对象。
然后判断是否存在原生create,如果有,调用。
如果没有,通过ctor函数,让ctort.prototype = prototype;
var result = new ctor();
ctor.prototype = null;
var baseCreate = function(prototype) {
if (!_.isObject(prototype)) return {};
if (nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
};
4.var property
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
生成安全的取对象属性的方法,防止undefined或null取属性值而报错。
关键点:
obj == null ? void 0 : obj[key];
obj == null 实际上是一个隐式转换,就是当obj是null或undefined的时候。
==的隐式转换规则,详见Ecmascript: http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.1
如果双方类型一致,对比值:
如果是undefined, true
如果是null, true
如果是number,
如果其中一个是NaN,不相等
如果值相等,相等
+0, -0, 0是相等的。
如果是String,
当两个字符串长度一致,而且对应位置字符一致那么相等。
如果是Boolean
当两者都是true或者false时候相等。
如果是Object
当两者的指针指向一个对象时相等。
如果类型不一致,
null, undefined相等
string,boolean和number比较时候会转换成数字再比较
boolean和其他的比较会转换成number,true1 false 0
Object和string或number比较会先调用toString或valueOf,得到值后在比较。
5. optimizeCb
用于优化回调函数:
1) 绑定上下文context,如果有context,返回绑定context的函数,用于后续操作。如果没有context,直接返回
2)通过客户端传入的argCount决定返回函数的参数个数,防止使用arguments对象,因为在一些旧的v8版本中,使用
arguments会导致函数得不到浏览器优化。
6.createreduce
在函数内部创建一个闭包的迭代函数,然后返回一个函数,判断参数,初始化然后调用这个迭代函数。
闭包作用
闭包大致有这么几个作用:避免命名冲突;私有化变量;变量持久化,让函数参数固定值
这里的作用主要就是变量(函数)持久化,好处就是重复调用的时候不需要再重新创建函数,从而提升执行速度。
为什么要用两层闭包呢?第一层闭包持久化iterator函数,调用reduce和reduceRight函数避免重复新建函数。第二层闭包保存keys,index,length这些变量。
7.find
调用情况如下,以findIndex为例,我们一个个分析它的函数

[%OU7EM5.png)
8.filter
对每个元素根据传入的函数进行计算,如果true,将这个元素放入数组,最后返回数组。
内部还是先用optimizeCb进行处理函数的绑定和优化,然后执行each,对每个元素处理。
9.contains
1.调用values把对象的值转换成数组返回
2.调用indexOf >=0 判断是否在给定的数组(或对象中)
3.使用createIndexFinder生成indexOf方法,关键点有:
1)根据开始index和dir值,生成循环的条件
2)判断是否被查找的元素是不是NaN(obj !== obj),如果是的话,对每个元素调用isNaN判断是不是NaN,如果有的话,返回true
10. isNaN
_.isNaN = function(obj) {
return _.isNumber(obj) && obj !== +obj;
};
一般我们判断NaN的方法只需要:a !== a,那么就是NaN了。
而这里是为了同时检验出:new Object(NaN)
这个数的类型(toString)是Number,如果+obj的话就转换成了NaN,满足new Object(NaN) !== NaN
另附对象转换成数字:
When the [[DefaultValue]] internal method of O is called with hint Number, the following steps are taken:
- Let valueOf be the result of calling the [[Get]] internal method of object O with argument "
valueOf". - If IsCallable(valueOf) is true then,
- Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list.
- If val is a primitive value, return val.
- Let toString be the result of calling the [[Get]] internal method of object O with argument "
toString". - If IsCallable(toString) is true then,
- Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
- If str is a primitive value, return str.
- Throw a TypeError exception.
首先调用valueOf,如果可执行,返回值,否则调用toString,返回值。
11.invoke
_.invoke(obj, method)
对obj的每个元素执行method方法,结果组成数组并返回;
如果method是自定义函数,那么执行method,否则,获得eachvalue[method]并执行。
12.shuffle
乱序排列一个数组,几个关键点:
1)返回的是新数组
2)有可能顺序是不变的
3)random的
3)核心是:
if (random !== index) shuffle[index] = shuffle[random]
shuffle[random] = set[index];
13.partial
给函数设置预定义的变量,允许使用占位符。
核心思想是在partial函数中处理参数,然后返回一个闭包函数,把两部分参数组装在一起。
_.throttle(function, wait, [options]) _.after = function(times, func) {
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
因为参数也是函数内的一个变量,所以返回的闭包函数对参数的操作也是同一个内存位置,因此直接更新times进行判断。
_.template(templateString, [settings]) var escapes = {
"'": "'",
'\\': '\\',
'\r': 'r',
'\n': 'n',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
2.然后对捕获的内容处理,然后组装成js代码的字符串形式
对所有匹配的正则都做处理,组装成一个大的js代码字符串。
再组装,增加参数定义,常用函数定义等内容在前头。
最后使用new Function创建render函数,函数的参数有两个:
第一个参数是传入的变量对象,如果有setting.variable的话,使用这个字符串作为变量名,然后模板中都是用这个变量名调用和访问,速度会快。
如果没有的话,就命名为obj,然后通过with(obj) {函数体}的方式来使用这个传入的数据。
[%OU7EM5.png)
Underscore-分析的更多相关文章
- HiShop2.x版本中的上传插件分析,得出所用的模板语言为Underscore.js 1.6.0且自己已修改
效果: 上传组件非常的酷,但是分析其使用JS写法使用了模板语言的,代码如下: <script type="text/j-template" id="tpl_popb ...
- underscore.js依赖库函数分析二(查找)
查找: 在underscore.js封装了对dom查找的操作,find()和filter()函数,find()函数的查找操作是返回首个与条件相符的元素值,filter()函数是找到与条件相符的所有元素 ...
- underscore.js依赖库函数分析一(遍历)
Underscore简介: underscore是一个非常简洁,实用的javascript库,和jQuery封装类型差不多,但underscore是backbone的依赖 库,想运行backbone就 ...
- underscore.js 源码分析5 基础函数和each函数的使用
isArrayLike 检测是数组对象还是纯数组 var property = function(key) { return function(obj) { return obj == null ? ...
- underscore.js 分析6 map函数
作用:通过转换函数(iteratee迭代器)映射列表中的每个值产生价值的新数组.iteratee传递三个参数:value,然后是迭代 index. _.map([1, 2, 3], function( ...
- underscore.js 分析 第四天
查看underscore包含多少属性和方法 通过阅读JavaScript 获取对象的键的数组 var a = _; var arr = Object.keys(a); console.log(arr) ...
- underscore.js 分析 第三天
// Create a safe reference to the Underscore object for use below. // 为Underscore对象创建一个安全的引用 // _为一个 ...
- underscore.js 分析 第二天
Underscore源码中有这么句obj.length === +obj.length意思是typeof obj.length == number,即检测obj的长度是否是数字我的理解:这么写是来检测 ...
- underscore.js 分析 第一天
Underscore 是一个非常实用的Javascript类库. 通过研究他能提高自身的JS水平. 我们看到整个代码被 (function() { /* 代码 */ }.call(this)); 包 ...
- Underscore.js 1.3.3 源码分析收藏
Underscore是一个提供许多函数编程功能的库,里面包含了你期待(在Prototype.js和Ruby中)的许多功能.但是没有扩展任何内置的Javascript对象,也就是说它没有扩展任何内置对象 ...
随机推荐
- ajax+php+mysql 实现点赞、局部刷新,每个IP只能对一篇文章点赞一次
主要流程: 点赞—>判断当前设备IP是否对当前文章有过点赞记录—>若有记录,弹出提示“已经赞过了”; 若无记录,当前文章点赞数+1,并在记录设备IP点赞记录的表中插入信息. 文章表 art ...
- 那些年,坑死自己的事之fread/fwrite
今天继续看牛人做过的东西,这个小程序并不大,加上相当多的注释行,才5000多行.这个小程序是在linux下实现的,之前自己也一直用vi来看并加以更加详细的注释,但是效率实在太低.于是将其转移到wind ...
- Selenium 简单的例子
Selenium是一个web自动化验收测试框架. Selenium Client Driver - Selenium 2.0 Document http://seleniumhq.github.i ...
- WebStorm 2016.2 破解方法
http://www.jetbrains.com/ 以前的 http://idea.lanyus.com/ 不能激活了 有帖子说的 http://15.idea.lanyus.com/ http:// ...
- DevExpress.XtraEditors.xtraScrollableControl
DevExpress.XtraEditors.xtraScrollableControl里面加一个有高度的控件就有滚动条了
- 「理解HTTP」之常见的状态码segmentfault
状态码的职责是当客户端向服务器端发送请求时,描述返回请求结果.借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了什么错误. RFC2616定义的状态码,由3位数字和原因短信组成.数字中的第一 ...
- Pycharm创建py文件时自定义头部模板
File->settings->Editor->File and Code Templates->Python Script #!/usr/bin/env python # - ...
- flume+kafka+spark streaming整合
1.安装好flume2.安装好kafka3.安装好spark4.流程说明: 日志文件->flume->kafka->spark streaming flume输入:文件 flume输 ...
- python 小程序 查找最大的python文件
使用os.path模块方法介绍 1. 扫描标准库目录 I 通过glob模块遍历一个目录下面的所有文件,glob接收shell中常用文件名模式语法:"?"代表任何单个字符,* ...
- Python学习日志(二)
在网易云课堂看到小甲鱼的python视频,想起以前看就是看他的视频学C的虽然后来不了了之都怪我自己啦,于是决定跟着这个视频来学python啦! IDLE IDLE其实是一个python shell , ...