3.1jQuery中$.Callbacks的函数对象的实现
$.Callbacks作用: $.Callbacks用于管理函数队列。
$.Callbacks的使用: 我们通过调用$.Callbacks(options)获取到一个Callbacks实例
内部API分别有:
- add => 向内部队列添加函数
- fire依次执行队列里的函数
构造参数分别有:
- “stopOnFalse” => 内部队列里的函数是依次执行的,当某个函数的返回值是false时停止继续执行剩下的函数
- “memory” => 当函数队列fire一次后内部会记录当前fire的参数。当下次调用add的时候,会把记录的参数传递给新添加的函数并立即执行这个新添加的函数。
(function(root){
// 用于缓存构造传入的参数值
var optionsCache = {}
var _ = {
// 定义Callbacks
callbacks: function(options){
options = typeof options === "string" ? (optionsCache[options] || createOptions(options)) : {};
var list = [] // 队列添加处理函数
var index,length,testTing,memory,start,starts
var fire = function(data){// 执行队列里的处理函数
memory = options.memory && data
index = starts || 0
start = 0
testTing = true
length = list.length
for(;index < length;index++) {
if(list[index].apply(data[0],data[1]) === false && options.stopOnfalse){
break; // 终止后面的处理函数的执行
}
}
}
var self = {
// 向内部队列添加函数
add: function(){
var args = Array.prototype.slice.call(arguments)
start = list.length
args.forEach(function(fn){
// 使用toString.call用于检索数据类型
if(toString.call(fn) === "[object Function]") {
if(!options.unique || !self.has(fn,list))list.push(fn) // 处理函数的唯一性
}
})
if(memory){
starts = start
fire(memory) // 如果memory为undefined则不执行fire
}
return this
},
// 上下文的绑定
fireWith: function(context,arguments){
var args = [context,arguments]
if(!options.once || !testTing){
fire(args) //调用外面的fire方法
}
},
// 依次执行队列里的函数
fire: function(){
self.fireWith(this,arguments)
},
// inArray作为一个接口对外使用
has: function(fn,array){
return self.inArray(fn,array) > -1
},
// 判断数组中是否存在某元素
inArray: function(elem,arr){
return arr === null ? -1 : [].indexOf.call(arr,elem)
}
}
return self
}
}
// 创建参数
function createOptions(options){
// 按参数值设置为缓存对象中的属性对象,初始为{}
var object = optionsCache[options] = {}
// 可按空格分割字符串成数组时遍历分割字符串
options.split(/\s+/).forEach(value => {
object[value] = true // 按分割字符串值作为当前创建对象的属性,初始为true
});
return object // 返回当前创建的参数对象
}
root.$ = _;
})(this) // this指向当前window对象
3.2Function.call和Function.apply以及Function.bind的使用区别
代码举例理解如下:
<script>
/**
* 如果当作类使用时,this指向当前实例对象
* 如果当作构造函数使用时,this指向window
* 如果作函数使用时fn是Function实例对象存在
*/
function fn(){
this.name = "max"
console.log("当前this指向=>",this)
}
new fn() // 当作类使用,this指向当前实例对象
fn() // 当作函数使用,this指向当前window对象
console.log(fn.apply(Object)) // 调用当前fn函数,改变它内部this的指向
/**
* 模拟slice.call调用方式
*/
Array.prototype.mySlice = function(start,end){
var result = new Array()
start = start || 0
end = end || this.length
for(var i = start;i < end;i++){
result.push(this[i])
}
return result
}
function Fn(a,b,c,d){
console.log("arguments=>",arguments)
return [].mySlice.call(arguments) // 调用当前原型函数mySlice,改变它内部this的指向
}
console.log(Fn(1,2,3,4))
/**
* Function原型方法call和apply的使用区别
*/
function FN(a,b,c,d){
console.log("this指向=>",this)
console.log("a,b,c,d=>",a,b,c,d)
}
var obj = {}
FN.call(obj,1,2,3,4) // 打印结果为:this指向=> Object a,b,c,d=> 1 2 3 4
FN.apply(obj,[1,2,3,4]) // 打印结果为:this指向=> Object a,b,c,d=> 1 2 3 4
/**
* Function原型方法bind的使用
*/
var FNBind = FN.bind(obj,5,4) // 创建FN的副本
console.log(FNBind(3,2)) // 打印结果为:this指向=> Object a,b,c,d=> 1 2 3 4
</script>