本篇介紹javascript函數的相關概念javascript
var fn = function(){
console.log(1)
}
複製代碼
function fnf(){
console.log(1)
}
複製代碼
傳遞參數 參數名稱,參數字符串java
var fnc = new Function('name','age','console.log(name,age)');
fnc('33',33)
複製代碼
var + 函數名字
,而=後的做爲參數進行賦值操做function
定義的函數,在變量提高的時候會總體進行提高;//函數表達式
console.log('--函數表達式開始-',fn)
var fn = function(){
console.log(1)
}
console.log('--函數表達式結束-',fn)
/** 函數fun */
console.log('--function開始-',fnf)
function fnf(){
console.log(1)
}
console.log('--function結束-',fnf)
複製代碼
具名函數是有函數名字的函數,面試
var fnNameFn = function(){}
function fnNameFn2(){}
console.log(fnNameFn.prototype)
複製代碼
無函數名稱、如當即執行函數,ajax
(function(){ }())
複製代碼
箭頭函數涉及的內容比較多,最多見的就是this指向的問題。箭頭函數最多見的使用場景就是回調函數了編程
let arrowFun = ()=>{}
console.log(arrowFun.prototype) // undefined
複製代碼
箭頭函數的定義格式瀏覽器
// 直接返回值
let arrfn = ()=> 2;
console.log(arrfn())
//傳遞參數進行判斷
let arrfn2 = (name)=> name !='mfy';
console.log(arrfn2())
複製代碼
函數的參數分爲實參
和形參
markdown
function add(num1,num2){} // num1 、num2是形參
var a=1,b=3;
add(a,b) // a,b 爲實參
複製代碼
let funMfy =function(){
console.log(arguments)
}
funMfy('mfy','23')
//箭頭函數
let fnnn = ()=>{
console.log(arguments)
}
fnnn('mfy',33) //報錯
複製代碼
let fyy = function(...args){
console.log(args)
}
fyy('mfy',32,[])
複製代碼
函數的使用在js中很是很是多了,其實如下的相關介紹,無非就是在基礎函數中進行變換和使用纔有了下面的名此閉包
一個函數和對其周圍狀態(lexical environment,詞法環境)
的引用捆綁在一塊兒(或者說函數被引用包圍),這樣的組合就是閉包(closure)
。也就是說,閉包讓你能夠在一個內層函數中訪問到其外層函數的做用域。在 JavaScript
中,每當建立一個函數,閉包就會在函數建立的同時被建立出來。app
function clouser(){
let a = '666'
return function(){
console.log(a)
}
}
let bfn = clouser();
bfn();//666
複製代碼
擴展知識點:變量提高
做用域
閉包應用:工廠函數
當即執行函數
框架
高階函數(higher-order-function)指操做函數的函數
,通常地,有如下兩種狀況:
javascript
中的函數顯然知足高階函數的條件,在實際開發中,不管是將函數看成參數傳遞,仍是讓函數的執行結果返回另一個函數,這兩種情形都有不少應用場景。下面將對這兩種狀況進行詳細介紹;
把函數看成參數傳遞,表明能夠抽離出一部分容易變化的業務邏輯,把這部分業務邏輯放在函數參數中,這樣一來能夠分離業務代碼中變化與不變的部分。其中一個常見的應用場景就是回調函數。
回調函數是最多見的參數傳遞了在ajax異步請求的應用中,回調函數的使用很是頻繁。想在ajax請求返回以後作一些事情,但又並不知道請求返回的確切時間時,最多見的方案就是把callback函數
看成參數傳入發起ajax請求的方法中,待請求完成以後執行callback函數
;
function ajax(callback){
$.ajax( 'http://xx.com/getUserInfo?' + userId, function( data ){
//不肯定何時返回,進行回調執行
if ( typeof callback === 'function' ){
callback( data );
}
});
}
複製代碼
不少框架已經異步處理的時候都使用了函數做爲參數傳入 Vue的this.nextTick
、React 的setState
閉包
、 工廠函數
、
function People(){}
function Factort(){
var instance = null
return function(){
if(!instance)
instance = new People();
}
return instance;
}
複製代碼
函數的柯里化(currying)
又稱部分求值。一個currying的函數首先會接受一些參數,接受了這些參數以後,該函數並不會當即求值,而是繼續返回另一個函數,剛纔傳入的參數在函數造成的閉包中被保存起來。待到函數被真正須要求值的時候,以前傳入的全部參數都會被一次性用於求值.簡稱閉包;
//通用的柯里化函數
var curring = function(fn){
var args = [];
return function(){
if(arguments.length ==0){
return fn.apply(this,args);
}else{
[].push.apply(args,arguments);
}
}
}
var cost1 = (function(){
var money = 0;
return function(){
for(var i=0;i<arguments.length;i++){
money+=arguments[i]
}
return money;
}
})()
var cost3 = curring(cost1);
cost3(100);
cost3(200);
cost3(100);
console.log(cost3())
複製代碼
傳遞多個參數時候
/** * 求值柯里化 */
var curring3= function(fn){
//獲取fn外的其餘參數
var args = [].slice.call(arguments,1);
return function(){
// 獲取fn的全部參數
var innerArgs =[].slice.call(arguments);
// 最終參數列表重合展開
var finnalArgs = args.concat(innerArgs);
//將參數列表展開,並傳入fn中
return fn.apply(null,finnalArgs)
}
}
var cost6 = (function(){
var money = 0;
return function () {
for (var i = 0, l = arguments.length; i < l; i++) {
money += arguments[i];
}
return money;
}
})()
var costC = curring3(cost6,300,233);
console.log(costC(44))
console.log(costC(2003,444))
複製代碼
Array.prototype
上的方法本來只能用來操做array對象。但用call和apply能夠把任意對象看成this傳入某個方法,這樣一來,方法中用到this的地方就再也不侷限於原來規定的對象,而是加以泛化並獲得更廣的適用性
有沒有辦法把泛化this的過程提取出來呢?反柯里化(uncurrying)就是用來解決這個問題的。反柯里化主要用於擴大適用範圍,建立一個應用範圍更廣的函數。使原本只有特定對象才適用的方法,擴展到更多的對象。
Function.prototype.unCurring=function(){
var _this = this;
return function(){
var obj = Array.prototype.shift.call(arguments);
return _this.apply(obj,arguments); //更改當前的this指向
}
}
//另外一種方法實現
Function.prototype.currying = function() {
var _this = this;
return function() {
return Function.prototype.call.apply(_this, arguments);
}
}
複製代碼
遞歸函數則是本身調用本身自己,最多見的一個就是對象的深拷貝
以及斐波那契
惰性函數
表示函數執行的分支只會在函數第一次調用的時候執行,在第一次調用過程當中,該函數會被覆蓋爲另外一個按照合適方式執行的函數,這樣任何對原函數的調用就不用再通過執行的分支了。
javascript
的瀏覽器事件兼容
function addEvent(type, element, fun) {
if (element.addEventListener) {
element.addEventListener(type, fun, false);
}
else if(element.attachEvent){
element.attachEvent('on' + type, fun);
}
else{
element['on' + type] = fun;
}
}
//添加事件
//第一次綁定
var ele = document.getElementById("bind-event");
addEvent('bind-event',ele,()=>{
console.log(111)
});
//第二次綁定
var ele1= document.getElementById("bind-event2");
addEvent('click',ele1,()=>{
console.log(222)
})
複製代碼
咱們每次綁定的時候都回去判斷當前是否支持,而在一個瀏覽器中,咱們只須要進行判斷一次便可;
惰性函數的本質就是函數重寫
,所謂惰性載入,指函數執行的分支只會發生一次,有兩種實現惰性載入的方式;
function addEvent(type, element, fun){
if (element.addEventListener) {
addEvent = function(type, element, fun){
element.addEventListener(type, fun, false);
}
}else if(element.attachEvent){
addEvent = function(type, element, fun){
element.attachEvent('on' + type, fun);
}
}else{
addEvent =function(type,element,fun){
element['on' + type] = fun;
}
}
return addEvent(type, element, fun)
}
複製代碼
在這個惰性載入的addEvent()
中,if語句的每一個分支都會爲addEvent變量賦值,有效覆蓋了原函數。最後一步即是調用了新賦函數。下一次調用addEvent()
時,便會直接調用新賦值的函數,這樣就不用再執行if語句了;
var addEvent = (function () {
if (document.addEventListener) {
return function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if (document.attachEvent) {
return function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else {
return function (type, element, fun) {
element['on' + type] = fun;
}
}
})();
複製代碼
簡單來講,一個函數的返回結果只依賴於它的參數,而且在執行過程裏面沒有反作用,咱們就把這個函數叫作純函數
。這麼說確定比較抽象,咱們把它掰開來看:
var a =1;
function ac(b){
return a+b
}
複製代碼
此時不是純函數,由於此時函數的結果依賴的函數外部的變量a
;
const a = 1
const foo = (x, b) => x + b
foo(1, 2) // => 3
複製代碼
此時函數依賴函數傳遞過來的參數,當傳遞的參數爲1,2的時候,不管如何都不會改變函數傳出的結果 一個函數的返回結果只依賴於它的參數。
👉🏻 引用類型數據 看成參數傳入的時候,若是內部更改了引用類型的數據,那麼他就不是純函數
,由於出現了反作用;
這個高頻點,另分出來進行解釋
-《javascript 高級程序設計第四版》