javascript函式定義以及常見用法
我們知道,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毫秒之後執行一次
上面講的是函式最常見基本的用法,個人表述有不恰當的地方請指正