摘要:獲取返回的匿名函數(shù)這個(gè)匿名函數(shù)會(huì)保留原本的作用域鏈有意思的是函數(shù)參數(shù)也是可以被我們捕獲到的這就給我們靈活的創(chuàng)造一些函數(shù)提供了便利,比如我們需要?jiǎng)?chuàng)造一個(gè)函數(shù)工廠,這個(gè)工廠可以根據(jù)我們提供的參數(shù)生產(chǎn)出不同的函數(shù)。
關(guān)于this的討論本文是在看《Javascript函數(shù)式》編程一書寫下的一些記錄。和大家分享。不足之處還望大家指正。
首先來看這么幾段代碼
function globalThis(){return this;} globalThis(); //=>window or global object globalThis.call("haha"); //=>"haha" globalThis.apply("abc",[]); //=>"abc
可以看到,this的一般就是由調(diào)用他的對(duì)象決定的,如果進(jìn)行綁定了的話,相當(dāng)于說這個(gè)函數(shù)的調(diào)用對(duì)象只能夠是你綁定的那個(gè)對(duì)象,是不能夠更改的。
var bindThis = globalThis.bind("abc") bindThis(); //=>"abc" bindThis.call("x") //=>"abc" bindThis.apply("y",[]); //=>"abc
當(dāng)然,如果我看到這本書推薦大家使用underscore庫。用法如下
_.bind(globalThis,"abc")
這樣的操作也是可以的。如果說有很多個(gè)函數(shù)都需要綁定到同一個(gè)對(duì)象上去怎么辦呢?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");函數(shù)的閉包
相信大家都或多或少踩過閉包這個(gè)坑吧,確實(shí)一開始接觸感覺很不能理解。我個(gè)人粗淺理解是閉包是一個(gè)函數(shù)執(zhí)行過后返回一個(gè)內(nèi)部函數(shù),這個(gè)內(nèi)部函數(shù)將保留包含這個(gè)內(nèi)部函數(shù)的函數(shù)的作用域鏈。也就是里面把外面包住了,簡稱閉包2333。
function captureOut(){ var a = 123; return function(){ console.log("a:"+a); } } var getA = captureOut();//獲取captureOut返回的匿名函數(shù) getA();//這個(gè)匿名函數(shù)會(huì)保留原本的作用域鏈 //=>a:123
有意思的是函數(shù)參數(shù)也是可以被我們捕獲到的
function capturePara(PARA){ return function(){ console.log(PARA); } } var getP = capturePara("I"m the parameters"); getP();//I"m the parameters
這就給我們靈活的創(chuàng)造一些函數(shù)提供了便利,比如我們需要?jiǎng)?chuàng)造一個(gè)函數(shù)工廠,這個(gè)工廠可以根據(jù)我們提供的參數(shù)生產(chǎn)出不同的函數(shù)。見下面代碼
function createDivider(divFactor){ return function(num){ return num/divFactor } } var div9 = createDivider(9);//創(chuàng)造一個(gè)可以用來除以9的函數(shù) var div3 = createDivider(3);//除以3的 div9(81);//=>9 _.map([9,18,27],div3);//=>[3,6,9]
既然可以訪問函數(shù)內(nèi)部變量,那么自然也可以訪問this咯,可是this是會(huì)隨著調(diào)用對(duì)象不同而變化的,我們可以通過其他名字來保存this
function captureThis(NAME){ this.name = NAME; var that = this; return function(){ return that.name; } } var getThis = captureThis("小花"); getThis.call({}); //=>小花
可以看到,雖然我們重新把getThis綁定到其他地方去了,還是能夠得到我們的“小花”。如果我們?cè)僖淮卫?b>captureThis()函數(shù)來創(chuàng)建一個(gè)新的函數(shù),綁定新的值不會(huì)影響到原來的“小花”
var getHong = captureThis("小紅"); getHong.call({}); //=>小紅
剛剛我們討論的都是內(nèi)部變量和外部變量名字不同的情況,如果相同會(huì)出現(xiàn)什么現(xiàn)象呢?繼續(xù)往下看吧
var name = "大黃"; function captureName(name){ return function(){ return name; } } var getName = captureName("阿狗"); getName();//?
會(huì)領(lǐng)養(yǎng)到阿狗還是大黃呢?其實(shí)這個(gè)還算簡單,返回的閉包就是返回原來的作用域鏈,首先訪問到的當(dāng)然是最近的name,因此正確答案是“阿狗”(直接拷貝代碼到console就可以測試)
再來看下面的例子
function captureName(name){ return function(name){ return name; } } var getName = captureName("阿黃"); getName("大狗");//=>?
這一次其實(shí)也差不多,相同的變量同時(shí)存在于外包函數(shù)參數(shù)和內(nèi)部匿名函數(shù)的參數(shù)中,我們還是按照就近原則,最近的當(dāng)然是內(nèi)部匿名函數(shù)的參數(shù),因此這次拿到的是“大狗”。
注意,只要拿到了閉包的返回函數(shù),即便是修改原來外部的函數(shù)也不會(huì)對(duì)現(xiàn)有接收到的返回函數(shù)造成影響。比如說把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}
是不是覺得有點(diǎn)暈,我也有點(diǎn)暈。書上是說,“由于引用對(duì)象同時(shí)存在于閉包內(nèi)部和閉包外部,它的變化可以跨越看似私有的界限,很容易導(dǎo)致混亂,所以通常都盡量減少暴露捕獲變量的風(fēng)險(xiǎn),把捕獲的對(duì)象作為私有數(shù)據(jù)。”
var pingpong = (function(){ var private=0; return{ inc:function(n){ return private+=n; }, dec:function(n){ return private-=n; } } })(); pingpong.inc(3)//=>3
這樣對(duì)象是很安全的,甚至可以禁止往閉包里添加函數(shù)!
pingpong.showP = function(){return PRIVATE;} pingpong.showP();//notdefined
總結(jié):靈活利用this以及閉包是實(shí)現(xiàn)函數(shù)式編程的基礎(chǔ),而正如我們看到的,函數(shù)式編程是一種安全而優(yōu)美的編程方式~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/87968.html
摘要:作用域作用域是指程序源代碼中定義變量的區(qū)域。采用詞法作用域,也就是靜態(tài)作用域。而與詞法作用域相對(duì)的是動(dòng)態(tài)作用域,函數(shù)的作用域是在函數(shù)調(diào)用的時(shí)候才決定的。前面我們已經(jīng)說了,采用的是靜態(tài)作用域,所以這個(gè)例子的結(jié)果是。 JavaScript深入系列的第二篇,JavaScript采用詞法作用域,什么語言采用了動(dòng)態(tài)作用域?兩者的區(qū)別又是什么?還有一個(gè)略難的思考題,快來看看吧。 作用域 作用域是指...
摘要:在中的應(yīng)用采用詞法作用域,也就是靜態(tài)作用域。那什么又是詞法作用域或者靜態(tài)作用域呢請(qǐng)繼續(xù)往下看靜態(tài)作用域與動(dòng)態(tài)作用域因?yàn)椴捎玫氖窃~法作用域函數(shù)的作用域在函數(shù)定義的時(shí)候就決定了。 開篇 當(dāng)我們?cè)陂_始學(xué)習(xí)任何一門語言的時(shí)候,都會(huì)接觸到變量的概念,變量的出現(xiàn)其實(shí)是為了解決一個(gè)問題,為的是存儲(chǔ)某些值,進(jìn)而,存儲(chǔ)某些值的目的是為了在之后對(duì)這個(gè)值進(jìn)行訪問或者修改,正是這種存儲(chǔ)和訪問變量的能力將狀態(tài)給...
摘要:靜態(tài)作用域指的是一段代碼,在它執(zhí)行之前就已經(jīng)確定了它的作用域,簡單來說就是在執(zhí)行之前就確定了它可以應(yīng)用哪些地方的作用域變量。 靜態(tài)作用域指的是一段代碼,在它執(zhí)行之前就已經(jīng)確定了它的作用域,簡單來說就是在執(zhí)行之前就確定了它可以應(yīng)用哪些地方的作用域(變量)。 動(dòng)態(tài)作用域–函數(shù)的作用域是在函數(shù)調(diào)用的時(shí)候才決定的 JavaScript采用的是詞法作用域即靜態(tài)作用域; // 靜態(tài)作用域: va...
摘要:中作用域的問題可以說是老生常談,個(gè)人認(rèn)為的作用域中存在著兩種作用域,一種是詞法作用域,一種是動(dòng)態(tài)作用域。但是自動(dòng)有了箭頭函數(shù)后,箭頭函數(shù)中的并不是動(dòng)態(tài)作用域,而是屬于詞法作用域,再其定義時(shí)就已經(jīng)確定好了,相當(dāng)于。 js中作用域的問題可以說是老生常談,個(gè)人認(rèn)為js的作用域中存在著兩種作用域,一種是詞法作用域,一種是動(dòng)態(tài)作用域。 詞法作用域 詞法作用域就是定義在詞法階段的作用域,也就是說由...
摘要:原文原文原文詞法作用域作用域有兩種常見的模型,一種叫做詞法作用域,一種叫做動(dòng)態(tài)作用域。其中詞法作用域更常見,被大多數(shù)語言采用,包括。值得注意的是,一個(gè)函數(shù)作用域只有可能存在于一個(gè)父級(jí)作用域中,不會(huì)同時(shí)存在兩個(gè)父級(jí)作用域。 原文: 原文1 | 原文2 Lexical Scope - 詞法作用域 作用域有兩種常見的模型,一種叫做 詞法作用域 Lexical Scope,一種叫做...
摘要:而閉包的神奇之處正是可以阻止事情的發(fā)生。拜所聲明的位置所賜,它擁有涵蓋內(nèi)部作用域的閉包,使得該作用域能夠一直存活,以供在之后任何時(shí)間進(jìn)行引用。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫閉包。 引子 先看一個(gè)問題,下面兩個(gè)代碼片段會(huì)輸出什么? // Snippet 1 a = 2; var a; console.log(a); // Snippet 2 console.log(a); v...
閱讀 1419·2021-09-22 15:52
閱讀 1459·2019-08-30 15:44
閱讀 895·2019-08-30 14:24
閱讀 2705·2019-08-30 13:06
閱讀 2700·2019-08-26 13:45
閱讀 2782·2019-08-26 13:43
閱讀 1015·2019-08-26 12:01
閱讀 1436·2019-08-26 11:56