尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

JavaScript基础笔记-函数[下]

JavaScript基础笔记-函数[下]
📅 发布时间:2026/6/20 3:30:39

注意:本篇学习笔记基于原网站: JavaScript教程 - 廖雪峰的官方网站
笔记仅作学习留档使用

本篇目录

闭包
箭头函数(ES6)
标签函数
生成器(ES6)

闭包

在函数内部写函数,将内部函数作为结果值返回。

  • 调用原函数返回内部函数,调用内部函数返回函数过程结果。
  • 每次调用原函数都会返回一个新的函数,即使传入相同的参数,这些新函数的调用结果互不影响。
function lazy_sum(arr) {let sum = function () {return arr.reduce(function (x, y) {return x + y;});}return sum;
}let f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); // 15
let f1 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f; // false

返回的函数并没有立刻执行,而是直到调用了f()才执行,所以返回函数不要引用任何循环变量,或者后续会发生变化的变量,要不然会这样:

function count() {let arr = [];for (var i=1; i<=3; i++) {//这里是var定义arr.push(function () {return i * i;});}return arr;
}let results = count();
let [f1, f2, f3] = results;
f1(); // 16
f2(); // 16
f3(); // 16

非要用那可以这么写:

/*1.创建一个函数,用该函数的参数绑定循环变量当前的值*/
function count() {let arr = [];for (var i=1; i<=3; i++) {arr.push((function (n) { // n绑定循环变量当前的值return function () {return n * n;}})(i));}return arr;
}let [f1, f2, f3] = count();f1(); // 1
f2(); // 4
f3(); // 9/*2.或者把循环变量i用let定义在for循环体中*/
function count() {let arr = [];for (let i=1; i<=3; i++) {arr.push(function () {return i * i;});}return arr;
}
  • (function (x) { return x * x }) (3); :这种写法的意思是“创建一个匿名函数并立刻执行”

使用实例:计数器

function create_counter(initial) {let x = initial || 0;return {inc: function () {x += 1;return x;}}
}let c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3let c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
  • let x = initial || 0 :将变量 initial赋值给 x,但如果 initial是假值(falsy),则使用 0作为默认值。
  • 常见假值:undefined 、null、false、0、NaN、""(空字符串)

箭头函数(ES6)

在高阶函数(函数笔记上篇)里用过一次,相当于匿名函数

x => x * x
//等价于↓
function (x) {return x * x;
}/*多条语句的情况*/
x => {if (x > 0) {return x * x;}else {return - x * x;}
}/*参数数量不为1的情况*/
(x, y) => x * x + y * y// 两个参数
() => 3.14// 无参数
// 可变参数
(x, y, ...rest) => {let i, sum = x + y;for (i=0; i<rest.length; i++) {sum += rest[i];}return sum;
}

如果要返回对象要加():

// SyntaxError:
x => { foo: x }
// ok:
x => ({ foo: x })

this

箭头函数内部的this比较特殊,是词法作用域,由上下文确定。用上篇里的例子:

let obj = {birth: 1990,getAge: function () {let b = this.birth; // 1990let fn = function () {return new Date().getFullYear() - this.birth; // this指向window或undefined};return fn();}
};//用this可以解决
//箭头函数定义在 getAge方法内部,而 getAge方法的 this指向调用它的对象 obj
let obj = {birth: 1990,getAge: function () {let b = this.birth; // 1990let fn = () => new Date().getFullYear() - this.birth; // this指向obj对象return fn();}
};
obj.getAge(); // 25

由于this在箭头函数中按照词法作用域是绑定的,所以用call()或者apply()无法对this进行绑定,传入的第一个参数会被忽略

let obj = {birth: 1990,getAge: function (year) {let b = this.birth; // 1990let fn = (y) => y - this.birth; // this.birth仍是1990return fn.call({birth:2000}, year);}
};
obj.getAge(2015); // 25

标签函数

用一个模拟sql数据查询解释

//变量声明
const email = "test@example.com";
const password = 'hello123';
//定义函数
function sql(strings, ...exps) {console.log(`SQL: ${strings.join('?')}`);console.log(`SQL parameters: ${JSON.stringify(exps)}`);return {name: '小明',age: 20};
}
//调用
const result = sql`SELECT * FROM users WHERE email=${email} AND password=${password}`;
//打印
console.log(JSON.stringify(result));

原博这里说的比较简略,我详细解释一下可能有点难懂的部分:

function sql(strings, ...exps) {
  • strings:接收模板字符串的所有静态部分
    这里strings= ["SELECT * FROM users WHERE email=", " AND password=", ""]
    注意:这里在第二个插值 ${password}之后,虽然没有静态文本,但仍然有一个位置存在,所以strings最后接收到一个"",如果输入语句在最后一个动态插值后没有别的字符就会这样。
  • ...exps:接收模板字符串中的所有动态插值(${...}部分)
    这里exps= ["test@example.com", "hello123"]

console.log(`SQL: ${strings.join('?')}`);

这里将 strings数组用 ?连接起来,是模拟SQL参数化查询,?是数据库用的参数占位符,表示我还不知道这里要放什么数据,先用这个符号占一下位置。
打印显示为:SQL: SELECT * FROM users WHERE email=? AND password=?


console.log(`SQL parameters: ${JSON.stringify(exps)}`);

打印所有参数值,JSON.stringify(exps)函数作用是将参数数组转换为 JSON 字符串。
打印结果会显示为:SQL parameters: ["test@example.com","hello123"]


const result = sql`SELECT * FROM users WHERE email=${email} AND password=${password}`;

这就是标签模板语法的调用方式,反引号 ```包裹的是模板字串,${email}和 ${password}是变量插值,整个结构被传递给 sql函数,普通调用的话其实应该是sql(["SELECT * FROM users WHERE email=", " AND password=", ""], email, password)


console.log(JSON.stringify(result));

将函数返回的对象转换为 JSON 字符串
输出:{"name":"小明","age":20}


这样调用的时候会简单很多

let id = 123;
let age = 21;
let score = 'A';update`UPDATE users SET age=${age}, score=${score} WHERE id=${id}`;

生成器(ES6)

看上去像一个函数,但可以返回多次,借鉴了Python的generator的概念和语法。由function*定义(注意多出的*号),除了return语句,还可以用yield返回多次。可以实现需要用面向对象才能实现的功能。

function* foo(x) {yield x + 1;yield x + 2;return x + 3;
}

以斐波那契数列的函数当例子:

function* fib(max) {lett,a = 0,b = 1,n = 0;while (n < max) {yield a;[a, b] = [b, a + b];n ++;}return;
}
//直接调用不行
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}/*调用方法*/
//方法一:不断地调用generator对象的next()
let f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}//方法二:直接用for ... of循环迭代generator对象
function* fib(max) {leta = 0,b = 1,n = 0;while (n < max) {yield a;[a, b] = [b, a + b];n ++;}return;
}for (let x of fib(10)) {console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}

相关新闻

  • 对比tensorflow,从0开始学pytorch(五)--CBAM
  • GitPuk基础到实践,如何详细掌管代码
  • easy_nbt(Bugku杂项入门)

最新新闻

  • 苏州欧路达智能科技:工业物资智能管控柜及刀具管理柜全系解决方案推荐 - 品牌推荐官
  • CefFlashBrowser:让经典Flash内容重获新生的全能浏览器解决方案
  • 2026 郑州高新区奢侈品黄金回收门店盘点指南:五大品牌深度测评对比 - 奢侈品回收
  • 2026年武汉市老百姓优先选择的五家贵金属回收门店 黄金回收白银回收铂金回收彩金回收合规靠谱门店测评合集+联系方式 - 亦辰小黄鸭
  • B型轻集料混凝土批发,这样选材不踩坑
  • SPI通信错误处理:从硬件原理到软件实践的深度解析

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号