帶你學習javascript的函數進階(二)

上一篇文章分享了《帶你學習Javascript中的函數進階(一)》,今天繼續學習javascript的函數進階的內容。


1 嚴格模式

1.1 什麼是嚴格模式

JavaScript除了提供正常模式外,還提供了嚴格模式(strict mode)。ES5的嚴格模式是採用具有限制性Javascript變體的一種方式。即在嚴格的條件下運行js代碼。
嚴格模式在IE10以上版本的瀏覽器中才會被支持,舊版本瀏覽器會被忽略。
嚴格模式對正常的javascript語義做了一些更改:

  1. 消除了Javascrip語法的一些不合理、不嚴謹之處,減少了一些怪異行爲。
  2. 消除了代碼運行的一些不安全之處,保證代碼運行的安全。
  3. 提高編譯器效率,增加運行速度。
  4. 禁用了在ECMAScript的未來版本中可能會定義的一些語法,爲未來新版本的Javascript做好鋪墊。比

如一些保留字:class,enum,export,extends,import,super不能做變量。

1.2 開啓嚴格模式

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

  1. 爲腳本整個腳本開啓嚴格模式

爲整個腳步文件開啓嚴格模式,需要在所有語句之前做一個特定語句"use strict"

<scirpt>
  "use strict"
	console.log("這是最嚴格模式")
 </scirpt>
  1. 爲函數開啓嚴格模式

要給某個函數開啓嚴格模式,需要把"use strict";(或’use strict’)聲明放在函數體所有語句前。

<script>
 	function fn() {
		'use strict' //下面的代碼按照嚴格模式進行
	} 
 </script>

3.3 嚴格模式中的變化

嚴格模式對javascript的語
法和行爲,都做了一些改變

  1. 變量規定
  • 在正常模式中,如果一個變量沒有聲明就賦值,默認的事全局變量。
  • var 命令聲明,然後再使用
<script>
  ‘use strict’
	num = 10
	console.log(num)
 </script>

效果如下圖
image.png
嚴禁刪除已經聲明的變量。

  1. 嚴格模式下this指向問題
  • 以前在全局作用域函數中的this指向window對象。
  • 嚴格模式下全局作用域中函數中的this事undefined。
  • 以前構造函數時不加new也可以調用,當普通函數,this指向全局對象。
  • 嚴格模式下,如果構造函數不加new調用,this會報錯。 new實例化的構造函數指向創建的對象實例。
  • 嚴格模式下,定時器裏的this指向還是window.
  • 嚴格模式下,事件、對象還是指向調用者。
  1. 函數變化
  • 嚴格模式下函數不能有重名的參數
  • 函數必須聲明在頂層,新版本的js會引入“塊級作用域”(ES6中已引入)。爲了與新版本接軌,不允許在非函數的代碼塊內聲明函數,如在if,for語句中聲明函數。

2 高階函數

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

function fn(callback) {
	callback && callback()
}
fn(function(){
	alert('lanfeng')
})
function fn() {
	return function() {
  }
}
fn()

此時fn就是一個高階函數
函數也是一種數據類型,同樣可以作爲參數,傳遞給另外一個參數使用,最典型的就是作爲回調函數

3 閉包

3.1 變量作用域

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

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

3.2 什麼是閉包

閉包指有權訪問另外一個函數作用域中變量的函數。也就是說,一個作用域可以訪問另外一個函數內部的局部變量。

//fn 外面的作用域可以訪問fn內部的局部變量
function fn() {
	var num = 10
  function fun () {
  	console.log(num) //可以訪問num
  }
  return fun
}
var f = fn()
f() //10
//fn 外面的作用域可以訪問fn內部的局部變量
function fn() {
	var num = 10
  
  // 返回一個匿名函數
  return function() { 
  	console.log(num) //可以訪問num
  }
}
var f = fn()
f() //10

閉包的主要作用: 延伸了變量的作用範圍

3.3 閉包案例

  1. 循環註冊點擊事件
//html
<ul class="nav">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
</ul>
//js
//點擊li輸出當前li的索引
//利用動態田徑屬性方式
var lis = document.querySelector('.nav').querySelectorAll('li')
for(var i=0 ;i<lis.length; i++) {
  lis.index = i
	lis[i].onclick = function() {
  	console.log(this.index)
  }
}
//利用閉包的方式
var lis = document.querySelector('.nav').querySelectorAll('li')
for(var i=0 ;i<lis.length; i++) {
  (function(i) {
  	lis[i].onclick = function() {
  	console.log(i)
  }
  })(i)
	
}
  1. 循環中的setTimeout()
//html
<ul class="nav">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
</ul>
//js
//利用閉包
var lis = document.querySelector('.nav').querySelectorAll('li')
for(var i=0 ;i<lis.length; i++) {
  (function(i){
  	setTimeout(function() {
    	console.log(lis[i].innerHTML)
    },3000)
  })(i)
}
  1. 計算打車價格
var car =function() {
		var start = 13;
    var total = 0;
  return {
    //正常價格
  		price: function(n) {
      	if(n <= 3) {
        	total = start
        } else {
        	total = start + (n-3)* 5
        	}
        return total;
      }, 
    	// 擁堵之後
    	yd: function(flag) {
      	flag? total+ 10 :total
      } 
  	}
	}()
console.log(car.price(5))
console.log(car.yd(true))

3.4 閉包總結

  1. 閉包是什麼?

閉包就是一個函數(一個作用域可以訪問另外一個函數的局部變量)

  1. 閉包的作用是什麼?

延伸變量的作用範圍

4 遞歸

4.1 什麼是遞歸

如果一個函數在內部可以調用其本身,那麼這個函數就是遞歸函數。
遞歸函數的作用和循環效果一樣
由於遞歸很容易發生“棧溢出”(stack overflow),所以必須要加退出條件 return

4.2 利用遞歸求數學題

  1. 求123…*n
function fn(n) {
  if(n = 1) {
  	return 1
  }
	return n * fn(n-1)
}
console.log(fn(3)) // 6

4.3 利用遞歸求:根據id返回對應的數據對象

var data = [{
	id:1,
  name:'家電',
  goods: [
    {
      id: 11,
      gname: '冰箱'
    },
    {
    	id: 12,
      gname: '洗衣機'
    }
  ]
},
            {
            id: 2,
              name: '服飾'
            }
 ]
function getObj(arr, id) {
  var o = {}
	arr.forEach(function(item){
  	if(item.id === id) {
    	o= item
    } else if(item.goods && item.goods.length>0) {
    		o =getObj(item.goods, id);
    }
  })
  return o
}
console.log(getObj(data, 1))

5 遞歸

5.1 淺拷貝和深拷貝

  1. 淺拷貝只是拷貝一層,更深層次對象級別的只拷貝引用。
  2. 深拷貝拷貝多層,每一級別的數據都會拷貝。
  3. Object.assign(target, …sources) es6新增方法可以淺拷貝
var obj = {
	id: 1,
  name: 'andy',
  msg: {
   age: 18
  }
}
var o = {}
for(var k in obj) {
  // k是屬性名
	o[k] = obj[k]
}
console.log(o)
o.msg.age = 20
console.log(obj) //obj發生變化

//用es6語法糖
Object.assign(o, obj)

image.png

//深拷貝,應用遞歸的方法
function deepCopy(newObj, oldObj) {
	for(var k in oldObj) {
  	//判斷我們的屬性值屬於哪種類型
    var item = oldObj[k]
    // 判斷是否是數組
    if(item instanceof Array) {
    	newObj[k] = []
      deepCopy(newObj[k], item)
      
    } else if(item instanceof Object) {
      //判斷是否是對象
      newObj[k] = {}
      deepCopy(newObj[k], item)
    } else { // 屬於簡單數據類型
    	 newObj[k] = item
    }  
    
  }
}
deepCopy(o,obj)
console.log(o)

總結

本篇文章主要分享了函數的嚴格模式、高階函數、閉包、遞歸、深拷貝、淺拷貝等知識點的用法及應用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章