Skip to content

数据类型的常用方法 ​

对象 ​

创建对象(引用类型) ​

javascript
1、构造函数创建:
	var obj = new object();

2、字面量对象创建:
	{}表示创建对象,本质是new object();
	var obj = {键值对,键值对,键值对 };   //key默认是字符串,""可加可不加,包含原型链信息;

3、方法创建
  var obj = Object.create(null)     // 创建的对象不含原型链
1、构造函数创建:
	var obj = new object();

2、字面量对象创建:
	{}表示创建对象,本质是new object();
	var obj = {键值对,键值对,键值对 };   //key默认是字符串,""可加可不加,包含原型链信息;

3、方法创建
  var obj = Object.create(null)     // 创建的对象不含原型链

判断是否是 object ​

javascript
1、Object.prototype.toString.call(obj) === '[object Object]'
2、instanceof :任何引用类型([]、{})  obj instanceof Object  的结果都是true;
3、constructor:查看构造函数,返回构造函数名(除了Null、Undefined) arr.constructor.name ;
              (返回构造函数) arr.constructor obj.constructor === Object;
4、Object.getPrototypeOf(obj) === Object.prototype ;
1、Object.prototype.toString.call(obj) === '[object Object]'
2、instanceof :任何引用类型([]、{})  obj instanceof Object  的结果都是true;
3、constructor:查看构造函数,返回构造函数名(除了Null、Undefined) arr.constructor.name ;
              (返回构造函数) arr.constructor obj.constructor === Object;
4、Object.getPrototypeOf(obj) === Object.prototype ;

判断是否是空对象 ​

javascript
1、使用Object.keys()方法获取对象的所有键,并检查键的数量是否为0。如果键的数量为0,表示对象为空对象。
	function isEmptyObject(obj){
   	return Object.keys(obj).length === 0;
	}

2、使用JSON.stringify()方法将对象转换为字符串,并检查字符串的长度是否为2。如果字符串长度为2,表示对象为空对象。
	function isEmptyObject(obj){
   	return JSON.stringify(obj) === "{}";
	}

3、Reflect.ownKeys(obj) 返回目标对象自身的属性key组成的数组。
   Reflect.ownKeys(obj).length === 0   // 对象为空

4、以上方法都不适用于包含原型属性的对象,要判断一个对象是否为空对象,并且适用于包含原型属性的对象,可以使用以下方法:
	function isEmptyObject(obj){
  	 for(var key in obj) {
    	   if(obj.hasOwnProperty(key))
       	    return false;
   	}
   	return true;
	}
1、使用Object.keys()方法获取对象的所有键,并检查键的数量是否为0。如果键的数量为0,表示对象为空对象。
	function isEmptyObject(obj){
   	return Object.keys(obj).length === 0;
	}

2、使用JSON.stringify()方法将对象转换为字符串,并检查字符串的长度是否为2。如果字符串长度为2,表示对象为空对象。
	function isEmptyObject(obj){
   	return JSON.stringify(obj) === "{}";
	}

3、Reflect.ownKeys(obj) 返回目标对象自身的属性key组成的数组。
   Reflect.ownKeys(obj).length === 0   // 对象为空

4、以上方法都不适用于包含原型属性的对象,要判断一个对象是否为空对象,并且适用于包含原型属性的对象,可以使用以下方法:
	function isEmptyObject(obj){
  	 for(var key in obj) {
    	   if(obj.hasOwnProperty(key))
       	    return false;
   	}
   	return true;
	}

对象的操作(读取、赋值、删除、转换) ​

javascript
1、使用.操作符访问对象的属性
	obj.age

2、访问对象的属性[]
	obj['age'];

3、删除对象的属性delete:
	delete obj.age;

4、对象转原始类型:
  调用了 Symbol.toPrimitive 方法,返回一个函数
1、使用.操作符访问对象的属性
	obj.age

2、访问对象的属性[]
	obj['age'];

3、删除对象的属性delete:
	delete obj.age;

4、对象转原始类型:
  调用了 Symbol.toPrimitive 方法,返回一个函数

对象的方法 ​

javascript
1、Object.is:比较两个值是否相等:
    Object.is(value1,value2) // Object.is(NaN,NaN) -> true    Object.is({},{}) -> false

2、Object.assign:对象合并:
    Object.assign(target,obj1,obj2,)

3、取出对象的key(对象自有的可枚举属性,非定义在原型链上的)或值:
    const obj = { foo: 'bar', baz: 42 };
    obj.prototype.name = 'aaa';    // 无法用 Object.keys 获取

    //取出对象的key Object.keys
    Object.keys(obj)   => ["foo", "baz"]

    //取出对象的值 Object.values
    Object.values(obj) => ["bar", 42]

4、Object.hasOwnProperty() :key的判断;方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
   const object1 = {property1:42};
   console.log(object1.hasOwnProperty('property1'));

5、Object.hasOwn() :检查某个对象自身是否拥有某个属性,接收两个参数,一个是对象,一个是属性(ES13)。
   const object1 = {property1:42};
   console.log(Object.hasOwn(object1,'property1'));

6、Object.entries() :返回键值对组成的数组;成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
     Object.entries(obj) => [ ["foo", "bar"], ["baz", 42] ]

7、Object.fromEntries() : 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的。
  数组转换:
     Object.fromEntries([['foo', 1], ['bar', 2] ])    =>   {foo: 1, bar: 2}

8、Object.getPrototypeOf():用于获取指定对象的原型(即 `[[Prototype]]` 属性的值)。
   Object.getPrototypeOf(obj) 可以获取对象 `obj` 的原型对象。

9、Object.defineProperty(obj, prop, desc) : 直接在一个对象上定义一个新属性,或者修改一个已经存在的属性;
																						obj :  第一个参数就是要在哪个对象身上添加或者修改属性
																						prop : 第二个参数就是添加或修改的属性名
                                            desc : 配置项,一般是一个对象(value:当前值  get:读取时内部调用的函数  set:写入时内部调用的函数 enumerable:是否可以遍历  configurable:是否可再次修改配置项 writable:是否可重写)
   Object.defineProperty(person,'sex',{
       value:"男",       //设置属性值
       enumerable:true,  //控制属性是否可以枚举,默认值是false
       writable:true,    //控制属性是否可以被修改,默认值是false
       configurable:true //控制属性是否可以被删除,默认值是false
    })

10、Object.getOwnPropertyDescriptor(obj,str):获取对象的属性描述符。
    Object.getOwnPropertyDescriptor({name:'aaa',age:18},'name');  // {value: 'aaa', writable: true, enumerable: true, configurable: true}

11、queryString快速转换为对象:
     const queryString = "?name=jimmy&age=18&height=1.88";
     const paramObj = Object.fromEntries(new URLSearchParams(queryString));
     console.log(paramObj);   =>   { name: 'jimmy', age: '18', height: '1.88' }

12、js对象转queryString:
	function objectToQueryString(obj) {
   	 const params = new URLSearchParams();
    	for (let key in obj) {
       	 if (obj.hasOwnProperty(key)) {
         	   params.append(key, obj[key]);
       	 }
    	}
   	 return params.toString();
	}
	const obj = { name: "John", age: 30, job: "developer" };
	const queryString = objectToQueryString(obj);
	console.log(queryString);     =>  "name=John&age=30&job=developer"
1、Object.is:比较两个值是否相等:
    Object.is(value1,value2) // Object.is(NaN,NaN) -> true    Object.is({},{}) -> false

2、Object.assign:对象合并:
    Object.assign(target,obj1,obj2,)

3、取出对象的key(对象自有的可枚举属性,非定义在原型链上的)或值:
    const obj = { foo: 'bar', baz: 42 };
    obj.prototype.name = 'aaa';    // 无法用 Object.keys 获取

    //取出对象的key Object.keys
    Object.keys(obj)   => ["foo", "baz"]

    //取出对象的值 Object.values
    Object.values(obj) => ["bar", 42]

4、Object.hasOwnProperty() :key的判断;方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
   const object1 = {property1:42};
   console.log(object1.hasOwnProperty('property1'));

5、Object.hasOwn() :检查某个对象自身是否拥有某个属性,接收两个参数,一个是对象,一个是属性(ES13)。
   const object1 = {property1:42};
   console.log(Object.hasOwn(object1,'property1'));

6、Object.entries() :返回键值对组成的数组;成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
     Object.entries(obj) => [ ["foo", "bar"], ["baz", 42] ]

7、Object.fromEntries() : 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的。
  数组转换:
     Object.fromEntries([['foo', 1], ['bar', 2] ])    =>   {foo: 1, bar: 2}

8、Object.getPrototypeOf():用于获取指定对象的原型(即 `[[Prototype]]` 属性的值)。
   Object.getPrototypeOf(obj) 可以获取对象 `obj` 的原型对象。

9、Object.defineProperty(obj, prop, desc) : 直接在一个对象上定义一个新属性,或者修改一个已经存在的属性;
																						obj :  第一个参数就是要在哪个对象身上添加或者修改属性
																						prop : 第二个参数就是添加或修改的属性名
                                            desc : 配置项,一般是一个对象(value:当前值  get:读取时内部调用的函数  set:写入时内部调用的函数 enumerable:是否可以遍历  configurable:是否可再次修改配置项 writable:是否可重写)
   Object.defineProperty(person,'sex',{
       value:"男",       //设置属性值
       enumerable:true,  //控制属性是否可以枚举,默认值是false
       writable:true,    //控制属性是否可以被修改,默认值是false
       configurable:true //控制属性是否可以被删除,默认值是false
    })

10、Object.getOwnPropertyDescriptor(obj,str):获取对象的属性描述符。
    Object.getOwnPropertyDescriptor({name:'aaa',age:18},'name');  // {value: 'aaa', writable: true, enumerable: true, configurable: true}

11、queryString快速转换为对象:
     const queryString = "?name=jimmy&age=18&height=1.88";
     const paramObj = Object.fromEntries(new URLSearchParams(queryString));
     console.log(paramObj);   =>   { name: 'jimmy', age: '18', height: '1.88' }

12、js对象转queryString:
	function objectToQueryString(obj) {
   	 const params = new URLSearchParams();
    	for (let key in obj) {
       	 if (obj.hasOwnProperty(key)) {
         	   params.append(key, obj[key]);
       	 }
    	}
   	 return params.toString();
	}
	const obj = { name: "John", age: 30, job: "developer" };
	const queryString = objectToQueryString(obj);
	console.log(queryString);     =>  "name=John&age=30&job=developer"

json 字符串 ​

javascript
var str = '{"username":"lisi","age"= 18}';    //外层'',内层属性名(key)加"";

将json转化为字符串(JSON.stringify):
  var str = JSON.stringify(obj);

将json字符串转化为json对象(JSON.parse):
  var str = '{"username":"lisi","age"= 18}';
  var o2 = JSON.parse(str);
var str = '{"username":"lisi","age"= 18}';    //外层'',内层属性名(key)加"";

将json转化为字符串(JSON.stringify):
  var str = JSON.stringify(obj);

将json字符串转化为json对象(JSON.parse):
  var str = '{"username":"lisi","age"= 18}';
  var o2 = JSON.parse(str);

数组 ​

数组的创建(引用类型) ​

javascript
1、使用构造函数创建:
var arr = new Array(10);     //长度为10的空数组
var arr = Array.from({ length:10 }, (_, index) => index); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2、使用字面量方式创建   []表示数组;
var arr3 = [];
var arr4['你好','再见'];
3、清空数组
arr.length = 0;
4、清除数组
arr = null;
1、使用构造函数创建:
var arr = new Array(10);     //长度为10的空数组
var arr = Array.from({ length:10 }, (_, index) => index); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2、使用字面量方式创建   []表示数组;
var arr3 = [];
var arr4['你好','再见'];
3、清空数组
arr.length = 0;
4、清除数组
arr = null;

判断是否是数组 ​

javascript
数组自带:Array.isArray([])方法
数组原型:Array.prototype.isPrototypeOf([]) === Array.prototype 方法
原型方法:Object.prototype.toString.call([]) 方法
非严谨方法:[] instanceof Array
数组自带:Array.isArray([])方法
数组原型:Array.prototype.isPrototypeOf([]) === Array.prototype 方法
原型方法:Object.prototype.toString.call([]) 方法
非严谨方法:[] instanceof Array

遍历 ​

javascript
1、for循环
  for(i = 0;i<arr.length;i++){
    console.log(arr[i]);
  }   //正序遍历
2、for in 用来遍历对象(只能遍历可枚举属性,遍历对象的键,会遍历对象的原型链):
遍历对象(无序存储):
   for (var key in o){
    console.log(key , o[key]);
  }
遍历数组(有序存储)(空元素无法遍历,不建议使用for in 遍历数组,因为输出的顺序是不固定的):
  for (var i in arr){
    console.log(arr[i]);
  }
3、for...of 是ES6的标准,该方法遍历的是对象的属性所对应的值(value:键值),所以它用来遍历数组时得到每个元素的值:
for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)

4、for await...of (ES9,使用了for await...of ,外层需要async)
for await...of 语句创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括:内置的String,Array,类似数组对象 (例如arguments或 NodeList),TypedArray,Map,Set 和用户定义的异步/同步迭代器。它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。
1、for循环
  for(i = 0;i<arr.length;i++){
    console.log(arr[i]);
  }   //正序遍历
2、for in 用来遍历对象(只能遍历可枚举属性,遍历对象的键,会遍历对象的原型链):
遍历对象(无序存储):
   for (var key in o){
    console.log(key , o[key]);
  }
遍历数组(有序存储)(空元素无法遍历,不建议使用for in 遍历数组,因为输出的顺序是不固定的):
  for (var i in arr){
    console.log(arr[i]);
  }
3、for...of 是ES6的标准,该方法遍历的是对象的属性所对应的值(value:键值),所以它用来遍历数组时得到每个元素的值:
for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)

4、for await...of (ES9,使用了for await...of ,外层需要async)
for await...of 语句创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括:内置的String,Array,类似数组对象 (例如arguments或 NodeList),TypedArray,Map,Set 和用户定义的异步/同步迭代器。它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。

数组的常用 API ​

javascript
1、Array.prototype.push():在数组尾部插入一个或多个元素,返回值length;
	arr.push(1,2,[4]);   //不会展开数组

2、Array.prototype.pop():删除数组中最后一个元素并返回这个元素,如说是空数组返回undefined;
	arr.pop();
8、Array.prototype.unshift(value):在数组的头部插入元素,返回值为length;

9、Array.prototype.toString():将数组中所有的元素进行toString操作;

3、Array.prototype.concat():连接(合并)一个或多个数组;不改变原有数组而是新建数组;返回值为一个新数组;
	用Array.prototype.concat 复制的数组属于浅拷贝,第一层数组属于新建(深拷贝),内部嵌套的数组属于内存地址(浅拷贝);

4、Array.prototype.join():将数组中每个元素都转换成字符串连接起来(toString),返回一个字符串;
	arr.join([aeparator]):[aeparator]是分隔符,默认为 , (null和undefined没有toString方法,默认为空);
	var str = arr.join();

5、Array.prototype.reverse():用于颠倒数组的所有参数,返回值为原数组;
	arr.reverse();

6、Array.prototype.sort():通过特定的规则给数组排序(默认转化为字符串按照Unicode编码排序),返回值为排序后的原数组;
        arr.sort(function(a,b){
          return a-b;
        });   //升序
        arr.sort(function(a,b){
          return b-a;
        });    //降序
        arr.sort(function(){
          return -1;     //倒序排序
          return 1;      //不变
        });
      //按照对象的某个属性值的大小顺序进行排序(从小到大)
        list.sort(function (obj1, obj2) {
            let val1 = +obj1.relation_mark;
            let val2 = +obj2.relation_mark;
            if (val1 < val2) {
              return -1;
            } else if (val1 > val2) {
              return 1;
            } else {
              return 0;
            }
        })

7、Array.prototype.shift():将数组的第一个元素移出数组,其他元素前移,长度减一,返回被删除的元素;

10、Array.prototype.slice(start,end?):数组中截取一个片段,包含start不包含end;返回值为一个新数组,支持链式调用;
    start(number):开始索引,默认值为0;
    end(number):结束索引,不写就是默认到最后一项;
    结果是新数组的浅拷贝;

11、Array.prototype.splice(start,deleteCount,value):删除数组中的元素(start处)修改原数组,返回值是所有被删除的元素组成的数组;
    start:开始索引;
    deleteCount :删除步长;
    value:插入的元素;

12、Array.prototype.indexOf():用于在数组中查找元素,如果找到元素则返回索引下标,如果没有返回-1;
   arr.indexOf(selectIndex,[fromIndex]):
   selectIndex:索引的元素
   fromIndex:开始索引的位置

   [2, 5, 9, 1, 5, 9, 2].indexOf(5);  // 输出: 1

13、 Array.prototype.forEach():遍历数组为每个数组执行回调函数,修改原数组;
     arr.forEach(function(val){
           //函数表达式
    });

14、Array.prototype.filter():用于在数组中进行检索,检查每一个元素是否符合给定布尔表达式的条件,将符合表达式的元素组成一个新数组;返回一个通过布尔表达式的元素组成的新数组;
   var newArr = arr.filter(function(val){    //val 为arr中的每一个参数
       return 布尔表达式;                 //返回满足表达式(true)的元素
   }):

15、Array.prototype.map():数组的数据映射(遍历数组为每个数组执行回调函数;修改或操作数组中的元素),返回一个修改后的新数组;
    arr.map(function(val){
       //函数表达式
       return    ;
    })

15、Array.prototype.every() 比较数组,返回布尔值,全真为真,一假全假。
		返回值:`true/false`
        不会改变原数组
        vue 中实例:常用于在全选上面
        this.checkedAll = this.list.every((items) => items.flag)
		//当全部选中时,则改变checkdAll复选框的状态;

15、Array.prototype.some() 比较数组,返回布尔值,一真为真,全假为假。
		返回值:`true/false`
      


16、Array.prototype.flatMap():与 map 方法和深度depth为1的flat几乎相同(map后Array.flat(1));
                                                     
                                                         
18、Array.prototype.from(obj [,callback]):    将类数组转化为数组并操作,返回值为一个新数组;
    let arr = Array.from(a)
    Array.from({ length: 5 }, (v, i) => i)   // [0,1,2,3,4]


19、Array.prototype.of(value):              将一组数值转化为数组,返回值为新的数组;
    Array.of(1,2,[3,4],{id:5})               // [1,2,[3,4],{id:5}]


20、Array.prototype.copywithin(target, start, end):  将数组中的元素拷贝到其他位置,返回当前数组;
                                                    target:覆盖的起始索引  start:copy数据的起始索引  end:copy数据的结束索引。

21、Array.prototype.find(callback):         查找满足条件的第一个元素

22、Array.prototype.findIndex(callback):    查找满足条件的第一个元素的索引

23、Array.prototype.includes('value'):      检查某个数组中是否包含某个值;返回一个布尔值

24、Array.prototype.at():                   接收一个整数值并返回该索引的项目,允许正数和负数;用于取出数组中的项。
   	Array.at(-1);

25、 Array.prototype.flat():   该方法可以按照指定的深度将多维数组展开,然后作为一个新数组返回,深度的默认值为 1。如果想要全部展开,只需传递一个 Infinity(无穷大)即可。
     Array.flat(Infinity);

26、Array.prototype.findLast(callback):         查找满足条件的最后元素

27、Array.prototype.findLastIndex(callback):    查找满足条件的最后元素的索引

28、Array.prototype.findLast(n => n):          根据条件从数组的最后一个元素向前查找元素

29、Array.prototype.toReversed()                                // 该方法返回一个新数组,新数组的元素顺序与原数组相反。

30、Array.prototype.toSorted(compareFn)                         // 该方法返回一个新数组,新数组的元素是原数组元素的排序结果。

31、Array.prototype.toSpliced(start, deleteCount, ...items)     // 该方法返回一个新数组,新数组删除了原数组从指定位置开始的指定数量的元素。
                                                             			 start:开始索引;
                                                               		 deleteCount :删除步长;
                                                                	 value:插入的元素;

32、Array.prototype.with(index, value)                          // 该方法不修改原数组,返回一个新数组,新数组在指定索引位置的元素被替换为指定值。

33、Array.prototype.some(callback(currentValue,index,arr),thisValue) // 该方法用于检测数组中的元素是否满足指定条件(函数提供);不会对空数组进行检测; 不会改变原始数组。
                                                                      	currentValue	必须。当前元素的值
                                                                      	index	可选。当前元素的索引值
                                                                      	arr	可选。当前元素属于的数组对象
  const numbers = [1, 3, 5, 8, 9];
  const hasEvenNumber = numbers.some(element => element % 2 === 0);
  console.log(hasEvenNumber); // 输出: true

  const obj = {
    even: 2,
    odd: 3,
    check: function() {
      return this.even % 2 === 0;
    }
  };
  const numbers = [1, 3, 5, obj.even, 9];
  const hasEvenNumber = numbers.some(function(element) {
    return this.check();
  }, obj);
  console.log(hasEvenNumber); // 输出: true


34、 Array.prototype.fill(value, start, end)                   // 该方法用于将一个固定值替换数组的元素,直接修改原数组
                                                                	value 必需。填充的值。
																																	start 可选。开始填充位置。
																																	end 可选。停止填充位置 (默认为 array.length)
	let arr1 = [1, 2, 3, 4, 56, 7, 7, 8, 9];
	arr1.fill(4, 2, 5);          //   [1, 2, 4, 4, 4, 7, 7, 8, 9]

35、Array.prototype.groupBy() // Object.groupBy(data,callback) // 该方法将一个数组按照某个属性进行分组,返回一个新数组
  	const people = [  { name: 'Alice', age: 20 },  { name: 'Bob', age: 25 },  { name: 'Charlie', age: 30 }];
		const groups = people.groupBy(p => p.age);
  	// { 20: [{ name: 'Alice', age: 20 }], 25: [{ name: 'Bob', age: 25 }], 30: [{ name: 'Charlie', age: 30 }] }
1、Array.prototype.push():在数组尾部插入一个或多个元素,返回值length;
	arr.push(1,2,[4]);   //不会展开数组

2、Array.prototype.pop():删除数组中最后一个元素并返回这个元素,如说是空数组返回undefined;
	arr.pop();
8、Array.prototype.unshift(value):在数组的头部插入元素,返回值为length;

9、Array.prototype.toString():将数组中所有的元素进行toString操作;

3、Array.prototype.concat():连接(合并)一个或多个数组;不改变原有数组而是新建数组;返回值为一个新数组;
	用Array.prototype.concat 复制的数组属于浅拷贝,第一层数组属于新建(深拷贝),内部嵌套的数组属于内存地址(浅拷贝);

4、Array.prototype.join():将数组中每个元素都转换成字符串连接起来(toString),返回一个字符串;
	arr.join([aeparator]):[aeparator]是分隔符,默认为 , (null和undefined没有toString方法,默认为空);
	var str = arr.join();

5、Array.prototype.reverse():用于颠倒数组的所有参数,返回值为原数组;
	arr.reverse();

6、Array.prototype.sort():通过特定的规则给数组排序(默认转化为字符串按照Unicode编码排序),返回值为排序后的原数组;
        arr.sort(function(a,b){
          return a-b;
        });   //升序
        arr.sort(function(a,b){
          return b-a;
        });    //降序
        arr.sort(function(){
          return -1;     //倒序排序
          return 1;      //不变
        });
      //按照对象的某个属性值的大小顺序进行排序(从小到大)
        list.sort(function (obj1, obj2) {
            let val1 = +obj1.relation_mark;
            let val2 = +obj2.relation_mark;
            if (val1 < val2) {
              return -1;
            } else if (val1 > val2) {
              return 1;
            } else {
              return 0;
            }
        })

7、Array.prototype.shift():将数组的第一个元素移出数组,其他元素前移,长度减一,返回被删除的元素;

10、Array.prototype.slice(start,end?):数组中截取一个片段,包含start不包含end;返回值为一个新数组,支持链式调用;
    start(number):开始索引,默认值为0;
    end(number):结束索引,不写就是默认到最后一项;
    结果是新数组的浅拷贝;

11、Array.prototype.splice(start,deleteCount,value):删除数组中的元素(start处)修改原数组,返回值是所有被删除的元素组成的数组;
    start:开始索引;
    deleteCount :删除步长;
    value:插入的元素;

12、Array.prototype.indexOf():用于在数组中查找元素,如果找到元素则返回索引下标,如果没有返回-1;
   arr.indexOf(selectIndex,[fromIndex]):
   selectIndex:索引的元素
   fromIndex:开始索引的位置

   [2, 5, 9, 1, 5, 9, 2].indexOf(5);  // 输出: 1

13、 Array.prototype.forEach():遍历数组为每个数组执行回调函数,修改原数组;
     arr.forEach(function(val){
           //函数表达式
    });

14、Array.prototype.filter():用于在数组中进行检索,检查每一个元素是否符合给定布尔表达式的条件,将符合表达式的元素组成一个新数组;返回一个通过布尔表达式的元素组成的新数组;
   var newArr = arr.filter(function(val){    //val 为arr中的每一个参数
       return 布尔表达式;                 //返回满足表达式(true)的元素
   }):

15、Array.prototype.map():数组的数据映射(遍历数组为每个数组执行回调函数;修改或操作数组中的元素),返回一个修改后的新数组;
    arr.map(function(val){
       //函数表达式
       return    ;
    })

15、Array.prototype.every() 比较数组,返回布尔值,全真为真,一假全假。
		返回值:`true/false`
        不会改变原数组
        vue 中实例:常用于在全选上面
        this.checkedAll = this.list.every((items) => items.flag)
		//当全部选中时,则改变checkdAll复选框的状态;

15、Array.prototype.some() 比较数组,返回布尔值,一真为真,全假为假。
		返回值:`true/false`
      


16、Array.prototype.flatMap():与 map 方法和深度depth为1的flat几乎相同(map后Array.flat(1));
                                                     
                                                         
18、Array.prototype.from(obj [,callback]):    将类数组转化为数组并操作,返回值为一个新数组;
    let arr = Array.from(a)
    Array.from({ length: 5 }, (v, i) => i)   // [0,1,2,3,4]


19、Array.prototype.of(value):              将一组数值转化为数组,返回值为新的数组;
    Array.of(1,2,[3,4],{id:5})               // [1,2,[3,4],{id:5}]


20、Array.prototype.copywithin(target, start, end):  将数组中的元素拷贝到其他位置,返回当前数组;
                                                    target:覆盖的起始索引  start:copy数据的起始索引  end:copy数据的结束索引。

21、Array.prototype.find(callback):         查找满足条件的第一个元素

22、Array.prototype.findIndex(callback):    查找满足条件的第一个元素的索引

23、Array.prototype.includes('value'):      检查某个数组中是否包含某个值;返回一个布尔值

24、Array.prototype.at():                   接收一个整数值并返回该索引的项目,允许正数和负数;用于取出数组中的项。
   	Array.at(-1);

25、 Array.prototype.flat():   该方法可以按照指定的深度将多维数组展开,然后作为一个新数组返回,深度的默认值为 1。如果想要全部展开,只需传递一个 Infinity(无穷大)即可。
     Array.flat(Infinity);

26、Array.prototype.findLast(callback):         查找满足条件的最后元素

27、Array.prototype.findLastIndex(callback):    查找满足条件的最后元素的索引

28、Array.prototype.findLast(n => n):          根据条件从数组的最后一个元素向前查找元素

29、Array.prototype.toReversed()                                // 该方法返回一个新数组,新数组的元素顺序与原数组相反。

30、Array.prototype.toSorted(compareFn)                         // 该方法返回一个新数组,新数组的元素是原数组元素的排序结果。

31、Array.prototype.toSpliced(start, deleteCount, ...items)     // 该方法返回一个新数组,新数组删除了原数组从指定位置开始的指定数量的元素。
                                                             			 start:开始索引;
                                                               		 deleteCount :删除步长;
                                                                	 value:插入的元素;

32、Array.prototype.with(index, value)                          // 该方法不修改原数组,返回一个新数组,新数组在指定索引位置的元素被替换为指定值。

33、Array.prototype.some(callback(currentValue,index,arr),thisValue) // 该方法用于检测数组中的元素是否满足指定条件(函数提供);不会对空数组进行检测; 不会改变原始数组。
                                                                      	currentValue	必须。当前元素的值
                                                                      	index	可选。当前元素的索引值
                                                                      	arr	可选。当前元素属于的数组对象
  const numbers = [1, 3, 5, 8, 9];
  const hasEvenNumber = numbers.some(element => element % 2 === 0);
  console.log(hasEvenNumber); // 输出: true

  const obj = {
    even: 2,
    odd: 3,
    check: function() {
      return this.even % 2 === 0;
    }
  };
  const numbers = [1, 3, 5, obj.even, 9];
  const hasEvenNumber = numbers.some(function(element) {
    return this.check();
  }, obj);
  console.log(hasEvenNumber); // 输出: true


34、 Array.prototype.fill(value, start, end)                   // 该方法用于将一个固定值替换数组的元素,直接修改原数组
                                                                	value 必需。填充的值。
																																	start 可选。开始填充位置。
																																	end 可选。停止填充位置 (默认为 array.length)
	let arr1 = [1, 2, 3, 4, 56, 7, 7, 8, 9];
	arr1.fill(4, 2, 5);          //   [1, 2, 4, 4, 4, 7, 7, 8, 9]

35、Array.prototype.groupBy() // Object.groupBy(data,callback) // 该方法将一个数组按照某个属性进行分组,返回一个新数组
  	const people = [  { name: 'Alice', age: 20 },  { name: 'Bob', age: 25 },  { name: 'Charlie', age: 30 }];
		const groups = people.groupBy(p => p.age);
  	// { 20: [{ name: 'Alice', age: 20 }], 25: [{ name: 'Bob', age: 25 }], 30: [{ name: 'Charlie', age: 30 }] }
reduce ​

arr.reduce(callback,[init])

第一个回调函数,回调函数必须有返回值,,一般返回第一个 prev 的值;

回调函数的四个参数:回调函数的结果,当前值,项的索引,数组对象;

第二个参数为可选值,用于初始值,放到 callback 里进行计算;(可以放一个空数组,之后可以使用第一个值 concat)

reduceRight

从后边开始循环;

理解:

js
let arr = [1, 2, 3, 4, 5]
let arr2 = arr.reduce((p, c) => {
  return p
}, [])
// 第二个参数作为p第一次循环的值,如果没有则取数组中第一项,则c从第二项开始;
// p为上一次回调函数的结果,如果没有return p,则没有结果,则reduce没有意义;
// 上述代码中,p没有和c进行交互,p一直是[],则arr2结果为[];
let arr = [1, 2, 3, 4, 5]
let arr2 = arr.reduce((p, c) => {
  return p
}, [])
// 第二个参数作为p第一次循环的值,如果没有则取数组中第一项,则c从第二项开始;
// p为上一次回调函数的结果,如果没有return p,则没有结果,则reduce没有意义;
// 上述代码中,p没有和c进行交互,p一直是[],则arr2结果为[];
简单使用 ​
js
var arr = [1, 2, 3, 4, 5]
var sum = arr.reduce((x, y) => x + y) //15
var mul = arr.reduce((x, y) => x * y) //
var arr = [1, 2, 3, 4, 5]
var sum = arr.reduce((x, y) => x + y) //15
var mul = arr.reduce((x, y) => x * y) //
数组去重案例 ​
js
let arr = [1, 2, 3, 4, 4, 1]
let newArr = arr.reduce((pre, cur) => {
  if (!pre.includes(cur)) {
    return pre.concat(cur)
  } else {
    return pre
  }
}, []) // 当有第二个参数时,第一次先循环一个空数组,第二次循环添加了一个的数组
console.log(newArr) // [1, 2, 3, 4]
let arr = [1, 2, 3, 4, 4, 1]
let newArr = arr.reduce((pre, cur) => {
  if (!pre.includes(cur)) {
    return pre.concat(cur)
  } else {
    return pre
  }
}, []) // 当有第二个参数时,第一次先循环一个空数组,第二次循环添加了一个的数组
console.log(newArr) // [1, 2, 3, 4]
对象案例 ​

仅演示使用方法,案例不在

js
arr.reduce((pre, curr) => {
  if (curr.length === maxLen) {
    pre[curr[0]] = curr.length // 将pre对象的键名,等于键值,这里的curr[0]为第一个;
  }
  return pre // 返回的是上一次回调函数的结果,最终会把最后一个结果返回出去;
}, {})
arr.reduce((pre, curr) => {
  if (curr.length === maxLen) {
    pre[curr[0]] = curr.length // 将pre对象的键名,等于键值,这里的curr[0]为第一个;
  }
  return pre // 返回的是上一次回调函数的结果,最终会把最后一个结果返回出去;
}, {})
修改对象的值(常用) ​
js
var obj = {
  name: 'hhh',
  age: '18',
}
var obj2 = Object.keys(obj).reduce((o, c) => {
  o[c] = 18 + obj[c]
  return o
}, {})

console.log(obj2) // {name: '18hhh', age: '1818'}
var obj = {
  name: 'hhh',
  age: '18',
}
var obj2 = Object.keys(obj).reduce((o, c) => {
  o[c] = 18 + obj[c]
  return o
}, {})

console.log(obj2) // {name: '18hhh', age: '1818'}
reduce 代替 map ​
js
let arr = [0, 1, 2, 3, 4, 5]
arr.map((item) => item * 2)
arr.reduce((p, c) => {
  p.push(c * 2)
  return p
}, [])
let arr = [0, 1, 2, 3, 4, 5]
arr.map((item) => item * 2)
arr.reduce((p, c) => {
  p.push(c * 2)
  return p
}, [])
reduce 代替 filter ​
js
let arr = [0, 1, 2, 3, 4]
arr.filter((item) => item < 3)
arr.reduce((p, c) => {
  c < 3 && p.push(c)
  return p
}, [])
let arr = [0, 1, 2, 3, 4]
arr.filter((item) => item < 3)
arr.reduce((p, c) => {
  c < 3 && p.push(c)
  return p
}, [])

将类数组转换为真正的数组 ​

该函数可以调用任意数量的形参;

  • Array.prototype.slice.call(arguments);

  • [].slice.call(arguments)

  • Array.from(arguments)

js
function addOne() {
  return Array.prototype.slice.call(arguments)
}
console.log(addOne(1, 2, 3, 4, 5))
function addOne() {
  return Array.prototype.slice.call(arguments)
}
console.log(addOne(1, 2, 3, 4, 5))

添加指定长度的空数组 ​

Array.apply(null,{length:20})

会加入 20 个空的数组,20 个长度的数组;

可以简写:Array.apply(null,Array(20));

es6 写法:Array.from({length:20})或Array(20).fill(); // fill 里面也可以填写内容,以什么来填充;

js
Array.apply(null, { length: 20 }).map((item, index) => {
  console.log(index) // 打印20次
})
Array.apply(null, { length: 20 }).map((item, index) => {
  console.log(index) // 打印20次
})

修改原数组代替 concat ​

Array.prototype.push.apply(arr1,arr2)

由于 concat 不能直接修改原数组,可以通过此方法将 arr2 合并到 arr1 身上,apply 第二个参数接受数组;

缺点:如果第二个数组太大时,不建议使用此方法来进行合并,因为一个函数能够接收的参数个数是有限的;

解决方法:将参数数组切块后循环传入目标

js
function concatOfArray(arr1, arr2) {
  var QUANTUM = 32768
  for (var i = 0, len = arr2.length; i < len; i += QUANTUM) {
    Array.prototype.push.apply(arr1, arr2.slice(i, Math.min(i + QUANTUM, len)))
  }
  return arr1
}
// 验证:
var arr1 = [1, 2, 3, 4]
var arr2 = []
for (var i = 0; i < 1000000; i++) {
  arr2.push(i)
} //循环添加多个i
Array.prototype.push.apply(arr1, arr2) //爆栈
concatOfArray(arr1, arr2) //正常输出;
function concatOfArray(arr1, arr2) {
  var QUANTUM = 32768
  for (var i = 0, len = arr2.length; i < len; i += QUANTUM) {
    Array.prototype.push.apply(arr1, arr2.slice(i, Math.min(i + QUANTUM, len)))
  }
  return arr1
}
// 验证:
var arr1 = [1, 2, 3, 4]
var arr2 = []
for (var i = 0; i < 1000000; i++) {
  arr2.push(i)
} //循环添加多个i
Array.prototype.push.apply(arr1, arr2) //爆栈
concatOfArray(arr1, arr2) //正常输出;

测试随机数取哪些数 ​

如果需要测试随机数都取到了哪些数,通过创建空数组方法,添加到数组里面去;

js
Array.from({length:20}).map(i=>Math.ceil(Math.random()*6)))
Array.from({length:20}).map(i=>Math.ceil(Math.random()*6)))

随机验证码 ​

js
Math.random().toString(36).substr(2, 6)
Math.random().toString(36).substr(2, 6)

字符串 ​

字符串的不可变性 ​

字符串在创建后是不可变的,每次对字符串进行操作,都会返回一个新的字符串。

常用 Api ​

javascript
1、String.prototype.charAt():在字符串中获取指定索引的字符;返回一个字符;
    str.charAt(index)

2、String.prototype.charCodeAt():返回字符串中指定索引字符对应的Unicode编码;返回一个Unicode编码;
    str.charCodeAt(index)
    数字48-57;大写字母:65-90;小写字母:97-122;
   String.prototype.fromCharCode(unicode) :返回Unicode对应的字符;

3、String.prototype.concat() :将所有字符连接起来;返回一个新字符串;
    str.concat(value)

4、String.prototype.indexOf():在str中查找匹配的字符串;返回值为第一个满足条件的索引值或-1;
    str.indexOf(searchstr,fromindex):
    searchstr:需要在字符串中查找的字符串;
    fromindex:开始查找的位置;

5、 String.prototype.lastIndexOf():用于在字符串中从后向前查找字符串;返回值为第一个满足条件的索引值或-1;
    str.lastIndexOf(searchstr,fromindex):
    searchstr:需要在字符串中查找的字符串;
    fromindex:开始查找的位置;

6、 String.prototype.slice():截取字符串中的字符串片段(索引可以为负数);返回一个新字符串;如果没有截取到字符串返回空字符串;
    str.slice(start,end):包含start,不包含end;

7、  String.prototype.split():将字符串用指定的分离器切割成多个字符串;返回值是所有字符串组成的新数组;
     str.split(sep):
     sep:分离器,用于切割字符串
     var mail = 'nihao@qq.com';
     var str = mail.split('@');

8、String.prototype.substr():用于在字符串中截取字符串,从start开始;返回值是一个新字符串;
    str.substr(start,length):
    start:开始索引;
    length:长度;

9、String.prototype.substring():用于在字符串中截取片段;返回一个新字符串;
    str.substring(start,end):包含start,不包含end;
                             当start>end时,自动交换两个参数位置;当参数<0或非数字时,当做0;
    start:开始索引;
    end:结束索引;

10、String.prototype.toUpperCase():转大写
   String.prototype.toLowerCase() :转小写

11、 String.prototype.at():方法接收一个整数值并返回该索引的项目,允许正数和负数;用于取出字符串中的项。

12、String.prototype.trim() :去除字符串前后空格。

13、String.prototype.padStart(): 字符串补全长度,从头部开始,返回一个新的字符串,支持链式调用。
   String.prototype.padStart(10,'*')  =>  从头开始处用* 补齐10位

14、String.prototype.padEnd(): 字符串补全长度,从尾部开始,返回一个新的字符串,支持链式调用。
   String.prototype.padEnd(10,'*')  =>  从尾开始处用* 补齐10位

15、String.prototype.trimStart():方法从字符串的开头删除空格,trimLeft()是此方法的别名。

16、String.prototype.trimEnd():方法从一个字符串的右端移除空白字符,trimRight()是此方法的别名。

17、String.prototype.replaceAll():新字符串中所有满足 pattern 的部分都会被replacement 替换;返回一个新字符串;原始字符串保持不变。
  'aabbcc'.replaceAll('b', '.');  =>  'aa..cc'
1、String.prototype.charAt():在字符串中获取指定索引的字符;返回一个字符;
    str.charAt(index)

2、String.prototype.charCodeAt():返回字符串中指定索引字符对应的Unicode编码;返回一个Unicode编码;
    str.charCodeAt(index)
    数字48-57;大写字母:65-90;小写字母:97-122;
   String.prototype.fromCharCode(unicode) :返回Unicode对应的字符;

3、String.prototype.concat() :将所有字符连接起来;返回一个新字符串;
    str.concat(value)

4、String.prototype.indexOf():在str中查找匹配的字符串;返回值为第一个满足条件的索引值或-1;
    str.indexOf(searchstr,fromindex):
    searchstr:需要在字符串中查找的字符串;
    fromindex:开始查找的位置;

5、 String.prototype.lastIndexOf():用于在字符串中从后向前查找字符串;返回值为第一个满足条件的索引值或-1;
    str.lastIndexOf(searchstr,fromindex):
    searchstr:需要在字符串中查找的字符串;
    fromindex:开始查找的位置;

6、 String.prototype.slice():截取字符串中的字符串片段(索引可以为负数);返回一个新字符串;如果没有截取到字符串返回空字符串;
    str.slice(start,end):包含start,不包含end;

7、  String.prototype.split():将字符串用指定的分离器切割成多个字符串;返回值是所有字符串组成的新数组;
     str.split(sep):
     sep:分离器,用于切割字符串
     var mail = 'nihao@qq.com';
     var str = mail.split('@');

8、String.prototype.substr():用于在字符串中截取字符串,从start开始;返回值是一个新字符串;
    str.substr(start,length):
    start:开始索引;
    length:长度;

9、String.prototype.substring():用于在字符串中截取片段;返回一个新字符串;
    str.substring(start,end):包含start,不包含end;
                             当start>end时,自动交换两个参数位置;当参数<0或非数字时,当做0;
    start:开始索引;
    end:结束索引;

10、String.prototype.toUpperCase():转大写
   String.prototype.toLowerCase() :转小写

11、 String.prototype.at():方法接收一个整数值并返回该索引的项目,允许正数和负数;用于取出字符串中的项。

12、String.prototype.trim() :去除字符串前后空格。

13、String.prototype.padStart(): 字符串补全长度,从头部开始,返回一个新的字符串,支持链式调用。
   String.prototype.padStart(10,'*')  =>  从头开始处用* 补齐10位

14、String.prototype.padEnd(): 字符串补全长度,从尾部开始,返回一个新的字符串,支持链式调用。
   String.prototype.padEnd(10,'*')  =>  从尾开始处用* 补齐10位

15、String.prototype.trimStart():方法从字符串的开头删除空格,trimLeft()是此方法的别名。

16、String.prototype.trimEnd():方法从一个字符串的右端移除空白字符,trimRight()是此方法的别名。

17、String.prototype.replaceAll():新字符串中所有满足 pattern 的部分都会被replacement 替换;返回一个新字符串;原始字符串保持不变。
  'aabbcc'.replaceAll('b', '.');  =>  'aa..cc'

字符串的 html 方法 ​

不建议使用这些方法,因为它们创建的标签通常无法表达语义;

  • big 标签:big()
  • b 标签:bold()
  • i 标签:italics()
  • tt 标签:fixed()
  • font color 标签:fontcolor(color)
  • font size 标签:fontsize(size)
  • a 标签:link(url)
  • a name 标签:anchor(name);
  • small 标签:small()
  • strike 标签:strike()
  • sub 标签:sub()
  • sup 标签:sup()
js
'wyy'.link('http://wyy.wing.vip') // <a href='http://wyy.wing.vip'>wyy</a>
'str'.fontcolor('red') // <font color='red'>str</font>
'wyy'.link('http://wyy.wing.vip') // <a href='http://wyy.wing.vip'>wyy</a>
'str'.fontcolor('red') // <font color='red'>str</font>

深浅拷贝 ​

对象的浅拷贝 ​

javascript
1、const obj2 = Object.assign({},obj1)      //相当于对象合并,新增的对象方法
2、const obj2 = {...obj1}                   //展开运算
1、const obj2 = Object.assign({},obj1)      //相当于对象合并,新增的对象方法
2、const obj2 = {...obj1}                   //展开运算

数组的拷贝 ​

javascript
concat方法 和 展开运算 对于一维数组基本类型是深拷贝,对于二维数组是浅拷贝;

const arr2 = [].concat(arr1);           //数组合并
const arr2 = [...arr1];                 //数组展开
concat方法 和 展开运算 对于一维数组基本类型是深拷贝,对于二维数组是浅拷贝;

const arr2 = [].concat(arr1);           //数组合并
const arr2 = [...arr1];                 //数组展开

ES6 新增深拷贝方法 structuredClone() ​

javascript
适用于:
1、克隆无限嵌套的对象和数组
2、克隆循环引用
3、克隆各种 JavaScript 类型,例如 Date 、 Set 、 Map 、 RegExp 、Error、 ArrayBuffer 、 Blob 、 File 、 ImageData 等等
4、转移任何可转移对象

const original = {
    a: 1,
    b: { c: 2 },
    d: [3, 4],
    e: new Date(),
    f: new Map([['key', 'value']])
};

const clone = structuredClone(original);

需要注意的是,structuredClone() 并不支持所有类型,例如 Symbol 对象、Function 对象、DOM以及其他一些不可序列化的对象就不能被复制。
适用于:
1、克隆无限嵌套的对象和数组
2、克隆循环引用
3、克隆各种 JavaScript 类型,例如 Date 、 Set 、 Map 、 RegExp 、Error、 ArrayBuffer 、 Blob 、 File 、 ImageData 等等
4、转移任何可转移对象

const original = {
    a: 1,
    b: { c: 2 },
    d: [3, 4],
    e: new Date(),
    f: new Map([['key', 'value']])
};

const clone = structuredClone(original);

需要注意的是,structuredClone() 并不支持所有类型,例如 Symbol 对象、Function 对象、DOM以及其他一些不可序列化的对象就不能被复制。

对象的深拷贝 ​

javascript
// 只能处理基本对象、数组和原子类型。任何其他类型都可以以难以预测的方式处理
const obj2 = JSON.parse(JSON.stringify(obj1))
// 只能处理基本对象、数组和原子类型。任何其他类型都可以以难以预测的方式处理
const obj2 = JSON.parse(JSON.stringify(obj1))

循环遍历深拷贝 ​

javascript
function deepCopy(obj) {
  let newobj = obj.constructor === Array ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (obj[key] && typeof obj[key] === 'object') {
        newobj[key] = deepCopy(obj[key]);
      } else {
        newobj[key] = obj[key];
      }
    }
  }
  return newobj;
}


// 使用递归的方式来拷贝正则表达式。以下是一个示例代码:

function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  let clone = Array.isArray(obj) ? [] : {};

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }

  return clone;
}

通过递归的方式,我们检查对象的每个属性值。如果属性值是正则表达式,我们通过创建一个新的正则表达式对象来进行深拷贝。
对于其他类型的属性值,我们继续递归调用 `deepClone` 函数来进行深拷贝。
function deepCopy(obj) {
  let newobj = obj.constructor === Array ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (obj[key] && typeof obj[key] === 'object') {
        newobj[key] = deepCopy(obj[key]);
      } else {
        newobj[key] = obj[key];
      }
    }
  }
  return newobj;
}


// 使用递归的方式来拷贝正则表达式。以下是一个示例代码:

function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  let clone = Array.isArray(obj) ? [] : {};

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }

  return clone;
}

通过递归的方式,我们检查对象的每个属性值。如果属性值是正则表达式,我们通过创建一个新的正则表达式对象来进行深拷贝。
对于其他类型的属性值,我们继续递归调用 `deepClone` 函数来进行深拷贝。

深拷贝解决对象的循环引用 ​

javascript
核心思路:可以使用递归实现深拷贝,并使用一个Map来记录已经拷贝过的对象,避免循环引用的问题。
function deepClone(obj, map = new Map()) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (map.has(obj)) {
    return map.get(obj);
  }

  let clone = Array.isArray(obj) ? [] : {};

  map.set(obj, clone);

  for (let key in obj) {
    clone[key] = deepClone(obj[key], map);
  }

  return clone;
}
核心思路:可以使用递归实现深拷贝,并使用一个Map来记录已经拷贝过的对象,避免循环引用的问题。
function deepClone(obj, map = new Map()) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (map.has(obj)) {
    return map.get(obj);
  }

  let clone = Array.isArray(obj) ? [] : {};

  map.set(obj, clone);

  for (let key in obj) {
    clone[key] = deepClone(obj[key], map);
  }

  return clone;
}

深拷贝高级用法解决循环引用 ​

javascript
function deepClone(obj) {
  return new Promise((resolve) => {
    const { port1, port2 } = new MessageChannel() // 通信
    port1.postMessage(obj)
    port2.onmessage = (msg) => {
      resolve(msg.data)
    }
  })
}
const obj2 = await deepClone({ a: 1, b: 2 })
function deepClone(obj) {
  return new Promise((resolve) => {
    const { port1, port2 } = new MessageChannel() // 通信
    port1.postMessage(obj)
    port2.onmessage = (msg) => {
      resolve(msg.data)
    }
  })
}
const obj2 = await deepClone({ a: 1, b: 2 })

定时器 ​

setTimeout ​

setTimeout(fn[,delay,arg1,arg2,...]);

后面的 arg 会作为参数传递给定时器函数中;

只执行一次,不用加单位,单位是毫秒;

清除 Timeout 定时器:clearTimeout(定时器);

setTimeout 的原理

采用定时器需要动用红黑树,创建定时器对象和迭代等操作;

很多人为了立即异步执行一个任务,会调用setTimeout(function(){},0)使用 0 毫秒来达到效果,由于事件循环自身的特点,定时器的精确度不够。事实上,采用定时器需要动用红黑树,创建定时器对象和迭代等操作,而setTimeout(fn, 0)的方式较为浪费性能。实际上,process.nextTick()方法的操作相对较为轻量,具体代码如下:

js
process.nextTick = function (callback) {
  //on the way out, don't bother.
  // it won't get fired anyway
  if (process._exiting) return

  if (tickDepth >= process.maxTickDepth) maxTickWarn()

  var tock = { callback: callback }
  if (process.domain) tock.domain = process.domain
  nextTickQueue.push(tock)
  if (nextTickQueue.length) {
    process._needTickCallback()
  }
}
process.nextTick = function (callback) {
  //on the way out, don't bother.
  // it won't get fired anyway
  if (process._exiting) return

  if (tickDepth >= process.maxTickDepth) maxTickWarn()

  var tock = { callback: callback }
  if (process.domain) tock.domain = process.domain
  nextTickQueue.push(tock)
  if (nextTickQueue.length) {
    process._needTickCallback()
  }
}

每次调用process.nextTick()方法,只会将回调函数放入队列中,在下一轮 Tick 时取出执行。定时器中采用红黑树的操作时间复杂度为 0(lg(n)),nextTick()的时间复杂度为 0(1)。相较之下,process.nextTick()更高效。

setTimeout 的特性

  1. setTimeout 写入的毫秒数不一定是准确的,由于事件循环的机制问题,需要等待微任务执行完毕之后再执行 setTimeout
  2. setTimeout 嵌套五次,至少是 4 毫秒,不是 0 毫秒
  3. setTimeout 调用的 this 指向是 window

setInterval ​

setInterval(函数,时间(毫秒));

间歇性执行,每隔相同的时间执行一次;

常用于倒计时;清除:clearInterval(定时器);

每个定时器开启的时候,都有一个自己的 id 数字,如果需要清除定时器,则需要清除定时器的 id; 返回值就是定时器的 id 值;

定时器如果不清除,会一直占用内存,可以设置一个变量,用来保存这个定时器,之后设置一个清除定时器的方法;

requestAnimationFrame ​

requestAnimationFrame() IE10+ 不需要设置间隔,会自动调用; 案例:

js
var a = 100
function step() {
  a--
  if (a === 0) return
  requestAnimationFrame(step)

  //如果需要传入参数
  // requestAnimationFrame(()=>step(1))
}
step()
var a = 100
function step() {
  a--
  if (a === 0) return
  requestAnimationFrame(step)

  //如果需要传入参数
  // requestAnimationFrame(()=>step(1))
}
step()

兼容处理:

js
if (!window.requestAnimationFrame) {
  requestAnimationFrame = function (fn) {
    setTimeout(fn, 17) // 因为刷新频率是16.7ms执行一次,所以是17;
  }
}
if (!window.requestAnimationFrame) {
  requestAnimationFrame = function (fn) {
    setTimeout(fn, 17) // 因为刷新频率是16.7ms执行一次,所以是17;
  }
}

时间对象 ​

常用方法: ​
方法描述
Date()返回当日的日期和时间;传参时间戳还原时间。
getDate()从 Date 对象返回一个月中的某一天 (1 ~ 31)。
getDay()从 Date 对象返回一周中的某一天 (0 ~ 6)。
getMonth()从 Date 对象返回月份 (0 ~ 11)。
getFullYear()从 Date 对象以四位数字返回年份。
getYear()请使用 getFullYear() 方法代替。
getHours()返回 Date 对象的小时 (0 ~ 23)。
getMinutes()返回 Date 对象的分钟 (0 ~ 59)。
getSeconds()返回 Date 对象的秒数 (0 ~ 59)。
getMilliseconds()返回 Date 对象的毫秒(0 ~ 999)。
getTime()返回 1970 年 1 月 1 日至今的毫秒数。
getTimezoneOffset()返回本地时间与格林威治标准时间 (GMT) 的分钟差。
getUTCDate()根据世界时从 Date 对象返回月中的一天 (1 ~ 31)。
getUTCDay()根据世界时从 Date 对象返回周中的一天 (0 ~ 6)。
getUTCMonth()根据世界时从 Date 对象返回月份 (0 ~ 11)。
getUTCFullYear()根据世界时从 Date 对象返回四位数的年份。
getUTCHours()根据世界时返回 Date 对象的小时 (0 ~ 23)。
getUTCMinutes()根据世界时返回 Date 对象的分钟 (0 ~ 59)。
getUTCSeconds()根据世界时返回 Date 对象的秒钟 (0 ~ 59)。
getUTCMilliseconds()根据世界时返回 Date 对象的毫秒(0 ~ 999)。
parse()返回 1970 年 1 月 1 日午夜到指定日期(字符串)的毫秒数。
setDate()设置 Date 对象中月的某一天 (1 ~ 31)。
setMonth()设置 Date 对象中月份 (0 ~ 11)。
setFullYear()设置 Date 对象中的年份(四位数字)。
setYear()请使用 setFullYear() 方法代替。
setHours()设置 Date 对象中的小时 (0 ~ 23)。
setMinutes()设置 Date 对象中的分钟 (0 ~ 59)。
setSeconds()设置 Date 对象中的秒钟 (0 ~ 59)。
setMilliseconds()设置 Date 对象中的毫秒 (0 ~ 999)。
setTime()以毫秒设置 Date 对象。
setUTCDate()根据世界时设置 Date 对象中月份的一天 (1 ~ 31)。
setUTCMonth()根据世界时设置 Date 对象中的月份 (0 ~ 11)。
setUTCFullYear()根据世界时设置 Date 对象中的年份(四位数字)。
setUTCHours()根据世界时设置 Date 对象中的小时 (0 ~ 23)。
setUTCMinutes()根据世界时设置 Date 对象中的分钟 (0 ~ 59)。
setUTCSeconds()根据世界时设置 Date 对象中的秒钟 (0 ~ 59)。
setUTCMilliseconds()根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。
toSource()返回该对象的源代码。
toString()把 Date 对象转换为字符串。
toTimeString()把 Date 对象的时间部分转换为字符串。
toDateString()把 Date 对象的日期部分转换为字符串。
toGMTString()请使用 toUTCString() 方法代替。
toUTCString()根据世界时,把 Date 对象转换为字符串。
toLocaleString()根据本地时间格式,把 Date 对象转换为字符串。
toLocaleTimeString()根据本地时间格式,把 Date 对象的时间部分转换为字符串。
toLocaleDateString()根据本地时间格式,把 Date 对象的日期部分转换为字符串。
UTC()根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。
valueOf()返回 Date 对象的原始值。

设置时间 ​

date.setDate(date.getDate() + 7);

设置时间需要先获取时间;

有get的属性都可以set;set 有容错能力,如:61 秒就是 1 分 1 秒;

js
// 设置日期加7天;
var date = new Date() // 从声明开始就已经定死了,一直是该时间;
date.setDate(date.getDate() + 7)

// 设置日期加7天;
var date = new Date()
date.setDate(date.getDate() + 7)
// 设置日期加7天;
var date = new Date() // 从声明开始就已经定死了,一直是该时间;
date.setDate(date.getDate() + 7)

// 设置日期加7天;
var date = new Date()
date.setDate(date.getDate() + 7)

获取星期和月数 ​

  • 获取这个月有多少天:new Date(y,m,0).getDate();

  • 获取当前是这个月的周几:new Date(y,m,0).getDay();

  • 获取这个月的第一天是周几:new Date(y,m-1,0).getDay()+1;

    先获取上一个月多少天,再获取星期时加一天就是这个月的第一天;

  • 如果想获取当前月份最后一天,可以直接设置日为 0,setDate(0)

js
var date = new Date() //获取当前时间
var y = date.getFullYear() //获取年
var m = date.getMonth() + 1 //获取月
var d = new Date(y, m, 0).getDate() //获取当前这个月有多少天
var week = new Date(y, m - 1, 0).getDay() + 1 //获取当前这个月第一天是周几
if (week >= 7) {
  week = 0
} //7+1会为8,所以等于0
var date = new Date() //获取当前时间
var y = date.getFullYear() //获取年
var m = date.getMonth() + 1 //获取月
var d = new Date(y, m, 0).getDate() //获取当前这个月有多少天
var week = new Date(y, m - 1, 0).getDay() + 1 //获取当前这个月第一天是周几
if (week >= 7) {
  week = 0
} //7+1会为8,所以等于0

格式化时间 ​

英文状态 ​

字符串格式时间:

toString(); Thu May 02 2019 01:24:10 GMT+0800 (中国标准时间)

toDateString(); Thu May 02 2019;

toTimeString(); 01:24:56 GMT+0800;

toUTCString(); 显示世界时间;

转成本地时间 ​

toLocaleString(); //2019-7-11 21:49:52

toLocaleDateString(); //2019-7-11

toLocaleTimeString(); //上午 9:00:00;

设置一个倒计时 ​

计算两个时间的间隔,用第一个时间减去第二个时间;

  1. 计算出目标时间和现在时间的间隔多少毫秒,用目标时间减去现在的时间,之后再除以一千显示为秒;

    计算倒计时剩下的时间:

    js
    var leftTime = new Date(enddate) - new Date() //计算剩余的毫秒数
    var days = parseInt(leftTime / 1000 / 60 / 60 / 24, 10) //计算剩余的天数
    var hours = parseInt((leftTime / 1000 / 60 / 60) % 24, 10) //计算剩余的小时
    var minutes = parseInt((leftTime / 1000 / 60) % 60, 10) //计算剩余的分钟
    var seconds = parseInt((leftTime / 1000) % 60, 10) //计算剩余的秒数
    
    s = 1242626
    m = s / 60
    h = s / 60 / 60
    t = s / 60 / 60 / 24
    var leftTime = new Date(enddate) - new Date() //计算剩余的毫秒数
    var days = parseInt(leftTime / 1000 / 60 / 60 / 24, 10) //计算剩余的天数
    var hours = parseInt((leftTime / 1000 / 60 / 60) % 24, 10) //计算剩余的小时
    var minutes = parseInt((leftTime / 1000 / 60) % 60, 10) //计算剩余的分钟
    var seconds = parseInt((leftTime / 1000) % 60, 10) //计算剩余的秒数
    
    s = 1242626
    m = s / 60
    h = s / 60 / 60
    t = s / 60 / 60 / 24
  2. 根据计算出的时间写出时间戳,也可以再加入补零的操作

  3. 倒计时思想:

    • 获取时间,根据时间得到年月日,时分秒
    • 补零
    • 用一个定时器让时间跑起来

计算一个循环花了多长时间 ​

js
let startTime = new Date().getTime() // 记录一个开始时间毫秒
for (var i = 0; i < 10000; i++) {}
let endTime = new Date().getTime() // 记录一个结束时间毫秒
console.log(endTime - startTime)

// 当然也可以使用console.time来获取;
let startTime = new Date().getTime() // 记录一个开始时间毫秒
for (var i = 0; i < 10000; i++) {}
let endTime = new Date().getTime() // 记录一个结束时间毫秒
console.log(endTime - startTime)

// 当然也可以使用console.time来获取;

时间的比较 ​

不要直接通过时间对比,是不相等的,想要相等,可以对比时间戳

js
let date = new Date('2019/6/1')
let date2 = new Date('2019/6/1')
console.log(date == date2) // false
console.log(date.getTime() === date2.getTime()) //true
// +号可以快速进行Number转换成时间戳
let date = new Date('2019/6/1')
let date2 = new Date('2019/6/1')
console.log(date == date2) // false
console.log(date.getTime() === date2.getTime()) //true
// +号可以快速进行Number转换成时间戳

时间插件: http://momentjs.cn/

比 moment 打包更小的插件:dayjs https://github.com/iamkun/dayjs

常见 bug ​

如果获取最后一天出错了,跳了月份,可以设置 setMonth(28)即可,或者 29,再 getMonth+1

时间格式化函数 ​

js
function format(value) {
  let data = new Date(value)
  let Y = data.getFullYear()
  let M = data.getMonth() + 1
  let R = data.getDate()
  let h = data.getHours()
  let m = data.getMinutes()
  let s = data.getSeconds()
  let f = (d) => String(d).padStart('2', '0')
  return `${Y}-${f(M)}-${f(R)} ${f(h)}:${f(m)}:${f(s)}`
}
function format(value) {
  let data = new Date(value)
  let Y = data.getFullYear()
  let M = data.getMonth() + 1
  let R = data.getDate()
  let h = data.getHours()
  let m = data.getMinutes()
  let s = data.getSeconds()
  let f = (d) => String(d).padStart('2', '0')
  return `${Y}-${f(M)}-${f(R)} ${f(h)}:${f(m)}:${f(s)}`
}

Math ​

​

方法描述
abs(x)返回数的绝对值。
acos(x)返回数的反余弦值。
asin(x)返回数的反正弦值。
atan(x)以介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值。
atan2(y,x)返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间)。
ceil(x)对数进行上舍入。
floor(x)对数进行下舍入,超出精度四舍五入。
cos(x)返回数的余弦。
exp(x)返回 e 的指数。
log(x)返回数的自然对数(底为 e)。
max(x,y)返回 x 和 y 中的最高值,可以存在多个参数。
min(x,y)返回 x 和 y 中的最低值,可以存在多个参数。
pow(x,y)返回 x 的 y 次幂。
random()返回 0 ~ 1 之间的随机数。
round(x)把数四舍五入为最接近的整数。
sin(x)返回数的正弦。
sqrt(x)返回数的平方根。
tan(x)返回角的正切。
toSource()返回该对象的源代码。
valueOf()返回 Math 对象的原始值。
自定范围随机数 ​
javascript
function random(min, max) {
  // return Math.round(Math.random() * (max - min) + min);
  return Math.floor(Math.random() * (max - min + 1) + min)
}
function random(min, max) {
  // return Math.round(Math.random() * (max - min) + min);
  return Math.floor(Math.random() * (max - min + 1) + min)
}

Math.random ​

Math.random();取随机数,取出来的是 0-1 的随机小数;

套用下面的公式取某个整数范围内随机选择的一个值

js
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

取 n-m 的随机数:Math.random()*(m-n+1)+n;

比如 3-10 的随机数:Math.random()*8+3;

理解随机数:Math.ceil(Math.random()*6) 取 1-6;向上取整不会包括 0;因为不会到 6,所以是 6;

数字精度解决 ​

js
// 按照有效数字位数进行四舍五入,默认6位有效数字
function signFigures(num, rank = 6) {
  if (!num) return num
  const sign = num / Math.abs(num)
  const number = num * sign
  const temp = rank - 1 - Math.floor(Math.log10(number))

  let ans
  if (temp > 0) {
    ans = parseFloat(number.toFixed(temp))
  } else if (temp < 0) {
    ans = Math.round(number / Math.pow(10, temp)) * temp
  } else {
    ans = Math.round(number)
  }
  return ans * sign
}

signFigures(0.1 + 0.2) // 0.3
signFigures(0.56 * 100) // 56
signFigures(0.57 * 100) // 57
// 按照有效数字位数进行四舍五入,默认6位有效数字
function signFigures(num, rank = 6) {
  if (!num) return num
  const sign = num / Math.abs(num)
  const number = num * sign
  const temp = rank - 1 - Math.floor(Math.log10(number))

  let ans
  if (temp > 0) {
    ans = parseFloat(number.toFixed(temp))
  } else if (temp < 0) {
    ans = Math.round(number / Math.pow(10, temp)) * temp
  } else {
    ans = Math.round(number)
  }
  return ans * sign
}

signFigures(0.1 + 0.2) // 0.3
signFigures(0.56 * 100) // 56
signFigures(0.57 * 100) // 57