js高级第四天
課程回顧:
? 原型鏈:由原型構(gòu)成鏈狀結(jié)構(gòu),提供成員查找機(jī)制
? 繼承:組合繼承:構(gòu)造函數(shù)和原型對(duì)象
? 屬性:調(diào)用父構(gòu)造函數(shù)的時(shí)候用call改變this指向
? 方法:父實(shí)例對(duì)象賦值給子原型對(duì)象,最后指回構(gòu)造函數(shù)本身
? 新增方法:
? 數(shù)組:forEach,filter,some
? 字符串:trim
? 語法:數(shù)組.方法名(function ( val, index, obj ) { });
ES6中的新增方法
ES6 中給我們新增了一些方法,可以很方便的操作數(shù)組或者字符串,這些方法主要包括:數(shù)組方法字符串方法數(shù)組方法:
迭代(遍歷)方法:forEach()、map()、filter()、some()、every();這些方法都是遍歷數(shù)組的forEach()
array.forEach(function(currentValue, index, arr))遍歷數(shù)組currentValue:數(shù)組當(dāng)前項(xiàng)的值 index:數(shù)組當(dāng)前項(xiàng)的索引 arr:數(shù)組對(duì)象本身 var arr = ['red','blue','yellow','orange'];arr.forEach(function (elm,i,arrAbc) {console.log(elm,i,arrAbc); });filter()
array.filter(function(currentValue, index, arr))filter() 方法創(chuàng)建一個(gè)新的數(shù)組,新數(shù)組中的元素是通過檢查指定數(shù)組中符合條件的所有元素,主要用于篩選數(shù)組注意它直接返回一個(gè)新數(shù)組currentValue: 數(shù)組當(dāng)前項(xiàng)的值index:數(shù)組當(dāng)前項(xiàng)的索引arr:數(shù)組對(duì)象本身?回調(diào)函數(shù)里面添加return添加返回條件 var arr = [100,66,99,123,333,33,44,66];var reArr = arr.filter(function (elm, a, n) {// console.log(elm,a, n);return elm % 2 == 0;});console.log(reArr);some()
array.some(function(currentValue, index, arr)) 【注意:找到或者滿足條件立刻停止】some() 方法用于檢測(cè)數(shù)組中的元素是否滿足指定條件. 通俗點(diǎn)查找數(shù)組中是否有滿足條件的元素注意它返回值是布爾值, 如果查找到這個(gè)元素, 就返回true , 如果查找不到就返回false.如果找到第一個(gè)滿足條件的元素,則終止循環(huán). 不在繼續(xù)查找.currentValue: 數(shù)組當(dāng)前項(xiàng)的值?index:數(shù)組當(dāng)前項(xiàng)的索引arr:數(shù)組對(duì)象本身 var arr = [100,200,300,400]; var re = arr.some(function (elm,i,arr) {// console.log(elm,i,arr);console.log(i);return elm >= 200;}); console.log(re);查詢商品案例
1.把數(shù)據(jù)渲染到頁面中(forEach)【insertAdjacentHTML】var tbody = document.querySelector('tbody');data.forEach(function (ele, i) {// console.log(ele);var tr = '<tr><td>' + ele.id +'</td><td>' + ele.pname + '</td><td>' + ele.price + '</td></tr>';tbody.insertAdjacentHTML('beforeend',tr);});2.根據(jù)價(jià)格顯示數(shù)據(jù)var btn = document.querySelector('.search-price');var start = document.querySelector('.start');var end = document.querySelector('.end');btn.onclick = function () {var reArr = data.filter(function (ele, i) {return start.value <= ele.price && ele.price <= end.value;});tbody.innerHTML = '';sreArr.forEach(function (ele) {var tr = '<tr><td>' + ele.id +'</td><td>' + ele.pname + '</td><td>' + ele.price + '</td></tr>';tbody.insertAdjacentHTML('beforeend',tr);});};3.根據(jù)商品名稱顯示數(shù)據(jù) var sele = document.getElementById('sele');sele.onchange = function () {var n = [];var id = sele.value;data.some(function (ele) {if (id == 0) {n = data;return true;}else if (ele.id == id) {n.push(ele);return true;}});tbody.innerHTML = '';n.forEach(function (ele, i) {// console.log(ele);var tr = '<tr><td>' + ele.id +'</td><td>' + ele.pname + '</td><td>' + ele.price + '</td></tr>';tbody.insertAdjacentHTML('beforeend',tr);});}必做題:求這個(gè)是數(shù)組所有數(shù)的和,求數(shù)組最大值和最小值,及最大值的下標(biāo)和最小值的下標(biāo),求平均值;var arr = [[123,45,66],[1234,23,45,56,67],[435,67,78,43,67,78,673,34]]字符串方法:
str.trim()trim:刪除字符串兩側(cè)的空白符<input type="text" id="txt"><input type="button" value="點(diǎn)擊" id="btn"><script type="text/javascript">// var str = new String('abcd');// var str = ' abc defg abcd ';// console.log( str );// console.log( str.trim() );var btn = document.getElementById('btn');var txt = document.getElementById('txt');btn.onclick = function () {if ( txt.value.trim().length > 0 ) {alert('允許提交');} else {alert('不允許提交');}}</script>函數(shù)進(jìn)階
函數(shù)的定義和調(diào)用
函數(shù)聲明方式function 關(guān)鍵字(命名函數(shù))
函數(shù)表達(dá)式(匿名函數(shù))【自調(diào)用函數(shù)】
new Function() var fn = new Function(‘參數(shù)1’,‘參數(shù)2’…, ‘函數(shù)體’)
var fn = new Function('a','b','console.log(a,b);');fn(123,456);Function 里面參數(shù)都必須是字符串格式第三種方式執(zhí)行效率低,也不方便書寫,因此較少使用所有函數(shù)都是Function 的實(shí)例(對(duì)象) 函數(shù)也屬于對(duì)象// var n = 3; // var fn = function () {}函數(shù)的調(diào)用方式
函數(shù)定義:命名函數(shù),匿名函數(shù)
調(diào)用函數(shù):好多種
this指向
? this指向誰,如果大家記不住,那么就可以這樣來記:
? 構(gòu)造函數(shù)中的this指向的是實(shí)例對(duì)象
? 其他的都是調(diào)用者
 
改變函數(shù)內(nèi)部this 指向
JavaScript 為我們專門提供了一些函數(shù)方法來幫我們更優(yōu)雅的處理函數(shù)內(nèi)部this的指向問題,常用的有bind()、call()、apply() 三種方法。
call 方法
call() 方法調(diào)用一個(gè)對(duì)象。簡(jiǎn)單理解為調(diào)用函數(shù)的方式,但是它可以改變函數(shù)的this指向。
fun.call(thisArg, arg1, arg2, ...) thisArg:在fun 函數(shù)運(yùn)行時(shí)指定的this 值arg1,arg2:傳遞的其他參數(shù)返回值就是函數(shù)的返回值,因?yàn)樗褪钦{(diào)用函數(shù)function Father () {this} function Son () { Father.call(this,1,2) }因此當(dāng)我們想改變this 指向,同時(shí)想調(diào)用這個(gè)函數(shù)的時(shí)候,可以使用call,比如繼承var obj = {name : '阿飛',fei : function () {console.log(this);}}var o = {name : '帶土'};// 函數(shù).call(對(duì)象)// console.log( obj.fei );obj.fei.call(o);apply 方法
fun.apply(thisArg, [argsArray]):調(diào)用函數(shù)thisArg:在fun函數(shù)運(yùn)行時(shí)指定的this值argsArray:傳遞的值,必須包含在數(shù)組里面返回值就是函數(shù)的返回值,因?yàn)樗褪钦{(diào)用函數(shù)因此apply 主要跟數(shù)組有關(guān)系,比如使用Math.max() 求數(shù)組的最大值var arr = [23,45,56,23,54];var n = Math.max.apply(null,arr);console.log(n);改變this指向:fn.apply(obj,[數(shù)組])fn.call(obj,a,b,c,d)bind 方法
bind() 方法不會(huì)調(diào)用函數(shù)。但是能改變函數(shù)內(nèi)部this 指向fun.bind(thisArg, arg1, arg2, ...)thisArg:在fun 函數(shù)運(yùn)行時(shí)指定的this 值arg1,arg2:傳遞的其他參數(shù)返回由指定的this 值和初始化參數(shù)改造的原函數(shù)拷貝因此當(dāng)我們只是想改變this 指向,并且不想調(diào)用這個(gè)函數(shù)的時(shí)候,可以使用bindvar btn = document.querySelector('input');btn.onclick = function () {this.disabled = true;window.setTimeout(function () {this.disabled = false;}.bind(btn),2000); }call apply bind 總結(jié)
fun.call(obj,arg1,arg2......); fun.apply(obj,[a,b,c]) fun.bind(obj,arg1,arg2......);相同點(diǎn): 都可以改變函數(shù)內(nèi)部的this指向.區(qū)別點(diǎn): 1.call 和apply 會(huì)調(diào)用函數(shù), 并且改變函數(shù)內(nèi)部this指向. 2.call 和apply 傳遞的參數(shù)不一樣, call 傳遞參數(shù)aru1, aru2..形式apply 必須數(shù)組形式[arg] 3.bind 不會(huì)調(diào)用函數(shù), 可以改變函數(shù)內(nèi)部this指向主要應(yīng)用場(chǎng)景: 1.call 經(jīng)常做繼承. 2.apply 經(jīng)常跟數(shù)組有關(guān)系.比如借助于數(shù)學(xué)對(duì)象實(shí)現(xiàn)數(shù)組最大值最小值 3.bind 不調(diào)用函數(shù),但是還想改變this指向. 比如改變定時(shí)器內(nèi)部的this指向嚴(yán)格模式
JS:兩種模式[類似于HTML版本]1、正常模式2、嚴(yán)格模式什么是嚴(yán)格模式
JavaScript 除了提供正常模式外,還提供了嚴(yán)格模式(strictmode)。ES5 的嚴(yán)格模式是采用具有限制性JavaScript 變體的一種方式,即在嚴(yán)格的條件下運(yùn)行JS 代碼。
 嚴(yán)格模式在IE10 以上版本的瀏覽器中才會(huì)被支持,舊版本瀏覽器中會(huì)被忽略。
 嚴(yán)格模式對(duì)正常的JavaScript 語義做了一些更改:
開啟嚴(yán)格模式
開啟嚴(yán)格模式:“use strict”
<script>"use strict"</script>:腳本開啟嚴(yán)格模式 <script>function fn () {"use strict"}</script>為函數(shù)開啟嚴(yán)格模式嚴(yán)格模式可以應(yīng)用到整個(gè)腳本或個(gè)別函數(shù)中。因此在使用時(shí),我們可以將嚴(yán)格模式分為為腳本開啟嚴(yán)格模式和為函數(shù)開啟嚴(yán)格模式兩種情況。
為腳本開啟嚴(yán)格模式
為整個(gè)腳本文件開啟嚴(yán)格模式,需要在所有語句之前放一個(gè)特定語句“use strict”;(或‘use strict’;)。 <script>"use strict";console.log("這是嚴(yán)格模式。"); </script>因?yàn)?#34;use strict"加了引號(hào),所以老版本的瀏覽器會(huì)把它當(dāng)作一行普通字符串而忽略。為函數(shù)開啟嚴(yán)格模式
要給某個(gè)函數(shù)開啟嚴(yán)格模式,需要把“use strict”; (或'use strict'; ) 聲明放在函數(shù)體所有語句之前。function fn(){"use strict";return "這是嚴(yán)格模式。";}將"use strict"放在函數(shù)體的第一行,則整個(gè)函數(shù)以"嚴(yán)格模式"運(yùn)行。嚴(yán)格模式中的變化
嚴(yán)格模式對(duì)Javascript的語法和行為,都做了一些改變。
變量規(guī)定
變量申明必須加var,而且不準(zhǔn)刪除變量在正常模式中,如果一個(gè)變量沒有聲明就賦值,默認(rèn)是全局變量。嚴(yán)格模式禁止這種用法,變量都必須先用var命令聲明,然后再使用。 n = 3; 嚴(yán)禁刪除已經(jīng)聲明變量。例如,delete x; 語法是錯(cuò)誤的。嚴(yán)格模式下this 指向問題
嚴(yán)格模式下,普通函數(shù)this是undefined;以前在全局作用域函數(shù)中的this 指向window 對(duì)象。 嚴(yán)格模式下全局作用域中函數(shù)中的this是undefined。其他的沒有變化: 以前構(gòu)造函數(shù)時(shí)不加new也可以調(diào)用,當(dāng)普通函數(shù),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 。 事件、對(duì)象還是指向調(diào)用者。函數(shù)變化
參數(shù)不能重名函數(shù)不能有重名的參數(shù)。函數(shù)必須聲明在頂層.新版本的JavaScript 會(huì)引入“塊級(jí)作用域”(ES6 中已引入)。為了與新版本接軌,不允許在非函數(shù)的代碼塊內(nèi)聲明函數(shù)。【if,for等里面定義函數(shù)也不可以,但是現(xiàn)在不可以】更多嚴(yán)格模式要求參考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode錯(cuò)誤寫法: function fn (a,a) {console.log(a+a);} fn(1,2);JS:正常模式,嚴(yán)格模式 開啟嚴(yán)格模式:"use strict";腳本開啟,函數(shù)開啟 變量嚴(yán)格,普通函數(shù)this指向undefined,函數(shù)參數(shù)不能重名......高階函數(shù)
高階函數(shù)是對(duì)其他函數(shù)進(jìn)行操作的函數(shù),它接收函數(shù)作為參數(shù)或?qū)⒑瘮?shù)作為返回值輸出。把函數(shù)作為參數(shù),或者把函數(shù)作為返回值的的函數(shù),稱為高階函數(shù)此時(shí)fn就是一個(gè)高階函數(shù)
函數(shù)也是一種數(shù)據(jù)類型,同樣可以作為參數(shù),傳遞給另外一個(gè)參數(shù)使用。最典型的就是作為回調(diào)函數(shù)。
同理函數(shù)也可以作為返回值傳遞回來
<script>function fn(callback){callback&&callback();}fn(function(){alert('hi');}) </script><script>function fn(){return function() {}}fn(); </script>課程回顧:
? 函數(shù)定義:命名函數(shù),匿名函數(shù),new Function()
? 調(diào)用函數(shù):普通函數(shù),事件處理程序,方法…
? this指向:構(gòu)造函數(shù)this指向?qū)嵗龑?duì)象,其他this指向調(diào)用者
? 改變this指向:call,apply,bind【fun.方法(對(duì)象,參數(shù))】
? 嚴(yán)格模式:“use strict”;腳本開啟嚴(yán)格,函數(shù)開啟嚴(yán)格
? 高階函數(shù):把函數(shù)當(dāng)做參數(shù)或者把函數(shù)當(dāng)做返回值的函數(shù),就是高階函數(shù)
閉包
變量作用域
變量根據(jù)作用域的不同分為兩種:全局變量和局部變量。函數(shù)內(nèi)部可以使用全局變量。函數(shù)外部不可以使用局部變量。當(dāng)函數(shù)執(zhí)行完畢,本作用域內(nèi)的局部變量會(huì)銷毀。什么是閉包
閉包作用:延伸變量的作用范圍。
閉包(closure)指有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù)。【很多種解釋,都并不權(quán)威】
簡(jiǎn)單理解就是,一個(gè)作用域可以訪問另外一個(gè)函數(shù)內(nèi)部的局部變量。
<script>function fn1(){// fn1 就是閉包函數(shù)var num = 10;function fn2(){console.log(num); // 10}fn2()}fn1(); </script>思考:如何再函數(shù)外面訪問到函數(shù)內(nèi)部的變量
function fn () { var i = 7;return function () {console.log(i);}// function fn1 () {// console.log(i);// }// fn1(); } var n = fn(); n();練習(xí):
注冊(cè)事件練習(xí):打印索引值
var lis = document.querySelectorAll('li'); for (var i = 0; i < lis.length; i++) {(function (index) {lis[index].onclick = function () {console.log(index);}})(i); }? 
 ? 
 思考題:
遞歸
什么是遞歸
遞歸:**如果一個(gè)函數(shù)在內(nèi)部可以調(diào)用其本身,那么這個(gè)函數(shù)就是遞歸函數(shù)。簡(jiǎn)單理解:函數(shù)內(nèi)部自己調(diào)用自己, 這個(gè)函數(shù)就是遞歸函數(shù)函數(shù)的遞歸,遞歸函數(shù)遞歸:函數(shù)調(diào)用函數(shù)其本身**注意:**遞歸函數(shù)的作用和循環(huán)效果一樣,由于遞歸很容易發(fā)生“棧溢出”錯(cuò)誤(stack overflow),所以必須要加退出條件return。練習(xí):
利用遞歸求1~n的任意一個(gè)數(shù)的階乘//利用遞歸函數(shù)求1~n的階乘 1 * 2 * 3 * 4 * ..nfunction fn(n) {if (n == 1) { //結(jié)束條件return 1;}return n * fn(n - 1);}console.log(fn(3)); 利用遞歸求斐波那契數(shù)列// 利用遞歸函數(shù)求斐波那契數(shù)列(兔子序列) 1、1、2、3、5、8、13、21... // 用戶輸入一個(gè)數(shù)字 n 就可以求出 這個(gè)數(shù)字對(duì)應(yīng)的兔子序列值 // 我們只需要知道用戶輸入的n 的前面兩項(xiàng)(n-1 n-2)就可以計(jì)算出n 對(duì)應(yīng)的序列值 function fb(n) {if (n === 1 || n === 2) {return 1;}return fb(n - 1) + fb(n - 2); } console.log(fb(3));思考題羊村:50人家,每戶一只羊每戶只能看別人家的羊有木有病每戶只能殺自己家的羊第一天,第二天 ,第三天,砰砰砰幾聲槍響,問殺了幾只羊 利用遞歸遍歷數(shù)據(jù)var data = [{id : 1,name : '家電'},{id : 2,name : '服飾'}];var data = [{id: 1,name: '家電',goods: [{id: 11,gname: '冰箱',goods: [{id: 111,gname: '海爾'}, {id: 112,gname: '美的'},]}, {id: 12,gname: '洗衣機(jī)'}]}, {id: 2,name: '服飾' }]; //1.利用 forEach 去遍歷里面的每一個(gè)對(duì)象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;// 2. 我們想要得里層的數(shù)據(jù) 11 12 可以利用遞歸函數(shù)// 里面應(yīng)該有g(shù)oods這個(gè)數(shù)組并且數(shù)組的長(zhǎng)度不為 0 } else if (item.goods && item.goods.length > 0) {o = getID(item.goods, id);}});return o; }深拷貝和淺拷貝
? 拷貝不能直接賦值,對(duì)象賦值的是地址
var obj = {name : '張三豐',age : 22}; var newObj = obj; console.log(newObj);淺拷貝:
只拷貝最外面一層
var obj = {name : '張三豐',age : 22};var newObj = {};for (key in obj) {newObj[key] = obj[key];}console.log(newObj);es6:新方法Object.assign(target, sources);console.log(newObj);深拷貝
var obj = {name : '1張三豐',age : 22,messige : {sex : '男',score : 16},color : ['red','purple','qing']}var newObj = {};function kaobei (newObj,obj) {for (key in obj) {if (obj[key] instanceof Array) {newObj[key] = [];kaobei(newObj[key],obj[key]);} else if (obj[key] instanceof Object) {newObj[key] = {};kaobei(newObj[key],obj[key])} else {newObj[key] = obj[key];}}}obj.messige.sex = 99;kaobei(newObj,obj);console.log(newObj);總結(jié)