My Little World

基础知识

一些有思想提醒作用的话

把不变的部分隔离出来,把可变的部分封装起来

多态最根本的作用就是通过把过程化的条件分支语句转化为对象的多态性,从而消除这些条件分支语句

(每个对象应该做什么,已成为了该对象的一个方法,被安装在对象的内部,每个对象负责它们自己的行为,所以这些对象可以根据同一个消息,有条不紊的分别进行各自的工作 ====> 将行为分布在各个对象中,并让对象各自负责自己的行为<—面向对象设计优点)

对象以方法的形式包含了过程,而闭包则是在过程中以环境的形式包含了数据

小知识点

1.原型继承过程:对象把请求委托给它的构造器的原型

1
2
3
4
5
6
7
8
9
10
var A = function(){};
A.prototype = {name:'seven'};
var B = function(){};
B.color='red';
B.prototype = new A();
B.prototype.color = 'green'
var b = new B();
console.log(b.name,b.color)

//seven green

2.用new 调用构造器时,如果构造器显示返回了一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是this;
若不显示返回任何数据,或者是返回一个非对象类型的数据,则会正常返回this

3.使用Dom 方法时,注意是否会造成this 丢失

1
2
3
4
<script>
let getId = document.getElementById; //原来 getElementById this指向document
getId('DIV1') //现在指向window
</script>

4.使用call/apply时,如果第一个参数传入null,那么函数体内的this会指向window

5.闭包作用:封装变量;延续局部变量寿命
闭包和内存泄露有关系的地方是,使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些DOM节点,就比较可能造成内存泄露。因为IE浏览器中,由于BOM和DOM对象是使用C++以COM对象的方式实现的,而COM对象的垃圾收集机制采用引用计数策略,这时,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收。

解决办法是将循环引用中的变量设为null,方便回收。

高阶函数一些例子

一个单例模式

1
2
3
4
5
6
var getSingle = function(fn){
var ret;
return function(){
return ret || (ret = fn.apply(this,arguments));
}
}

AOP(切面编程) 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 Function.prototype.before = function(beforeFn){
return ()=>{
beforeFn.apply(this,arguments);
return this.apply(this,arguments);
}
}
Function.prototype.after = function(afterFn){
return ()=>{
this.apply(this,arguments);
afterFn.apply(this,arguments);
}
}
var func = function (){console.log(2)}
func = func.before(()=>{console.log(1)}).after(()=>{console.log(3)})
func()
//1
//2
//3

部分求值 currying

一个curring的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来,待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 var currying = function(fn){
let args = [];
return function(){
if(arguments.length === 0){
return fn.apply(this,args);
}else{
[].push.apply(args,arguments);
return arguments.callee;
}
}
};
var cost = (function(){
var money = 0;
return function (){
for(var i = 0,l=arguments.length;i<l;i++){
money += arguments[i];
}
return money;
}
})();

var cost = currying(cost);
cost(100);
console.log(cost(200))
console.log(cost())

函数节流

多次重复调用,按时间限制调用次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var throttle = function(fn,interval){
var _self = fn,timer,firstTime = true;
return fucntion(){
var args = arguments,_me = this;
if(fiestTime){
_self.apply(_me,args);
return firstTime = false;
}
if(timer){
return false;
}
timer = setTimeout(function(){
clearTimeout(timer);
timer = null;
_self.apply(_me,args);
},interval||500)
}
}

分时函数

大批量数据要执行同一函数,分批次执行任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 var timeChunk = function(ary,fn,count){
var obj,t;
var len = ary.length;
var start = function(){
for(var i = 0;i<Math.min(count||1,ary.length);i++){
var obj = ary.shift();
fn(obj);
}
}
return function(){
t=setInterval(function(){
if(ary.length === 0){
return clearInterval(t)
}
start();
},200)
}
}

惰性加载函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 var addEvent = function(elem,type,handler){
if(window.addEventListener){
addEvent = function(elem,type,handler){
elem.addEventListerner(type,handler,false)
}
}else if(window.attachEvent){
addEvent = function(elem,type,handler){
elem.attachEvent('on'+type,handler)
}
}
addEvent(elem,type,handler);
}
//addEvent 在第一次进入条件分支之后,在函数内部会重写这个函数,重写之后的函数就是我们期望的函数,在下一次进入addEvent
//函数时,addEvent函数不存在条件分支,无需再进行判断