每日一个知识点:JavaScript 箭头函数与普通函数比较

xml 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS箭头函数 vs 普通函数</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: #333;
            line-height: 1.6;
            padding: 20px;
            min-height: 100vh;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        header {
            text-align: center;
            margin-bottom: 40px;
            padding: 20px;
        }
        
        h1 {
            font-size: 2.5rem;
            color: #2c3e50;
            margin-bottom: 10px;
        }
        
        .subtitle {
            font-size: 1.2rem;
            color: #7f8c8d;
        }
        
        .comparison {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin-bottom: 40px;
        }
        
        .card {
            flex: 1;
            min-width: 300px;
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
            padding: 25px;
            transition: transform 0.3s ease;
        }
        
        .card:hover {
            transform: translateY(-5px);
        }
        
        .card h2 {
            color: #2c3e50;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 2px solid #3498db;
        }
        
        .difference {
            margin-bottom: 15px;
        }
        
        .difference h3 {
            color: #3498db;
            margin-bottom: 5px;
        }
        
        .code-example {
            background: #2c3e50;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 5px;
            margin: 15px 0;
            overflow-x: auto;
            font-family: 'Consolas', monospace;
        }
        
        .keyword {
            color: #f92672;
        }
        
        .function {
            color: #66d9ef;
        }
        
        .comment {
            color: #75715e;
        }
        
        .usage {
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
            padding: 25px;
            margin-bottom: 40px;
        }
        
        .usage h2 {
            color: #2c3e50;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 2px solid #3498db;
        }
        
        .scenarios {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }
        
        .scenario {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            border-left: 4px solid #3498db;
        }
        
        .scenario h3 {
            color: #2c3e50;
            margin-bottom: 10px;
        }
        
        .conclusion {
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
            padding: 25px;
            text-align: center;
        }
        
        .conclusion h2 {
            color: #2c3e50;
            margin-bottom: 20px;
        }
        
        .highlight {
            background: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
            padding: 25px;
            border-radius: 10px;
            margin-top: 20px;
        }
        
        footer {
            text-align: center;
            margin-top: 40px;
            color: #7f8c8d;
        }
        
        @media (max-width: 768px) {
            .comparison {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>JavaScript 箭头函数与普通函数</h1>
            <p class="subtitle">全面比较两种函数类型的区别与适用场景</p>
        </header>
        
        <div class="comparison">
            <div class="card">
                <h2>普通函数</h2>
                
                <div class="difference">
                    <h3>this 绑定</h3>
                    <p>拥有自己的 <code>this</code> 上下文,取决于调用方式</p>
                    <div class="code-example">
                        <span class="keyword">function</span> <span class="function">Person</span>() {<br>
                        &nbsp;&nbsp;this.age = 0;<br>
                        &nbsp;&nbsp;setInterval(<span class="keyword">function</span> growUp() {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// 这里的this指向全局对象或undefined</span><br>
                        &nbsp;&nbsp;&nbsp;&nbsp;this.age++;<br>
                        &nbsp;&nbsp;}, 1000);<br>
                        }
                    </div>
                </div>
                
                <div class="difference">
                    <h3>构造函数</h3>
                    <p>可以用作构造函数,使用 <code>new</code> 关键字</p>
                    <div class="code-example">
                        <span class="keyword">function</span> <span class="function">Car</span>(make, model) {<br>
                        &nbsp;&nbsp;this.make = make;<br>
                        &nbsp;&nbsp;this.model = model;<br>
                        }<br><br>
                        const myCar = <span class="keyword">new</span> Car('Toyota', 'Camry');
                    </div>
                </div>
                
                <div class="difference">
                    <h3>arguments 对象</h3>
                    <p>有自己的 <code>arguments</code> 对象,包含所有传入参数</p>
                    <div class="code-example">
                        <span class="keyword">function</span> <span class="function">showArgs</span>() {<br>
                        &nbsp;&nbsp;console.log(arguments);<br>
                        &nbsp;&nbsp;<span class="comment">// 输出: [1, 2, 3, callee: ƒ, Symbol(...): ...]</span><br>
                        }<br><br>
                        showArgs(1, 2, 3);
                    </div>
                </div>
            </div>
            
            <div class="card">
                <h2>箭头函数</h2>
                
                <div class="difference">
                    <h3>this 绑定</h3>
                    <p>没有自己的 <code>this</code>,继承自父作用域</p>
                    <div class="code-example">
                        <span class="keyword">function</span> <span class="function">Person</span>() {<br>
                        &nbsp;&nbsp;this.age = 0;<br>
                        &nbsp;&nbsp;setInterval(() => {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// 这里的this继承自Person函数</span><br>
                        &nbsp;&nbsp;&nbsp;&nbsp;this.age++;<br>
                        &nbsp;&nbsp;}, 1000);<br>
                        }
                    </div>
                </div>
                
                <div class="difference">
                    <h3>构造函数</h3>
                    <p>不能用作构造函数,使用 <code>new</code> 会抛出错误</p>
                    <div class="code-example">
                        const Car = (make, model) => {<br>
                        &nbsp;&nbsp;this.make = make;<br>
                        &nbsp;&nbsp;this.model = model;<br>
                        };<br><br>
                        <span class="comment">// 抛出TypeError: Car is not a constructor</span><br>
                        const myCar = <span class="keyword">new</span> Car('Toyota', 'Camry');
                    </div>
                </div>
                
                <div class="difference">
                    <h3>arguments 对象</h3>
                    <p>没有自己的 <code>arguments</code> 对象,但可以访问外部函数的arguments</p>
                    <div class="code-example">
                        <span class="keyword">function</span> <span class="function">outer</span>(a, b) {<br>
                        &nbsp;&nbsp;const inner = () => {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;console.log(arguments);<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// 输出: [1, 2, callee: ƒ, Symbol(...): ...]</span><br>
                        &nbsp;&nbsp;};<br>
                        &nbsp;&nbsp;inner();<br>
                        }<br><br>
                        outer(1, 2);
                    </div>
                </div>
            </div>
        </div>
        
        <div class="usage">
            <h2>使用场景建议</h2>
            <div class="scenarios">
                <div class="scenario">
                    <h3>使用箭头函数的情况</h3>
                    <ul>
                        <li>需要继承外部this上下文时</li>
                        <li>简短的回调函数</li>
                        <li>函数式编程(map、filter、reduce等)</li>
                        <li>不需要自己this绑定的函数</li>
                    </ul>
                </div>
                
                <div class="scenario">
                    <h3>使用普通函数的情况</h3>
                    <ul>
                        <li>需要作为构造函数使用时</li>
                        <li>需要可变的this上下文</li>
                        <li>需要访问arguments对象</li>
                        <li>对象的方法(通常需要访问对象本身)</li>
                        <li>生成器函数(function*)</li>
                    </ul>
                </div>
            </div>
            
            <div class="highlight">
                <h3>关键区别总结</h3>
                <p>箭头函数是ES6引入的语法糖,主要优点是更简洁的语法和词法作用域的this绑定。</p>
                <p>普通函数更适合需要动态上下文、构造函数或需要arguments对象的场景。</p>
            </div>
        </div>
        
        <div class="conclusion">
            <h2>总结</h2>
            <p>箭头函数和普通函数各有其用途,理解它们的区别对于编写正确的JavaScript代码至关重要。</p>
            <p>在大多数现代JavaScript开发中,箭头函数因其简洁性和更可预测的this绑定而更受欢迎,</p>
            <p>但在某些特定场景下,普通函数仍然是不可或缺的。</p>
        </div>
        
        <footer>
            <p>© 2023 JavaScript函数比较 | 设计用于教育目的</p>
        </footer>
    </div>
</body>
</html>

在 JavaScript 中,箭头函数(Arrow Function)是 ES6 引入的一种简化函数语法的特性,与普通函数(Function Declaration/Expression)在行为和特性上有显著差异。以下从多个维度对比两者的核心区别,并结合实际场景说明适用场景。

​​1. 语法简洁性​​

箭头函数的语法更简洁,省略了 function关键字(部分场景可省略大括号和 return),适合需要匿名函数的场景(如回调)。

​普通函数示例​​:

javascript 复制代码
// 函数表达式
const add = function(a, b) {
  return a + b;
};

// 函数声明
function multiply(a, b) {
  return a * b;
}

​箭头函数示例​​:

ini 复制代码
const add = (a, b) => a + b; // 单行直接返回,省略大括号和 return
const logName = name => console.log(name); // 单个参数可省略参数括号

​​2. this的指向​​

这是两者最核心的差异。普通函数的 this是​​动态绑定​ ​的(取决于调用方式),而箭头函数的 this是​​词法绑定​​的(继承自外层作用域,定义时确定,无法修改)。

普通函数的 this:

  • 全局调用:this指向全局对象(浏览器中为 window,Node.js 中为 global)。

  • 对象方法调用:this指向调用该方法的对象。

  • 构造函数调用:this指向新创建的实例对象。

  • call/apply/bind调用:this被显式指定为目标对象。

​示例​​:

javascript 复制代码
const obj = {
  name: "Alice",
  sayHello: function() {
    console.log(`Hello, ${this.name}`); // this 指向 obj
  }
};
obj.sayHello(); // 输出 "Hello, Alice"

箭头函数的 this:

  • 无独立 this,直接继承外层作用域的 this(无论是否通过 call/apply/bind修改)。

  • 常用于避免回调函数中 this丢失的问题(如定时器、事件监听器)。

​示例​​:

javascript 复制代码
const obj = {
  name: "Alice",
  sayHello: function() {
    setTimeout(() => {
      console.log(`Hello, ${this.name}`); // 箭头函数的 this 继承自外层的 sayHello(this 指向 obj)
    }, 1000);
  }
};
obj.sayHello(); // 1秒后输出 "Hello, Alice"(普通函数 setTimeout 回调的 this 会指向 window)

​​3. 构造函数与 new​​

普通函数可以作为构造函数(通过 new调用),而箭头函数​​不能作为构造函数​ ​(调用 new会报错)。

普通函数作为构造函数:

ini 复制代码
function Person(name) {
  this.name = name;
}
const p = new Person("Bob");
console.log(p.name); // 输出 "Bob"(this 指向新实例 p)

箭头函数尝试 new:

ini 复制代码
const Animal = (name) => {
  this.name = name; // 箭头函数无独立 this,此处 this 指向外层作用域(如全局 window)
};
const a = new Animal("Cat"); // 报错:Animal is not a constructor

​​4. arguments对象​​

普通函数内部可通过 arguments对象访问所有传入的参数(类数组),而箭头函数​​没有自己的 arguments对象​ ​(但可通过剩余参数 ...args实现类似效果)。

普通函数使用 arguments:

ini 复制代码
function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}
sum(1, 2, 3); // 输出 6

箭头函数使用剩余参数替代:

dart 复制代码
const sum = (...args) => {
  return args.reduce((total, num) => total + num, 0);
};
sum(1, 2, 3); // 输出 6

​​5. yield与生成器函数​​

箭头函数​​不能使用 yield关键字​ ​(除非在嵌套函数中),因此无法作为生成器函数(Generator Function)。普通函数可以通过 function*声明生成器。

​示例​​:

javascript 复制代码
// 普通生成器函数
function* gen() {
  yield 1;
  yield 2;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }

// 箭头函数尝试使用 yield(报错)
const badGen = () => {
  yield 1; // 语法错误:Unexpected token 'yield'
};

​​6. 原型与 prototype属性​​

普通函数拥有 prototype属性(用于存储实例方法),而箭头函数​​没有 prototype属性​​(因为无法作为构造函数)。

​验证​​:

javascript 复制代码
function foo() {}
console.log(foo.prototype); // { constructor: foo }(存在 prototype)

const bar = () => {};
console.log(bar.prototype); // undefined(无 prototype)

​​7. 适用场景对比​​

​​总结​​

箭头函数是普通函数的语法糖,但其核心差异在于 this的绑定机制和设计目标。箭头函数更适合​​需要固定 this上下文​ ​的场景(如回调、函数式编程),而普通函数则适用于​​需要动态 this ​ 或​​作为构造函数​ ​的场景。实际开发中需根据需求选择,避免因 this指向错误导致问题。

相关推荐
东风西巷2 小时前
Rubick:基于Electron的开源桌面效率工具箱
前端·javascript·electron·软件需求
unfetteredman3 小时前
Error: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found
前端·javascript·vite
程序员小续4 小时前
React 官方严令禁止:Hook 不能写在 if/else,真相竟然是…
前端·javascript·程序员
小奋斗4 小时前
深入浅出:JavaScript中 三大异步编程方案以及应用
javascript·面试
尝尝你的优乐美4 小时前
封装那些Vue3.0中好用的指令
前端·javascript·vue.js
敲代码的彭于晏4 小时前
localStorage 不够用?试试 IndexedDB !
前端·javascript·浏览器
chxii5 小时前
5.4 4pnpm 使用介绍
前端·javascript·vue.js
米开朗积德5 小时前
项目多文件JSON数值比对
javascript
sorryhc5 小时前
【AI解读源码系列】ant design mobile——Image图片
前端·javascript·react.js