你疏漏的 JS 函數硬核知識?這里幫你總結了

重點

更多前端知識 誠邀各位前端從事者愛好者加入前端大佬技術交流社區,本社區主要分享技術棧、個人心得、技術交流、問題解惑等前端體系交流

點擊下方文字加入

前端大佬技術交流社區

1. 函數的定義和調用

1.1 函數的定義方式

  1. 方式1 函數聲明方式 function 關鍵字 (命名函數)

    function f1() {console.log('命名函數')
    }
    
  2. 方式2 函數表達式(匿名函數)

    var f2 = function () {console.log('匿名函數')
    }
    
  3. 方式3 new Function()

    /*參數1:函數形參參數2:函數形參參數3:函數體*/
    var f3 = new Function('m', 'n', 'console.log(m-n)')
    // 傳入實參
    f3(4,2)

注意

  • Function 里面參數都必須是字符串格式
  • 第三種方式執行效率低,也不方便書寫,因此較少使用

1.2 函數的調用

 // 普通函數:命名函數和匿名函數
function f1() {console.log('人生何處不相逢');
}
var f2 = function () {console.log('寒江孤影,江湖故人,相逢何必曾相識');
}
// 對象中的函數,專業點叫做方法,通過 對象.方法 方式調用
var Person = {speak: function () {console.log('人生處處是歌聲');}
}
// 構造函數:通過 new 關鍵字調用
function Star() { }
new Star()
// 事件處理函數:事件觸發時被調用
element.onclick = function () { }
// 定時器函數:由定時器選擇時機調用
setInterval(function () { }, 1000)
// 立即執行函數:立即調用
(function () {console.log('first off')
}())

2.this

2.1函數內部的this指向

這些 this 的指向,是當我們調用函數的時候確定的。調用方式的不同決定了this 的指向不同

一般指向我們的調用者.

在這里插入圖片描述

2.2改變函數內部 this 指向

2.2.1 call方法

call()方法調用一個對象。簡單理解為調用函數的方式,但是它可以改變函數的 this 指向

應用場景: 經常做繼承.

var o = {name: 'andy'
}function fn(a, b) {console.log(this);console.log(a+b)
};
fn(1,2)// 此時的this指向的是window 運行結果為3
fn.call(o,1,2)//此時的this指向的是對象o,參數使用逗號隔開,運行結果為3

以上代碼運行結果為:

在這里插入圖片描述

復習使用this實現繼承

2.2.2 apply方法

apply 方法的用于與call 非常類似,區別在于,不能以參數列表的形式傳遞實參,必須以數組的形式傳遞

         var o = {name: 'andy'}function fn(a, b) {console.log(this);console.log(a + b)};// 普通調用fn(1, 2)// call調用,將函數中的this修改為o對象fn.call(o, 1, 2)// apply 調用,區別在于參數列表必須以數組形式傳遞fn.apply(o,[1,2])

可以看到,我們傳入函數的實參是數組,但是函數內部會自動展開為參數列表

利用這一特性,我們可以結合 Math.max 方法求數組的最大值或者最小值

Math.max 方法可以求一組數字的最大值,語法如下

Math.max(1,2,3,4,5)

參數為參數列表形式

利用apply 可以將數組傳入

var numbers = [3, 2, 44, 11, 66, 7]
var max=Math.max.apply(null,numbers)
console.log(max);

也可以利用 ES6 的 Spread syntax 語法

var max=Math.max(...numbers)

2.2.3 bind方法

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

bind() 方法不會調用函數,但是能改變函數內部this 指向

如果只是想改變 this 指向,并且不想調用這個函數的時候,可以使用bind

應用場景:不調用函數,但是還想改變this指向

 var o = {name: 'andy'};function fn(a, b) {console.log(this);console.log(a + b);
};
var f = fn.bind(o, 1, 2); //此處的f是bind返回的新函數
f();//調用新函數  this指向的是對象o 參數使用逗號隔開

在這里插入圖片描述

解惑

上面的代碼

var f = fn.bind(o, 1, 2)

的作用就是將 fn 函數拷貝了一份,名稱叫做 f,同時將函數 f 中的 this 修改為對象o,所以函數 f 與 fn 的函數體是一樣的,只不過內部 this 的指向不同了

如下代碼,才是調用執行函數 f,而上面的代碼僅僅完成上面的任務,但不會執行函數 fn 也不會執行新函數 f

f()

應用

頁面中有1個div,默認為紅色,鼠標懸浮后,變為藍色,3秒之后恢復成紅色

var div = document.querySelector('div')
div.addEventListener('mouseover', function () {this.style.backgroundColor = 'blue'setTimeout(function () {div.style.backgroundColor = 'red'}, 3000);
})

定時器中,this=window,所以不能使用this,必須使用元素名稱div

當然可以使用 var that=this 的方式

但這兩種方式都有問題,如實現下面的效果

當前頁面上有3個div,默認都為紅色,鼠標懸浮到某個div上,顏色變為藍色,3秒后恢復成紅色

 var divs = document.querySelectorAll('div')for (var i = 0; i < divs.length; i++) {divs[i].addEventListener('mouseover', function () {// 這里的this=當前觸發事件的某個具體divthis.style.backgroundColor = 'blue'setTimeout(function () {// 下面的代碼應該怎么寫}, 3000);})
}

定時器中的this=window,所以不能使用window

也不能使用divs[i],因為 i 的索引在事件發生時,并不是你想象中的索引

當然可以使用 that=this 的方式,但會多創建局部變量

可以利用bind方法

在這里插入圖片描述

這里使用bind最合適,因為僅僅是修改了函數中this的指向,并不會馬上執行,3秒之后由系統再次調用

注意:bind 方法會創建一個新函數,所以3秒后調用的是新函數,在新函數中,this=div

問?上面不是需要聲明一個變量接收bind創建的新函數嗎?為什么這里不需要?

同學,請先搞清楚:什么時候需要返回值,什么時候不需要

2.2.4 call、apply、bind三者的異同

  • 共同點 : 都可以改變this指向

  • 不同點:

    • call 和 apply 會調用函數, 并且改變函數內部this指向.
    • call 和 apply傳遞的參數不一樣,call傳遞參數使用逗號隔開,apply使用數組傳遞
    • bind 不會調用函數, 可以改變函數內部this指向.
  • 應用場景

    1. call 經常做繼承.
    2. apply經常跟數組有關系. 比如借助于數學對象實現數組最大值最小值
    3. bind 不調用函數,但是還想改變this指向. 比如改變定時器內部的this指向.

3.嚴格模式

3.1什么是嚴格模式

JavaScript 除了提供正常模式外,還提供了嚴格模式(strict mode)。ES5 的嚴格模式是采用具有限制性 JavaScript變體的一種方式,即在嚴格的條件下運行 JS 代碼。

嚴格模式在 IE10 以上版本的瀏覽器中才會被支持,舊版本瀏覽器中會被忽略。

嚴格模式對正常的 JavaScript 語義做了一些更改:

1.消除了 Javascript 語法的一些不合理、不嚴謹之處,減少了一些怪異行為。

2.消除代碼運行的一些不安全之處,保證代碼運行的安全。

3.提高編譯器效率,增加運行速度。

4.禁用了在 ECMAScript 的未來版本中可能會定義的一些語法,為未來新版本的 Javascript 做好鋪墊。比如一些保留字如:class,enum,export, extends, import, super 不能做變量名

聊聊 TS

3.2開啟嚴格模式

嚴格模式可以應用到整個腳本或個別函數中。因此在使用時,我們可以將嚴格模式分為為腳本開啟嚴格模式和為函數開啟嚴格模式兩種情況。

  • 腳本開啟嚴格模式
  • 函數開啟嚴格模式
 <script>// 在當前腳本中啟用嚴格模式:script開始標記和結束標記之間生效// 'use strict'var name='yhb'age=20function fn(){// 在函數中開啟嚴格模式'use strict'gender='男'}fn()</script>

3.3嚴格模式中的變化

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode

嚴格模式對 Javascript 的語法和行為,都做了一些改變。

'use strict'
num = 10 
console.log(num)//嚴格模式后使用未聲明的變量
--------------------------------------------------------------------------------
var num2 = 1;
delete num2;//嚴格模式不允許刪除變量:刪除變量的目的是希望釋放內存,處理方式一般是將變量的值設置為null
--------------------------------------------------------------------------------
function fn() {console.log(this); // 嚴格模式下全局作用域中函數中的 this 是 undefined
}
fn();  
--------------------------------------------------------------------------------- function Star() {this.gender = '男';
}
// 不加new 調用Star,則this=undefined
console.log(Star().gender)
// 加new 調用Star,則this=對象
console.log(new Star().gender)
----------------------------------------------------------------------------------
setTimeout(function() {console.log(this); //嚴格模式下,定時器 this 還是指向 window
}, 2000);  

另外,嚴格模式下函數的參數名稱應該唯一

// 非嚴格模式下
function f1(m, m) {console.log(m + m)
}
f1(1,2) // 4,分析一下原因為什么事4

嚴格模式下,會報錯

4.高階函數

高階函數是對其他函數進行操作的函數,它接收函數作為參數或將函數作為返回值輸出。

函數作為參數:

在這里插入圖片描述

函數作為返回值

在這里插入圖片描述

函數也是一種數據類型,同樣可以作為參數,傳遞給另外一個參數使用。最典型的就是作為回調函數。

同理函數也可以作為返回值傳遞回來

函數作為參數案例:

function fn(m, n, callback) {console.log(m + n)// 函數主體執行結束后才會執行回調函數callback && callback()
}
fn(3, 4, function () {console.log('我就是回調函數')
})

jquery 中大量應用了回調函數,比如動畫完成后執行某個操作

5.閉包

5.1變量的作用域復習

變量根據作用域的不同分為兩種:全局變量和局部變量。

  1. 函數內部可以使用全局變量。
  2. 函數外部不可以使用局部變量。
  3. 當函數執行完畢,本作用域內的局部變量會銷毀。

5.2什么是閉包

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

在JS中,函數每次創建,都會生成閉包(closure),這個閉包包含函數及其詞法環境(大概類似于執行上下文)

閉包是一種執行機制:內部函數總是可以訪問其所在的外部函數中聲明的變量和參數,即使在其外部函數執行結束之后

/*在一個函數中又嵌套函數,在JS中是沒有問題的1)內部作用域可以訪問外部作用域,所以f2中可以訪問f1中的變量2)在全局作用域內,不訪問函數f1中的變量*/function f1() {var m = 100return function() {console.log(m)}        }var myfunc=f1()// myfunc 是一個變量,引用了f2的地址,myfunc() 就相當于執行了 f2()myfunc()  // f2()// console.log(m)

通過上面案例發現:閉包可以延伸變量的作用范圍。

解惑

一般情況下,下面代碼執行后,外部函數f1就執行完畢了,那么函數內部的成員數據都會被銷毀,包括變量 m,但是因為內部函數f2使用了變量m,而函數f2又被返回給了變量 myfunc,即變量myfuc引用了內部函數f2,此時

f2還沒有執行,所以外部函數f1就不能釋放自己的變量m

 f1()

我們可以將 子函數f2 稱作閉包函數(有爭議)

我們再對閉包做一個總結:函數創建時,形成一個閉包,閉包讓內部函數可以訪問外部函數的變量和參數,并且通過向外返回內部函數,使得在函數外部也可以訪問函數內部的數據

閉包的三個特性

1)函數嵌套函數

2)函數內部可以訪問函數外部的變量和參數

3)外部函數執行完畢后,參數和變量不會被垃圾回收機制回收

5.3閉包的案例

  1. 利用閉包的方式得到當前li 的索引號
for (var i = 0; i < lis.length; i++) {
// 利用for循環創建了4個立即執行函數
// 立即執行函數也成為小閉包因為立即執行函數里面的任何一個函數都可以使用它的i這變量
(function(i) {lis[i].onclick = function() {console.log(i);}})(i);
}	

但是,這種案例使用閉包其實并不是最好的解決方案,因為每次循環都要創建一個函數,而且每個i 的值都會被保存,不能釋放,所以執行效率會低

將i的值存儲于li標簽的自定義屬性中的方式更加可取

代碼 (任務單)

  1. 閉包應用-3秒鐘之后,打印所有li元素的內容

下面代碼遍歷所有li標簽,創建了三個定時器,3秒之后打印每個li標簽元素內容

 for (var i = 0; i < lis.length; i++) {(function(i) {setTimeout(function() {console.log(lis[i].innerHTML);}, 3000)})(i);
}

其實,使用我們前面學習的 bind 方法也是可以的

代碼 (任務單)

  1. 閉包應用-計算打車價格
/*需求分析
打車起步價13(3公里內),  之后每多一公里增加 5塊錢.  用戶輸入公里數就可以計算打車價格
如果有擁堵情況,總價格多收取2塊錢擁堵費*/var car = (function () {var start_price = 13var start_juli = 3var total = 0return {price: function (juli) {if (juli <= start_juli) {total = start_price} else if (juli > 3) {total = start_price + (juli - start_juli) * 5}return total},yondu: function (flag) {return flag ? total + 2 : total}}})()
console.log(car.price(3));
console.log(car.price(10));
console.log(car.yondu(false));
console.log(car.yondu(true));

解惑

1、立即執行函數中的代碼立即執行,不會等待調用,所以 變量 car 引用的是一個對象

2、引用的對象中包含兩個函數 price 和 yongdu,這兩個函數屬于立即執行函數的子函數

3、子函數中引用了外部函數中的變量,所以形成了閉包

4、上面的案例并非非要這么編寫程序,只是為了練習閉包的使用

6.遞歸

6.1什么是遞歸

**遞歸:**如果一個函數在內部可以調用其本身,那么這個函數就是遞歸函數。簡單理解:函數內部自己調用自己, 這個函數就是遞歸函數

**注意:**遞歸函數的作用和循環效果一樣,由于遞歸很容易發生“棧溢出”錯誤(stack overflow),所以必須要加退出條件return。

在這里插入圖片描述

6.2利用遞歸求1~n的階乘

//利用遞歸函數求1~n的階乘 1 * 2 * 3 * 4 * ..nfunction fn(n) {if (n == 1) { //結束條件return 1;}return n * fn(n - 1);}console.log(fn(3));

在這里插入圖片描述

6.3利用遞歸求斐波那契數列

// 利用遞歸函數求斐波那契數列(兔子序列)  1、1、2、3、5、8、13、21...
// 用戶輸入一個數字 n 就可以求出 這個數字對應的兔子序列值
// 我們只需要知道用戶輸入的n 的前面兩項(n-1 n-2)就可以計算出n 對應的序列值
function fb(n) {if (n === 1 || n === 2) {return 1;}return fb(n - 1) + fb(n - 2);
}
console.log(fb(3));

6.4利用遞歸遍歷數據

// 我們想要做輸入id號,就可以返回的數據對象var data = [{id: 1,name: '家電',goods: [{id: 11,gname: '冰箱',goods: [{id: 111,gname: '海爾'}, {id: 112,gname: '美的'},]}, {id: 12,gname: '洗衣機'}]}, {id: 2,name: '服飾'
}];
//1.利用 forEach 去遍歷里面的每一個對象function getID(json, id) {var o = {};json.forEach(function(item) {// console.log(item); // 2個數組元素if (item.id == id) {// console.log(item);o = item;return o;// 2. 我們想要得里層的數據 11 12 可以利用遞歸函數// 里面應該有goods這個數組并且數組的長度不為 0 } else if (item.goods && item.goods.length > 0) {o = getID(item.goods, id);}});return o;
}

重點

更多前端知識 誠邀各位前端從事者愛好者加入前端大佬技術交流社區,本社區主要分享技術棧、個人心得、技術交流、問題解惑等前端體系交流

點擊下方文字加入

前端大佬技術交流社區

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248614.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248614.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248614.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

7 月 1 日

7 月 1 日 今日內容 1.計算機基礎知識 2.python簡介 3.快速入門 昨日回顧 無內容詳細 1.計算機基礎知識 輸入輸出設備 CPU 硬盤 電源 中央處理器 處理各種數據 相當于人的大腦 內存 存儲數據 硬盤 存儲數據的 什么是操作系統 控制計算機工作的流程 軟件 什么是應用程序 安裝在操…

再見了 React、Angular,Vue3 才是 yyds

切記一定要看到最后&#xff01;&#xff01;&#xff01; 最近看到一篇文章上面是一作者資訊一位IT前輩&#xff0c;問他怎么看待工作 2 年的前端開發&#xff0c;月薪就高達 30k、40k 的現狀。 他說&#xff0c;在眾多編程技術中&#xff0c;前端算比較容易入門和提升的&am…

HBase實戰:記一次Safepoint導致長時間STW的踩坑之旅

本文記錄了HBase中Safepoint導致長時間STW此問題的解決思路及辦法。上篇文章回顧&#xff1a;HBase Replication詳解?過 程 記 錄現象&#xff1a;小米有一個比較大的公共離線HBase集群&#xff0c;用戶很多&#xff0c;每天有大量的MapReduce或Spark離線分析任務在進行訪問&a…

scrapy 第一個案例(爬取騰訊招聘職位信息)

import scrapy import jsonclass TzcSpider(scrapy.Spider):# spider的名字&#xff0c;唯一name tzc# 起始地址start_urls [https://hr.tencent.com/position.php?keywordspython&tid0&lid2268]# 每個url爬取之后會調用這個方法def parse(self, response):tr resp…

系統帶你學習 WebAPIs 第一講

Web APIs 本篇學習目標&#xff1a; 能夠通過ID來獲取元素 能夠通過標簽名來獲取元素 能夠通過class來獲取元素 能夠通過選擇器來獲取元素 能夠獲取body和html元素 能夠給元素注冊事件 能夠修改元素的內容 能夠區分innerText和innerHTML的區別 能夠修改像div這類普通元素的屬性…

react-webpack config webpack@3.4.1

1.最重要的一點 yarn add webpack3.4.1 -g 2. 解決跨域請求 webpack.json 中添加 https://segmentfault.com/q/1010000008190876?_ea1579884 webpack config less -----框架 ----查看考鏈接 https://blog.csdn.net/mjzhang1993/article/details/79013430轉載于:https://w…

系統帶你學習 WebAPIs 第二講

Web APIs 本篇學習目標&#xff1a; 能夠說出排他操作的一般實現步驟 能夠使用html5中的dataset方式操作自定義屬性 能夠根據提示完成百度換膚的案例 能夠根據提示完成全選案例 能夠根據提示完成tab欄切換案例 能夠區分元素節點、文本節點、屬性節點 能夠獲取指定元素的父元素 …

在微信瀏覽器中 location.reload() 不刷新解決方案(直接調用方法)

1、問題 在微信瀏覽器中&#xff0c;需要時刷新當前頁面。 正常情況下我們直接使用 location.reload 方法來刷新。 2、解決方法 function realod(){var {search,href} window.location;href href.replace(/&?t_reload(\d)/g,)window.location.href href(search?&:…

Python爬蟲學習筆記1:request、selenium、ChromeDrive、GeckoDriver等相關依賴安裝

系列學習筆記參考&#xff1a;python3網絡爬蟲開發實戰 requests # pip install requests import requestsselenium Selenium是一個自動化測試工具&#xff0c;利用它我們可以驅動瀏覽器執行特定的動作&#xff0c;如點擊、下拉等 操作 。 對于一些 JavaScript誼染的頁面來說&a…

系統帶你學習 WebAPIs 第三講

Web APIs 本篇學習目標&#xff1a; 能夠使用removeChild()方法刪除節點 能夠完成動態生成表格案例 能夠使用傳統方式和監聽方式給元素注冊事件 能夠說出事件流執行的三個階段 能夠在事件處理函數中獲取事件對象 能夠使用事件對象取消默認行為 能夠使用事件對象阻止事件冒泡 能…

CSS3文本與字體

一、CSS3 換行 1、word-break&#xff08;規定自動換行的處理方法&#xff09; word-break: normal / break-all / keep-all;/* normal&#xff1a;使用瀏覽器默認的換行規則 break-all&#xff1a;允許在單詞內換行 keep-all&#xff1a;只能在半角空格或連字符處換行 */ 兼容…

系統帶你學習 WebAPIs 第四講

Web APIs 本篇學習目標&#xff1a; 能夠說出常用的3-5個鍵盤事件 能夠知道如何獲取當前鍵盤按下的是哪個鍵 能夠知道瀏覽器的頂級對象window 能夠使用window.onload事件 能夠使用window.onresize事件 能夠說出兩種定時器的區別 能夠使用location對象的href屬性完成頁面之間的跳…

linux chrome 安裝過程記錄

最近&#xff0c;由于公司需要做爬蟲抓取一些新聞&#xff0c;在開發過程中&#xff0c;發現有些網站有一定的反爬措施&#xff0c;通過瀏覽器訪問一切正常&#xff0c;通過其他方式&#xff0c;包括&#xff1a;curl&#xff0c;urlconnection 等&#xff0c;就算加入了cookie…

系統帶你學習 WebAPIs 第五講

Web APIs 本篇學習目標: 能夠說出常見 offset 系列屬性的作用 能夠說出常見 client 系列屬性的作用 能夠說出常見 scroll 系列屬性的作用 能夠封裝簡單動畫函數 **1.1. **元素偏移量 offset 系列 1.1.1 offset 概述 offset 翻譯過來就是偏移量&#xff0c; 我們使用 offset系…

ajax請求相關問題

Ajax中async:false/true的作用&#xff1a; async. 默認是 true&#xff0c;即為異步方式&#xff0c;$.ajax執行后&#xff0c;會繼續執行ajax后面的腳本&#xff0c;直到服務器端返回數據后&#xff0c;觸發$.ajax里的success方法&#xff0c;這時候執行的是兩個線程。 async…

有贊美業微前端的落地總結

2020年4月&#xff0c;有贊美業的前端團隊歷經7個月時間&#xff0c;完成了美業PC架構從單體SPA到微前端架構的設計、遷移工作。PPT在去年6月份就有了&#xff0c;現在再整理一下形成文章分享給大家。 頭圖 目錄 Part 01 “大話”微前端 微前端是什么 背景 目標 達成價值 …

bcp文件, 逗號文件

bcp 實用工具 https://docs.microsoft.com/zh-cn/sql/tools/bcp-utility?viewsql-server-2017 大容量復制程序實用工具 (bcp) 可以在 Microsoft SQL Server 實例和用戶指定格式的數據文件間大容量復制數據。 使用 bcp 實用工具可以將大量新行導入 SQL Server 表&#xff0c;或…

遠程登錄和復制文件

命令&#xff1a; ssh 對應英文&#xff1a; secure shell 使用&#xff1a; ssh [-P] 用戶名ip 優點&#xff1a; 加密和壓縮&#xff0c;即安全和提高傳輸速度 注意&#xff1a; 除了windows系統外的系統默認有ssh客戶端&#xff0c;直接使用命令便可&#xff1b; windows系統…

Markdown 編輯器才是yyds|CSDN編輯器測評

前言 今天小編為大家介紹一款編輯器&#xff0c;也正是小編書寫這篇文章所使用的Markdown編輯器&#xff0c;正是廣大博友想要發布文章的工具。那么 你知道他的都有哪些方便之處么 下面小編帶你了解一下 Markdown是什么 Markdown是一種輕量標記語言,通過簡單的語法&#xff…

JVM對象已死

(一) 引用計數法 每有一個引用就加1&#xff0c;每失效一個就減1&#xff0c;為0表示可回收&#xff1b;但是此方法無法解決相互引用的情況 (二) 根搜索算法 從一系列的GCRoots對象為起點向下搜索&#xff0c;搜索的路徑稱為引用鏈&#xff0c;當一個對象沒有任何引…