一、数组
-
数组的遍历
- ES5 中数组的遍历方式
- for:经常用,不太简洁
- forEach:没有返回值,代码块中不能使用break、continue
- map:返回新的数组
- filter:返回新的数组
- some:返回 boolean
- every:返回 boolean
- reduce:接收一个函数作为累加器,第一个参数式回调函数,回调函数的参数一共有4个:
- prevValue:必需,上一次回调返回的值
- currentValue:必需,数组中当前被处理的元素
- index:可选
- array:可选
- ES6 中数组的遍历方式
- find
- findIndex
- for of
- values
- keys
- entries
- ES5 中数组的遍历方式
-
伪数组
- 伪数组有以下两个特征:1. 按索引方式储存数据;2. 具有 length 属性
-
Array.from()
let arrayList = { 0: "es5", 1: "es6", length: 2 }; let newArr = Array.from(arrayList); newArr.push("es7");
-
-
如何判断是否是数组?
- typeof
- instanceof
- constructor
- Object.prototype.toString
-
-
函数
-
参数与解构赋值结合
-
参数作用域
作用域链:当在JS中使用一个变量的时候,首先JS会尝试在当前作用域下去寻找该变量,如果没有找到,再到它上一层作用域寻找。以此类推直到找到该变量为止,如果最后也没找到,直接报错!
let x = 1; function foo(x, y = x) { console.log(y); } foo(2); // 2
let x = 1; function foo(y = x) { console.log(y); } foo(); // 1
function foo(y = x) { let x = 2; console.log(y); } // 定义函数时直接报错 x 未定义
3.扩展运算符:把数组或者类数组展开用逗号隔开的值,应用场景如下:
-
复制数组
// 由于数组是按照引用传值的,不能直接赋值。 let arr1 = [1, 2]; let arr2 = arr1; arr1.push(3); console.log(arr1); // [1, 2, 3] console.log(arr2); // [1, 2, 3]
// ES5 方式 let arr1 = [1, 2]; let arr2 = []; arr1.forEach(function(value) { arr2.push(value); }); arr1.push(3); console.log(arr1); // [1, 2, 3] console.log(arr2); // [1, 2]
// ES6 方式 let arr1 = [1, 2]; let arr2 = [...arr1]; arr1.push(3); console.log(arr1); // [1, 2, 3] console.log(arr2); // [1, 2]
数组合并
// ES5 方式 let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; arr1.concat(arr2); console.log(arr1); // [1, 2, 3]
// ES6 方式 let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; // [1, 2, 3, 4, 5, 6] arr1.push(...arr2); console.log(arr1); // [1, 2, 3, 4, 5, 6]
let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; // [1, 2, 3, 4, 5, 6] let arr3 = [...arr1, ...arr2]; console.log(arr); // [1, 2, 3, 4, 5, 6]
剩余参数:把逗号隔开的值组合成一个数组,应用场景如下:
-
不定参数 arguments
// 案例:计算函数所有参数的和 // ES5 方式 function sum() { let result = 0; for(let i = 0; i <= arguments.length; i++) { result += arguments[i]; } return result; } sum(1, 2, 3); sum(1, 2, 3, 67, 45, 100);
// ES6 方式 function sum(...args) { let result = 0; args.forEach(function(value) { result += value; }); return result; } sum(1, 2, 3); sum(1, 2, 3, 67, 45, 100);
function sum(...args) { return args.reduce(function(prevValue, currentValue) { return prevValue + currentValue; }, 0); } sum(1, 2, 3); sum(1, 2, 3, 67, 45, 100);
解构赋值
let [a, b, ...c] = [1, 2, 3, 4]; console.log(a, b, c); // 1 2 [3, 4]
let {b, a, ...args} = {a: 1, b: 2, c: 3, d: 4}; console.log(a, b, args); // 1 2 {c: 3, d: 4}
二、箭头函数
-
定义函数的几种方式
foo(1, 2); function foo(x, y) { return x + y; } foo(1, 2);
let foo = function(x, y) { return x + y; } foo(1, 2);
let foo = (x, y) => { return x + y; } foo(1, 2);
let foo = (x, y) => x + y; foo(1, 2);
let x = x => x; // 等价于 function x(x) { return x; }
-
-
-
-
-
-
this 的本质
-
全局函数的this指向全局对象window;
-
当函数作为对象的方法被调用时,this 指向该对象。即谁调用函数this就指向谁;
-
匿名函数的this指向全局对象window;
-
箭头函数的this指向的是定义时的this对象,而不是执行时的this对象。
-
-
使用箭头函数的注意事项
- 箭头函数的this指向的是定义时的this对象,而不是执行时的this对象。
- 不可以当作构造函数
- 不可以使用 arguments
三、对象的扩展
- 属性简洁表示法
- 属性名表达式
- Object.is()
- Object.assign()
- in
- 对象的遍历方式
- for in
- Object.keys()
- Object.getOwnPropertyNames()
- Reflect.ownKeys()
四、作业
- 简述 bind、call、apply 的作用及区别。
call 和 apply 的区别:传参的方式不同
- call(obj, param1, param2, param3…)
- apply(obj, [param1, param2, param3…])
bind 与 call / apply 的区别:
- bind 返回的是一个新的函数,需要再调用一下才会执行
- bind 的传参方式同 call, 即:bind(obj, param1, param2, …)
- call / apply 是立即执行,bind 返回的是一个函数,便于稍后调用。
2.简述什么是递归函数?
递归就是一个函数在它的函数体内调用它自身。执行递归函数将反复调用其自身,每调用一次就进入新的一层。递归函数必须有结束条件。
当函数在一直递推,直到遇到墙后返回,这个墙就是结束条件。
所以递归要有两个要素,结束条件与递推关系
3.简述深拷贝和浅拷贝,手写一个实现深拷贝的函数。
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 。
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象。
区别:浅拷贝基本类型之前互不影响,引用类型其中一个对象改变了地址,就会影响另一个对象;深拷贝
改变新对象不会影响原对象,他们之前互不影响。
//赋值
//对象赋值
let obj1 = { name: '张三', action: { say: 'hi'};
let obj2 = obj1;
obj2.name = '李四';
obj2.action.say = 'hello'
console.log('obj1',obj1)
// obj1 { name: '李四', action: { say: 'hello'}
console.log('obj2',obj2)
// obj2 { name: '李四', action: { say: 'hello'}
//浅拷贝
let obj1 = { name: '张三', action: { say: 'hi'};
let obj2 = Object.assign({}, obj1);
obj2.name = '李四';
obj2.action.say = 'hello'
console.log('obj1',obj1)
// obj1 { name: '张三', action: { say: 'hello'}
console.log('obj2',obj2)
// obj2 { name: '李四', action: { say: 'hello'}
//展开运算符
let obj1 = { name: '张三', action: { say: 'hi'};
let obj2 = {... obj1};
obj2.name = '李四';
obj2.action.say = 'hello'
console.log('obj1',obj1)
// obj1 { name: '张三', action: { say: 'hello'}
console.log('obj2',obj2)
// obj2 { name: '李四', action: { say: 'hello'}
//深拷贝
let obj1 = { name: '张三', action: { say: 'hi'};
let obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.action.say = 'hello'
console.log('obj1',obj1)
// obj1 { name: '张三', action: { say: 'hi'}
console.log('obj2',obj2)
// obj2 { name: '李四', action: { say: 'hello'}