本文是在看《Javascript函数式》编程一书写下的一些记录。和大家分享。不足之处还望大家指正。
关于this的讨论
首先来看这么几段代码
function globalThis(){return this;}
globalThis();
//=>window or global object
globalThis.call('haha');
//=>'haha'
globalThis.apply('abc',[]);
//=>'abc
可以看到,this的一般就是由调用他的对象决定的,如果进行绑定了的话,相当于说这个函数的调用对象只能够是你绑定的那个对象,是不能够更改的。
var bindThis = globalThis.bind('abc')
bindThis();
//=>'abc'
bindThis.call('x')
//=>'abc'
bindThis.apply('y',[]);
//=>'abc
当然,如果我看到这本书推荐大家使用underscore库。用法如下
_.bind(globalThis,'abc')
这样的操作也是可以的。如果说有很多个函数都需要绑定到同一个对象上去怎么办呢?underscore提供了bindAll(obj,methondName)
var buttonView = {
label : 'underscore',
onClick: function(){ alert('clicked: ' + this.label); },
onHover: function(){ console.log('hovering: ' + this.label); }
};
_.bindAll(buttonView, 'onClick', 'onHover');
函数的闭包
相信大家都或多或少踩过闭包这个坑吧,确实一开始接触感觉很不能理解。我个人粗浅理解是闭包是一个函数执行过后返回一个内部函数,这个内部函数将保留包含这个内部函数的函数的作用域链。也就是里面把外面包住了,简称闭包2333。
function captureOut(){
var a = 123;
return function(){
console.log("a:"+a);
}
}
var getA = captureOut();//获取captureOut返回的匿名函数
getA();//这个匿名函数会保留原本的作用域链
//=>a:123
有意思的是函数参数也是可以被我们捕获到的
function capturePara(PARA){
return function(){
console.log(PARA);
}
}
var getP = capturePara("I'm the parameters");
getP();//I'm the parameters
这就给我们灵活的创造一些函数提供了便利,比如我们需要创造一个函数工厂,这个工厂可以根据我们提供的参数生产出不同的函数。见下面代码
function createDivider(divFactor){
return function(num){
return num/divFactor
}
}
var div9 = createDivider(9);//创造一个可以用来除以9的函数
var div3 = createDivider(3);//除以3的
div9(81);//=>9
_.map([9,18,27],div3);//=>[3,6,9]
既然可以访问函数内部变量,那么自然也可以访问this咯,可是this是会随着调用对象不同而变化的,我们可以通过其他名字来保存this
function captureThis(NAME){
this.name = NAME;
var that = this;
return function(){
return that.name;
}
}
var getThis = captureThis("小花");
getThis.call({});
//=>小花
可以看到,虽然我们重新把getThis绑定到其他地方去了,还是能够得到我们的“小花”。如果我们再一次利用captureThis()
函数来创建一个新的函数,绑定新的值不会影响到原来的“小花”
var getHong = captureThis("小红");
getHong.call({});
//=>小红
刚刚我们讨论的都是内部变量和外部变量名字不同的情况,如果相同会出现什么现象呢?继续往下看吧
var name = "大黄";
function captureName(name){
return function(){
return name;
}
}
var getName = captureName("阿狗");
getName();//?
会领养到阿狗还是大黄呢?其实这个还算简单,返回的闭包就是返回原来的作用域链,首先访问到的当然是最近的name,因此正确答案是“阿狗”(直接拷贝代码到console就可以测试)
再来看下面的例子
function captureName(name){
return function(name){
return name;
}
}
var getName = captureName("阿黄");
getName("大狗");//=>?
这一次其实也差不多,相同的变量同时存在于外包函数参数和内部匿名函数的参数中,我们还是按照就近原则,最近的当然是内部匿名函数的参数,因此这次拿到的是“大狗”。
注意,只要拿到了闭包的返回函数,即便是修改原来外部的函数也不会对现有接收到的返回函数造成影响。比如说把captureName改为null,那么照样可以使用getName。
不过下面的代码可能让你有些困惑
function showObj(obj){
return function(){
return obj
}
}
var a = 10;
var showA = showObj(a);
showA();//=>10;
a=20;
showA();//=>10;
var b = {name:"daming"}
var showB = showObj(b);
showB();//{name:"daming"}
b.age =12;
showB();//{name:"daming",age:12}
b=null;
showB();//{name:"daming",age:12}
是不是觉得有点晕,我也有点晕。书上是说,“由于引用对象同时存在于闭包内部和闭包外部,它的变化可以跨越看似私有的界限,很容易导致混乱,所以通常都尽量减少暴露捕获变量的风险,把捕获的对象作为私有数据。”
var pingpong = (function(){
var private=0;
return{
inc:function(n){
return private+=n;
},
dec:function(n){
return private-=n;
}
}
})();
pingpong.inc(3)//=>3
这样对象是很安全的,甚至可以禁止往闭包里添加函数!
pingpong.showP = function(){return PRIVATE;}
pingpong.showP();//notdefined
总结:灵活利用this以及闭包是实现函数式编程的基础,而正如我们看到的,函数式编程是一种安全而优美的编程方式~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。