咱們知道,js函數有多種寫法,函數聲明 ,函數表達式,Function式構造函數,自執行函數,包括Es6的箭頭函數,Class類寫法,高階函數,函數節流/函數防抖,下面我就開始講關於上面幾種類型的最基本用法。javascript
函數聲明式寫法前端
這種寫法是最基本的寫法 ,使用關鍵字 function 定義函數,函數聲明後不會當即執行,會在咱們須要的時候調用到。這種函數是全局的,若是有兩個同名的聲明式函數存在,那麼第二個會覆蓋第一個。java
function Test(){ }
有個面試題以下,問輸出:react
function test1(){ alert('test1') } ; test1() ; function test1(){ alert('test2') } ;
答案是:'test2'面試
函數表達式寫法編程
定義一個變量,指向一個函數,其實能夠看作是一個匿名函數。這種函數在聲明以後才能調用,在聲明以前調用會報錯。數組
var test=function(){ }
有個面試題以下,問輸出:antd
var test=function(){ alert('test1') } ; test() ; var test=function(){ alert('test2') } ;
答案是:test1閉包
Function式構造函數app
經過 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毫秒以後執行一次
上面講的是函數最多見基本的用法,我的表述有不恰當的地方請指正