摘要:函數(shù)的調(diào)用者是異步函數(shù),不會為回調(diào)函數(shù)指定值。值為表示在全局對象下執(zhí)行該函數(shù)執(zhí)行方法,返回一個函數(shù)作為回調(diào)函數(shù),并且將需要向它傳遞的作為參數(shù)。
重要
函數(shù)中的thisJavaScript的this是有函數(shù)求值是的調(diào)用者決定的
JavaScript的this是有函數(shù)求值是的調(diào)用者決定的
JavaScript的this是有函數(shù)求值是的調(diào)用者決定的
函數(shù)中的this在調(diào)用時才有意義,函數(shù)的調(diào)用者決定函數(shù)中this的指向,每個函數(shù)調(diào)用時都會有this屬性。
function Point2D(x, y) { this.x = x; this.y = y; } Point2D.prototype.showLength = function() { var length = Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); console.log(length); }; Point2D.prototype.showLengthAsync = function() { var self = this; // 將this的值保存下來,傳入異步函數(shù) setTimeout(function() { // setTimeout是異步函數(shù),在調(diào)用回調(diào)函數(shù)時沒有指定匿名函數(shù)的this, self.showLength(); //因為回調(diào)函數(shù)沒有指定this,非嚴格模式下默認指向全局對象 }, 1000); }; var x = 30, y = 40; var p = new Point2D(3, 4); var f = Point2D.prototype.showLength;
1.f():輸出50,因為函數(shù)Point2D.prototype.showLength的調(diào)用者是變量f,變量f、x、y、Ponit2D函數(shù)在同一個對象中。
所以函數(shù)Point2D.prototype.showLength中this指向的是包含變量f、x、y、Ponit2D函數(shù)的對象。
this.x = 30,this.y = 40,所以f()是輸出50;
Point2D.prototype.showLength = function() { var length = Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); console.log(length); };
2.setTimeout(p.showLength, 500); :延時500ms后輸出50。函數(shù)p.showLength的調(diào)用者是異步函數(shù)setTimeout,setTimeout不會為回調(diào)函數(shù)指定this值。
在非嚴格模式下,p.showLength中的this默認指向全局變量
this.x = 30,this.y = 40,所以setTimeout(p.showLength, 500)延時500ms后輸出50;
借用bind()方法可以將函數(shù)綁定到對象上,即將函數(shù)內(nèi)的this指向bind(p)方法中傳入的p對象
setTimeout(p.showLength.bind(p), 500); // 延時500ms后輸出5,因為函數(shù)p.showLength指向?qū)ο髉,p的x屬性為3,y屬性為4
3.p.showLengthAsync();: 延時1000ms后輸出5。
Point2D.prototype.showLengthAsync = function() { var self = this; // 將this的值保存下來,傳入異步函數(shù) setTimeout(function() { // setTimeout是異步函數(shù),在調(diào)用回調(diào)函數(shù)時沒有指定匿名函數(shù)的this, self.showLength(); //因為回調(diào)函數(shù)沒有指定this,非嚴格模式下默認指向全局對象 }, 1000); };
p.showLengthAsync函數(shù)的調(diào)用者是p對象本身,由于setTimeout不會為回調(diào)函數(shù)指定this值。所以在p.showLengthAsync函數(shù)中使用變量self將p.showLengthAsync函數(shù)調(diào)用的this值(即對象p)保存下來
回調(diào)函數(shù)中才可以利用變量self訪問到對象p,完成正確調(diào)用;
4.箭頭函數(shù)
箭頭函數(shù)很特殊,箭頭函數(shù)中沒有定義this,所以可以使用外層函數(shù)的this。
Point2D.prototype.showLengthAsync = function() { setTimeout( () => this.showLength(), 1000); // 箭頭函數(shù)沒有定義this,可以訪問外層函數(shù)的this };call()
函數(shù)的call()方法可以指定函數(shù)調(diào)用時的this值。函數(shù)中調(diào)用時的this值是可以改變的
并且,call()方法可以從第二個參數(shù)開始,指定傳入調(diào)用函數(shù)的參數(shù),以逗號分隔(多個原始形式的參數(shù))
function Point2D(x, y) { this.x = x; this.y = y; } Point2D.prototype.showLength = function() { var length = Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); console.log(length); }; var p = new Point2D(1, 1); console.log(p.showLength()); // ==> 1.4142... 調(diào)用p.length方法的是p對象本身,所以this.x和this.y均等于1 var obj = {x: 3, y: 4}; console.log(p.showLength.call(obj)); // ==> 5 使用函數(shù)p.showLength的call()方法改變函數(shù)調(diào)用時this的指向, //使其指向?qū)ο髈bj,所以this.x=3,this.y=4 function foo() { // 使用Array.prototype.slice函數(shù)的call()方法指定函數(shù)調(diào)用時的this指向arguments對象,將其切分為數(shù)組 var args = Array.prototype.slice.call(arguments); console.log(Array.isArray(arguments)); // false console.log(Array.isArray(args)); // true }
apply()call()的作用:改變當前函數(shù)調(diào)用時的this值
函數(shù)的apply()方法與call()方法作用完全一致,只是在調(diào)用時傳入的參數(shù)有區(qū)別:
call()方法:第一個參數(shù)接收新的this值,后面的參數(shù)逗號分隔,逐個排列,傳入調(diào)用函數(shù)中
apply()方法:第一個參數(shù)接收新的this值,第二個參數(shù)接收一個數(shù)組,將數(shù)組整體作為參數(shù)傳入調(diào)用函數(shù)中
// 定義一個函數(shù),實現(xiàn)一種變換,將傳入其中的函數(shù)中參數(shù)的順序顛倒 function __reverseArgs__(fn) { return function() { var args = Array.prototype.slice.call(arguments); return fn.apply(this, args.reverse()); // 這里的this表示這個匿名函數(shù)的調(diào)用者 }; } var foo = function() {console.log(Array.from(arguments));}; var foo2 = __reverseArgs__(foo); foo2(1, 2, 3, 4);
注意return fn.apply(this, args.reverse());中的this。因為__reverseArgs__(fn)函數(shù)返回一個新的函數(shù),apply()中的this指向調(diào)用這個新函數(shù)的對象。
foo2接收了__reverseArgs__(foo)返回的新函數(shù),調(diào)用foo2(1, 2, 3, 4)時,因為foo2在全局對象下,所以this的值是全局對象。
__reverseArgs__(fn)方法應(yīng)該只改變傳入函數(shù)中參數(shù)的順序,不改變原來函數(shù)調(diào)用的作用域。所以使用this將函數(shù)的調(diào)用改回傳入函數(shù)的作用域。
bind()bind()方法與call()和apply()方法的最大區(qū)別在于返回值:call()和apply()都會立即執(zhí)行,返回結(jié)果;而bind()方法會返回一個函數(shù),并且可以通過bind()向函數(shù)中傳遞已經(jīng)確定的參數(shù),對于異步調(diào)用很有幫助。
function add(x, y) { return x + y; } // call()和apply()會立即執(zhí)行;bind()方法會返回一個函數(shù)對象 console.log(add.call(null, 1, 2)); // ==> 3 ,使用call()方法在全局對象下對傳入的參數(shù)1,2執(zhí)行函數(shù) console.log(add.apply(null, [1, 2])); // ==> 3 apply()方法在全局對象下對傳入的參數(shù)1,2執(zhí)行函數(shù) console.log(add.bind(null, 1, 2)); // ==> function () { [native code] }, 返回一個函數(shù) // 傳入兩個參數(shù) let add1 = add.bind(null, 1, 2); // bind()方法執(zhí)行時,將1和2對應(yīng)傳遞給x,y,返回一個函數(shù)。再調(diào)用返回的函數(shù)時,不用再傳遞參數(shù) console.log(add1()); // ==> 3 為傳遞參數(shù),直接調(diào)用,使用bind()時傳入的參數(shù)值 // 傳入一個參數(shù) let add2 = add.bind(null, 1); //bind()時只傳遞一個參數(shù)1給x,返回一個函數(shù),在調(diào)用返回函數(shù)時只需炫迪一個參數(shù)給y即可 console.log(add2(3)); // ==> 4 只需傳遞一個參數(shù)給y即可 // 不傳遞參數(shù) let add3 = add.bind(null); //調(diào)用bind()時不傳遞參數(shù),返回一個函數(shù),在調(diào)用返回函數(shù)時要傳遞2個參數(shù) console.log(add3(2, 3)); // ==> 5 需要傳遞兩個參數(shù),與調(diào)用原函數(shù)沒有區(qū)別。。。不建議使用
可以看出bind()的最大用處在于返回一個函數(shù),并且可以向函數(shù)內(nèi)傳遞確定的參數(shù)值(在bind()執(zhí)行時時便已經(jīng)確定的參數(shù))。調(diào)用返回的函數(shù)時,無需再傳入bind()時傳入的參數(shù)---實現(xiàn)函數(shù)的部分調(diào)用
應(yīng)用場景:類似于setTimeout(fn, 1000);的異步函數(shù),需要一個函數(shù)作為參數(shù),在1s后執(zhí)行。有時對于已經(jīng)知道fn調(diào)用時傳入的參數(shù)值時,便可以使用bind(),先將參數(shù)傳遞進去,返回一個函數(shù);等待時間到后,無需再向該函數(shù)傳入?yún)?shù),立即執(zhí)行即可
function setBodyState(state) { document.body.className = state; } setBodyState.call(null, "state1"); // 立即執(zhí)行setBodyState函數(shù),將document.body.className設(shè)置為"state1"。 // this值為null表示在全局對象下執(zhí)行該函數(shù) setTimeout(setBodyState.bind(null, "state2"), 1500); // 執(zhí)行bind()方法,返回一個函數(shù)作為回調(diào)函數(shù),并且將需要向它傳遞 //的"state2"作為參數(shù)。1500ms后立即執(zhí)行返回的函數(shù)即可,無需再傳入?yún)?shù)
bind()方法在異步函數(shù)中的應(yīng)用,主要由于其返回一個函數(shù),并且可以傳入?yún)?shù)值的特性,可以減少異步函數(shù)調(diào)用的部分問題。
高階函數(shù)實例 Closure中訪問外部函數(shù)的arguments、this、形參和局部變量// __multi__()抽象一個過程,將傳入的函數(shù)進行擴展,使其第一個參數(shù)接收類數(shù)組 // 調(diào)用原來的方法fn對每個第一個數(shù)組參數(shù)中的每個元素執(zhí)行fn方法 function __multi__(fn) { return function(arrayLike, ...args) { return Array.from(arrayLike).map(item => fn(item, ...args)); }; } function __multi__(fn) { return function(arrayLike, ...args) { // 返回一個函數(shù)(創(chuàng)建一個Closure),返回的函數(shù)接收夜歌類數(shù)組對象和rest參數(shù)作為參數(shù) return Array.from(arrayLike).map(function(value) { return fn(value, ...args); }); }; } function add(x, y) { return x + y;} var add2 = __multi__(add); console.log(add2([1,2,3], 4)); // ==> [5, 6, 7]
1.注意map()方法如果需要返回值,一定要在傳入map()的函數(shù)中返回值,因為默認的返回值是undefined`
2.Closure中對于外層函數(shù)的局部變量、形參、實參對象arguments和this的訪問問題:
__multi__()返回一個函數(shù)(創(chuàng)建一個Closure),返回的函數(shù)保留對外層函數(shù)作用域的訪問能力
但this值和實參對象arguments是根據(jù)調(diào)用函數(shù)時確定的,如果要在Closure中訪問到調(diào)用時的this和arguments對象,需要將其保存在外部函數(shù)局部作用域的變量中。
function __multi__(fn) { var self = this; var outerArgs = arguments; return function(arrayLike, ...args) { return Array.from(arrayLike).map(function(value) { console.log(self); // 可以訪問到外層函數(shù)的調(diào)用者 console.log(outerArgs); //可以訪問到外層函數(shù)的實參列表,相當于訪問外層函數(shù)的局部變量 console.log(this); // 訪問到的this值是返回函數(shù)的調(diào)用者 console.log(arguments); // 訪問到的arguments是傳入返回函數(shù)的實參 return fn(value, ...args); // 可以訪問到外部函數(shù)的形參 }); }; }
Closure中可以訪問到外部函數(shù)的形參(形參的特性與局部變量相同)
function __multi__(fn, a = 2) { console.log(arguments[0]); return function(arrayLike, ...args) { return Array.from(arrayLike).map(function(value) { console.log(a); // 可以訪問到外層函數(shù)的形參a return fn(value, ...args); // 可以訪問到外部函數(shù)的形參fn }); }; }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/82074.html
摘要:所以相同點是,在全局范圍內(nèi),全局變量終究是屬于老大的。只生效一次引入了。只生效一次在箭頭函數(shù)中,與封閉詞法環(huán)境的保持一致。我通常把這些原始函數(shù)叫做構(gòu)造函數(shù)。在里面你可以嵌套函數(shù),也就是你可以在函數(shù)里面定義函數(shù)。 showImg(https://img-blog.csdnimg.cn/20190522000008399.jpg?x-oss-process=image/watermark,...
摘要:關(guān)鍵字計算為當前執(zhí)行上下文的屬性的值。毫無疑問它將指向了這個前置的對象。構(gòu)造函數(shù)也是同理。嚴格模式無論調(diào)用位置,只取顯式給定的上下文綁定的,通過方法傳入的第一參數(shù),否則是。其實并不屬于特殊規(guī)則,是由于各種事件監(jiān)聽定義方式本身造成的。 this 是 JavaScript 中非常重要且使用最廣的一個關(guān)鍵字,它的值指向了一個對象的引用。這個引用的結(jié)果非常容易引起開發(fā)者的誤判,所以必須對這個關(guān)...
摘要:箭頭函數(shù)沒有自己的值,箭頭函數(shù)中所使用的來自于函數(shù)作用域鏈。使用箭頭函數(shù)打印對于內(nèi)層函數(shù),它本身并沒有值,其使用的來自作用域鏈,來自更高層函數(shù)的作用域。 《JavaScript 深入淺出》系列: JavaScript 深入淺出第 1 課:箭頭函數(shù)中的 this 究竟是什么鬼? JavaScript 深入淺出第 2 課:函數(shù)是一等公民是什么意思呢? 普通函數(shù)與箭頭函數(shù) 普通函數(shù)指的是...
摘要:想想也是難以置信,這應(yīng)該全歸功于對框架的依賴,促使助長了自己對學(xué)習(xí)的懈怠。真正的成了離職就失業(yè)的尷尬境地。我們接下來來了解下中的的使用和作用。以前對中的理解很簡單粗暴誰調(diào)用就指向誰。如果例題中有不對的地方希望予以指教留言評論 前言 使用JavaScript有很長一段時間了,但是以前過多都是使用,從不去及理解其中原理,單單只是去生拼硬湊。這樣的開發(fā)居然做了2年。匪夷所思居然項目中Java...
摘要:原文鏈接參考深入理解原型和閉包完結(jié)王福朋博客園中的作用域詳解博客園 前言 王福朋老師的 JavaScript原型和閉包系列 文章看了不下三遍了,最為一個初學(xué)者,每次看的時候都會有一種 大徹大悟 的感覺,而看完之后卻總是一臉懵逼。原型與閉包 可以說是 JavaScirpt 中理解起來最難的部分了,當然,我也只是了解到了一些皮毛,對于 JavaScript OOP 更是缺乏經(jīng)驗。這里我想總...
摘要:注意該方法的作用和方法類似,只有一個區(qū)別,就是方法接受的是若干個參數(shù)的列表,而方法接受的是一個包含多個參數(shù)的數(shù)組。指定的參數(shù)列表。返回值返回值是你調(diào)用的方法的返回值,若該方法沒有返回值,則返回。 溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命溫馨提示-續(xù):打call原本是屬于我們偶像宅文化中的專業(yè)名詞,指的是飯們在看live時在臺下配合愛豆演出的節(jié)奏喊口號,舉例:超...
閱讀 2701·2021-09-22 15:58
閱讀 2240·2019-08-29 16:06
閱讀 912·2019-08-29 14:14
閱讀 2815·2019-08-29 13:48
閱讀 2461·2019-08-28 18:01
閱讀 1509·2019-08-28 17:52
閱讀 3331·2019-08-26 14:05
閱讀 1626·2019-08-26 13:50