• 笔记


    //使用原型实现观察者模式
    function Observer() {
    	this.fns = [];
    }
    
    Observer.prototype = {
    	//订阅
    	subscribe: function(fn) {
    		this.fns.push(fn);
    	},
    	//退订
    	unsubscribe: function(fn) {
    		this.fns = this.fns.filter(function(el) {
    			if(el !== fn) {
    				return el;
    			}
    		});
    	},
    	//更新
    	update: function(o,thisObj) {
    		var scope = thisObj || window;
    		this.fns.forEach(function(el) {
    			el.call(scope,o);
    		});
    	}
    };
    
    var ob = new Observer();
    
    var f1 = function(data) {
    	console.log('haode' + data);
    }
    
    var f2 = function(data) {
    	console.log('ok' + data);
    }
    
    ob.subscribe(f1);
    ob.subscribe(f2);
    
    ob.update('我回来了~');
    
    ob.unsubscribe(f1);
    ob.update('我回来了~');
    
    /**
    haode我回来了~
    ok我回来了~
    ok我回来了~
    **/
    
    //实现forEach,返回的是一个数组
    Array.prototype.filter = function(fn,thisObj) {
    	var scope = thisObj || window;
    	var a = [];
    	for(var i = 0;i < this.length; i++) {
    		if(!fn.call(scope,this[i],i,this)) {
    			continue;
    		}
    		a.push(this[i]);
    	}
    	return a;
    }
    
    //实现forEach
    Array.prototype.forEach = function(fn,thisObj) {
    	var scope = thisObj ||window;
    	for(var i = 0;i < this.length;i++) {
    		fn.call(scope,this[i],i,this);
    	}
    }
    
    //使用on/off功能,定义jQuery版的观察者
    (function($) {
    	var o = $({});
    	$.subscribe = function() {
    		o.on.apply(o,arguments);
    	};
    	$.unsubscribe = function() {
    		o.off.apply(o,arguments);
    	};
    	$.publish = function() {
    		o.trigger.apply(o,arguments);
    	};
    }(jQuery));
    
    //回调函数
    function handle(e, a, b, c) {
        // `e`是事件对象,不需要关注
        console.log(a + b + c);
    };
    
    //订阅
    $.subscribe("/some/topic", handle);
    //发布
    $.publish("/some/topic", ["a", "b", "c"]); // 输出abc
    
    
    $.unsubscribe("/some/topic", handle); // 退订
    
    //订阅
    $.subscribe("/some/topic", function (e, a, b, c) {
        console.log(a + b + c);
    });
    
    $.publish("/some/topic", ["a", "b", "c"]); // 输出abc
    
    //退订(退订使用的是/some/topic名称,而不是回调函数哦,和版本一的例子不一样
    $.unsubscribe("/some/topic");
    
    //$.on 订阅者实现
    EventEmiter.prototype.on = function(event,cb) {
    	//event可以是事件名数组
    	if(event instanceof Array) {
    		event.forEach( fn => {
    			this.on(fn,cb);
    		});
    	}
    	if(this.events[event]) {
    		this.events[event].push(cb);
    	} else {
    		this.events[event] = cb;
    	}
    }
    
    //$.emit 发布者实现
    EventEmiter.prototype.emit = function(event) {
    	let args = Array.from(arguments).slice(1);
    	let cbs = this.events[event];
    	if(cbs) {
    		cbs.forEach( cb => {
    			cb.apply(this,args);
    		})
    	}
    }
    
    //$$.off 移除事件
    EventEmiter.prototype.off = function(event,cb) {
    	//没有参数的情况
    	if(!arguments) {
    		this.events = Object.create(null);
    	}
    	//只指定事件
    	if(event instanceof Array) {
    		event.forEach(evt => {
    			this.off(evt,cb);
    		});
    	}
    	//提供了事件和回调
    	if(cb) {
    		let cbs = this.events[event];
    		if(cbs) {
    			for(var i = 0;i < cbs.length;i++) {
    				if(cbs[i] == cb || cbs[i].cbName == cb) {
    					cbs.splice(i,1);
    					break;
    				}
    			}
    		}
    	}
    }
    
    //实现call
    Function.prototype.call = function(thisObj) {
    	let scope = thisObj || window;
    	scope.fn = this;
    	let args = [...arguments].slice(1); //[...arr] 类数组变为数组
    	let result = scope.fn(...args);
    
    	delete scope.fn;
    
    	return result;
    }
    
    //实现apply
    Function.prototype.apply = function(thisObj) {
    	let scope = thisObj || window;
    	let args = arguments[1],result;
    	scope.fn = this;
    	if(args) {
    		result = scope.fn(...args);
    	} else {
    		result = scope.fn();
    	}
    
    	delete scope.fn;
    	return result;
    }
    
    // 使用 call 或者 apply 实现 bind
    // bind 的输入:接受一个或者多个参数,第一个是要绑定的上下文,额外参数当作绑定函数的前置函数(最后concat的原因)
    // bind 的输出:返回原函数的拷贝
    Function.prototype.bind = function(thisObj) {
    
    	if(typeof this !== 'function') {
    		return;
    	}
    
    	let _self = this;
    	let args = Array.prototype.slice.call(arguments, 1);
    	let fnNop = function() {}
    	let fnBound = function() {
    		let _this = this instanceof _self ? this:thisObj;
    		return _self.apply(_this,args.concat(Array.prototype.slice.call(arguments)));
    	}
    
    	if(this.prototype) {
    		fnNop.prototype = this.prototype;
    	}
    
    	fnBound.prototype = new fnNop;
    
    	return fnBound;
    }
    
    //手写实现promise,遵循promiseA+规范,pending(等待状态),fulfilled(成功状态)、rejected(失败状态)
    function Promise(executor) {
    	var self = this;
    	self.status = 'pending';
    	self.value = undefined; //接受成功的值
    	self.reason = undefined; //接受失败回调传递的值
    	self.onResolved = []; //专门存放成功的回调,使用数组是因为回调可能会有多个
    	self.onRejected = []; //专门存放失败的回调
    
    	function resolve(value) {
    		if(self.status == 'pending') {
    			self.value = value; //将成功的原因保存
    			self.status = 'fulfilled';
    			self.onResolved.forEach(fn => fn()); //依次调用保存的函数
    		}
    	}
    	function reject(reason) {
    		if(self.status == 'pending') {
    			self.reason = reason; //将失败的结果保存
    			self.status = 'rejected';
    			self.onRejected.forEach(fn => fn());
    		}
    	}
    	executor(resolve,reject);
    }
    
    function resolvePromise(promise2,x,resolve,reject) {
    	if(promise2 == x) { //防止回调地狱的形成,需要判断他俩之间的关系
    		return reject(new TypeError('循环引用'));
    	}
    	if(x!=null && (typeof x === 'Object' || typeof x === 'function')) {
    		try {
    			var then = x.then;
    			if(typeof then === 'function') {
    				then.call(x,(y) => {
    					if(called) return;
    					called = true;
    					resolvePromise(promise2,y,resolve,reject); //递归解析,重复执行,直到返回的不是一个promise为止
    				},(e) => {
    					if(called) return;
    					called = true;
    					reject(e);
    				});
    			} else {
    				resolve(x);
    			}
    		} catch(error) {
    			reject(error);
    		}
    	} else {
    		resolve(x);
    	}
    }
    
    Promise.prototype.then = function(onfulfilled,onrejected) {
    	onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val=>val;
    	onrejected = typeof onrejected == 'function' ? onrejected : err => {
    		throw err;
    	}
    	var self = this;
    	var promise2;
    	promise2 = new Promise((resolve,reject) => {
    		if(self.status == 'fulfilled') {
    			var x = onfulfilled(self.value);
    			resolvePromise(promise2,x,resolve,reject);
    		}
    		if(self.status == 'rejected') {
    			var x = onrejected(self.reason);
    			resolvePromise(promise2,x,resolve,reject);
    		}
    		if(self.status == 'pending') {
    			self.onResolved.push(function() {
    				var x = onfulfilled(self.value);
    				resolvePromise(promise2,x,resolve,reject);
    			});
    
    			self.onRejected.push(function() {
    				var x = onrejected(self.reason);
    				resolvePromise(promise2,x,resolve,reject);
    			});
    		}
    	});
    }
    

      

  • 相关阅读:
    函数式接口
    方法引用
    接口组成更新
    .Net Framework4.5中Asp.net mvc使用Singal R轮训实现导入进度条功能
    .net mvc使用FlexPaper插件实现在线预览PDF,EXCEL,WORD的方法
    可编辑树Ztree的使用(包括对后台数据库的增删改查)
    使用chosen插件实现多级联动和置位
    在ASP.NET MVC中使用区域来方便管理controller和view
    使用datepicker日期插件
    Linq to sql中使用DateDiff()
  • 原文地址:https://www.cnblogs.com/sunLemon/p/10941174.html
Copyright © 2020-2023  润新知