我們知道,js函數有多種寫法,函數聲明 ,函數表達式,Function式構造函數,自執行函數,包括Es6的箭頭函數,Class類寫法,高階函數,函數節流/函數防抖,下麵我就開始講關於上面幾種類型的最基本用法。 函數聲明式寫法 這種寫法是最基本的寫法 ,使用關鍵字 function 定義函數,函數聲明 ...
我們知道,js函數有多種寫法,函數聲明 ,函數表達式,Function式構造函數,自執行函數,包括Es6的箭頭函數,Class類寫法,高階函數,函數節流/函數防抖,下麵我就開始講關於上面幾種類型的最基本用法。
函數聲明式寫法
這種寫法是最基本的寫法 ,使用關鍵字 function 定義函數,函數聲明後不會立即執行,會在我們需要的時候調用到。這種函數是全局的,如果有兩個同名的聲明式函數存在,那麼第二個會覆蓋第一個。
function Test(){ }
有個面試題如下,問輸出:
function test1(){ alert('test1') } ; test1() ; function test1(){ alert('test2') } ;
答案是:'test2'
函數表達式寫法
定義一個變數,指向一個函數,其實可以看做是一個匿名函數。這種函數在聲明之後才能調用,在聲明之前調用會報錯。
var test=function(){ }
有個面試題如下,問輸出:
var test=function(){ alert('test1') } ; test() ; var test=function(){ alert('test2') } ;
答案是:test1
Function式構造函數
通過 JavaScript 函數構造器(Function())實例化來定義函數,前面定義各種變數,最後定義函數的返回值或者是輸出,這種函數不太常用。
var test= new Function("a", "b", "return a * b");
test();
自執行函數
這種函數沒有名稱,只有聲明體,實際上是一個 匿名自我調用的函數。這種函數的好處是保持變數獨立,不被外部變數污染,形成一個封閉的函數執行環境。
寫法如下:
(function(){ })(); 這種寫法比較常見,比如Jquery框架裡面就用到這種寫法: ‘use strict’; ;(function(context,win){
})(Jquery||undefined,window)
還有像閉包的寫法,經常會遇到像下麵類似的面試題的寫法:
var divs=tr.getElementsByTagName("div"); for(var i=0;i<divs.length;i++){ (function(div){ div.onclick=function(){ alert(this.innerHTML); } })(divs[i]) }
箭頭函數
這種聲明方式是Es6引入的寫法,箭頭函數是簡寫形式的函數表達式,並且它的內部的this指向的不是自己,指向的是當前執行環境的頂級對象(如window,react組件中指向的是當前組件的class父級組件),箭頭函數總是匿名的。寫法如下:
const test=()=>{ }
比如下麵的函數中的this指向的是window
const test={ array:[1,2], show:()=>{ console.log(this. array) } } test.show();//undefined
而下麵react組件的onSearch中的this指向的是Test這個組件,通過this可以找到Test組件下麵定義的函數或者state,props。註意constructor中註釋的代碼是為了將onSearch的this指向Test組件,和箭頭函數是兩個不同寫法,但是有同等效果。
import {Button} from 'antd' class Test extends Component { constructor(props) { super(props); //this.onSearch = this.onSearch.bind(this) } //onSearch(){ console.log(this); //} onSearch=()=>{ console.log(this); } render() { return ( < div > <Button onClick={this.onSearch}>測試</Button> < /div> ) } }
Class類寫法
Js之前是沒有類的概念的,之前都是將一些屬性掛載在函數的實例上或者通過原型來實現基於函數的類的概念。就比如下麵的寫法
function Test (){ this.name=’’; //this.show=function(){ //} } Test.prototype.show=function(){ Console.log(this.name) } new Test().show();
ES6引入了Class(類)這個概念,作為對象的模板,通過class關鍵字,可以定義類。基本上,ES6的class可以看作只是一個語法糖,它的絕大部分功能,ES5都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法.
基本寫法:
class test { //第一種 Show() { alert('show'); } //第二種 //Show=()=>{ //} } var test1 = new test(); var test2= new test();
註意這個類中的這兩種方法的寫法是有區別的
第一種聲明的方法會指向test的原型prototype上
test1. Show=== test2.Show//true
第二種聲明的方法會指向test的實例,每次實例化都會生成一個Show方法。
test1. Show=== test2.Show//false
繼承寫法如下,這樣newTest 就會繼承test中的Show
class newTest extends test{ Show() { super. Show(); alert('newshow'); } } var test=new newTest (); test. Show()
如果newTest 中沒有聲明Show方法,就會調用父類test中的Show方法,如果申明瞭就會調用newTest 的Show方法。子級調用父級的方法用super關鍵字訪問如
super. Show();
- 高階函數
高階函數英文叫Higher-order function。JavaScript的函數其實都指向某個變數。既然變數可以指向函數,函數的參數能接收變數,那麼一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。簡單的說法就是“高階函數就是可以把函數作為參數,或者是將函數作為返回值的函數。”,其實最典型的應用就是回調函數了。
高階函數大致有下麵幾個場景
1.函數回調
$.get(‘’,{},function(data){ }) var test=function(callback){ callback.apply(this,arguments) }
2函數柯里化
在一個函數中首先填充幾個參數(然後再返回一個新函數)的技術稱為柯里化(Currying),這個定義可能有點難理解,先看下一個簡單的函數柯里化的實現:
var currency=function(fn){ var self=this; var arr=[]; return function(){ if(arguments.length==0){ return fn.apply(this,arr ); } else{ [].push.apply(arr,arguments); return arguments.callee; } } }
然後再看一下調用:
var sum=function(){ var total=0; var argArr=arguments; for (var i = 0; i < argArr.length; i++) { total+=argArr[i]; } return total; } var test= currency(sum); test(100,200); test(300) alert(test());
其實簡單的解釋就是currency函數裡面定義一個局部變數arr數組,然後返回一個函數,返回的函數體里對變數arr進行了賦值,每次當函數傳入參數的時候都會將參數push到arr裡面,然後返回函數體,形成了一個閉包。當沒有參數傳入的時候就直接執行傳入的sum函數,然後執行函數sum傳入的的參數就是arr.
3.函數擴展
函數擴展一般是通過原型來擴展,傳入一個回調函數,比如給Array擴展一個函數Filter代碼如下:
Array.prototype.Filter=function(callback){ ….. }
做過react 開發的都知道有高階組件的概念,其實高階組件是通過高階函數演變的,只不過傳入的參數是組件,然後返回值是一個組件,來看下麵的一段代碼
export default simpleHoc(Usual); import React, { Component } from 'react'; const simpleHoc = WrappedComponent => { console.log('simpleHoc'); return class extends Component { render() { return <WrappedComponent {...this.props}/> } } } export default simpleHoc;
函數節流/函數防抖
一般做前端時間比較長的人對這個概念比較熟了,但是剛接觸的人估計會有點懵逼。
這兩個概念都是優化高頻率執行js代碼的一種手段,來看下他們的基本概念
函數節流:函數在設定的時間間隔內最多執行一次
應用場景:高頻率點擊事件
var isEnable=true; document.getElementById("testSubmit").onclick=function(){ if(!isEnable){ return; } isEnable=false; setTimeout(function(){ console.log("函數節流測試"); isEnable = true; }, 500); }
函數防抖:函數在一段時間內不再被調用的時候執行
應用場景:onresize onscroll事件,oninput事件
Var timer=null; Window. onscroll=function(){ clearTimeout(timer); timer = setTimeout(function(){ console.log("函數防抖測試"); }, 500); }
從上面兩個事件可以看出來區別:
函數節流在第一次操作之後的500毫秒內再次點擊就只執行一次,不會重置定時器,不會重新計時
函數防抖是在持續觸發onscroll事件的時候會重置重置定時器,重新計時,直到不觸發事件的500毫秒之後執行一次
上面講的是函數最常見基本的用法,個人表述有不恰當的地方請指正