javascript
JavaScript从入门到放弃 -(五)函数进阶(高级用法)
目錄
- 1. 函數(shù)的定義和調(diào)用
- 1.1 函數(shù)定義的3種方式
- 1.2 函數(shù)調(diào)用方式(常見的6種)
- 1.2.1 普通函數(shù)的調(diào)用
- 1.2.2 對(duì)象中的函數(shù)調(diào)用
- 1.2.3 構(gòu)造函數(shù)的調(diào)用
- 1.2.4 DOM元素綁定事件調(diào)用函數(shù)
- 1.2.5 定時(shí)器中調(diào)用函數(shù)
- 1.2.6 立即執(zhí)行函數(shù)
- 2. 函數(shù)內(nèi)部的this指向
- 2.1 this指向
- 2.1.1 普通函數(shù)
- 2.1.2 對(duì)象中的函數(shù)
- 2.1.3 構(gòu)造函數(shù)
- 2.1.4 綁定事件函數(shù)
- 2.1.5 定時(shí)器函數(shù)
- 2.1.6 立即執(zhí)行函數(shù)
- 2.2 改變函數(shù)內(nèi)部this指向
- 2.2.1 call方法
- 2.2.2 apply方法
- 2.2.3 bind方法(用得最多的一個(gè)方法)
- 2.2.4 call、apply、bind總結(jié)
- 3. 嚴(yán)格模式
- 3.1 什么是嚴(yán)格模式
- 3.2 開啟嚴(yán)格模式
- 3.2.1 為腳本開啟嚴(yán)格模式
- 3.2.2 為函數(shù)開啟嚴(yán)格模式
- 3.2.3 嚴(yán)格模式中的變化
- 3.3 函數(shù)變化
- 4. 高階函數(shù)
- 4.1 接收函數(shù)作為參數(shù)
- 4.2 將函數(shù)作為返回值輸出
- 5. 閉包
- 5.1 變量作用域
- 5.2 什么是閉包
- 5.3 閉包的作用
- 5.4 閉包案例
- 5.4.1 循環(huán)注冊(cè)點(diǎn)擊事件
- 5.4.2 循環(huán)中的setTimeout(定時(shí)器)
- 5.4.3 打車價(jià)格
- 6. 遞歸
- 6.1 什么是遞歸
- 6.2 利用遞歸求數(shù)學(xué)題
- 6.2.1 求1 * 2 * 3...* n 階乘
- 6.2.2 求斐波那契數(shù)列
- 6.2.3 利用遞歸遍歷數(shù)據(jù)
- 6.3 淺拷貝與深拷貝
- 6.3.1 淺拷貝
- 6.3.2 深拷貝
學(xué)習(xí)目標(biāo):
- 能夠說出函數(shù)的多種定義和調(diào)用方式;
- 能夠說出和改變函數(shù)內(nèi)部this的指向;
- 能夠說出嚴(yán)格模式的特點(diǎn);
- 能夠把函數(shù)作為參數(shù)和返回值傳遞;
- 能夠說出閉包的作用;
- 能夠說出遞歸的兩個(gè)條件;
- 能夠說出深拷貝和淺拷貝的區(qū)別。
1. 函數(shù)的定義和調(diào)用
1.1 函數(shù)定義的3種方式
注意:
- Function 首字母大寫,并且里面的參數(shù)必須是字符串格式
- 第3種方式執(zhí)行效率較低,也不方便書寫,因此較少使用,僅做了解即可;
- 所有函數(shù)都是Function的實(shí)例(對(duì)象)(因?yàn)樗械暮瘮?shù)都是通過new Function得出來的)。
驗(yàn)證:
var f = new Function('a','b','console.log(a+b)'); f(1,2); // 所有函數(shù)都是Function的實(shí)例(對(duì)象) console.dir (f); console.log (f instanceof Object); // 返回True關(guān)鍵字instanceof 的作用:判斷前者(f)屬不屬于后者(Object)
所以,這里得出一個(gè)重要的結(jié)論:函數(shù)也屬于對(duì)象。
也再一次印證了 js 里面的萬物皆對(duì)象。
到此為止,就可以畫出函數(shù)的原型三角關(guān)系:
1.2 函數(shù)調(diào)用方式(常見的6種)
1.2.1 普通函數(shù)的調(diào)用
function fn() {console.log('普通函數(shù)') } //調(diào)用方法 fn(); // 或者 fn.call()1.2.2 對(duì)象中的函數(shù)調(diào)用
var o = {sayHi:function() {console.log('對(duì)象方法中的函數(shù)')} } // 調(diào)用方法 o.sayHi()1.2.3 構(gòu)造函數(shù)的調(diào)用
function Star() {} // 調(diào)用方法 new Star();1.2.4 DOM元素綁定事件調(diào)用函數(shù)
// 點(diǎn)擊了按鈕即可調(diào)用此函數(shù) btn.onclick = function(){};1.2.5 定時(shí)器中調(diào)用函數(shù)
// 定時(shí)器自動(dòng)調(diào)用 setInterval(function(){},1000); // 自動(dòng)每隔 1 秒調(diào)用一次1.2.6 立即執(zhí)行函數(shù)
// 寫法:()(); (function(){console.log('立即執(zhí)行函數(shù)'); })(); // 立即執(zhí)行函數(shù)是自動(dòng)調(diào)用2. 函數(shù)內(nèi)部的this指向
2.1 this指向
這些this的指向,是當(dāng)我們調(diào)用函數(shù)的時(shí)候確定的,調(diào)用方式的不同決定了this的指向不同,一般指向我們的調(diào)用者。
this指向出現(xiàn)的多種情況:
| 普通函數(shù)調(diào)用 | window |
| 構(gòu)造函數(shù)調(diào)用 | 實(shí)例對(duì)象、原型對(duì)象里的方法也指向?qū)嵗龑?duì)象 |
| 對(duì)象方法調(diào)用 | 該方法所屬對(duì)象 |
| 事件綁定方法 | 綁定事件對(duì)象 |
| 定時(shí)器函數(shù) | window |
| 立即執(zhí)行函數(shù) | window |
2.1.1 普通函數(shù)
function fn() {console.log('普通函數(shù)的this:' + this); } fn(); // 完整的寫法:window.fn(); 即,指向函數(shù)的調(diào)用者結(jié)果輸出:
2.1.2 對(duì)象中的函數(shù)
var o = {sayHi: function() {console.log('對(duì)象方法的this:' + this);} } o.sayHi(); // 指向的是對(duì)象o結(jié)果輸出:
2.1.3 構(gòu)造函數(shù)
// 構(gòu)造函數(shù):指向ldh這個(gè)實(shí)例對(duì)象,原型對(duì)象里的this 指向的也是ldh這個(gè)實(shí)例對(duì)象 function Star() {}; Star.prototype.sing=function(){ } var ldh= new Star();2.1.4 綁定事件函數(shù)
// 4. 綁定事件函數(shù) var btn = document.querySelector('button'); btn.onclick = function() {console.log('綁定時(shí)間函數(shù)的this:' + this) }; // 點(diǎn)擊了按鈕就可以調(diào)用這個(gè)函數(shù)綁定事件函數(shù)this指向的是函數(shù)的調(diào)用者btn這個(gè)按鈕對(duì)象
結(jié)果輸出:
2.1.5 定時(shí)器函數(shù)
// 定時(shí)器函數(shù) setInterval(function() { // 完整的寫法是 window.setIntervalconsole.log('定時(shí)器的this:' +this); }, 1000);定時(shí)器函數(shù)的this指向也是window
結(jié)果輸出:
2.1.6 立即執(zhí)行函數(shù)
// 立即執(zhí)行函數(shù) (function() {console.log('立即執(zhí)行函數(shù)的this:' + this); })();立即執(zhí)行函數(shù) this 還是指向的window。
結(jié)果輸出:
2.2 改變函數(shù)內(nèi)部this指向
JavaScript 為我們專門提供了一些函數(shù) 方法來幫我們更優(yōu)雅的處理函數(shù)內(nèi)部this的指向問題。常用的有bind()、call()、apply()三種方法。
2.2.1 call方法
call()方法可以調(diào)用一個(gè)函數(shù)。簡單理解為調(diào)用函數(shù)的方式,它可以改變函數(shù)的 this 指向。
應(yīng)用場(chǎng)景: 一般應(yīng)用于繼承.。
語法規(guī)范:
fun.call(thisArg,arg1,arg2,...)- thisArg:目標(biāo)對(duì)象;
- arg1,arg2:傳遞的參數(shù)
示例:
// 改變this 指向 var o = {name:'andy' }function fn() {console.log(this); }; fn.call(o);call 的作用:1)可以調(diào)用函數(shù);2)可以改變函數(shù)內(nèi)的this指向;3)可以實(shí)現(xiàn)繼承(主要作用)。
2.2.2 apply方法
apply() 方法可以調(diào)用一個(gè)函數(shù)。簡單理解為調(diào)用函數(shù)的方式,它也可以改變函數(shù)的 this 指向。
apply 一般應(yīng)用于操作數(shù)組數(shù)據(jù)。
應(yīng)用場(chǎng)景::經(jīng)常跟數(shù)組有關(guān)系
比如:求最大值、最小值。
由于數(shù)組沒有求最大值的方法(只有數(shù)學(xué)對(duì)象里面才有Math.max()),我們可以利用apply,借助于數(shù)學(xué)內(nèi)置對(duì)象求最大值。
語法規(guī)范:
fun.apply(thisArg,[argsArray])2.2.3 bind方法(用得最多的一個(gè)方法)
bind() 方法不能調(diào)用函數(shù),但是能改變函數(shù)內(nèi)部this 指向,返回的是原函數(shù)改變this指向之后產(chǎn)生的新函數(shù);
應(yīng)用場(chǎng)景
如果有的函數(shù)我們不需要立即調(diào)用,但又想改變這個(gè)函數(shù)內(nèi)部的this指向時(shí)。
語法結(jié)構(gòu):
fun.bind(thisArg,arg1,arg2...)- thisArg:在fun函數(shù)運(yùn)行時(shí)指定的this值;
- arg1、arg2:傳遞的其他參數(shù);
- 返回由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝。
bind 的基本使用
var o = {name:'andy' } function fn(a,b){console.log(a + b); } var f=fn.bind(o,1,2); f();bind 的應(yīng)用
點(diǎn)擊按鈕,禁用3秒后開啟
2.2.4 call、apply、bind總結(jié)
相同點(diǎn):
都可以改變函數(shù)內(nèi)部的this指向。
不同點(diǎn):
主要應(yīng)用場(chǎng)景:
在不同應(yīng)用場(chǎng)景,合理選用這3個(gè)方法。
3. 嚴(yán)格模式
3.1 什么是嚴(yán)格模式
JavaScript 除了提供正常模式外,還提供了嚴(yán)格模式(strict mode),ES5 的嚴(yán)格模式具有限制性,它是 JavaScript變體的一種方式,即在嚴(yán)格的條件下運(yùn)行 JS 代碼。
嚴(yán)格模式在 IE10 以上版本的瀏覽器中才會(huì)被支持,舊版本瀏覽器中會(huì)被忽略。
嚴(yán)格模式對(duì)正常的 JavaScript 語義做了一些更改:
1.消除了 Javascript 語法的一些不合理、不嚴(yán)謹(jǐn)之處,減少了一些怪異行為。(比如原先的變量可以不聲明直接賦值)
2.消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全。
3.提高編譯器效率,增加運(yùn)行速度。
4.禁用了在 ECMAScript 的未來版本中可能會(huì)定義的一些語法,為未來新版本的 Javascript 做好鋪墊。比如一些保留字如:class,enum,export, extends, import, super 不能做變量名。
3.2 開啟嚴(yán)格模式
嚴(yán)格模式可以應(yīng)用到整個(gè)腳本或個(gè)別函數(shù)中。因此在使用時(shí),我們可以將嚴(yán)格模式分 為為腳本開啟嚴(yán)格模式和為函數(shù)開啟嚴(yán)格模式兩種情況。
3.2.1 為腳本開啟嚴(yán)格模式
有的 script 腳本是嚴(yán)格模式,有的 script 腳本是正常模式,這樣不利于文件合并,所以可以將整個(gè)腳本文件放在一個(gè)立即執(zhí)行的匿名函數(shù)之中。這樣獨(dú)立創(chuàng)建一個(gè)作用域而不影響其他 script 腳本文件。
為整個(gè)腳本文件開戶嚴(yán)格模式,只需要在所有語句之前放一個(gè)特定語句"use strict"; (或 ‘use strict’;),單引號(hào)、雙引號(hào)均可。
<script>"use strict"; //開啟了嚴(yán)格模式... </script>因?yàn)?" use strict "加了引號(hào),所以老版本瀏覽器會(huì)把它當(dāng)作一行普通字符串而忽略。
嚴(yán)格模式要求比較多,比較規(guī)范,如果擔(dān)心自己駕馭不了,可以僅為某一個(gè)函數(shù)開啟嚴(yán)格模式。
3.2.2 為函數(shù)開啟嚴(yán)格模式
要給某個(gè)函數(shù)開啟嚴(yán)格模式,需要把“use strict”; (或 ‘use strict’; ) 聲明放在函數(shù)體所有語句之前。
function fn(){"use strict";return "123"; } //當(dāng)前fn函數(shù)開啟了嚴(yán)格模式3.2.3 嚴(yán)格模式中的變化
嚴(yán)格模式對(duì) Javascript 的語法和行為,都做了一些改變。
-
變量規(guī)定
- 在正常模式中,如果變量沒有聲明就賦值,默認(rèn)是全局變量。嚴(yán)格模式禁止這種用法,變量必須先用var聲明,然后再使用。
- 嚴(yán)禁刪除已經(jīng)聲明的變量。比如,delete X; 語法是錯(cuò)誤的
-
this指向問題
- 正常模式下,全局作用域函數(shù)中的this指向window對(duì)象;
- 嚴(yán)格模式下,全局作用域函數(shù)中的this指向undefined;
- 正常模式下,構(gòu)造函數(shù)不加new可以當(dāng)普通函數(shù)調(diào)用,this指向全局對(duì)象;
- 嚴(yán)格模式下,如果構(gòu)造函數(shù)不加new調(diào)用,由于this指向的是undefined,如果給它賦值,則會(huì)報(bào)錯(cuò);
- new實(shí)例化的構(gòu)造函數(shù)指向創(chuàng)建的對(duì)象實(shí)例;
- 定時(shí)器this仍是指向window
3.3 函數(shù)變化
- 不能有重名的參數(shù)
- 函數(shù)必須聲明在頂層,新版本的JavaScript會(huì)引入“塊級(jí)作用域”(ES6中已引入)。為了與新版本接軌,不允許在非函數(shù)的代碼塊內(nèi)聲明函數(shù)。
另外,嚴(yán)格模式也不允許有8進(jìn)制
更多嚴(yán)格模式要求參閱:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode
4. 高階函數(shù)
高階函數(shù):是對(duì)其他函數(shù)進(jìn)行操作的函數(shù),它接收函數(shù)作為參數(shù)或?qū)⒑瘮?shù)作為返回值輸出。
函數(shù)可以當(dāng)做參數(shù)來進(jìn)行傳遞,回調(diào)函數(shù)
4.1 接收函數(shù)作為參數(shù)
<script> function fn(callback) {callback && callback(); } fn(function(){alert('hi')}); </script>4.2 將函數(shù)作為返回值輸出
<script> function fn() {return function(){}; } fn(); </script>此時(shí) fn 就是一個(gè)高階函數(shù)。
函數(shù),也是一種數(shù)據(jù)類型,同樣可以作為參數(shù),傳遞給另外一個(gè)參數(shù)使用。最典型的就是作為回調(diào)函數(shù)。
實(shí)例:
回調(diào)函數(shù)是高階函數(shù)的一個(gè)運(yùn)用
補(bǔ)充說明:
實(shí)例中的callback && callback()語句,表示如果callback不存在,就不執(zhí)行函數(shù)調(diào)用。如果 運(yùn)算符是“||”,則不管callback存不存在都調(diào)用, 不存在就報(bào)錯(cuò)。
運(yùn)算符 && 的作用,保持符號(hào)兩邊都為真,一個(gè)不為真就停止后面的腳本。
5. 閉包
JavaScript 中的 閉包 和 異步,并稱兩大難點(diǎn)。
5.1 變量作用域
變量根據(jù)作用域的不同分為兩種: 全局變量和局部變量
5.2 什么是閉包
閉包:指有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù)。
——《JavaScript高級(jí)程序設(shè)計(jì)》
或簡單理解為,一個(gè)作用域可以訪問另外一個(gè)函數(shù)內(nèi)部的局部變量。
例如:
// fun這個(gè)函數(shù)作用域,訪問了另外一個(gè)函數(shù)fn里面的局部變量num function fn(){var num = 10;function fun(){console.log(num);}fun(); } fn();以上代碼,就產(chǎn)生了閉包,而變量所在的函數(shù)fn,就是閉包函數(shù)。
在斷點(diǎn)調(diào)試Scope 里,可清晰看到產(chǎn)生的過程
5.3 閉包的作用
閉包的主要作用:延伸了變量的作用范圍。
代碼驗(yàn)證:
// fn外面的作用域也可以訪問fn內(nèi)部的局部變量(利用了return) function fn(){var num = 10;return function(){console.log(num);} } var f = fn(); f();5.4 閉包案例
5.4.1 循環(huán)注冊(cè)點(diǎn)擊事件
HTML結(jié)構(gòu)
<ul class="nav"><li>榴蓮</li><li>臭豆腐</li><li>鯡魚罐頭</li><li>大豬蹄子</li></ul>JavaScript 代碼
1)用以前的方法獲取當(dāng)前l(fā)i的索引號(hào)
var lis = document.querySelector('.nav').querySelectorAll('li');for (var i = 0; i < lis.length; i++) { // for是同步任務(wù)lis[i].index = i;lis[i].onclick = function() { // function是異步任務(wù)console.log(this.index);}}2)利用閉包的方式獲得當(dāng)前l(fā)i 的索引號(hào)(本案例面試中常用)
for (var i = 0; i < lis.length; i++) {// 利用for循環(huán)創(chuàng)建了4個(gè)立即執(zhí)行函數(shù)(function(i) { // ②然后在這里傳入變量"i"lis[i].onclick = function() {console.log(i);}})(i); // ①首先在這里傳入變量 "i"}方式2 )使用立即執(zhí)行函數(shù)(function(){})()產(chǎn)生了閉包。
但這種方法在本案例中,反而不如方式1)高效,且容易內(nèi)存泄漏(如果一直不點(diǎn)擊,那么變量i就不會(huì)被銷毀)。
立即執(zhí)行函數(shù)也叫小閉包
5.4.2 循環(huán)中的setTimeout(定時(shí)器)
要求:3 秒種之后,打印所有l(wèi)i元素的內(nèi)容。
HTML結(jié)構(gòu)
<ul class="nav"><li>榴蓮</li><li>臭豆腐</li><li>鯡魚罐頭</li><li>大豬蹄子</li></ul>JavaScript 代碼
var lis = document.querySelector('.nav').querySelectorAll('li'); for (var i = 0; i < lis.length; i++) { // for是同步任務(wù)(function(i) { // 先創(chuàng)建一個(gè)立即執(zhí)行函數(shù)setTimeout(function() { // 是異步任務(wù)console.log(lis[i].innerHTML);}, 3000);})(i); }異步任務(wù),主要有3種情況:
1)回調(diào)函數(shù);
2)定時(shí)器中的回調(diào)函數(shù);
3)事件中的回調(diào)函數(shù)。
5.4.3 打車價(jià)格
要求:
- 打車起步價(jià)13(3公里內(nèi));
- 之后每多一公里增加5塊錢,用戶輸入公里數(shù)就可以計(jì)算打車價(jià)格;
- 如果有擁堵情況,總價(jià)格多收取10塊錢擁堵費(fèi)。
JavaScript 代碼
<script>var car = (function() {var start = 13; // 起步價(jià)(局部變量)var total = 0; // 總價(jià) (局部變量)return {// 正常的費(fèi)用price: function(n) { // n:公里數(shù)if (n <= 3) {total = start; } else {total = start + (n - 3) * 5}return total;},// 擁堵之后的費(fèi)用yd: function(flag) {return flag ? total + 10 : total;}}})();console.log(car.price(5));; // 假設(shè)是5公里(n)console.log(car.yd(true)); // true:有擁堵情況</script>6. 遞歸
6.1 什么是遞歸
遞歸:如果一個(gè)函數(shù)在內(nèi)部可以調(diào)用其本身,那么這個(gè)函數(shù)就是遞歸函數(shù)。
簡單理解:函數(shù)內(nèi)部自己調(diào)用自己,這個(gè)函數(shù)就是遞歸函數(shù)。
<script>// 遞歸函數(shù):函數(shù)內(nèi)部自己調(diào)用自己function fn(){fn();}fn(); </script>遞歸函數(shù)的作用和循環(huán)效果一樣;
由于遞歸很容易發(fā)生“棧溢出”錯(cuò)誤(stack overflow),所以必須要加退出條件return。
6.2 利用遞歸求數(shù)學(xué)題
6.2.1 求1 * 2 * 3…* n 階乘
<script>// 利用遞歸函數(shù)求1~n的階乘function fn(n) { // 用戶輸入幾,就求 1~n之間的階乘if (n == 1) {return 1;}return n * fn(n - 1);}console.log(fn(3)); // 假設(shè)用戶輸入3</script>代碼解析:
假如用戶輸入的是3,
1)由于 if (n==1)判斷為false,因此不執(zhí)行return 1。而去執(zhí)行后面的n * fn(n-1),傳入3后的返回值為 3 * fn(3 - 2)。即return 3 * fn(2);
2)計(jì)算fn(2)
fn(2)相當(dāng)于再次調(diào)用了fn的函數(shù),那么此時(shí)里面的fn,傳遞的就是2了。相當(dāng)于
fn(2 - 1)即 fn(1),亦即n =1。此時(shí),經(jīng)過判斷 if(n==1),就執(zhí)行return 1;,
return 3 * (2 * 1) // <=> return n * fn(n - 1)// 最后,返回6fn(2)計(jì)算過程:
//return 3 * fn(2) //return 3 * (2 * fn(1)) //return 3 * (2 * 1) //return 3 * (2) //return 6總結(jié):
我們利用遞歸函數(shù),求了1~n之間的階乘。
其主要思路是,不管是求1 ~ n 之間的階乘,還是求1~n之間的累加和,都是用我們的前一項(xiàng)(n)乘以后一項(xiàng)(n - 1)。只不過,后一項(xiàng)需要用函數(shù)來重新執(zhí)行一次;
遞歸函數(shù)還必須要加一個(gè)判斷條件,和一個(gè)退出條件。如果正好處于第1項(xiàng),就直接把第1項(xiàng)返回即可,不需要再進(jìn)行階乘或累加和。
6.2.2 求斐波那契數(shù)列
- 利用遞歸求斐波那契數(shù)列(免子序列)1、1、2、2、3、5、8、13、21…
- 用戶輸入一個(gè)數(shù)字n,就可以求出這個(gè)數(shù)字對(duì)應(yīng)的免子序列值。
分析:
JavaScript 代碼:
<script>// 利用遞歸求斐波那契數(shù)列(免子序列)1、1、2、3、5、8、13、21...// 用戶輸入一個(gè)數(shù)字n 就可以求出這個(gè)數(shù)字對(duì)應(yīng)的免子序列值。function fb(n) {if (n === 1 || n === 2) { // 給遞歸函數(shù)加一個(gè)退出的判斷條件return 1;}return fb(n - 1) + fb(n - 2);}console.log(fb(4)); // 輸出 3console.log(fb(8)); // 輸出 21 </script>6.2.3 利用遞歸遍歷數(shù)據(jù)
var data = [{id: 1,name: '家電',goods: [{id: 11,gname: '冰箱'}, {id: 12,gname: '洗衣機(jī)'}]}, {id: 2,name: '服飾' }];案例要求:根據(jù)上面創(chuàng)建的對(duì)象,要求輸入 id 后,返回對(duì)應(yīng)的數(shù)據(jù)對(duì)象
思路:
利用 forEach 去遍歷里面的每一個(gè)對(duì)象。
forEach:可以遍歷數(shù)組并得到數(shù)據(jù)中的每個(gè)元素。
這里采用封裝函數(shù)來實(shí)現(xiàn):
function getID(json, id) {// 1、利用forEach遍歷里面的每個(gè)數(shù)組對(duì)象json.forEach(function(item) {//console.log(item); // 返回2個(gè)數(shù)組元素if (item.id == id) {console.log(item);// 2、獲取最里層的數(shù)據(jù)對(duì)象11、12利用遞歸函數(shù)}}); } console.log(getID(data, 1));但是,上面這個(gè)forEach 只能得到最外層的兩個(gè)id 為1 和2的兩個(gè)對(duì)象。而對(duì)于里層的兩個(gè)id分別為11和12的對(duì)象卻得不到。
這時(shí),要想獲取里層的11、12,就可以把forEach或這個(gè)函數(shù)再執(zhí)行一次,那么就利用到了遞歸函數(shù)。
從表面看,這里沒有專門設(shè)置遞歸的退出條件。但是,由于使用了if …else…做執(zhí)行遞歸的條件,因此不再需要單獨(dú)的退出設(shè)置。
至此,已能打印出篩選后的數(shù)據(jù)對(duì)象。但需要實(shí)現(xiàn)的是將篩選得到的值返回,而不是打印,以給我們?cè)谀承┣闆r下使用。因此,需要先保數(shù)據(jù)保存出來。
需要聲明一個(gè)空對(duì)象 o ,用于保存篩選完成后的數(shù)據(jù),完整函數(shù)如下:
function getID(json, id) {var o = {};json.forEach(function(item) {//console.log(item); // 返回2個(gè)數(shù)組元素if (item.id == id) {// console.log(item);o = item;return item;// 利用遞歸得到里層的數(shù)據(jù)11、12} else if (item.goods && item.goods.length > 0) {o = getID(item.goods, id);}});return o; } console.log(getID(data, 1));; console.log(getID(data, 11));;6.3 淺拷貝與深拷貝
ES6淺拷貝語法:
Object.assign(*target,...sourcer*)- target:目標(biāo)對(duì)象(拷貝給誰);
- sourcer:拷貝對(duì)象(拷貝誰)。
6.3.1 淺拷貝
var obj= {id:1,name:'andy'};var o={};1)、利用原生 JavaScript 實(shí)現(xiàn)把對(duì)象obj的每一項(xiàng)拷貝給對(duì)象o
思路:用for...in 來遍歷 obj 這個(gè)對(duì)象,把每一項(xiàng)拿出來給o
2)、利用ES6新增的淺拷貝方法
Object.assign(o,obj);console.log(o);實(shí)際開發(fā)中更 推薦 assign 方法實(shí)現(xiàn)淺拷貝。
6.3.2 深拷貝
<script>var obj={id:1,name:'andy',msg:{age:18}}var o={}; </script>由于有多層數(shù)據(jù),所以用遞歸更合適:先遍歷外層數(shù)據(jù)(id、name),再遍歷里層數(shù)據(jù)(msg)
封裝函數(shù)實(shí)現(xiàn)深拷貝
function deepCopy(newObj, oldObj) {for (var k in oldObj) {// 判斷屬性值屬于簡單數(shù)據(jù)類型還是復(fù)雜數(shù)據(jù)類型// 1、先拿到值才能判斷——獲取屬性值 oldObj[k]var item = oldObj[k];// 2、判斷這個(gè)值是否是數(shù)組;if (item instanceof Array) {newObj[k] = []; // 相當(dāng)于 o.color=[]deepCopy(newObj[k], item)} else if (item instanceof Object) {// 3、判斷這個(gè)值是否是對(duì)象newObj[k] = [];deepCopy(newObj[k], item)} else {// 4、屬于簡單數(shù)據(jù)類型newObj[k] = item;}}} deepCopy(o, obj) // 函數(shù)調(diào)用 console.log(o);上一篇:JavaScript從入門到放棄 -(四)E5 新增方法
下一篇:JavaScript從入門到放棄 -(六)正則表達(dá)式
總結(jié)
以上是生活随笔為你收集整理的JavaScript从入门到放弃 -(五)函数进阶(高级用法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-While循环
- 下一篇: gradle idea java ssm