咱们知道,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毫秒以后执行一次
上面讲的是函数最多见基本的用法,我的表述有不恰当的地方请指正