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