JavaScripta

241 阅读7分钟

//对文章做一些笔记 无法设置仅自己可见 只能发布

//原文章地址juejin.cn/post/684490…

第七篇: 函数的arguments为什么不是数组?如何转化成数组?

因为arguments本身并不能调用数组方法,它是一个另外一种对象类型,只不过属性从0开始排,依次为0,1,2...最后还有callee和length属性。我们也把这样的对象称为类数组

arguments 是一个对应于传递给函数的参数的类数组对象。

常见的类数组还有:

  • 用getElementsByTagName/ClassName()获得的HTMLCollection
  • 用querySelector获得的nodeList

那这导致很多数组的方法就不能用了,必要时需要我们将它们转换成数组,有哪些方法呢?

列举了4个转换为数组的方法,并调用数组的方法,来验证成功

第一个方法将自身arg作为参赛传递进去

Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例

apply可以接受参数,配合concat拼接数组

  1. 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
  1. 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哦!

  1. ES6展开运算符
function sum(a, b) {
  let args = [...arguments];
  console.log(args.reduce((sum, cur) => sum + cur));//args可以调用数组原生的方法啦
}
sum(1, 2);//3
  1. 利用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可以显式绑定, 这里就不说了。

主要这些场隐式绑定的场景讨论:

  1. 全局上下文
  2. 直接调用函数
  3. 对象.方法的形式调用
  4. DOM事件绑定(特殊)
  5. new构造函数绑定
  6. 箭头函数

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()是一样的效果

第二十三篇: 能不能写一个完整的深拷贝?

  1. 简易版 JSON.parse(JSON.stringify())
JSON.parse(JSON.stringify());