JavaScript...Function类型...

zzrshuiwuhen 2019-06-28

Function类型

Function与函数

函数是这样一段JavaScript代码 它只定义一次 但可能被执行或调用多次
Function类型是JavaScript提供的引用类型之一 通过Function类型创建Function对象
在JavaScript中 函数也是以对象的形式存在的 每个函数都是一个Function对象
函数名 本质就是一个变量名 是指向某个Function对象的引用

// 1.函数声明方式
function fun(){
    console.log('this is function');
}
// 2.字面量方式
var fn = function(){
    console.log('this is function too');
}
// 判断函数是否为Function类型的
console.log(fun instanceof Function);// true
console.log(fn instanceof Function);// true
// JavaScript中所有的函数都是Function类型的对象

/*
    3.创建Function类型的对象 - 是一个函数
      var 函数名 = new Function(参数,函数体);
      * 由于函数的参数和函数体都是以字符串形式传递给Function的
  */
var f = new Function('a','console.log(a)');
f(100);// 以函数方式进行调用
  • Object与Function
// 1.Object与Function都是自身的类型
console.log(Object instanceof Object);// true
console.log(Function instanceof Function);// true
// 2.Object自身是构造函数,而构造函数也是函数,是函数都是Function类型
console.log(Object instanceof Function);// true
// 3.Function是引用类型,用于创建对象,是对象都是Object类型
console.log(Function instanceof Object);// true
  • 代码的执行流程
..变量的声明提前
console.log(v);//undefined
var v = 100;
//如果使用函数声明方式定义函数时 - 函数的声明提前
fun()
function fun(){
    console.log('this is function');
}

Function类型

  • Function的apply()方法

Function的apply()方法用于调用一个函数 并且接受指定的this值 以及一个数组作为参数

// 定义函数
function fun(value){
    console.log('this is ' + value);
}
// 函数的调用方式
fun('function');// 语法结构:函数名称()
/*
    apply(thisArg,argArray)方法 -> 用于调用一个指定函数
    * 参数
      * thisArg - this
      * argArray - 数组,作为参数(实参)的列表
  */
fun.apply(null, ['function']);
  • Function的call()方法

Function的call()方法用于调用一个函数 并且接受指定的this值作为参数 以及参数列表

//定义函数
function fun(value value2){
    console.log('this is' + value);
}
//函数的调用方式
fun('function','张三');//语法结构:函数名称()

fun.apply(null,['function','张三']);
//call()方法 - 用于调用一个函数
fun.call(null,'function','张三');
  • Function的bind()方法

Function的bind()方法用于创建一个新的函数(称为绑定函数) 并且接受指定的this值作为参数 以及参数列表

// 定义函数
function fun(value){
    console.log('this is ' + value);
}
/*
    bind(thisArg, arg1, arg2, ...)方法
    * 作用 - 用于创建一个新函数(称为绑定函数)
    * 参数
      * thisArg - this
      * arg1, arg2, ... - 表示参数列表
    * 返回值 - 返回新的函数
 */
// var f = fun.bind();// 相对于从指定函数复制一份出来

fun('李四');// this is 李四

var f = fun.bind(null, '张三');
f();// this is 张三
  • 重载是什么

在其他开发语言中 函数具有一种特性 叫做重载 重载就是定义多个同名的函数 但每一个函数接受的参数的个数不同 程序会根据用时传递的实参个数进行判断 具体调用的是哪个函数
但是在JaveScript中 函数是没有重载现象的 也就是说 如果同时定义多个同名的函数 只有最后一个定义的函数是有效的

/*
    重载的含义
    1.定义多个同名的函数,但具有数量不同的参数
    2.调用函数,根据传递参数的个数调用指定的函数
 */
function add(a,b){
    return a + b;
}
function add(a,b,c){
    return a + b + c;
}
function add(a,b,c,d){
    return a + b + c + d;
}

add(1,2);// 3
add(1,2,3);// 6
add(1,2,3,4);// 10

// JavaScript的函数不存在重载 -> 当函数同名时,最后一次定义的函数有效
console.log(add(1,2));// NaN
console.log(add(1,2,3));// NaN
console.log(add(1,2,3,4));// 10
  • arguments对象

JavaScript提供了arguments对象 该对象可以模拟函数重载的现象 arguments对象是函数内部的本地变量 arguments已经不再是函数的属性了
arguments对象可以获取函数的所有参数 但arguments对象并不是一个数组 而是一个类数组对象(没有数组特有的方法)

/*
    JavaScript提供arguments对象
    * 该对象存储当前函数中所有的参数(实参) - 类数组对象
    * 场景 - 该对象一般用于函数中
    * 作用 - 用于获取当前函数的所有参数
    * 属性
    * length - 函数所有参数(实参)的个数
    * 用法 - 模拟实现函数的重载
 */
function add(){
    var num = arguments.length;
    switch (num) {
        case 2:
            return arguments[0] + arguments[1];
            break;
        case 3:
            return arguments[0] + arguments[1] + arguments[2];
            break;
        case 4:
            return arguments[0] + arguments[1] + arguments[2] + arguments[3];
            break;
    }
}
console.log(add(1,2));// 3
console.log(add(1,2,3));// 6
console.log(add(1,2,3,4));// 10
  • 函数的递归

调用自身的函数被称之为递归函数 在某种意义上说 递归近似于循环 两者都有重复执行相同的代码 并且两者都需要一个终止条件以避免无限循环或者无限递归

/* 函数的递归 -> 就是在指定函数的函数体中调用自身函数
function fun(){
    // 当前函数的逻辑内容
    console.log('this is function');
    // 调用自身函数 -> 实现递归
    fun();
}
fun();
*/

function fn(v){
    console.log(v);
    if (v >= 10) {
        return;
    }
    // fn(v + 1);
    arguments.callee(v + 1);
}
// fn(0);

var f = fn;
fn = null;
f(0);
// console.log(f);

特殊函数

  • 匿名函数

JavaScript可以将函数作为数据使用 作为函数本体 它像普通的数据一样 不一定要有名字 默认名字的函数被称之为匿名函数

function(a){return a;}
/*
    匿名函数的作用:
    1.将匿名函数作为参数传递给其他函数 - 回调函数
    2.将匿名函数用于执行一次性任务 - 自调函数
 */
  • 回调函数

当一个函数作为参数传递给另一个函数时 作为参数的函数被称之为回调函数

// 作为另一个函数(fn)的参数的函数(one) - 回调函数
var one = function(){
    return 1;
}

function fn(v){
    return v();
}
// one函数仅是作为fn函数的参数出现 - 并不是调用
// var result = fn(one);
/*
    以上代码等价于以下代码
    以下代码中作为参数的函数 - 匿名回调函数
  */
var result = fn(function(){return 1;});

console.log(result);// 1

回调函数的优点:
1.它可以在不做命名的的情况下传递函数(这意味着可以节省全局变量)
2.可以将一个函数调用操作委托给另一个函数(这意味着可以节省一些代码编写工作)
3.回调函数也有助于提升性能

  • 回调函数的参数
// 作为另一个函数(fn)的参数的函数(one) -> 回调函数
var one = function(w){
    return w;
}

function fn(v){// 形参是一个函数
    return v(100);// 函数的调用体
}

// var result = fn(one);// 实参必须是一个函数

var result = fn(function(w){return w;});

console.log(result);
  • 自调函数

自调函数就是定义函数后自行调用

/*
    自调函数 - 定义即调用的函数
    * 第一个小括号 - 用于定义函数
    * 第二个小括号 - 用于调用函数
 */
// 全局作用域 - 生命周期:JavaScript文件从执行到执行完毕
(function(value){
    // 函数作用域 - 生命周期:从函数调用到调用完毕
    console.log('this is ' + value);
})('function');
// 表达式语法
(function(value){
    // 函数作用域 - 生命周期:从函数调用到调用完毕
    console.log('this is ' + value);
}('function'));

!function(value){
    // 函数作用域 - 生命周期:从函数调用到调用完毕
    console.log('this is ' + value);
}('function');

+function(value){
    // 函数作用域 - 生命周期:从函数调用到调用完毕
    console.log('this is ' + value);
}('function');
  • 作为值的函数

将一个函数作为另一个函数的结果进行返回 作为结果返回的函数称之为值的函数

var one = function(){
    return 100;
}
// 作为值的函数 -> 内部函数的一种特殊用法
function fun(){
    var v = 100;
    // 内部函数
    return function(){
        return v;
    };
}

var result = fun();
//console.log(result);// one函数
//console.log(result());// 100

console.log(fun()());

闭包

  • 作用域链

很多开发语言中都具有块级作用域 但ECMAScript5版本中并没有跨级作用域 这经常会导致理解上的困惑
虽然ECMAScript5版本没有块级作用域 但具有函数作用域 在某个函数内部定义的便利的作用域就是该函数作用域
每一段JavaScript代码(全局代码或函数)都有一个与之关联的作用域链

var a = 10;// 全局变量
function fun(){
    var b = 100;// fun函数作用域的局部变量
    // 内部函数
    function fn(){
        var c = 200;// fn函数作用域的局部变量
        // 内部函数
        function f(){
            var d = 300;// f函数作用域的布局变量
            // 调用变量
            console.log(a);// 10
            console.log(b);// 100
            console.log(c);// 200
            console.log(d);// 300
        }
        f();
        // 调用变量
        // console.log(a);// 10
        // console.log(b);// 100
        // console.log(c);// 200
        // console.log(d);// d is not defined
    }
    fn();
    // 调用变量
    // console.log(a);// 10
    // console.log(b);// 100
    // console.log(c);// c is not defined
    // console.log(d);// d is not defined
}
fun();
  • 闭包

JavaScript允许函数嵌套 并且内部函数可以访问定义在外部函数中的所有变量和函数 以及外部函数能访问的所有变量和函数 但是 外部函数却不能够访问定义在内部函数中的变量和函数
当内部函数以某一种方式被任何一个外部函数作用域访问时 一个闭包距产生了
闭包就是词法表示包括不必计算的变量的函数 也就是说 该函数能使用函数外定义的变量

var n;// 定义变量,但不初始化值
function fun(){// 函数作用域
    var v = 100;
    // 进行初始化值 -> 一个函数
    n = function(){
        console.log(v);
    }
    // n();
}
fun();

n();// 100
  • 闭包的特点与作用

闭包的特点:
1.局部变量:在函数中定义有共享意义(如 缓存 计数器等)的局部变量(注:定义全局变量会对外造成污染)
2.内部函数:在函数(f)中声明有内嵌函数 内嵌函数(g)对函数(f)长得局部变量进行访问
3.外部使用:函数(f)向外返回此内嵌函数(g) 外部可以通过此内嵌函数持有并访问声明在函数(f)中的变量 而此变量在外部是通过其他途径无法访问的
闭包的作用:
1.提供可共享的局部变量
2.保护共享的局部变量 提供专门的读写变量的函数
3.避免全局污染

相关推荐