underscore源码阅读

1:函数式编程初探

2:if(obj.length === +obj.length)的判断

3:JS对象属性用中括号表示的优点在于可以用变量表示属性

4:callee,caller---JS高级程序设计P114-115

5:函数的length属性是希望接受的命名参数的个数,对象本身是没有length属性的

6:call与apply---JS高级P116-117 ①传递参数②扩充作用域

7:in运算符

判断对象是否为数组/对象的元素/属性:
  格式:(变量 in 对象),
  当“对象”为数组时,“变量”指的是数组的“索引”;
  当“对象”为对象是,“变量”指的是对象的“属性”。
  var arr = ["a","b","2","3","str"];
  var result = ("b" in arr);
  var result1 = (4 in arr);  
  输出:
  false

8:别名_.reduce = _.foldl = _.inject
9:find内部其实使用的是some

10:

// 迭代集合中的元素, 并将通过处理器验证的元素放到数组中并返回
each(obj, function(value, index, list) {
if(iterator.call(context, value, index, list))
results[results.length] = value;             //这个数组处理可以借鉴
});

 11:

// 依次调用集合中所有元素的同名方法, 从第3个参数开始, 将被以此传入到元素的调用方法中
// 返回一个数组, 存储了所有方法的处理结果
_.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method);
return _.map(obj, function(value) {
var func = isFunc ? method : value[method];
//确定func是什么
return func == null ? func : func.apply(value, args);
//如果func存在的话就进行函数运算,否则直接跳出
});
};

12:

// 返回集合中的最大值, 如果不存在可比较的值, 则返回undefined
_.max = function(obj, iterator, context) {
// 如果集合是一个数组, 且没有使用处理器, 则使用Math.max获取最大值
// 一般会是在一个数组存储了一系列Number类型的数据
if(!iterator && _.isArray(obj) && obj[0] === +obj[0])
return Math.max.apply(Math, obj);
// 对于空值, 直接返回负无穷大
if(!iterator && _.isEmpty(obj))
return -Infinity;
// 一个临时的对象, computed用于在比较过程中存储最大值(临时的)
var result = {
computed : -Infinity
};
// 迭代集合中的元素
each(obj, function(value, index, list) {
// 如果指定了处理器参数, 则比较的数据为处理器返回的值, 否则直接使用each遍历时的默认值
var computed = iterator ? iterator.call(context, value, index, list) : value;
// 如果比较值相比上一个值要大, 则将当前值放入result.value
computed >= result.computed && ( result = {
value : value,
computed : computed
});
});
// 返回最大值

return result.value;
};

13:clip-path视察滚动

14:

delay_.delay(function, wait, *arguments) 
类似setTimeout,等待wait毫秒后调用function。如果传递可选的参数arguments,当函数function执行时,arguments 会作为参数传入。

var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.

throttle_.throttle(function, wait, [options]) 
创建并返回一个像节流阀一样的函数,当重复调用函数的时候,至少每隔 wait毫秒调用一次该函数。对于想控制一些触发频率较高的事件有帮助。(愚人码头注:详见:javascript函数的throttle和debounce,感谢 @澳利澳先生 的翻译建议)

默认情况下,throttle将在你调用的第一时间尽快执行这个function,并且,如果你在wait周期内调用任意次数的函数,都将尽快的被覆盖。如果你想禁用第一次首先执行的话,传递{leading: false},还有如果你想禁用最后一次执行的话,传递{trailing: false}

var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);

debounce_.debounce(function, wait, [immediate]) 
返回 function 函数的防反跳版本, 将延迟函数的执行(真正的执行)在函数最后一次调用时刻的 wait 毫秒之后. 对于必须在一些输入(多是一些用户操作)停止到达之后执行的行为有帮助。 例如: 渲染一个Markdown格式的评论预览, 当窗口停止改变大小之后重新计算布局, 等等.

传参 immediate 为 true, debounce会在 wait 时间间隔的开始调用这个函数 。(愚人码头注:并且在 waite 的时间之内,不会再次调用。)在类似不小心点了提交按钮两下而提交了两次的情况下很有用。 (感谢 @ProgramKid 的翻译建议)

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

// debounce与throttle方法类似, 用于函数节流, 它们的不同之处在于:
// -- throttle关注函数的执行频率, 在指定频率内函数只会被执行一次;
// -- debounce函数更关注函数执行的间隔, 即函数两次的调用时间不能小于指定时间;
// 如果两次函数的执行间隔小于wait, 定时器会被清除并重新创建, 这意味着连续频繁地调用函数, 函数一直不会被执行, 直到某一次调用与上一次调用的时间不小于wait毫秒
// debounce函数一般用于控制需要一段时间之后才能执行的操作, 例如在用户输入完毕200ms后提示用户, 可以使用debounce包装一个函数, 绑定到onkeyup事件

15:

extend_.extend(destination, *sources) 
复制source对象中的所有属性覆盖到destination对象上,并且返回 destination 对象. 复制是按顺序的, 所以后面的对象属性会把前面的对象属性覆盖掉(如果有重复).

_.extend({name: 'moe'}, {age: 50});
=> {name: 'moe', age: 50}

16:

mixin_.mixin(object) 
允许用您自己的实用程序函数扩展Underscore。传递一个 {name: function}定义的哈希添加到Underscore对象,以及面向对象封装。

_.mixin({
  capitalize: function(string) {
    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
  }
});
_("fabio").capitalize(); _.capitalize("fabio");这两种写法都可以
=> "Fabio"

17.链式语法(Chaining)

您可以在面向对象或者函数的风格下使用Underscore, 这取决于您的个人偏好. 以下两行代码都可以 把一个数组里的所有数字乘以2.

_.map([1, 2, 3], function(n){ return n * 2; });
_([1, 2, 3]).map(function(n){ return n * 2; });

chain_.chain(obj) 
返回一个封装的对象. 在封装的对象上调用方法会返回封装的对象本身, 直道 value 方法调用为止.

var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}];
var youngest = _.chain(stooges)
  .sortBy(function(stooge){ return stooge.age; })
  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
  .first()
  .value();
=> "moe is 21"

18:template_.template(templateString, [settings]) 
API:

将 JavaScript 模板编译为可以用于页面呈现的函数, 对于通过JSON数据源生成复杂的HTML并呈现出来的操作非常有用。 模板函数可以使用 <%= … %>插入变量, 也可以用<% … %>执行任意的 JavaScript 代码。 如果您希望插入一个值, 并让其进行HTML转义,请使用<%- … %>。 当你要给模板函数赋值的时候,可以传递一个含有与模板对应属性的data对象 。 如果您要写一个一次性的, 您可以传对象 data 作为第二个参数给模板 template 来直接呈现, 这样页面会立即呈现而不是返回一个模板函数. 参数 settings 是一个哈希表包含任何可以覆盖的设置 _.templateSettings.

1 写法一
2 var template = _.template("<b><%- value %></b>");
3 template({value: '<script>'});
4 => "<b>&lt;script&gt;</b>"
5 写法二
6 var template = _.template("<b><%- value %></b>")({value: '<script>'});
7 都可以

源码分析:(之所以)_.template(!@#)(data);

// 创建一个函数, 将源码作为函数执行体, 将obj和Underscore作为参数传递给该函数
var render = new Function(settings.variable || 'obj', '_', source);
// 如果指定了模板的填充数据, 则替换模板内容, 并返回替换后的结果
if(data)
return render(data, _);
// 如果没有指定填充数据, 则返回一个函数, 该函数用于将接收到的数据替换到模板
// 如果在程序中会多次填充相同模板, 那么在第一次调用时建议不指定填充数据, 在获得处理函数的引用后, 再直接调用会提高运行效率
var template = function(data) {
return render.call(this, data, _);
};

19:①将内置对象常用方法缓存在局部变量中方便调用 ②对call的使用 ③各种判断 ④别名

原文地址:https://www.cnblogs.com/cndotabestdota/p/5665743.html