js函数

92 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情 本章节将会对js中函数内容做归纳整理。

函数基础

基础内容

  • 函数也是对象类型,函数名是指向函数对象的指针(不带括号的函数名会访问函数指针,带括号时才会执行函数)
  • 函数的定义方式:函数声明,函数表达式,箭头函数(前两种存在一定的差别,因为js在执行时会有函数提升的过程,函数声明的形式,函数的声明会被提升) 参数

函数传参

  • js中函数接受的参数表现为一个数组,js中的函数参数并没有严格的规则,在进行参数传递时多传或者少传都不影响函数的执行
  • 可以通过arugment对象获得函数调用时传入的所有参数
  • js函数中没有签名(接收参数的类型和数量)机制,因此也不存在函数重载,多次定义函数时最后一次的定义会将之前的定义进行覆盖。
// 默认传参
function makeKing(name = "Henry") {
  console.log(name);
}
// 参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
let x = 99;
function foo(p = x + 1) {
  console.log(p);
}
foo() // 100
x = 100;
foo() // 101
//上面代码中,参数`p`的默认值是`x + 1`。这时,每次调用函数`foo()`,都会重新计算`x + 1`,而不是默认`p`等于 100。
// 传参顺序
// 参数是按顺序初始化的,所以后定义默认值的参数可以引用先定义的参数, 参数初始化顺序遵循“暂时性死区”规则,即前面定义的参数不能引用后面定义的。
function makeKing(name = "Henry", numerals = name) {
  return `King ${name} ${numerals}`;
}
// 扩展符传参
// 将可迭代对象拆分成单个的值
let data = [1, 4];
let result = myFunction(...data); // 等价于myFunction(1, 4)
// 只能当做最后一位参数传入,否则会报错
function f(a, ...b, c) {// 报错
  // ...
}

执行机制

函数提升问题

函数声明提升(function declaration hoisting)。在执行代码时,JavaScript 引擎会先执行一遍扫描,把发现的函数声明提升到源代码树的顶部。因此即使函数定义出现在调用它们的代码之后,引擎也会把函数声明提升到顶部。要与函数表达式做区分,函数表达式并不会进行函数的声明的提前,只会对函数表达式中赋值给的变量做变量的提升函数可以作为参数传递给其他函数,同样可以作为返回值在函数中进行返回

// 函数声名
makeKing()
function makeKing(name = "Henry") {
  console.log(name);
}
// 函数表达式
makeKing();
const makeKing = function (name = "Henry") {
  console.log(name);
};

函数属性及内置方法

length属性

函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
//如果设置了默认值的参数不是尾参数,那么`length`属性也不再计入后面的参数了。
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。

name 属性

如果将一个匿名函数赋值给一个变量,name属性返回这个变量名字。 如果将一个具名函数赋值给一个变量,name属性返回这个具名函数原本的名字。

this

this指的是发生的函数调用时发生的绑定(具体内容会在之后结合实际代码进行总结)

apply()\call()和bind()

允许我们借助其他函数并在函数调用中改变 this 的指向

function fun() {
    console.log(this.a);
};
var obj = {
    a: 'da'
};
var a = 'da1';

fun(); // da1
fun.call(obj); // da
fun.apply(obj); // da
fun.bind(obj); // 使用bind创建一个新的函数,不会执行
函数事件对象

在触发某个事件的时候,都会产生一个event事件对象,作为参数传给监听函数。 这个对象中包含所有与事件相关的信息,包括触发事件的元素,事件的类型,以及其他与事件相关的信息。 例如: 鼠标事件触发时,事件对象中会包含鼠标的位置信息等;按键事件触发时,事件对象中则会包含与按键相关的信息。

var f = function () {};
f.name // "f"
const bar = function baz() { };
bar.name // "baz"

箭头函数

  • 箭头函数自带有return,下面这种写法相当于返回n+m let sum =(n,m)=> n+m;
  • 箭头函数返回值为一个匿名函数,传递参数为单个参数时,括号可以省略 let fn=n=>m=>n+m;
  • 箭头函数中没有arguments,接收任意参数时使用展开语法(纯数组结构,可以使用数组中提供的方法),箭头函数也没有prototype
  • 箭头函数中的this指向继承上级作用域中的this指向,且没有办法进行改变
  • 形参(带默认值的写法)let sum =(n=0,m=0)=> n+m;
  • 箭头函数没有[[Construct]]方法,所以不能被用作构造函数。

函数进阶

在js中,设计函数的内容还包括函数式编程、高阶函数、纯函数、回调函数、构造函数、异步函数、函数柯里化,这些在组织代码结构,优化代码编写上都是十分重要的概念,之后会专门出文章做总结。