//对文章做一些笔记 无法设置仅自己可见 只能发布
//原文章地址juejin.cn/post/684490…
第七篇: 函数的arguments为什么不是数组?如何转化成数组?
因为arguments本身并不能调用数组方法,它是一个另外一种对象类型,只不过属性从0开始排,依次为0,1,2...最后还有callee和length属性。我们也把这样的对象称为类数组。
arguments 是一个对应于传递给函数的参数的类数组对象。
常见的类数组还有:
- 用getElementsByTagName/ClassName()获得的HTMLCollection
- 用querySelector获得的nodeList
那这导致很多数组的方法就不能用了,必要时需要我们将它们转换成数组,有哪些方法呢?
列举了4个转换为数组的方法,并调用数组的方法,来验证成功
第一个方法将自身arg作为参赛传递进去
Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
apply可以接受参数,配合concat拼接数组
- Array.prototype.slice.call()
function sum(a, b) {
let args = Array.prototype.slice.call(arguments);
console.log(args.reduce((sum, cur) => sum + cur));//args可以调用数组原生的方法啦
}
sum(1, 2);//3
- Array.from()
function sum(a, b) {
let args = Array.from(arguments);
console.log(args.reduce((sum, cur) => sum + cur));//args可以调用数组原生的方法啦
}
sum(1, 2);//3
这种方法也可以用来转换Set和Map哦!
- ES6展开运算符
function sum(a, b) {
let args = [...arguments];
console.log(args.reduce((sum, cur) => sum + cur));//args可以调用数组原生的方法啦
}
sum(1, 2);//3
- 利用concat+apply
function sum(a, b) {
let args = Array.prototype.concat.apply([], arguments);//apply方法会把第二个参数展开
console.log(args.reduce((sum, cur) => sum + cur));//args可以调用数组原生的方法啦
}
sum(1, 2);//3
当然,最原始的方法就是再创建一个数组,用for循环把类数组的每个属性值放在里面,过于简单,就不浪费篇幅了。
第八篇: forEach中return有效果吗?如何中断forEach循环?
在forEach中用return不会返回,函数会继续执行。
let nums = [1, 2, 3];
nums.forEach((item, index) => {
return;//无效
})
中断方法:
- 使用try监视代码块,在需要中断的地方抛出异常。
- 官方推荐方法(替换方法):用every和some替代forEach函数。every在碰到return false的时候,中止循环。some在碰到return true的时候,中止循环
最后返回true或者false
返回找到的元素
Array.prototype.every() 如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false。
Array.prototype.some()如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false。
第九篇: JS判断数组中是否包含某个值
返回找到的元素
方法一:array.indexOf
此方法判断数组中是否存在某个值,如果存在,则返回数组元素的下标,否则返回-1。
方法二:array.includes(searcElement[,fromIndex])
此方法判断数组中是否存在某个值,如果存在返回true,否则返回false
方法三:array.find(callback[,thisArg])
返回数组中满足条件的第一个元素的值,如果没有,返回undefined
方法四:array.findeIndex(callback[,thisArg])
返回数组中满足条件的第一个元素的下标,如果没有找到,返回-1]
第十篇: JS中flat---数组扁平化
对于前端项目开发过程中,偶尔会出现层叠数据结构的数组,我们需要将多层级数组转化为一级数组(即提取嵌套数组元素最终合并为一个数组),使其内容合并且展开。那么该如何去实现呢?
需求:多维数组=>一维数组
let ary = [1, [2, [3, [4, 5]]], 6];// -> [1, 2, 3, 4, 5, 6]
let str = JSON.stringify(ary);//将对象转成字符串
1. 调用ES6中的flat方法
ary = ary.flat(Infinity);
2. replace + split
ary = str.replace(/(\[|\])/g, '').split(',')
//将正则为匹配任意[或者],替换为空,得到1,2,3,4,5,6 再以 ,为分隔符 split成数组
3. replace + JSON.parse
str = str.replace(/(\[|\])/g, '');
//将正则为匹配任意[或者],替换为空 得到1,2,3,4,5,6
str = '[' + str + ']';
// [ 1,2,3,4,5,6]
ary = JSON.parse(str);
4. 普通递归
let result = [];
let fn = function(ary) {
for(let i = 0; i < ary.length; i++) {
let item = ary[i];
if (Array.isArray(ary[i])){
fn(item);
} else {
result.push(item);
}
}
}
下面为自己手写
let str = JSON.stringify(arr)
console.log(arr.length)
arr1 = []
let fn = function(arr) {
for (let index = 0; index < arr.length; index++) {
if (arr[index] instanceof Array) {
fn(arr[index])
} else {
arr1.push(arr[index])
}
}
}
fn(arr)
5. 利用reduce函数迭代
function flatten(ary) {
return ary.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, []);
}
//如果是一维数组reduce将值取出,作为pre传入,执行reducer函数
//二维数组直接递归
let ary = [1, 2, [3, 4], [5, [6, 7]]]
console.log(flatten(ary))
6:扩展运算符
//只要有一个元素有数组,那么循环继续
while (ary.some(Array.isArray)) {
ary = [].concat(...ary);
}
//Array为ary[0],ary[1]...
//检测是数组,就展开加入
第十一篇: JS数组的高阶函数——基础篇
1.什么是高阶函数 概念非常简单,如下:
一个函数就可以接收另一个函数作为参数或者返回值为一个函数,这种函数就称之为高阶函数。
那对应到数组中有哪些方法呢?
2.数组中的高阶函数
- map
- reduce
- filter
- sort
第二十一篇: 谈谈你对JS中this的理解
谁调用方法 this就是指谁,没说明就是window
其实JS中的this是一个非常简单的东西,只需要理解它的执行规则就OK。
在这里不想像其他博客一样展示太多的代码例子弄得天花乱坠, 反而不易理解。
call/apply/bind可以显式绑定, 这里就不说了。
主要这些场隐式绑定的场景讨论:
- 全局上下文
- 直接调用函数
- 对象.方法的形式调用
- DOM事件绑定(特殊)
- new构造函数绑定
- 箭头函数
1. 全局上下文
全局上下文默认this指向window, 严格模式下指向undefined。
2. 直接调用函数
let obj = {
a: function() {
console.log(this);
}
}
let func = obj.a;
func();
这种情况是直接调用。this相当于全局上下文的情况。
3. 对象.方法的形式调用
obj.a();
这就是对象.方法的情况,this指向这个对象
4. DOM事件绑定
onclick和addEventerListener中 this 默认指向绑定事件的元素。 IE比较奇异,使用attachEvent,里面的this默认指向window。
5. new+构造函数
此时构造函数中的this指向实例对象。
6. 箭头函数?
创建时确定 箭头函数没有this, 因此也不能绑定。里面的this会指向当前最近的非箭头函数的this,找不到就是window(严格模式是undefined)。比如:
a: function() {
let do = () => {
console.log(this);
}
do();
}
}
obj.a(); // 找到最近的非箭头函数a,a现在绑定着obj, 因此箭头函数中的this是obj
第二十二篇: JS中浅拷贝的手段有哪些?
重要: 什么是拷贝?
首先来直观的感受一下什么是拷贝。
let arr = [1, 2, 3];
let newArr = arr;
newArr[0] = 100;
console.log(arr);//[100, 2, 3]
这是直接赋值的情况,不涉及任何拷贝。当改变newArr的时候,由于是同一个引用,arr指向的值也跟着改变。
现在进行浅拷贝:
let arr = [1, 2, 3];
let newArr = arr.slice();
newArr[0] = 100;
console.log(arr);//[1, 2, 3]
当修改newArr的时候,arr的值并不改变。什么原因?因为这里newArr是arr浅拷贝后的结果,newArr和arr现在引用的已经不是同一块空间啦!
这就是浅拷贝!
但是这又会带来一个潜在的问题:
let arr = [1, 2, {val: 4}];
let newArr = arr.slice();
newArr[2].val = 1000;
console.log(arr);//[ 1, 2, { val: 1000 } ]
咦!不是已经不是同一块空间的引用了吗?为什么改变了newArr改变了第二个元素的val值,arr也跟着变了。 这就是浅拷贝的限制所在了。它只能拷贝一层对象(基本数据类型),拷贝了对象的内存地址。如果有对象的嵌套,那么浅拷贝将无能为力。但幸运的是,深拷贝就是为了解决这个问题而生的,它能 解决无限极的对象嵌套问题,实现彻底的拷贝。当然,这是我们下一篇的重点。 现在先让大家有一个基本的概念。
ES6数组方法返回的数组就是浅拷贝
1. 手动实现
const shallowClone = (target) => {
if (typeof target === 'object' && target !== null) {
const cloneTarget = Array.isArray(target) ? []: {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = target[prop];
}
}
return cloneTarget;
} else {
return target;
}
}
2. Object.assign
Object.assign
let obj = { name: 'sy', age: 18 };
const obj2 = Object.assign({}, obj, {name: 'sss'});
console.log(obj2);//{ name: 'sss', age: 18 }
3. concat浅拷贝数组
let arr = [1, 2, 3];
let newArr = arr.concat();
newArr[1] = 100;
console.log(arr);//[ 1, 2, 3 ]
4. slice浅拷贝
let arr = [1, 2, 3];
let newArr = arr.concat();
newArr[1] = 100;
console.log(arr);//[ 1, 2, 3 ]
5. ...展开运算符
let arr = [1, 2, 3];
let newArr = [...arr];//跟arr.slice()是一样的效果
第二十三篇: 能不能写一个完整的深拷贝?
- 简易版 JSON.parse(JSON.stringify())
JSON.parse(JSON.stringify());