JS高级之深入浅出Function与构造函数

这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

大家好,我是一碗周,一个不想被喝(内卷)的前端。如果写的文章有幸可以得到你的青睐,万分有幸~

概述

Function是一个构造函数,可以通过该构造函数去创建一个函数,创建的函数是一个Function对象,实际上,不管使用什么方式创建的都是一个Function对象,本质上函数名仅仅是一个变量名,它指向某个Function对象的引用。

验证代码如下所示:

var f = function () {
  console.log('this is f function');
}
// 函数也是一个对象
console.log(f instanceof Object); // true
// 函数是Function类型的对象
console.log(f instanceof Function); // true
复制代码

利用Function构造函数创建函数

Function****构造函数创建一个新的Function对象。直接调用此构造函数可用动态创建函数。

语法结构如下:

var functionName = new Function ([arg1[, arg2[, ...argN]],] functionBody)
复制代码

其中functionName表示函数名称,[arg1[, arg2[, ...argN]],]表示可选的参数列表,functionBody表示函数

示例代码如下所示:

// 无参的函数
var fun = new Function('console.log("这是一个函数")')
fun() // 这是一个函数
// 带一个参数的函数
var fun = new Function('a', 'console.log("这个函数带一个参数:" + a)')
fun(100) // 这个函数带一个参数:100
// 带两个参数的函数
var fun = new Function(
  'a, b',
  'console.log("这是带两个参数的函数,分别是" + a + "和" + b);',
)
fun(100, 200) // 这是带两个参数的函数,分别是100和200

复制代码

在实际的开发中我们一般不使用这种方式创建函数,因为它毫无可读性。

Function与Object

  1. Object类型和Function是JavaScript中的引用类型之一

  2. 构造函数也是函数的一种

  3. 函数其实是一个Function类型的对象

  4. JavaScript中所有对象都是Object类型的

验证代码如下

console.log(Function instanceof Function) //true
console.log(Function instanceof Object) //true
console.log(Object instanceof Object) //true
console.log(Object instanceof Function) //true

复制代码

构造函数

自定义否则函数

构造函数又称为构造器或对象模板,是对象中的一个方法,在实例化时构造器被调用。在JavaScript中函数就可以作为构造器使用,因此不需要特别定义一个构造器方法。

创建构造函数的语法结构如下所示:

function Person(){
  this.属性名 = 属性值;
  this.方法名 = function() {
      方法体
}
var person = new Person();
复制代码

这里的Person是作为构造函数的名称,将Person实例化需要使用new关键字,还有一点需要说的就是构造函数一般首字母都是大写的。

如下代码展示了如何通过创建一个构造函数以及如何通过构造函数去实例化一个类:

// 自定义构造函数 -> 作用:创建对象
function Person(name, age, sex) {
  this.name = name
  this.age = age
  this.sex = sex
  this.print = function () {
    console.log(name + '今年' + age + '岁 性别' + sex)
  }
}
// 创建 一碗甜
var t = new Person('一碗甜', 18, '女')
hong.print() // 一碗甜今年18岁 性别女
// 创建 一碗周
var z = new Person('一碗周', 20, '男')
dong.print() //一碗粥今年20岁 性别男

复制代码

对象的constructor属性

Object对象提供的constructor属性,返回创建实例对象Object的构造函数的引用。

所有对象都会从它的原型上继承一个constructor属性:

值得注意的是此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。

示例代码如下:

// 创建 一碗周
var z = new Person('一碗周', 18, '男')
// 判断是否为 Person 构造函数的对象
console.log(z.constructor === Person)

复制代码

构造函数与函数

先看一段代码

function Hero() {
  // 当作是一个函数来使用
  var v = 100 // 局部变量
  // 当作是一个构造函数来使用
  this.set = function (value) {
    v = value
  }
  this.get = function () {
    return v
  }
}
复制代码

在这段代码中,首先我们定义了一个函数,那它也是一个构造函数,当然它还是一个对象。

既然它有三个方面的含义,那就有三个方面的操作,如下所示

  1. 直接当做函数调用

  2. 通过构造函数创建对象

  3. 当做对象为其添加属性或者方法

示例代码代码如下

// 直接调用
Hero()
// 通过构造函数创建对象
var hero = new Hero()
// 当做对象为其添加属性和方法
Hero.n = '一碗周'
console.log(Hero.n) // 一碗周

复制代码

Function对象的属性和方法

全局的Function对象没有自己的属性和方法,但是,因为它本身也是一个函数,所以它也会通过原型链从自己的原型链Function.prototype上继承一些属性和方法。

length属性

length属性指明函数的形参个数,示例代码如下所示:

// 定义两个空函数
function fun(a, b, c, d) {}

function fn() {}

// 测试 length 属性
console.log(fun.length) // 4
console.log(fn.length) // 0

复制代码

apply()方法

**apply()**方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

语法格式如下:

func.apply(thisArg, [argsArray])
复制代码

参数解释如下:

  • thisArg必选的。在func函数运行时使用的this值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为nullundefined时会自动替换为指向全局对象,原始值会被包装。

  • argsArray可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func函数。如果该参数的值为nullundefined,则表示不需要传入任何参数。从ECMAScript5开始可以使用类数组对象。

返回值是调用有指定this值和参数的函数的结果。

如下代码展示了apply()方法的用法:

// 定义一个函数
function fn(a) {
  console.log('this is ' + a)
}
fn.apply(null, ['函数']) // this is 函数

// 上面的调用方式等同于下面这种方式
fn('函数') // this is 函数

复制代码

call()方法

该方法的语法和作用与apply()方法类似,只有一个区别,就是call()方法接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组

如下代码展示了call()方法的用法:

function fn(a) {
  console.log('this is ' + a)
}
fn.call(null, '函数') // this is 函数

// 上面的调用方式等同于下面这种方式
fn('函数') // this is 函数

复制代码

bind()方法

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

参数解释如下:

function.bind(thisArg[, arg1[, arg2[, ...]]])
复制代码

参数

  • thisArg:调用绑定函数时作为this参数传递给目标函数的值。

  • arg1, arg2, ...:当目标函数被调用时,被预置入绑定函数的参数列表中的参数。

返回值是一个原函数的拷贝,并拥有指定的**this**值和初始参数。

如下代码展示了bind()方法的:

// 定义一个函数
var fun = function (a, b) {
  console.log('第一个参数的值为:' + a + '第二个参数的值为:' + b)
}
// 调用 fun()
fun(10, 20) // 第一个参数的值为:10第二个参数的值为:20
// 创建绑定函数
var fn = fun.bind(null, 100, 200) // 有参数默认值的功能
// 调用新创建的函数,不写实参
fn() // 第一个参数的值为:100第二个参数的值为:200

复制代码

Arguments对象

arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:

arguments[0]
arguments[1]
arguments[2]

复制代码

它的参数也是可以被重新定义的,该对象还提供了两个属性,分别是:

  • arguments.length:返回传递给函数的参数数量

  • arguments.callee :返回指向参数所属的当前执行的函数。如果这个属性后面紧跟一个 (),则表示调用此函数,因为arguments.callee === fun的结果为 true

如下代码展示了该对象的用法,代码如下:

/*
 * arguments 对象是一个存在于函数体中的特殊对象。
 * arguments 对象是一个类数组对象
 * arguments 对象对应传递给函数的实参
 */
// 定义一个函数
var fun = function () {
  console.log(arguments)
  // arguments.callee  指向参数所属的当前执行的函数。
  //如果给这个属性加一个括号则表示调用。因为 arguments.callee === fun 的结果为 true
  console.log(arguments.callee)
  // arguments.length  传递给函数的参数数量。
  console.log(arguments.length)
}
fun(1, 2, 3, 4, 5) 
复制代码

代码执行结果如下所示:

[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
[Function: fun]
5
复制代码

我们可以通过arguments.length属性,来判断传入参数的数量,来完成函数重载的功能,示例代码如下:

// 模拟函数的重载
function add() {
  // 记录参数数量
  var len = arguments.length
  // 通过 switch case 语句判断传入参数数量,来模拟重载的功能
  switch (len) {
    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

    default:
      break
  }
}
console.log(add(1, 2)) // 3
console.log(add(1, 2, 3)) // 6
console.log(add(1, 2, 3, 4)) // 10

复制代码

总结

本篇文章介绍了如何创建构造函数,如何通过构造函数去实例化一个对象;以及Function对象提供的方法和属性有哪些?怎么用,最后还介绍了一个Arguments对象。

写在最后

这是【从头学前端】系列文章的第四十九篇-《深入浅出Function与构造函数》,如果你喜欢这个专栏,可以给我或者专栏一个关注~

本系列文章在掘金首发,编写不易转载请获得允许

往期推荐

Guess you like

Origin juejin.im/post/7032453637662048286