我们知道, 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 毫秒之后执行一次
上面讲的是函数最常见基本的用法, 个人表述有不恰当的地方请指正
来源: https://www.cnblogs.com/a546558309/p/9614436.html