Skip to content

Latest commit

 

History

History
170 lines (133 loc) · 5.21 KB

common.md

File metadata and controls

170 lines (133 loc) · 5.21 KB

vue.js中有一些小函数可以单独摘出来加入到自己的代码库中

remove

function remove (arr, item) {
  if (arr.length) {
    var index = arr.indexOf(item);
    if (index > -1) {
      return arr.splice(index, 1)
    }
  }
}

经常会遇到这么一个需求,在一个数组中删除一个特定的元素,第一步要做的是根据元素找到对应的索引,第二部根据索引删除元素。其实我个人觉得这个封装到Array.prototype上也不为过,毕竟太常用到了。

if(!Array.prototype.remove){
	Array.prototype.remove = function(item){
		if(arguments.length===0){
			throw new TypeError('item to be removed is needed');
		}
		var indexOf = Array.prototype.indexOf;
		var splice = Array.prototype.splice;
		var list = Object(this);
		var index = indexOf.call(list,item);
		if(index > -1){
			splice.call(list,index,1);
			return true;
		}
		return false;
	}
}

之前讲javascript的polyfill时提到过,Array原型上的findIndex方法是个高配版的indexOf,它通过传入的回调判断是否满足条件,我们也可以按照这个思路下来加强remove方法。

if(!Array.prototype.removeBy){
	Array.prototype.removeBy = function(callback,thisArg){
		if (typeof callback !== 'function') {
			throw new TypeError('callback must be a function');
		}
		var findIndex = Array.prototype.findIndex;
		var splice = Array.prototype.splice;
		var list = Object(this);
		var index = findIndex.call(list,callback,thisArg);
		if(index>0){
			splice.call(list,index,1);
			return true;
		}
		return false;
	}
}

cached

function cached (fn) {
  var cache = Object.create(null);
  return (function cachedFn (str) {
    var hit = cache[str];
    return hit || (cache[str] = fn(str))
  })
}

这个函数的作用是对传入的函数进行一次包装,使其具有缓存结果的能力。在underscore.js里也有类似的代码:

_.memoize = function(func, hasher) {
	var memoize = function(key) {
		var cache = memoize.cache;
		var address = '' + (hasher ? hasher.apply(this, arguments) : key);
		if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
		return cache[address];
	};
	memoize.cache = {};
	return memoize;
};

基本思路是一致的,都是找个变量缓存结果,但是underscore还支持了定制缓存时的键。

camelize

var camelizeRE = /-(\w)/g;
var camelize = cached(function (str) {
	return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })
});

这个函数的作用是把中划线连接的字符串转换成驼峰的形式,vue还对驼峰化的结果进行了缓存。我们可以把这里的缓存功能去掉作为一个工具函数。

var camelize = (function(){
	var camelizeRE = /-(\w)/g;
	return function(str){
		return str.replace(camelizeRE,function (_, c) { return c ? c.toUpperCase() : ''; })
	}
})();

hyphenate

这个函数所做的和上面的camelize正好相反,它是把驼峰化的字符串转化为中划线连接的。

我们先看下vue中的实现:

var hyphenateRE = /([^-])([A-Z])/g;
var hyphenate = cached(function (str) {
	return str
		.replace(hyphenateRE, '$1-$2')
		.replace(hyphenateRE, '$1-$2')
		.toLowerCase()
});

我们结合实例看一下作者的思路,比如字符串aBcD,我们期望的中划线形式是a-bc-d,经过第一个replace方法我们得到了a-Bc-D,到这里我们只需转一下大小写就好了,同时注意到在这个情况下第二个replace是没有任何匹配结果的。那第二个replace是做什么,或者说什么情况下需要第二个replace,我的答案是字符串有连续大写字母的情况。比如字符串aBCD,第一个replace的结果是a-BC-D(请思考为什么),经过第二个replace我们得到a-B-C-D

关于中划线化这个方法,我想提出我的看法:

function hyphenate(str){
	var hyphenateRE = /([A-Z])/g;
	return str.replace(hyphenateRE,'-$1').toLowerCase();
}

我是这样考虑的:中划线化需要每个大写字母前面加个中划线,然后转小写即可。我能想到的和vue的方案有区别的情况是首字母是大写。vue的方案首字母大写不会在首字母前面加中划线,我的方案会加,但驼峰化的字符串一般而言首字母都是小写的啊。

capitalize

var capitalize = cached(function (str) {
	return str.charAt(0).toUpperCase() + str.slice(1)
});

在php里有个同样功能的函数叫ucfirst,就是把字符串首字母大写。

isReserved

function isReserved (str) {
	var c = (str + '').charCodeAt(0);
	return c === 0x24 || c === 0x5F
}

一般有个默认的规范是以_开头的为私有,在vue中一些属性和方法以$开头,因而这两个作为保留字

isNative

function isNative (Ctor) {
	return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}

这里native code的含义是:native代码实现的build-in函数,而不是javascript代码。毕竟有时希望原生的功能,而不是其他开发者polyfill的功能。