99%的人都学!JavaScript函数核心机制全解,精通的都涨薪了!

内容分享3周前发布
2 2 0

JavaScript 函数是 JS 的核心灵魂,理解其底层机制不仅能提升代码质量,更能应对复杂场景(列如框架源码、设计模式)。以下从核心机制入手,结合实例拆解,帮你彻底吃透函数本质。

一、函数的「定义本质」:不是 “代码块”,而是 “可执行对象”

JS 函数的本质是Function 类型的实例(和对象、数组一样是 “值”),这意味着:

  • 可以被赋值给变量 / 属性
  • 可以作为参数传递
  • 可以作为返回值返回
  • 有自己的属性和方法(如name、length、call())

常见定义方式及核心差异

1.函数声明(Function Declaration)

function foo() {} // 有函数提升(hoisting),在作用域内任何位置可调用

特点:会被整体提升到作用域顶部(比变量提升优先级高),可在定义前调用。

2.函数表达式(Function Expression)

const foo = function() {}; // 无函数提升,仅变量提升(值为undefined)

特点:本质是 “变量赋值”,定义前调用会报错(变量已声明但值为 undefined)。

3.箭头函数(Arrow Function)

const foo = () => {}; //this绑定、无arguments、不能作构造函数

本质是简化版函数表达式,但有 3 个关键限制(后面详解)。

4.Function 构造函数(不推荐)

const foo = new Function('a', 'b', 'return a + b'); // 字符串解析,性能差且不安全

特点:作用域是全局(而非当前作用域),几乎不用(除非动态生成代码)。

99%的人都学!JavaScript函数核心机制全解,精通的都涨薪了!

二、函数的「调用与 this 绑定」:this 指向由 “调用方式” 决定

this 是函数执行时的 “上下文对象”,其指向完全由调用方式决定,和定义位置无关。

4种核心调用方式及 this 指向

1.普通调用(独立调用)

function foo() { console.log(this); }
foo(); // 非严格模式:thiswindow;严格模式:thisundefined

本质:函数作为 “独立函数” 执行,无明确归属对象。

2.对象方法调用

const obj = {
    name: 'obj',
    foo() { console.log(this.name); }
};
obj.foo(); // this → obj(调用时的“点前面”的对象)

关键:this 指向调用时的直接所属对象(而非定义时的对象):

const bar = obj.foo;
bar(); // 此时是普通调用,thiswindow/undefined(和obj无关了)

3.构造函数调用(new)

function Person(name) {
  this.name = name; // this → 新创建的实例对象
}
const p = new Person('张三'); 

new 操作会强制 this 指向新生成的实例,且默认返回该实例(若手动 return 对象则覆盖)。

4.强制改变 this(call/apply/bind)

  • call(obj, arg1, arg2):立即执行,参数逐个传
  • apply(obj, [arg1, arg2]):立即执行,参数用数组传
  • bind(obj, arg1, arg2):返回新函数(不执行),参数预设
function foo(a, b) { console.log(this.x + a + b); }
const obj = { x: 10 };
foo.call(obj, 2, 3); // 10+2+3=15(this→obj)
foo.apply(obj, [2, 3]); // 同上
const bar = foo.bind(obj, 2); 
bar(3); // 10+2+3=15(bind预设了this和部分参数)

5.箭头函数的 this:“继承” 外层作用域的 this

箭头函数没有自己的 this,其 this 永远等于定义时外层作用域的 this(且无法通过 call/apply/bind 改变):

const obj = {
  foo() {
    const bar = () => { console.log(this); }; // this继承foo的this(即obj)
    bar();
  }
};
obj.foo(); // 输出obj

场景:解决回调函数中 this 丢失问题(如定时器、事件处理)。

99%的人都学!JavaScript函数核心机制全解,精通的都涨薪了!

三、函数的「作用域与闭包」:变量的 “生存规则”

作用域是函数创建时生成的 “变量访问边界”,闭包是作用域的 “特殊产物”。

1.作用域核心规则

  • 函数作用域:每个函数创建一个独立作用域,内部变量外部不可见
  • 作用域链:内部作用域可访问外部作用域变量(由内向外查找,找到即止)
const x = 10;
function outer() {
  const y = 20;
  function inner() {
    const z = 30;
    console.log(x + y + z); // 10+20+30=60(访问外层变量)
  }
  inner();
}
outer();

2.闭包:函数 “记住” 外层变量

内部函数被外部引用时,即使外部函数执行完毕,其作用域也不会销毁(内部函数仍在使用),这种现象就是闭包。

function outer() {
  let count = 0;
  return function inner() { // inner被外部引用,形成闭包
    count++;
    return count;
  };
}
const fn = outer(); 
console.log(fn()); // 1(count未被销毁)
console.log(fn()); // 2(继续累加)

核心价值

  • 实现私有变量(外部无法直接修改 count)
  • 模块化(隔离作用域,避免全局污染)
  • 延迟执行(如定时器、防抖节流)

注意:过度使用闭包可能导致内存泄漏(作用域不销毁),需及时解除引用(fn = null)。

99%的人都学!JavaScript函数核心机制全解,精通的都涨薪了!

四、函数的「参数机制」:灵活但需注意细节

JS 函数参数无类型限制,数量可动态调整,核心依赖arguments和 “参数默认值”。

1. arguments 对象(箭头函数无)

函数内部的arguments是类数组对象,包含所有实参(与形参 “松散绑定”):

function foo(a, b) {
  console.log(arguments[0]); // 1(实参)
  console.log(arguments.length); // 2
  a = 100; 
  console.log(arguments[0]); // 非严格模式:100(形参与arguments绑定);严格模式:1(不绑定)
}
foo(1, 2);

现代 JS 更推荐用剩余参数(…rest)(真正的数组,且更灵活):

function foo(...rest) { // rest是数组:[1,2,3]
  console.log(rest.reduce((a,b) => a+b)); // 6
}
foo(1,2,3);

2. 参数默认值

形参可设置默认值,当实参未传或为undefined时生效:

function foo(a = 10, b = 20) {
  return a + b;
}
foo(); // 30(a=10, b=20)
foo(5); // 25(a=5, b=20)

注意:默认值是 “运行时计算” 的,每次调用都会重新计算:

let x = 10;
function foo(a = x++) { return a; }
foo(); // 10(x变为11)
foo(); // 11(x变为12)

99%的人都学!JavaScript函数核心机制全解,精通的都涨薪了!

五、函数的「属性与方法」:隐藏的实用工具

函数作为对象,有自带属性和方法:

1.name:函数名(箭头函数的 name 由赋值变量决定)

function foo() {};
const bar = () => {};
console.log(foo.name); // "foo"
console.log(bar.name); // "bar"

2.length:形参数量(不包含默认值参数和剩余参数)

function foo(a, b = 10, ...rest) {}.
console.log(foo.length); // 1(仅a是无默认值的形参)

总结:核心机制串联

函数的本质是 “可执行对象”,其行为由:

  • 定义方式决定提升规则和特性(如箭头函数无 this)
  • 调用方式决定 this 指向
  • 作用域链决定变量访问范围,进而产生闭包
  • 参数机制决定实参形参的关联方式

99%的人都学!JavaScript函数核心机制全解,精通的都涨薪了!

© 版权声明

相关文章

2 条评论

  • 头像
    Heliotrope_my 投稿者

    深入学习能提升代码质量

    无记录
    回复
  • 头像
    淡雅石 读者

    就这?这不是基础吗?

    无记录
    回复