underscore.js源码解析【'_'对象定义及内部函数】
(function() { // Baseline setup
// -------------- // Establish the root object, `window` (`self`) in the browser, `global`
// on the server, or `this` in some virtual machines. We use `self`
// instead of `window` for `WebWorker` support.
/*
判断root是window/global/this
*/
var root = typeof self == 'object' && self.self === self && self ||
typeof global == 'object' && global.global === global && global ||
this; // Save the previous value of the `_` variable.
/*
保存全局下之前的'_'变量
若变量冲突,则可以利用此变量进行恢复
*/
var previousUnderscore = root._; // Save bytes in the minified (but not gzipped) version:
/*
原型赋值,以便压缩
*/
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; // Create quick reference variables for speed access to core prototypes.
/*
将内置对象原型中的常用方法赋值给引用变量,以便更方便的引用
*/
var push = ArrayProto.push,
slice = ArrayProto.slice,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
/*
定义了一些ECMAScript 5方法
*/
var nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeCreate = Object.create; // Naked function reference for surrogate-prototype-swapping.
/*
定义一个裸函数
*/
var Ctor = function(){}; // Create a safe reference to the Underscore object for use below.
/*
创建'_'函数(对象)
*/
var _ = function(obj) {
/*
如果'_'的prototype在obj的原型链上,直接返回obj
*/
if (obj instanceof _) return obj;
/*
如果不在,new一个'_'对象
*/
if (!(this instanceof _)) return new _(obj);
/*
如果都不是,则将obj的引用放在_.wrapped属性中????????????????????????????????????????????????????????????????
*/
this._wrapped = obj;
}; // Export the Underscore object for **Node.js**, with
// backwards-compatibility for their old module API. If we're in
// the browser, add `_` as a global object.
// (`nodeType` is checked to ensure that `module`
// and `exports` are not HTML elements.)
/*
判断宿主
*/
if (typeof exports != 'undefined' && !exports.nodeType) {
if (typeof module != 'undefined' && !module.nodeType && module.exports) {//node
exports = module.exports = _;
}
exports._ = _;
} else {//浏览器,放在window的属性下
root._ = _;
} // Current version.
_.VERSION = '1.8.3'; // Internal function that returns an efficient (for current engines) version
// of the passed-in callback, to be repeatedly applied in other Underscore
// functions.
/*
用于内部使用的高阶函数,传入回调函数
主要用来执行函数并改变所执行函数的作用域,最后加了一个argCount参数来指定参数个数
*/
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
/*
对参数个数小于等于4的情况进行分类处理
*/
switch (argCount == null ? 3 : argCount) {
case 1: return function(value) {
return func.call(context, value);
};
// The 2-parameter case has been omitted only because no current consumers
// made use of it.
case 3: return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
/*
当argCount不为null或1/3/4时,直接调用func.apply(context, arguments)
*/
return function() {
return func.apply(context, arguments);
};
}; var builtinIteratee; // An internal function to generate callbacks that can be applied to each
// element in a collection, returning the desired result — either `identity`,
// an arbitrary callback, a property matcher, or a property accessor.
/*
判断参数类型
*/
var cb = function(value, context, argCount) {
if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
if (value == null) return _.identity;
if (_.isFunction(value)) return optimizeCb(value, context, argCount);// 参数是函数,返回optimizeCb函数的执行结果
if (_.isObject(value)) return _.matcher(value);// 参数是对象,则返回一个能判断对象是否相等的函数
return _.property(value);// 默认返回一个获取对象属性的函数
}; // External wrapper for our callback generator. Users may customize
// `_.iteratee` if they want additional predicate/iteratee shorthand styles.
// This abstraction hides the internal-only argCount argument.
_.iteratee = builtinIteratee = function(value, context) {
return cb(value, context, Infinity);
}; // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
// This accumulates the arguments passed into an array, after a given index.
/*
类似于es6中的rest param(function f(a, b, ...args) {})
把startIndex后面的参数放到一个数组里,并作为参数传给fn
*/
var restArgs = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;//'+'相当于Number()
return function() {
var length = Math.max(arguments.length - startIndex, 0),
rest = Array(length),
index = 0;
for (; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
case 2: return func.call(this, arguments[0], arguments[1], rest);
}
/*
将startIndex之前的参数放进数组中
*/
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
}; // An internal function for creating a new object that inherits from another.
/*
创建一个继承自另一个对象的新对象(原型继承)
*/
var baseCreate = function(prototype) {
if (!_.isObject(prototype)) return {};
if (nativeCreate) return nativeCreate(prototype);//如果存在Object.create,则直接使用
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
}; /*
获取对象及其原型链上的方法或属性
*/
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
}; // Helper for collection methods to determine whether a collection
// should be iterated as an array or as an object.
// Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
/*
判断类数组类型(有length属性,并且0 < length < MAX_ARRAY_INDEX)
*/
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
}; ...... }());
小结:
1.闭包
整个函数在一个闭包中,避免污染全局变量。通过传入this(其实就是window对象)来改变函数的作用域。和jquery的自执行函数其实是异曲同工之妙。这种传入全局变量的方式一方面有利于代码阅读,另一方面方便压缩。
underscore写法:
(function(){
...
}.call(this));
jquery写法:
(function(window, undefined) {
...
})(window);
2.格式
var
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind,
nativeCreate = Object.create;
3.高阶函数的使用
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
参考资料:http://yalishizhude.github.io/2015/09/22/underscore-source/
underscore.js源码解析【'_'对象定义及内部函数】的更多相关文章
- underscore.js源码解析【对象】
// Object Functions // ---------------- // Keys in IE < 9 that won't be iterated by `for key in . ...
- underscore.js源码解析(五)—— 完结篇
最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...
- underscore.js源码解析(四)
没看过前几篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二) underscore.js源码解析(三) underscore.js源码GitHub地 ...
- underscore.js源码解析(三)
最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...
- underscore.js源码解析(二)
前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这 ...
- underscore.js源码解析(一)
一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读 ...
- underscore.js源码解析【函数】
// Function (ahem) Functions // ------------------ // Determines whether to execute a function as a ...
- underscore.js源码解析【数组】
// Array Functions // --------------- // Get the first element of an array. Passing **n** will retur ...
- underscore.js源码解析【集合】
// Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `f ...
随机推荐
- 46 【golang项目】完成了一个小小的播放器功能
项目地址:https://github.com/helww/mylab/tree/master/go/player 这个项目中用到了readme说明文件是一个markdown文件. 基础的控制语法,网 ...
- [leetcode]282. Expression Add Operators 表达式添加运算符
Given a string that contains only digits 0-9 and a target value, return all possibilities to add bin ...
- CentOS7 Failed to start LSB: Bring up/down networking.解决方法
https://www.cnblogs.com/bonjov1/p/4323836.html CentOS7 Failed to start LSB: Bring up/down networking ...
- 20165213Java第二次实验
实验二Java面向对象程序设计 实验1 实验目的与要求: 参考http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTEST 完成单元测试的学习 提交 ...
- 第一个VS2015 Xaramin Android项目
20170323新增:VS环境配置 打开VS,菜单栏选工具(Tools) 选项\ 一般有2个地方需要修改 1 2 新建第一个项目,什么都没有修改的情况下(已经配置好环境变量)直接运行,会发现如下错误: ...
- cookie方法封装
将cookie封装主要是为了方便使用,可通过修改参数直接引用在其他需要的地方,不用重新写. 1.添加,删除,修改cookie /** * @param name name:cookie的name * ...
- [c#.net]未能加载文件或程序集“”或它的某一个依赖项。系统找不到指定的文件
问题是这样嘀: 项目采用了三层架构和工厂模式,并借鉴了PetShop的架构,因为这个项目也是采用分布式的数据库,目前只有三个数据库,主要出于提高访问性能考虑. 原来是按照网上对PetShop的介绍来给 ...
- 下拉列表 通过option 改变div的内容
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- MySQL中Decimal类型和Float Double等区别
MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形 ...
- shell脚本学习-执行
跟着RUNOOB网站的教程学习的笔记 Shell与Shell脚本 Shell是用户与Linux系统的桥梁.它既是一种命令语言,也是一种程序设计语言. Shell脚本是一种Shell编写的脚本程序,其实 ...