在JavaScript中,函數是一等公民。JavaScript是一門面向對象的編程語言,可是同時也有不少函數式編程的特性,如Lambda表達式,閉包,高階函數等,函數式編程時一種編程範式。前端
function dada() {
var a = 1;
var b = function() {
console.log(a);
}
return b
// b 就是一個閉包函數,由於它能訪問dada函數的做用域
}複製代碼
JavaScript的函數也是對象,能夠有屬性,能夠賦值給一個變量,能夠放在數組裏做爲元素,能夠做爲其餘對象的屬性,什麼均可以作,別的對象能作的它也能作,別的對象不能作的它也能作。ajax
函數和其餘普通對象來講,是同樣的,有屬性有方法,普通對象能作的,函數也能作。學習JavaScript中的閉包和高級函數是基礎篇哦!算法
那麼什麼是閉包?閉包,就是有權訪問其外部做用域中的變量和參數的函數。編程
var func = (function() {
var item = 0;
return {
add: function(num) {
item += typeof num === 'number' ? num : 1;
},
value: function() {
return item;
}
}
})();複製代碼
閉包函數能夠訪問它建立時所處的上下文環境中的變量以及參數,this以及arguments除外。設計模式
閉包:數組
函數做爲返回值,高階函數除了能夠接受函數做爲參數外,還能夠把函數做爲結果值返回。閉包的造成與變量的做用於和變量的生命週期密切相關。緩存
變量做用域:網絡
var func = function() {
var a = 1;
console.log(a); // 1
}
func();
console.log(a); // Uncaught ReferenceError: a is not defined複製代碼
閉包是一個能夠訪問到其餘函數內部變量的函數,閉包的重點在於,變量的做用域,和,變量的生命週期。數據結構
變量的做用域閉包
// 變量的做用域
var my = function() {
var a = 1;
console.log('my', a); // 1
}
my();
console.log(a) // ReferenceError: a is not defined複製代碼
變量的聲明週期
// 變量的生命週期
let fu = function() {
let a = 0;
a++;
console.log('dada', a);
}
fu(); // 1
fu(); // 1
fu(); // 1
let func = function() {
let a = 0;
return function() {
a++;
console.log('a', a);
}
}
let fun = func()
fun(); // 1
fun(); // 2
fun(); // 3複製代碼
閉包中的變量沒有被銷燬,這個涉及到垃圾回收機制,即標記清楚和引用計數
function num() {
for(var i=0; i< 10; i++) {
setTimeout(function() {
console.log('da', i) // 10
},0)
}
}
num();
function num1() {
for(var i=0; i< 10; i++) {
(function (i) {
setTimeout(function() {
console.log('da', i)
},0)
})(i) // 1,2,3,...,10
}
}
num1()
複製代碼
什麼是閉包的例子:
function da() {
var a = 1;
function dada() {
console.log(a);
}
return dada
}
var d = da();
d(); // 1複製代碼
閉包若是不是那麼必要,請不要去建立它,因閉包在處理速度和內存消耗方面對性能具備負面影響。
閉包的形式與變量的做用域以及變量的生存週期有着密切的相關性。
變量的做用域:
變量的做用域指的是變量的有效範圍,當一個函數中聲明的一個變量不帶上關鍵字var的時候,這個變量就成爲了全局變量,當這個變量用var聲明的時候,這個變量就變成了局部變量,只有在函數內部才能訪問到這個變量,在函數外面是訪問不到的。舉例:
var func = function() {
var a = 1;
alert(a); // 1
};
func();
alert(a); // Uncaught ReferenceError: a is not defined複製代碼
嵌套例子:
var a = 1;
var fun = function() {
var b = 2;
var func1 = function() {
var c = 3;
alert(b); // 2
alert(a); // 1
}
func1();
alert(c); // c is not defined
};
fun();複製代碼
變量的生命週期:
閉包的又一重要概念,變量的生命週期,對於全局變量的生命週期來講是永久的,對於函數內部的局部變量來講,是短暫的,它們都會隨着調用的結束而被銷燬。
var func = function() {
var a = 1;
};
func();複製代碼
var func = function() {
var a = 1;
return function() {
a++;
alert(a);
}
};
var da = func();
da(); // 2
da(); // 3
da(); // 4複製代碼
閉包
函數做爲返回值
function num(arr) {
return arr.reduce(function (x,y) {
return x + y;
});
}
num([1,2,3]); // 6複製代碼
變成函數
function func(arr) {
var sum = function() {
return arr.reduce(function(x,y) {
return x + y;
});
}
return sum;
}
// 調用 函數
var da = func([1,2,3]); // 調用函數
// 運行
da(); // 6
複製代碼
var da1 = func([1,2]);
var da2 = func([1,2]);
da1 == da2 // false複製代碼
每次調用返回的都是一個新的函數
利用閉包進行緩存:
function add(a) {
return a + 1;
}複製代碼
利用閉包進行緩存:
閉包的做用
封裝變量,閉包能夠封裝造成私有變量:
var da = function() {
var a = 1;
for (var i=0; i < arguments.length; i++){
a = a * arguments[i];
}
return a;
}
alert(a(1,2,3));複製代碼
在JavaScript中是沒有塊級做用域的概念的:
function add() {
var arr = [ 1,2,3 ];
for (var i=0; i < arr.length; i++) {
alert( arr[i]);
}
var i; // 從新聲明變量
alert(i);
}複製代碼
塊級做用域效果,閉包:
(function() {
// 塊級做用域
})()複製代碼
延續局部變量的生命週期:
var myImg = function( src ) {
var img = new Image(0;
img.src = src;
};
myImg('http:///...');複製代碼
解決請求丟失問題:
var da = (function() {
var imgs = [];
return function(src) {
var img = new Image();
imgs.push(img);
img.src = src;
}
})();複製代碼
閉包是指有權訪問另外一個函數做用域中變量的函數。
閉包:函數對象能夠經過做用域關聯起來,函數體內的變量均可以保存在函數做用域內。
詞法做用域:做用域是在編寫代碼的時候肯定的動態做用域:做用域是在代碼運行的時候肯定的
<script>
function add(num){
var sum = 5;
return sum + num;
}
var sum = add(4);
</script>複製代碼
Execution Contexts = {
variable object:變量對象;
this value: this指針;
scope chain:做用域鏈;
}複製代碼
全局變量
function myFunction() {
var a = 4;
return a * a;
}複製代碼
var a = 4;
function myFunction() {
return a * a;
}複製代碼
var counter = 0;
function add() {
return counter += 1;
}
add();
add();
add();
// 計數器如今爲 3複製代碼
function add() {
var counter = 0;
return counter += 1;
}
add();
add();
add();
// 本意是想輸出 3, 但事與願違,輸出的都是 1 !複製代碼
function outter(){
var sky="blue";
function inner(){
console.log(sky);
}
return inner;
}
var result=outter();
result(); //"blue"複製代碼
函數與對其狀態即爲詞法環境的引用共同構成閉包,也就是,閉包可讓你從內部函數訪問外部函數做用域。
詞法做用域:
function init() {
var name = "dada";
// name 是一個被 init 建立的局部變量
function displayName() {
// displayName() 是內部函數,一個閉包
alert(name);
// 使用了父函數中聲明的變量
}
displayName();
}
init();複製代碼
閉包:
function mFunc() {
var name = "dada";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = mFunc();
myFunc();複製代碼
高階函數
什麼是高階函數,JavaScript中的函數都指向某個變量,既然變量能夠指向函數,函數的參數能接收變量,那麼一個函數就能夠接收另外一個函數做爲參數,就叫高階函數。
高級函數:
function add(x, y, f) {
return f(x) + f(y);
}複製代碼
'use strict';
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow);
// [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);複製代碼
var f = function (x) {
return x * x;
};
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var result = [];
for (var i=0; i<arr.length; i++) {
result.push(f(arr[i]));
}複製代碼
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
});
// 25複製代碼
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x * 10 + y;
});
// 13579複製代碼
在一個數組中,刪除偶數,保留奇數:
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
r;
// [1, 5, 9, 15]複製代碼
回調函數
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element);
// 依次打印'A', 'B', 'C'
console.log(index);
// 依次打印0, 1, 2
console.log(self);
// self就是變量arr
return true;
});複製代碼
'use strict';
var arr = [10, 20, 1, 2];複製代碼
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr);
// [1, 2, 10, 20]複製代碼
var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1;
// ['A', 'B', 'C']
a2;
// ['A', 'B', 'C']
a1 === a2;
// true, a1和a2是同一對象複製代碼
every()方法能夠判斷數組的全部元素是否知足測試條件
find()方法用於查找符合條件的第一個元素
findIndex()方法返回這個元素的索引
高階函數即爲輸入參數裏有函數,或是輸出是函數的函數
function add() {
var num = 0
return function(a) {
return num = num + a
}
}
var adder = add()
adder(1)
// 輸出: 1
adder(2)
// 輸出: 3複製代碼
高階函數知足條件:函數做爲參數被傳遞,函數做爲返回值輸出
回調函數:
var getUserInfo = function( userId, callback ){
$.ajax( 'http://xxx.com/getUserInfo?' + userId, function( data ){
if ( typeof callback === 'function' ){
callback( data );
}
});
}
getUserInfo( 522624714, function( data ){
alert ( data.userName );
});複製代碼
//從小到大排列
[ 1, 5, 3 ].sort( function( a, b ){
return a - b;
});
// 輸出: [ 1, 3, 5 ]
//從大到小排列
[ 1, 5, 3 ].sort( function( a, b ){
return b - a;
});
// 輸出: [ 5, 3, 1 ]複製代碼
什麼是函數式編程,函數式編程時一種編程形式,讓你能將函數做爲參數傳遞給其餘函數而且可以將函數做爲值返回。
在JavaScript中,函數是一類特殊的對象:
function hello() {
console.log('hello');
}
hello();複製代碼
hello.name='da';
console.log(hello.name); // da複製代碼
const num = function(x) {
return x*x;
}
num(8); // 64複製代碼
高階函數是一個函數,它是接收函數做爲參數或者是將函數做爲輸出的值進行返回。高階函數實戰:
const arr1 = [1,2,3];
const arr2 = arr1.map(function(x) {
return x * 2;
});
console.log(arr2);複製代碼
const arr1 = [1,2,3];
const arr2 = arr1.map(x => x*2);複製代碼
結語
簡而言之,高階函數是一個函數,它是能夠接受函數做爲參數,還能夠做爲返回一個值返回,返回一個函數。閉包可讓你從內部函數訪問外部函數做用域。閉包便是一個函數,可以訪問另外一個函數做用域的變量的函數。
關於目前文章內容即涉及前端,PHP知識點,若是有興趣便可關注,很榮幸,能被您發現,真是慧眼識英!也感謝您的關注,在將來的日子裏,但願可以一直默默的支持我,我也會努力寫出更多優秀的做品。咱們一塊兒成長,從零基礎學編程,將 Web前端領域、數據結構與算法、網絡原理等通俗易懂的呈現給小夥伴。分享 Web 前端相關的技術文章、工具資源、精選課程、熱點資訊。
推薦閱讀
一、你知道多少this,new,bind,call,apply?那我告訴你
二、爲何學習JavaScript設計模式,由於它是核心
意見反饋:若本號內容有作得不到位的地方(好比:涉及版權或其餘問題),請及時聯繫咱們進行整改便可,會在第一時間進行處理。
感謝閱讀,原創不易,喜歡就點個贊吧,這是我寫做最大的動力。
這是一個有質量,有態度的博客