Javascript动态做用域

本文是在看《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库。用法以下app

_.bind(globalThis,'abc')

这样的操做也是能够的。若是说有不少个函数都须要绑定到同一个对象上去怎么办呢?underscore提供了bindAll(obj,methondName)ide

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是会随着调用对象不一样而变化的,咱们能够经过其余名字来保存thisthis

function captureThis(NAME){
    this.name = NAME;
    var that = this;
    return function(){
        return that.name;
    }
}
var getThis = captureThis("小花");
getThis.call({});
//=>小花

能够看到,虽然咱们从新把getThis绑定到其余地方去了,仍是可以获得咱们的“小花”。若是咱们再一次利用captureThis()函数来建立一个新的函数,绑定新的值不会影响到原来的“小花”code

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以及闭包是实现函数式编程的基础,而正如咱们看到的,函数式编程是一种安全而优美的编程方式~

相关文章
相关标签/搜索