【JavaScript 笔记】— 函数高级(变量作用域、解构赋值、方法、高阶函数、闭包(1)

apply


虽然在一个独立的函数调用中,根据是否是 strict 模式,this 指向 undefinedwindow,不过,我们还是可以控制this的指向的!

要指定函数的 this 指向哪个对象,可以用函数本身apply 方法,它接收两个参数,第一个参数就是需要绑定的 this 变量,第二个参数是 Array,表示函数本身的参数。

apply 修复 getAge() 调用:

function getAge() {

var y = new Date().getFullYear();

return y - this.birth;

}

var xiaoming = {

name: ‘小明’,

birth: 1990,

age: getAge

};

xiaoming.age(); // 25

getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

另一个与 apply() 类似的方法是 call(),唯一区别是:

  • apply() 把参数打包成 Array 再传入;

  • call() 把参数按顺序传入。

比如调用 Math.max(3, 5, 4),分别用 apply()call() 实现如下:

Math.max.apply(null, [3, 5, 4]);

Math.max.call(null, 3, 5, 4);

对普通函数调用,我们通常把 this 绑定为 null

装饰器


利用 apply(),我们还可以动态改变函数的行为

JavaScript 的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。

现在假定我们想统计一下代码一共调用了多少次 parseInt()。可以把所有的调用都找出来,然后手动加上 count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的 parseInt()

‘use strict’

var count = 0;

var oldParseInt = parseInt; // 保存原函数

window.parseInt = function() {

count += 1;

return oldParseInt.apply(null, arguments); // 调用原函数

};

// 测试:

parseInt(‘10’);

parseInt(‘20’);

parseInt(‘30’);

console.log('count = ’ + count); // 3

高阶函数(Array)

==============================================================================

高阶函数英文叫 Higher-order function。那么什么是高阶函数?

  • 一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。

一个最简单的高阶函数:

function add(x, y, f) {

return f(x) + f(y);

}

当我们调用 add(-5, 6, Math.abs) 时,参数 x,y 和 f 分别接收 -5,6 和 函数Math.abs,根据函数定义,我们可以推导计算过程为:

x = -5;

y = 6;

f = Math.abs;

f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11;

return 11;

用代码验证一下:

function add(x, y, f) {

return f(x) + f(y);

}

var x = add(-5, 6, Math.abs); // 11

console.log(x); // 11

编写高阶函数,就是让函数的参数能够接收别的函数。

map


比如我们有一个函数 f(x) = x2,要把这个函数作用在一个数组 [1, 2, 3, 4, 5, 6, 7, 8, 9] 上,就可以用 map 实现如下:

在这里插入图片描述

map() 方法定义在 JavaScript 的 Array 中,我们调用 Arraymap() 方法,传入我们自己的函数,就得到了一个新的 Array 作为结果:

function pow(x) {

return x * x;

}

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]

注意:map() 传入的参数是 pow,即函数对象本身

map() 作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的 f(x) = x2,还可以计算任意复杂的函数,比如,把 Array 的所有数字转为字符串只需要一行代码。

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

arr.map(String);

reduce


Arrayreduce() 把一个函数作用在这个 Array[x1, x2, x3...] 上,这个函数必须接收两个参数reduce() 把结果继续和序列的下一个元素做累积计算,其效果就是:

比方说对一个 Array 求和,就可以用 reduce 实现:

var arr = [1, 3, 5, 7, 9];

arr.reduce(function(x, y) {

return x + y;

}); // 25

要把 [1, 3, 5, 7, 9] 变换成整数 13579,reduce() 也能派上用场:

var arr = [1, 3, 5, 7, 9];

arr.reduce(function (x, y) {

return x * 10 + y;

}); // 13579

map、reduce练习


(1)不使用 parseInt() 函数,利用 mapreduce 操作实现一个 string2int() 函数。

思路:把字符串 13579 先变成 Array —— [1, 3, 5, 7, 9],再利用 reduce()

function string2int (s) {

s = s.split(‘’);

s = s.map(function (x) {

return +x;

});

s = s.reduce(function (x, y) {

return x * 10 + y;

});

return s;

}

/

function string2int(s) {

s = s.split(‘’);

s = s.map((x) => {

return +x;

});

s = s.reduce((x, y) => {

return x * 10 + y;

});

return s;

}

/

function string2int(s) {

return s.split(‘’).map(x => x * 1).reduce((x, y) => x * 10 + y);

}

/

function string2int(s) {

return s * 1;

}

/

function string2int(s) {

return +s;

}

(2)请把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。

输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']

function normalize(arr) {

arr = arr.map(function(x) {

return x.charAt(0).toUpperCase() + x.substring(1).toLowerCase();

})

return arr;

}

/

function normalize(arr) {

arr = arr.map((x) => {

return x.charAt(0).toUpperCase() + x.substring(1).toLowerCase();

})

return arr;

}

/

function normalize(arr) {

arr = arr.map((x) => x.charAt(0).toUpperCase() + x.substring(1).toLowerCase());

return arr;

}

(3)小明希望利用 map() 把字符串变成整数,他写的代码很简洁:

var arr = [‘1’, ‘2’, ‘3’];

var r;

r = arr.map(parseInt);

console.log®;

1, NaN, NaN

结果竟然是 1, NaN, NaN,小明百思不得其解,请帮他找到原因并修正代码。

错误原因:https://www.cnblogs.com/liuyfl/p/4476179.html

var arr = [‘1’, ‘2’, ‘3’];

var r;

r = arr.map(x => parseInt(x));

console.log®;

filter


filter 也是一个常用的操作,它用于把 Array 的某些元素过滤掉,然后返回剩下的元素。

filter() 接收一个函数,把传入的函数依次作用于每个元素,函数返回值为 true 则保留元素,为 false 则删除元素。

例如,在一个 Array 中,删掉偶数,只保留奇数,可以这么写:

var arr = [1, 2, 4, 5, 6, 9, 10, 15];

var r = arr.filter(function (x) {

return x % 2 !== 0;

});

r; // [1, 5, 9, 15]

把一个 Array 中的空字符串删掉,可以这么写:

var arr = [‘A’, ‘’, ‘B’, null, undefined, ‘C’, ’ '];

var r = arr.filter(function (s) {

return s && s.trim(); // 注意:IE9以下的版本没有trim()方法

});

r; // [‘A’, ‘B’, ‘C’]


filter() 接收的 回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示 Array 的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:

var arr = [‘A’, ‘B’, ‘C’];

var r = arr.filter(function (element, index, self) {

console.log(element); // 依次打印’A’, ‘B’, ‘C’

console.log(index); // 依次打印0, 1, 2

console.log(self); // self就是变量arr

return true;

});

利用 filter,可以巧妙地去除 Array 的重复元素:

var

r,

arr = [‘apple’, ‘strawberry’, ‘banana’, ‘pear’, ‘apple’, ‘orange’, ‘orange’, ‘strawberry’];

r = arr.filter(function (element, index, self) {

return self.indexOf(element) === index; // 保留

});

练习:请尝试用 filter() 筛选出素数:

function get_primes(arr) {

return arr.filter(function(ele) {

if (ele === 1) return false; // 1是特殊情况

let count = 0;

for (let i = 1; i < ele; i++) {

if (ele % i == 0) count++;

if (count >= 2) return false;

}

return true;

});

}

sort


Arraysort() 方法就是用于排序的,但是默认排序结果令人震惊

// 理想中的结果:

[‘Google’, ‘Apple’, ‘Microsoft’].sort(); // [‘Apple’, ‘Google’, ‘Microsoft’];

// 实际结果: apple排在了最后

[‘Google’, ‘apple’, ‘Microsoft’].sort(); // [‘Google’, 'Microsoft", ‘apple’]

// 无法理解的结果:

[10, 20, 1, 2].sort(); // [1, 10, 2, 20]

第二个排序把 apple 排在了最后,是因为字符串根据 ASCII 码进行排序,而小写字母 a 的ASCII码在大写字母 A 之后。

第三个排序结果是因为 Arraysort() 方法 默认把所有元素先转换为 String 再排序,结果 '10' 排在了 '2' 的前面,因为字符 '1' 比字符 '2' 的 ASCII 码小。

sort() 方法的默认排序规则十分反人类,好在 sort() 方法也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。

要按数字大小排序,我们可以这么写:

var arr = [10, 20, 1, 2];

arr.sort(function(x, y) {

if (x < y) {

return -1;

}

if (x > y) {

return 1;

}

return 0;

});

console.log(arr); // [1, 2,10, 20]

如果要倒序排序,我们可以把大的数放前面:

var arr = [10, 20, 1, 2];

arr.sort(function (x, y) {

if (x < y) {

return 1;

}

if (x > y) {

return -1;

}

return 0;

}); // [20, 10, 2, 1]

要注意,sort() 方法会直接对 Array 进行修改,它返回的结果仍是当前 Array

var a1 = [‘B’, ‘A’, ‘C’];

var a2 = a1.sort();

a1; // [‘A’, ‘B’, ‘C’]

a2; // [‘A’, ‘B’, ‘C’]

a1 === a2; // true, a1和a2是同一对象

every、find、findIndex、forEach


对于数组,除了 map()reducefilter()sort() 这些方法可以传入一个函数外,Array 对象还提供了很多非常实用的高阶函数。


every() 用于判断数组的所有元素是否满足测试条件

例如,给定一个包含若干字符串的数组,判断所有字符串是否满足指定的测试条件:

var arr = [‘Apple’, ‘pear’, ‘orange’];

arr.every(function (s) {

return s.length > 0;

}); // true, 因为每个元素都满足s.length>0

arr.every(function (s) {

return s.toLowerCase() === s;

}); // false, 因为不是每个元素都全部是小写


find() 用于查找符合条件的第一个元素,找到则返回该元素,否则返回 undefined

var arr = [‘Apple’, ‘pear’, ‘orange’];

arr.find(function (s) {

return s.toLowerCase() === s;

}); // ‘pear’, 因为pear全部是小写

arr.find(function (s) {

return s.toUpperCase() === s;

}); // undefined, 因为没有全部是大写的元素


findIndex() 用于查找符合条件的第一个元素,找到则返回该元素的索引,否则返回-1

var arr = [‘Apple’, ‘pear’, ‘orange’];

console.log(arr.findIndex(function (s) {

return s.toLowerCase() === s;

})); // 1, 因为’pear’的索引是1

console.log(arr.findIndex(function (s) {

return s.toUpperCase() === s;

})); // -1


forEach()map() 类似,也把每个元素依次作用于传入的函数,但不会返回新的数组

forEach() 常用于遍历数组,因此,传入的函数不需要返回值:

var arr = [‘Apple’, ‘pear’, ‘orange’];

// 依次打印每个元素

arr.forEach(function (x) {

console.log(x);

});

arr.forEach(console.log);

闭包

=====================================================================

函数作为返回值


高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

function lazy_sum(arr) {

var sum = function () {

return arr.reduce(function (x, y) {

return x + y;

});

}

return sum;

}

调用 lazy_sum() 时,返回求和函数;调用 f() 时返回计算结果。

var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()

f(); // 15

这个例子中,函数 lazy_sum 中又定义了函数 sum,并且,内部函数 sum 可以引用外部函数 lazy_sum 的参数和局部变量,当 lazy_sum 返回函数 sum 时,相关参数和变量都保存在返回的函数中,这种称为 闭包(Closure) 的程序结构拥有极大的威力。

再注意一点,当我们调用 lazy_sum() 时,每次调用都会返回一个新的函数,即使传入相同的参数:

var f1 = lazy_sum([1, 2, 3, 4, 5]);

var f2 = lazy_sum([1, 2, 3, 4, 5]);

f1 === f2; // false

f1()f2() 的调用结果互不影响。

闭包的细节


下面这个例子结果可能有点令人震惊:

function count() {

var arr = [];

for (var i = 1; i <= 3; i++) {

arr.push(function () {

return i * i;

});

}

return arr;

}

var results = count();

var f1 = results[0];

var f2 = results[1];

var f3 = results[2];

f1(); // 16

f2(); // 16

f3(); // 16

返回值全部都是 16,原因就在于返回的函数引用了变量 i,但它并非立刻执行。等到 3 个函数都返回时,它们所引用的变量 i 已经变成了 4,因此最终结果为 16

返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

function count () {

var arr = [];

for (var i = 1; i <= 3; i++) {

arr.push((function (n) {

return function() {

return n * n;

}

})(i));

}

return arr;

}

var results = count();

var f1 = results[0];

var f2 = results[1];

var f3 = results[2];

f1(); // 1

f2(); // 4

f3(); // 9

这里用了一个 创建一个匿名函数并立刻执行 的语法:

// 创建匿名函数需要用括号括起函数定义

(function (x) {

return x * x;

})(3); // 9

// 创建匿名函数【不能】这么写:

function (x) { return x * x } (3) // SyntaxError


说了这么多,难道闭包就是为了返回一个函数然后延迟执行吗?

当然不是!闭包有非常强大的功能。举个栗子:

在面向对象的程序设计语言里,比如 Java 和 C++,要在对象内部封装一个私有变量,可以用 private修饰一个成员变量。

在没有 class 机制,只有函数的语言里,借助闭包,同样可以封装一个私有变量。

我们用 JavaScript 创建一个计数器:

function create_counter(initial) {

var x = initial || 0;

return { // 返回一个对象

inc: function () {

x += 1;

return x;

}

}

}

它用起来像这样:

var c1 = create_counter();

c1.inc(); // 1

c1.inc(); // 2

c1.inc(); // 3

var c2 = create_counter(10);

c2.inc(); // 11

c2.inc(); // 12

c2.inc(); // 13

在返回的对象中,实现了一个闭包,该闭包携带了局部变量 x,并且,从外部代码根本无法访问到变量 x。换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来


闭包还可以把多参数的函数变成单参数的函数。

例如,要计算 x^y 可以用 Math.pow(x, y) 函数,不过考虑到经常计算 x2 或 x3,我们可以利用闭包创建新的函数 pow2pow3

function make_pow (n) {

return function(x) {

return Math.pow(x, n);

}

}

// 创建两个新函数:

var pow2 = make_pow(2);

var pow3 = make_pow(3);

console.log(pow2(5)); // 25

console.log(pow3(7)); // 343


脑洞大开

很久很久以前,有个叫阿隆佐·邱奇的帅哥,发现只需要用函数,就可以用计算机实现运算,而不需要 0123 这些数字和 +-*/ 这些符号。

JavaScript 支持函数,所以可以用 JavaScript 用函数来写这些计算。来试试:

// 定义数字0:

var zero = function (f) {

return function (x) {

return x;

}

};

// 定义数字1:

var one = function (f) {

return function (x) {

return f(x);

}

};

// 定义加法:

function add(n, m) {

return function (f) {

return function (x) {

return m(f)(n(f)(x)); // 先执行n(x),然后执行m(n(x))

}

}

}

// 计算数字2 = 1 + 1:

var two = add(one, one);

// 计算数字3 = 1 + 2:

var three = add(one, two);

// 计算数字5 = 2 + 3:

var five = add(two, three);

// 你说它是3就是3,你说它是5就是5,你怎么证明?

// 呵呵,看这里:

// 给3传一个函数,会打印3次:

(three(function () {

console.log(‘print 3 times’);

}))();

// 给5传一个函数,会打印5次:

(five(function () {

console.log(‘print 5 times’);

}))();

// 继续接着玩一会…

箭头函数

=======================================================================

ES6 标准新增了一种新的函数:Arrow Function(箭头函数)。

箭头函数有两种表达方式,第一种只包含一个表达式,连 { ... }return 都省略掉了

x => x * x

// 等价于下面

function (x) {

return x * x;

}

还有一种可以包含多条语句,这时候就不能省略 { ... }return

x => {

if (x > 0) {

return x * x;

}

else {

return - x * x;

}

}

如果参数不是一个,就需要用括号 () 括起来:

// 两个参数:

(x, y) => x * x + y * y

// 无参数:

() => 3.14

// 可变参数:

(x, y, …rest) => {

var 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 是词法作用域,由上下文确定。

回顾前面的例子,由于 JavaScript 函数对 this 绑定的错误处理,下面的例子无法得到预期结果:

var obj = {

birth: 1990,

getAge: function () {

var b = this.birth; // 1990

var fn = function () {

return new Date().getFullYear() - this.birth; // this指向window或undefined

};

return fn();

}

};

现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 obj

var obj = {

birth: 1990,

getAge: function () {

var b = this.birth; // 1990

var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象

return fn();

}

};

obj.getAge(); // 25

如果使用箭头函数,以下的写法就不需要了。

var _this = this;

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

var obj = {

birth: 1990,

getAge: function (year) {

var b = this.birth; // 1990

var fn = (y) => y - this.birth; // this.birth仍是1990

return fn.call({birth:2000}, year);

}

};

obj.getAge(2015); // 25

generator

============================================================================

generator(生成器) 是 ES6 标准引入的新的数据类型。

generator 跟函数很像,定义如下:

function* foo(x) {

yield x + 1;

yield x + 2;

return x + 3;

}

和函数不同的是:generator 由 function* 定义,并且除了 return ,还可以用 yield 返回多次。

generator 就是能够返回多次的“函数”?返回多次有啥用?

以一个著名的斐波那契数列为例,它由 0,1 开头:

function fib(max) {

var

t,

a = 0,

b = 1,

arr = [0, 1];

while (arr.length < max) {

[a, b] = [b, a + b];

arr.push(b);

}

return arr;

}

// 测试:

fib(5); // [0, 1, 1, 2, 3]

fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

函数只能返回一次,所以必须返回一个 Array

如果换成 generator,就可以一次返回一个数,不断返回多次。用 generator 改写如下:

function* fib(max) {

var

t,

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 和调用函数不一样,fib(5) 仅仅是创建了一个 generator 对象,还没有去执行它。

调用 generator 对象有两个方法,一是不断地调用 generator 对象的 next() 方法:

var 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}

next() 方法会执行 generator 的代码,然后,每次遇到 yield x; 就返回一个对象 {value: x, done: true/false},然后“暂停”。返回的 value 就是 yield 的返回值,done 表示这个 generator 是否已经执行结束了。如果 donetrue,则 value 就是 return 的返回值。

当执行到 donetrue 时,这个 generator 对象就已经全部执行完毕,不要再继续调用 next() 了。

第二个方法是直接用 for ... of 循环迭代 generator 对象,这种方式不需要我们自己判断 done

function* fib(max) {

var

t,

a = 0,

b = 1,

n = 0;

while (n < max) {

yield a;

[a, b] = [b, a + b];

n ++;

}

return;

}

for (var x of fib(10)) {

console.log(x); // 依次输出0, 1, 1, 2, 3, …

}

generator 和普通函数相比,有什么用?

因为 generato r可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个 generator 就可以实现需要用面向对象才能实现的功能。

例如,用一个对象来保存状态,得这么写:

var fib = {

a: 0,

b: 1,

n: 0,

max: 5,

next: function () {

var

r = this.a,

t = this.a + this.b;

this.a = this.b;

this.b = t;

if (this.n < this.max) {

this.n ++;

return r;

} else {

return undefined;

}

}

};

用对象的属性来保存状态,相当繁琐。


generator 还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。这个好处要等到后面学了AJAX以后才能体会到。

没有 generator 之前用 AJAX 时需要这么写代码:回调越多,代码越难看。

ajax(‘http://url-1’, data1, function (err, result) {

if (err) {

return handle(err);

}

ajax(‘http://url-2’, data2, function (err, result) {

if (err) {

return handle(err);

}

ajax(‘http://url-3’, data3, function (err, result) {

if (err) {

return handle(err);

}

return success(result);

});

});

});

有了 generator 后用 AJAX 时可以这么写:看上去是同步的代码,实际执行是异步的。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是附赠给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

详细大厂面试题答案、学习笔记、学习视频等资料领取,点击资料领取直通车

前端视频资料:

generator 和普通函数相比,有什么用?

因为 generato r可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个 generator 就可以实现需要用面向对象才能实现的功能。

例如,用一个对象来保存状态,得这么写:

var fib = {

a: 0,

b: 1,

n: 0,

max: 5,

next: function () {

var

r = this.a,

t = this.a + this.b;

this.a = this.b;

this.b = t;

if (this.n < this.max) {

this.n ++;

return r;

} else {

return undefined;

}

}

};

用对象的属性来保存状态,相当繁琐。


generator 还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。这个好处要等到后面学了AJAX以后才能体会到。

没有 generator 之前用 AJAX 时需要这么写代码:回调越多,代码越难看。

ajax(‘http://url-1’, data1, function (err, result) {

if (err) {

return handle(err);

}

ajax(‘http://url-2’, data2, function (err, result) {

if (err) {

return handle(err);

}

ajax(‘http://url-3’, data3, function (err, result) {

if (err) {

return handle(err);

}

return success(result);

});

});

});

有了 generator 后用 AJAX 时可以这么写:看上去是同步的代码,实际执行是异步的。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-E8JuUrWQ-1712996493934)]

[外链图片转存中…(img-df5q2OKc-1712996493934)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-jJaLoIp3-1712996493935)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是附赠给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

详细大厂面试题答案、学习笔记、学习视频等资料领取,点击资料领取直通车

[外链图片转存中…(img-1jWIbyzq-1712996493935)]

前端视频资料:

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值