前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >18Function类型

18Function类型

作者头像
Dreamy.TZK
发布2020-05-31 22:52:39
5440
发布2020-05-31 22:52:39
举报
文章被收录于专栏:小康的自留地小康的自留地

Function类型

Function类型与函数

函数是这样的一段 Javascript代码,它只定义一次,但可能被执行或调用多次。

Function类型是 JavaScript提供的引用类型之一,通过 Function类型创建 Function对象。

在Javascript中,函数也是以对象的形式存在的。每个函数都是一个 Function对象。

函数名,本质就是一个変量名,是指向某个Function对象的引用。

每一个函数都是一个Function类型的函数

代码语言:javascript
复制
function fn() {
  console.log("this is fn function");
}
var f = function () {
  console.log("this is f function");
};

// 函数是一个对象
console.log(fn instanceof Object); //true
console.log(f instanceof Object); //true
// 函数是Function类型的对象
console.log(fn instanceof Function); //true
console.log(f instanceof Function); //true
image-20200526231149385
image-20200526231149385

通过Function创建函数

语法:var 函数名 = new Function(args,statement);

  • args 字符串类型,表示当前创建函数的形参。如果是多个形参用逗号分隔
  • statement 表示当前创建函数的函数体(字符串类型)。
代码语言:javascript
复制
var fun = new Function("a,b", 'console.log("this is function "+a+" "+b)');
fun(100, 200);
image-20200526231256933
image-20200526231256933

Function与Object

Function即是自身类型也是Object类型。Object同理。

代码语言:javascript
复制
/**
 * Function类型时JavaScript中的引用类型之一
 * 引用类型都可以当作一个构造函数
 * 构造函数也是函数的一种
 * 构造函数是一个Function类型的对象
 * JavaScript中所有对象都是Object类型
 */
console.log(Function instanceof Function); //true
/**
 * Function类型时JavaScript中的引用类型之一
 * 引用类型都可以当作一个构造函数
 * 构造函数也是函数的一种
 * 构造函数是一个Function类型的对象
 * JavaScript中所有对象都是Object类型
 */
console.log(Function instanceof Object); //true

/**
 * Object类型是JavaScript中的引用类型之一
 * 引用类型都可以当作一个构造函数
 * 构造函数也是函数的一种
 * 构造函数是一个Function类型的对象
 */
console.log(Object instanceof Function); //true
/**
 * Object类型是JavaScript中的引用类型之一
 * 引用类型都可以当作一个构造函数
 * 构造函数也是函数的一种
 * 构造函数是一个Function类型的对象
 * JavaScript中所有对象都是Object类型
 */
console.log(Object instanceof Object); //true

自定义构造函数

构造函数又称对象模板或构造器,它的作用是创建JavaScript对象。构造函数有两种,分别如下:

  • JavaScript提供的构造函数 - 引用类型
  • 自定义构造函数

自定义构造函数声明方式

  1. 函数声明方式 function Hero() { // 定义属性 this.name = "张无忌"; // 定义方法 this.sayMe = function () { console.log("this is function "); }; }
  2. 字面量声明方式 var Hero = function (name) { // 定义属性 this.name = name; // 定义方法 this.sayMe = function () { console.log("this is function "); }; };

利用构造函数创建对象

创建对象的类型为声明时的函数。例如使用Hero构造函数创建对象,那么对象就是Hero类型的。

代码语言:javascript
复制
var hero = new Hero("张无忌");
console.log(hero);
image-20200527095808114
image-20200527095808114

构造函数与函数的异同点

  1. 相同点
    • 语法结构相同
  2. 不同点
    • 函数 函数包括函数体,而函数体里包括局部变量和函数
    • 构造函数 构造函数包括属性和方法

Constructor属性

image-20200527113922102
image-20200527113922102

JavaScript中所有对象都包含一个constructor属性,这个属性来源于Object对象。

代码语言:javascript
复制
// 定义一个构造函数
function Hero() {
  this.name = "张无忌";
  this.sayMe = function () {
    console.log("this is function ");
  };
}
// 使用构造函数创建对象
var hero = new Hero();
// 对象具有与构造函数相同的属性和方法
console.log(hero.name);
hero.sayMe();
// js中所有对象都是Object类型
console.log(hero.constructor);

构造函数与函数

定义一个函数时,它既是一个函数也是一个构造函数,同时又是一个对象。

代码语言:javascript
复制
function Hero() {
  // 当作是一个函数
  var v = 100;
  // 当作是一个构造函数来使用
  this.set = function (value) {
    v = value;
  };
  this.get = function () {
    return v;
  };
}
// 通过构造函数来创建对象
var hero = new Hero();
hero.set(2);
console.log(hero.get()); // 2

// 为对象Hero添加属性和方法
Hero.age = 18;
console.log(Hero.age); // 18

定义函数的方式与区别

定义方式

执行

效率

函数定义语句

函数名被声明提前

不存在效率问题

字面量表达式

函数体固定,无法动态执行

不存在效率问题

Function类型定义

函数体是字符串,可以动态执行

效率低

Function的属性与方法

length属性

获取形参的个数。调用方式如下:

代码语言:javascript
复制
// Function类型的length属性 - 获取函数(形参)的参数的个数
function fn(a, b, d, e, f) {
  console.log("this is a function");
}
fn(1);
console.log(fn.length);  // 5

Function的apply()方法

用于调用一个函数,并且接受指定的this值,以及一个数组作为参数。语法结构如下

func.apply(thisArg,[argsArray])

  • thisArg 指定this的值,表示当前调用函数的对象。如果不使用this值时,提供默认为null或者undefined
  • argsArray 用于接收指定参数的形参。

与函数调用体的区别在于接收的this值

代码语言:javascript
复制
function fn(a, b) {
  console.log("this is " + a + b);
}
// 调用函数
fn("function", "hello"); // this is functionhello
/**
 * apply(this,args)方法调用
 * 使用的对象调用方法的语法结构 -> 将函数作为对象使用
 * 参数
 *   this - 指定this的值,表示当前调用函数的对象
 *      如果不适用this值时,提供默认为null或者undefined值
 *   args - 数组,用于接收指定函数的实参
 * 与函数调用体的区别在于接收的this值
 */
fn.apply(null, ["function", "张无忌"]); //this is function张无忌

Function的call()方法

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

func.call(thisArg,arg1,arg2,...)

  • thisArg 用于指定this的值
  • 后边的参数御用接收函数的实参

call()与apply()方法区别 - 在于第二个参数

代码语言:javascript
复制
/**
 * call()方法 - 用于调用函数
 * 参数
 *   - thisArg - 用于指定this的值
 *   - arg1,arg2,... - 用于接受函数的实参
 * call()与apply()方法区别 - 在于第二个参数
 */
function fn(a, b) {
  console.log("this is function " + a + b);
}
fn.call(null, "12", "34"); //this is function 1234

Function的bind()方法

Function的bind()方法用于创建一个新的函数(称为绑定函数),井且接收指定的this值作为参数,以及参数列表。其语法结构如下

fun.bind(thisArg[,arg1[,arg2[,...]]])

  • thisArg 指定this的值,表示当前调用函数的对象。如果不使用this值时,提供默认为null或者undefined
  • arg 用于接收指定参数的形参。
  • 返回值 返回新创建的函数
  • 作用 实现函数的深复制

验证复制为深复制

代码语言:javascript
复制
var fn = function () {
  console.log("this is function ");
};
var f = fn.bind();
f(); //this is function 
fn = function () {
  console.log("this is function too");
};
f();//this is function

通过以上代码测试,当声明一个函数后,再次修改这个函数,并不会影响前边复制的f。因此bind方法实现的是深复制。

函数赋值也为深复制

代码语言:javascript
复制
var a = function () {
  console.log("this is a");
};
var b = a;
b(); // this is a
a = function () {
  console.log("this is new a");
};
b(); // this is a

关于bind()方法的参数

在复制函数时,bing()方法传入的参数会作为参数调用时默认传入的参数。例如:

代码语言:javascript
复制
var fn = function (v) {
  console.log("this is " + v);
};
fn("zhangwuji"); // this is zhangwuji
var f = fn.bind(null, "zhangwuji");
f() // this is zhangwuji

但是这并不意味着不能在向这个函数传递参数,例如给f()传入参数'a'那么相当于调用fn函数时传入了两个参数fn('zhangwuji','a')。例如如下测试:

代码语言:javascript
复制
var fn = function (v+w) {
  console.log("this is " + v+w);
};
fn("zhangwuji"); // this is zhangwujiundefined
var f = fn.bind(null, "zhouzhiruo");
f(" hahaha"); // this is zhouzhiruo hahaha

函数的重载

在其他开发语言中,函数具有一种特性,叫做重载。所谓重载,就是定义多个同名的函数,但每一个函数接收的参数的个数不同,程序会根据调用时传递的实参个数进行判断,具体调用的是哪个函数。

但是在JavaScript中不可以像下面的方式定义:

代码语言:javascript
复制
// 在JavaScript如果定义多个同名函数 -
function add(a, b) {
  return a + b;
}

function add(a, b, c) {
  return a + b + c;
}
console.log(add(1, 2)); // NaN
console.log(add(1, 3, 4)); // 8

arguments对象

存在于函数体中的特殊对象(原本是Function类型的arguments属性)。arguments对象是一个类数组对象,其中包含length属性:函数实参的个数,其作用是用于接收函数的参数(实参)

代码语言:javascript
复制
function fn() {
    console.log(arguments);
    console.log(arguments[0]);
}

fn(1, 2, 3, 4);
// [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4 }
// 1

模拟函数重载

代码语言:javascript
复制
function add() {
  var len = arguments.length;
  switch (len) {
    case 2:
      return arguments[0] + arguments[1];
    case 3:
      return arguments[0] + arguments[1] + arguments[2];
    case 4:
      return arguments[0] + arguments[1] + arguments[2] + arguments[3];
  }
}
console.log(add(1, 2));
console.log(add(1, 2, 3));
console.log(add(1, 2, 3, 4));
console.log(add(1, 2, 3, 4, 5));

JavaScript中没有函数重载,只能通过模拟来实现

递归

函数的递归:函数在当前函数体调用自身。

执行方式类似于循环语句的执行方式即反复执行指定的语句块内容。

执行递归函数时,必须提供结束执行的条件(出口)

如下为最简单的递归:

代码语言:javascript
复制
var v = 0;
function fn() {
  console.log("this is function ");
  v++;
  if (v > 3) {
    return;
  }
  // 调用自身函数
  fn();
}
fn();

如果在外部需要释放函数,那么函数内部的自调应该改为arguments.callee()

代码语言:javascript
复制
var v = 0;
function fn() {
  console.log("this is function ");
  v++;
  if (v > 3) {
    return;
  }
  // 调用自身函数
  //   fn();
  arguments.callee();
}
var f = fn;
fn = null;
f();

特殊函数(高阶函数)

匿名函数

所谓匿名函数就是没有名字的函数,但JavaScript的语法并不支持匿名函数。因此匿名函数的用法有两个

  • 回调函数 将一个函数作为另一个函数的参数使用,作为参数的函数称为回调函数
  • 自调函数 函数调用自身(定义即调用函数)

回调函数

将一个函数作为另一个函数的参数使用,作为参数的函数称为回调函数

回调函数的优势:

  • 匿名回调函数节省了全局命名空间
  • 将私有的数据内容开放给指定位置使用(仅仅)
  • 虽然可以使用私有数据,但不清楚来源一封装
image-20200529191355824
image-20200529191355824
image-20200529193718796
image-20200529193718796
代码语言:javascript
复制
var n = function (w) {
  console.log(w);
};
function fn(v) {
  var name = "张无忌";
  v(name); //将局部变量作为v()函数的实参传递
}
fn(function (w) {
  console.log(w); // 张无忌
});

自调函数

自调函数就是自己调用自己。简单语法如下两种:

代码语言:javascript
复制
// 国内常用方式
(function () {
  var w = 100; // 局部变量
  console.log("this is function");
})();
// 表达式方式
(function (v) {
  console.log("表达式" + v);
})("function");
  • 语法结构 第一个括号用于定义函数,第二个括号用于调用函数。
  • 作用 用于执行一次性的逻辑任务
  • 应用 作为整体逻辑代码的外层结构

作为值的函数

在函数的函数体中定义另一个函数 -> 内容(私有)函数

代码语言:javascript
复制
// 作为值的函数
function fn() {
  //在函数的函数体中定义另一个函数 -> 内容(私有)函数
  return function () {
    return 1;
  };
}
var result = fn();
console.log(result); // [Function]
console.log(result()); // 1

或者如下,返回一个函数

代码语言:javascript
复制
function fn() {
  function n() {
    return 1;
  }
  return n();
}
var result = fn();
console.log(result)

函数作为对象的方法

代码语言:javascript
复制
var fn = function fn() {
  console.log("this is function ");
};
// 将函数作为对象的方法
var obj = {
  fun: fn,
};
obj.fun(); // this is function 
fn(); // this is function

当函数作为对象的方法时,再次修改函数同样不会影响对象中已经赋值。

代码语言:javascript
复制
var fn = function fn() {
  console.log("this is function ");
};
// 将函数作为对象的方法
var obj = {
  fun: fn,
};
obj.fun();
fn();

fn = function () {
  console.log("this is function too");
};
obj.fun(); // this is function

闭包

作用域链

作用域是一层一层向下传递的。

例如

代码语言:javascript
复制
var a = "a";
function fun() {
  var b = "b";
  function fn() {
    //相对于f函数作用域的话,c相当于全局变量
    var c = "c";
    function f() {
      //函数作用域
      var d = "d";
      console.log(a); //a
      console.log(b); //b
      console.log(c); //c
      console.log(d); //d
    }
    f();
  }
  fn();
}
fun();

闭包是什么

简单来说,闭包就是访问在全局范围内访问局部作用域的变量。

以下三种方式均可称为闭包。

代码语言:javascript
复制
// 对象与函数

function fn1() {
  var v = 100;
  return {
    get: function () {
      return v;
    },
    set: function (value) {
      v = value;
    },
  };
}
var obj = fn1();
obj.set(200);
console.log(obj.get());
代码语言:javascript
复制
// 函数与构造函数

function fn2() {
  var v = 100;
  this.get = function () {
    return v;
  };
  this.set = function (value) {
    v = value;
  };
}
var obj = new fn2();
obj.set(200);
console.log(obj.get());
代码语言:javascript
复制
// 全局变量

var get, set;
function fn3() {
  var v = 100;
  get = function () {
    return v;
  };
  set = function (value) {
    v = value;
  };
}
fn3();
set(200);
console.log(get()); //200

回调函数不属于闭包。但加上参数可以改为闭包:

代码语言:javascript
复制
function fn1(v) {
  var v1 = 100;
  //   console.log(v2);
  v(v1);
}
function fn2(v) {
  var v2 = 200;
  console.log(v);
}
fn1(fn2); // 100

闭包结构并不固定,但当内部函数以某一种方式被任何一个外部函数作用域访问时,就可以成为闭包

  1. 闭包的特点
    • 局部变量 在函数中定义有共享意义(如:缓存、计数器等)的局部变量。(注:定义成全局变量会对外造成污染)
    • 内部函数 在函数(f)中声明有内嵌函数,内嵌函数(g)对函数(f)中的局部变量进行访问。
    • 外部使用 函数(f)向外返回此内嵌函数(g),外部可以通过此内嵌函数持有并访问声明在函数(f)中的局部变量,而此变量在外部是通过其他途径无法访问的。
  2. 闭包的作用
    • 提供可共享的局部变量。
    • 保护共享的局部变量。提供专门的读写变量的函数
    • 避免全局污染。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Function类型
    • Function类型与函数
      • Function与Object
        • 自定义构造函数
          • Constructor属性
            • 构造函数与函数
              • 定义函数的方式与区别
                • Function的属性与方法
                  • length属性
                  • Function的apply()方法
                  • Function的call()方法
                  • Function的bind()方法
                • 函数的重载
                  • arguments对象
                • 递归
                  • 特殊函数(高阶函数)
                    • 匿名函数
                    • 回调函数
                    • 自调函数
                    • 作为值的函数
                    • 函数作为对象的方法
                  • 闭包
                    • 作用域链
                    • 闭包是什么
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档