underscore 系列之防冲突与 Utility Functions

简介: underscore 使用 _ 作为函数的挂载对象,如果页面中已经存在了 _ 对象,underscore 就会覆盖该对象,所以 underscore 提供了 noConflict 功能,可以放弃 underscore 的控制变量 _,返回 underscore 对象的引用。

1.png


防冲突


underscore 使用 _ 作为函数的挂载对象,如果页面中已经存在了 _ 对象,underscore 就会覆盖该对象,举个例子:


var _ = {value: 1 }
// 引入 underscore 后
console.log(_.value); // undefined
复制代码


所以 underscore 提供了 noConflict 功能,可以放弃 underscore 的控制变量 _,返回 underscore 对象的引用。


var _ = {value: 1 }
// 引入 underscore 后
// 放弃 "_",使用 "$"
var $ = _.noConflict();
console.log(_.value); // 1
// 使用 underscore 的方法
$.each([1, 2, 3], alert);
复制代码


那么 noConflict 函数是如何实现的呢?


首先,在 underscore 执行的时候,会储存之前的 _ 对象,然后当执行 noConflict 函数的时候,再将之前储存的 _ 对象赋给全局对象,最后返回 underscore 对象。这样,我们就可以利用返回的 underscore 对象使用 underscore 提供的各种方法。


// 源码一开始的时候便储存之前的 _ 对象
var previousUnderscore = root._;
_.noConflict = function() {
    root._ = previousUnderscore;
    return this;
};
复制代码


是的,就是这么简单。你可以轻松为你的函数库添加防冲突功能。


接下来我们看 underscore 中的一些功能函数。


_.identity


_.identity = function(value) {
    return value;
};
复制代码


看起来匪夷所思的一个函数,传入一个值,然后返回该值,为什么不直接使用该值呢?


还记得我们在《underscore 系列之内部函数 cb 和 optimizeCb》中接触过这个函数吗?

如果我们自己编写了一个 _.map 函数:


_.map = function(arr, iteratee){
    return arr.map(iteratee)
}
复制代码


然而当我们这样使用 _.map([1, 2, 3]) 时便会报错,因为我们没有传入 iteratee 函数,然而使用 underscore 却没有问题,结果是返回一个相同的新数组,原因就在于当 iteratee 为 undefined 的时候,underscore 视为传入了 _.identity 函数。就相当于:


_.map = function(arr, iteratee){
    if (!iteratee) iteratee = _.identity
    return arr.map(iteratee)
}
复制代码


简而言之,如果我们想要复制一个数组:


var clonedArr = [1, 2, 3].map(_.identity) // [1, 2, 3]
复制代码


_.constant


_.constant = function(value) {
    return function() {
        return value;
    };
};
复制代码


该函数传入一个 value,然后返回一个返回该 value 的函数,这又有什么用呢?我们来看个 demo:


var value = 1;
var getValue = _.constant(value);
value = 2;
getValue(); // 1
getValue(); // 1
复制代码


这很容易让人想到 ES6 的 const,我一开始以为就是用来表示 ES6 的 const ,后来看了这个函数起源的 issue,才发现并非如此,它其实像下面的 _.noop 函数一样可以作为默认函数使用。


举个例子:


_.select(collection, filterFunction || function() { return true; })
复制代码


我们根据 filterFunction 筛选 collection 中符合条件的元素,如果没有传 filterFunction,我们就返回所有的元素,如果有 _.constant 函数,我们可以将其简化为:


_.select(collection, filterFunction || _.constant(true))
复制代码


尽管没有什么大的改变,但是语义更加明确。


_.noop


_.noop = function(){};
复制代码


一个空函数,看起来依旧没什么用……


noop 函数可以用于作为默认值,这样就可以省去是否存在的判断,举个例子:


// 不使用 noop
function a(value, callback){
    // 每次使用 callback 都要判断一次
    _.isFunction(callback) && callback()
}
// 使用 noop
function a(value, callback) {
    // 判断一次
    if(!_.isFunction(callback)) callback = _.noop;
    // 以后都可以直接使用
    callback()
}
复制代码


deepGet


var deepGet = function(obj, path) {
    var length = path.length;
    for (var i = 0; i < length; i++) {
        if (obj == null) return void 0;
        obj = obj[path[i]];
    }
    return length ? obj : void 0;
};
复制代码


deepGet 用于获得对象深层次的值。举个例子:


var obj = { 
    value: { 
        deepValue: 2
    } 
}
console.log(deepGet(obj, ['value', 'deepValue']))
复制代码


使用这个函数,可以避免深层次取值时,因为没有其中的一个属性,导致的报错。


shallowProperty


var shallowProperty = function(key) {
    return function(obj) {
      return obj == null ? void 0 : obj[key];
    };
};
复制代码


shallowProperty 也是用于获取对象的属性,也许你会好奇在开发中,直接使用. 不就可以获取对象的属性了,为什么还要写成这样呢?我们来举个例子:


// 获取 arr 所有元素的 name 属性
var arr = [
    {
        value: 1,
        name: 'Kevin'
    },
    {
        value: 2,
        name: 'Daisy'
    }
]
// 普通方式
var names = arr.map(function(item){
    return item.name;
})
// 使用 shallowProperty
var names = arr.map(shallowProperty('name'))
复制代码


_.property


_.property = function(path) {
    if (!_.isArray(path)) {
      return shallowProperty(path);
    }
    return function(obj) {
      return deepGet(obj, path);
    };
};
复制代码


_.property 结合了 deepGet 和 shallowProperty,可以获取元素深层次的值。上面一个例子也可以写成:


var names = arr.map(_.property('name'))
复制代码


_.propertyOf


_.propertyOf = function(obj) {
    if (obj == null) {
        return function(){};
    }
    return function(path) {
        return !Array.isArray(path) ? obj[path] : deepGet(obj, path);
    };
};
复制代码


_.property 返回一个函数,这个函数返回任何传入的对象的指定属性。


_.propertyOf_.property 相反。需要一个对象,并返回一个函数,这个函数将返回一个提供的属性的值。


我们写个例子:


// 获取 person 对象的所有属性值
var person = {
    name: 'Kevin',
    age: '18'
};
// 普通方式
var values = Object.keys(person).map((key) => person[key]); // ["Kevin", "18"]
// 使用 _.propertyOf
var values = Object.keys(person).map(_.propertyOf(person)); // ["Kevin", "18"
复制代码


_.random


返回一个 min 和 max 之间的随机整数。如果你只传递一个参数,那么将返回 0 和这个参数之间的整数。


_.random = function(min, max) {
    if (max == null) {
      max = min;
      min = 0;
    }
    return min + Math.floor(Math.random() * (max - min + 1));
  };
复制代码


注意:该随机值有可能是 min 或 max。


underscore 系列


underscore 系列目录地址:github.com/mqyqingfeng…


underscore 系列预计写八篇左右,重点介绍 underscore 中的代码架构、链式调用、内部函数、模板引擎等内容,旨在帮助大家阅读源码,以及写出自己的 undercore。


如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。


目录
相关文章
undefined reference to symbol 'dlsym@@GLIBC_2.17' libdl.so: error adding symbols: DSO missing from c
undefined reference to symbol 'dlsym@@GLIBC_2.17' libdl.so: error adding symbols: DSO missing from c
614 0
|
7月前
|
JavaScript
解决报错did you register the component correctly? For recursive components, make sure to provide the “na
解决报错did you register the component correctly? For recursive components, make sure to provide the “na
|
7月前
|
算法 项目管理 开发者
【Conan 入门教程 】深入解析Conan中的依赖关系的定义方法(In-depth Analysis of Dependency Definition Methods in Conan)
【Conan 入门教程 】深入解析Conan中的依赖关系的定义方法(In-depth Analysis of Dependency Definition Methods in Conan)
300 0
|
Rust 小程序
小程序警告:Now you can provide attr wxkey for a wxfor to improve performance
首先,无论什么程序,控制台中的警告都是会影响程序性能的。我们需要减少此类警告的出现,以提高程序的运行性能。 小程序开发的时候,遇到了如下的警告:
170 0
|
编译器
[√]添加预处理的2个不同方式:target_compile_definitions / add_definitions
[√]添加预处理的2个不同方式:target_compile_definitions / add_definitions
267 0
Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_ZMCertification", referenced from:解决方法
Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_ZMCertification", referenced from:解决方法
207 0
|
JavaScript
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent .(一)
大致意思就是props接收到的从父组件传过来的tableData不能直接修改。
155 0
|
JavaScript
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent .(二)
1.在data中声明一个变量接收props的值,然后再去改变data里的这个值 2. 用computed属性 3.用data保存数据,watch监听
105 0
|
并行计算
Hint: This means that multiple copies of the OpenMP runtime have been linked into the program.
Hint: This means that multiple copies of the OpenMP runtime have been linked into the program.
294 0
解决g++编译C++报错unresolved external... (undefined reference ...)
解决g++编译C++报错unresolved external... (undefined reference ...)
330 0
解决g++编译C++报错unresolved external... (undefined reference ...)