资讯专栏INFORMATION COLUMN

Javascript动态作用域

DC_er / 2499人阅读

摘要:获取返回的匿名函数这个匿名函数会保留原本的作用域链有意思的是函数参数也是可以被我们捕获到的这就给我们灵活的创造一些函数提供了便利,比如我们需要创造一个函数工厂,这个工厂可以根据我们提供的参数生产出不同的函数。

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87968.html

相关文章

  • JavaScript深入之词法作用动态作用

    摘要:作用域作用域是指程序源代码中定义变量的区域。采用词法作用域,也就是静态作用域。而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的。前面我们已经说了,采用的是静态作用域,所以这个例子的结果是。 JavaScript深入系列的第二篇,JavaScript采用词法作用域,什么语言采用了动态作用域?两者的区别又是什么?还有一个略难的思考题,快来看看吧。 作用域 作用域是指...

    gclove 评论0 收藏0
  • 深入学习js之——词法作用动态作用

    摘要:在中的应用采用词法作用域,也就是静态作用域。那什么又是词法作用域或者静态作用域呢请继续往下看静态作用域与动态作用域因为采用的是词法作用域函数的作用域在函数定义的时候就决定了。 开篇 当我们在开始学习任何一门语言的时候,都会接触到变量的概念,变量的出现其实是为了解决一个问题,为的是存储某些值,进而,存储某些值的目的是为了在之后对这个值进行访问或者修改,正是这种存储和访问变量的能力将状态给...

    shiweifu 评论0 收藏0
  • javascript静态作用动态作用

    摘要:静态作用域指的是一段代码,在它执行之前就已经确定了它的作用域,简单来说就是在执行之前就确定了它可以应用哪些地方的作用域变量。 静态作用域指的是一段代码,在它执行之前就已经确定了它的作用域,简单来说就是在执行之前就确定了它可以应用哪些地方的作用域(变量)。 动态作用域–函数的作用域是在函数调用的时候才决定的 JavaScript采用的是词法作用域即静态作用域; // 静态作用域: va...

    jimhs 评论0 收藏0
  • javascript中的作用(词法and动态)

    摘要:中作用域的问题可以说是老生常谈,个人认为的作用域中存在着两种作用域,一种是词法作用域,一种是动态作用域。但是自动有了箭头函数后,箭头函数中的并不是动态作用域,而是属于词法作用域,再其定义时就已经确定好了,相当于。 js中作用域的问题可以说是老生常谈,个人认为js的作用域中存在着两种作用域,一种是词法作用域,一种是动态作用域。 词法作用域 词法作用域就是定义在词法阶段的作用域,也就是说由...

    Taonce 评论0 收藏0
  • You-Dont-Know-JS - 词法作用

    摘要:原文原文原文词法作用域作用域有两种常见的模型,一种叫做词法作用域,一种叫做动态作用域。其中词法作用域更常见,被大多数语言采用,包括。值得注意的是,一个函数作用域只有可能存在于一个父级作用域中,不会同时存在两个父级作用域。 原文: 原文1 | 原文2 Lexical Scope - 词法作用域 作用域有两种常见的模型,一种叫做 词法作用域 Lexical Scope,一种叫做...

    bang590 评论0 收藏0
  • 先有蛋还是先有鸡?JavaScript 作用与闭包探析

    摘要:而闭包的神奇之处正是可以阻止事情的发生。拜所声明的位置所赐,它拥有涵盖内部作用域的闭包,使得该作用域能够一直存活,以供在之后任何时间进行引用。依然持有对该作用域的引用,而这个引用就叫闭包。 引子 先看一个问题,下面两个代码片段会输出什么? // Snippet 1 a = 2; var a; console.log(a); // Snippet 2 console.log(a); v...

    elisa.yang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<