新乡市网站建设_网站建设公司_跨域_seo优化
2025/12/17 4:18:24 网站建设 项目流程

注意:本篇学习笔记基于原网站: 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作为默认值。
  • 常见假值:undefinednullfalse0NaN""(空字符串)

箭头函数(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, ...
}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询