JavaScript 重点补全

✅ 数据类型

  • typeof:一元运算符
    • 检测基本数据类型和函数类型
    • 无法区分 nullundefinedtypeof null 返回 "object"
    • 通常较快,因为它是内置的类型检查机制
  • instanceof:二元运算符
    • 检测对象是否为特定构造函数的实例
    • 不能检测基本数据类型,只适用于引用类型
    • 可能较慢,因为涉及原型链的搜索
  • Object.protptype.toString.call():方法
    • 检测所有数据类型
    • 可以区分基本数据类型和引用类型
    • 可能较慢,因为涉及内部 [[Class]] 属性的获取
分类 类型 说明 示例 typeof instanceof Object.prototype.toString.call()
基本数据类型 undefined 未赋值 var a; undefined [object Undefined]
string 字符串 var a = 'hello'; string [object String]
number 数字 var a = 1; number [object Number]
boolean 布尔值 var a = true; boolean [object Boolean]
null 空值 var a = null; null [object Null]
symbol 符号(ES6) var a = Symbol(); symbol [object Symbol]
bigint 大整数(ES2020) var a = 1n; bigint [object BigInt]
引用数据类型 object 对象 var a = {}; object Object [object Object]
array 数组 var a = []; object Array [object Array]
function 函数 var a = function(){}; function Function [object Function]
date 日期 var a = new Date(); object Date [object Date]
regexp 正则 var a = /d{6}/g; object RegExp [object RegExp]
自定义数据类型 my 自定义类 class My {};
var a = new My();
object My [object Object]

✅ 引用类型数据的内置方法

Object

  • Object.assign(target, source1, source2, ...)复制所有可枚举属性的值从一个或多个源对象到目标对象

    var Alex = { name: "Alex", age: 20 };
    var Bob = { name: "Bob", age: 20, gender: "male" };
    var result = Object.assign(Bob, Alex);
    console.log(result);	// { name: 'Alex', age: 20, gender: 'male' }
    
  • Object.create(proto)创建一个新对象,使用指定的 proto 对象作为原型

    var proto = {
      func: function () {
        console.log(this.value);
      },
    };
    var obj = Object.create(proto);
    obj.value = "hello world";
    obj.func();		// hello world
    
  • Object.entries(obj):返回一个给定对象自身的所有可枚举属性的键值对数组

    var Alex = { name: "Alex", age: 20 };
    console.log(Object.entries(Alex));	// [ [ 'name', 'Alex' ], [ 'age', 20 ] ]
    
  • Object.fromEntries(iterable):将可迭代的键值对数组或 Map 对象转换为一个新的对象

    var a = [['a', 'b'], [1, 2]]
    console.log(Object.fromEntries(a));	// { '1': 2, a: 'b' }
    
  • Object.keys(obj):返回一个给定对象自身的所有可枚举属性键的数组

    var Alex = { name: "Alex", age: 20 };
    console.log(Object.keys(Alex));		// [ 'name', 'age' ]
    
  • Object.values(obj):返回一个给定对象自身的所有可枚举属性值的数组

    var Alex = { name: "Alex", age: 20 };
    console.log(Object.values(Alex));	// [ 'Alex', 20 ]
    
  • Object.freeze(obj):冻结一个对象的属性,使得属性不可配置,也不可写

  • Object.isFrozen(obj):判断一个对象是否被冻结

    var obj = { a: 1 };
    Object.freeze(obj);
    obj.a = 2;
    console.log(obj);					// { a: 1 }
    obj.b = 2;
    console.log(obj);					// { a: 1 }
    console.log(Object.isFrozen(obj));	// true
    
  • Object.seal(obj):防止对象添加新属性或修改现有属性的可配置性

  • Object.isSealed(obj):判断一个对象是否被密封

    var obj = { a: 1 };
    Object.seal(obj);
    obj.a = 2;
    console.log(obj);					// { a: 2 }
    obj.b = 2;
    console.log(obj);					// { a: 2 }
    console.log(Object.isSealed(obj));	// true
    
  • Object.defineProperty(obj, prop, descriptor):定义一个对象的新属性或修改现有属性的特性

    var obj = {};
    Object.defineProperty(obj, 'a', {
      value: 1,
      writable: false,			// 可写性
      enumerable: true,			// 可枚举性
      configurable: false,		// 可配置性
    });
    console.log(obj);			// { a: 1 }
    obj.a = 2;
    console.log(obj);			// { a: 1 }
    
  • Object.defineProperties(obj, props):定义一个对象的多个新属性或修改现有属性的特性

    var obj = {};
    Object.defineProperties(obj, {
      a: {
        value: 1,
        writable: false,
      },
      b: {
        value: 2,
        writable: true,
      },
    });
    console.log(obj.a, obj.b);	// 1 2
    obj.a = 2;
    obj.b = 3;
    console.log(obj.a, obj.b);	// 1 3
    
  • Object.is(value1, value2):比较两个值是否相同,类似于===操作符

    console.log(Object.is(123, 123));	// true
    console.log(Object.is(123, "123"));	// false
    

Array

基本操作方法
  • concat(Array)连接两个或多个数组,返回一个新数组

    var a = [1, 2 ,3];
    var b = [4, 5, 6];
    var c = a.concat(b);
    console.log(c);		// [ 1, 2, 3, 4, 5, 6 ]
    
  • copyWithin(target[, start[, end]]):在数组内,将指定位置的成员复制到其他位置,并返回修改后的数组

    • target:从该位置开始替换数据;如果为负数,则表示倒数(下同)
    • start:从该位置开始读取数据,默认为 0
    • end:到该位置前停止读取数据(不包括该位置),默认为 this.length
    var a = [0, 1, 2, 3, 4, 5];
    a.copyWithin(3, 0, 3);
    console.log(a);		// [ 0, 1, 2, 0, 1, 2 ]
    
  • entries():返回数组的可迭代对象,包含数组中每个索引的键值对

    var a = ["a", "b", "c"];
    for (var [key, value] of a.entries()) console.log(key, value);
    /*
     * 0 a
     * 1 b
     * 2 c
     */
    
  • fill(value[, start[, end]])填充,用一个固定值填充数组中从开始索引到结束索引内的全部元素

    var arr1 = new Array(5);
    arr1.fill(0);
    console.log(arr1);	// [ 0, 0, 0, 0, 0 ]
    
    var arr2 = [1, 1, 1, 1];
    arr2.fill(0, 1, 3);
    console.log(arr2);	// [ 1, 0, 0, 1 ]
    
  • filter(fn)过滤器,创建一个新数组,包含通过所提供函数实现的测试的所有元素

    var a = [1, 2, 3];
    console.log(a.filter((value) => value >= 2));	// [ 2, 3 ]
    
  • find(fn)查找值,返回数组中满足提供的测试函数的第一个元素的值

    var a = [1, 2, 3];
    console.log(a.find((value) => value >= 2));		// 2
    
  • findIndex(fn)查找索引,返回数组中满足提供的测试函数的第一个元素的索引

    var a = [1, 2, 3];
    console.log(a.findIndex((value) => value >= 2));	// 1
    
  • forEach(fn)遍历,对数组的每个元素执行一次给定的函数

    var a = [1, 2, 3];
    a.forEach((value) => console.log(value));
    /*
     * 1
     * 2
     * 3
     */
    
  • includes(item):判断一个数组是否包含一个指定的值

    var a = [1, 2, 3];
    console.log(a.includes(2), a.includes(4));	// true false
    
  • indexOf(item):返回在数组中可以找到一个给定元素的第一个索引

    var a = [1, 1, 1];
    console.log(a.indexOf(1));		// 0
    
  • join(separator):将数组的所有元素连接为字符串

    var a = [1, 2, 3];
    console.log(a.join(','));		// 1,2,3
    
  • keys():返回数组的可迭代对象,包含原始数组的

    var a = ["a", "b", "c"];
    for (let key of a.keys()) console.log(key);
    /*
     * 0
     * 1
     * 2
     */
    
  • lastIndexOf(item):返回在数组中可以找到一个给定元素的最后一个索引

    var a = [1, 1, 1];
    console.log(a.lastIndexOf(1));		// 2
    
  • map((currentValue[, index[, array]]) => {}[, thisArg])映射,创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值

    var a = ['a', 'b', 'c'];
    var b = a.map((value, index) => value + ' ' + index);
    console.log(b);		// [ 'a 0', 'b 1', 'c 2' ]
    
  • pop()尾出栈,删除数组的最后一个元素并返回该元素的值

    var a = [1, 2, 3];
    console.log(a.pop());		// 3
    console.log(a);				// [ 1, 2 ]
    
  • push(...items)尾压栈,向数组的末尾添加一个或多元素,并返回数组新的长度

    var a = [0, 1];
    console.log(a.push(2));		// 3
    console.log(a);				// [ 0, 1, 2 ]
    
  • reduce((accumulator, currentValue[, index[, array]]) => {}[, initialValue]):将数组元素计算为一个值(从左到右)

    var a = ["a", "b", "c"];
    console.log(a.reduce((acc, cur) => acc + cur, ""));		// abc
    
  • reduceRight((accumulator, currentValue[, index[, array]]) => {}[, initialValue]):将数组元素计算为一个值(从右到左)

    var a = ["a", "b", "c"];
    console.log(a.reduceRight((acc, cur) => acc + cur, ""));	// cba
    
  • reverse()反转数组的元素顺序

    var a = [1, 2, 3];
    console.log(a.reverse());	// [ 3, 2, 1 ]
    
  • shift()头出栈,删除并返回数组的第一个元素

    var a = [1, 2, 3];
    console.log(a.shift()); 	// 1
    console.log(a);				// [ 2, 3 ]
    
  • slice([start[, end]])切片,选取数组的一部分,并返回一个新数组

    var a = [1, 2, 3];
    console.log(a.slice(1, 3));		// [ 2, 3 ]
    
  • some(fn):检测数组元素中是否有元素符合指定条件

    var a = [1, 2, 3];
    console.log(a.some((value) => value < 3));	// true
    console.log(a.some((value) => value > 3));	// false
    
  • sort(fn):对数组的元素进行排序

    var a = [2, 1, 3];
    console.log(a.sort((a, b) => a - b));	// [ 1, 2, 3 ]
    console.log(a.sort((a, b) => b - a));	// [ 3, 2, 1 ]
    
  • splice(start, deleteCount[, item])从数组中添加或删除元素

    var a = [1, 2, 3];
    a.splice(1, 1, 1);		// [ 1, 1, 3 ]
    console.log(a);
    
  • toLocaleString():返回一个字符串表示数组中的元素

    var a = [1000, 2, 3];
    console.log(a.toLocaleString());	// 1,000,2,3
    
  • toString():返回一个字符串,表示指定的数组及其元素

    var a = [1000, 2, 3];
    console.log(a.toString());			// 1000,2,3
    
  • unshift(...items)头压栈,向数组的开头添加一个或多元素,并返回新的长度

    var a = [2, 3];
    console.log(a.unshift(1));	// 3
    console.log(a);				// [ 1, 2, 3 ]
    
  • values():返回一个新的 Array Iterator 对象,该对象包含数组每个索引的

    var a = ["a", "b", "c"];
    for (let value of a.values()) console.log(value);
    /*
     * a
     * b
     * c
     */
    
静态方法
  • Array.from(arrayLike[, mapFn[, thisArg]]):从类似数组或可迭代对象创建一个新的数组实例

    console.log(
      Array.from({
        1: "a",
        0: "b",
        2: "c",
        length: 3,
      })
    );	// [ 'b', 'a', 'c' ]
    
    console.log(Array.from("abc"));		// [ 'a', 'b', 'c' ]
    
    console.log(Array.from([1, 2, 3], (x) => x + x));	// [ 2, 4, 6 ]
    
  • Array.isArray():检查一个值是否为数组

    console.log(Array.isArray([1, 2, 3]));			// true
    console.log(Array.isArray([]));					// true
    console.log(Array.isArray(new Array()));		// true
    console.log(Array.isArray(Array.prototype));	// true
    console.log(Array.isArray("abc"));				// false
    console.log(Array.isArray(null));				// false
    console.log(Array.isArray(undefined));			// false
    
  • Array.of():创建一个具有可变数量参数的新数组实例

    console.log(Array.of(undefined, null, 1, "a"));	// [ undefined, null, 1, 'a' ]
    
案例:数组去重
  1. 使用双重循环

    var array = [1, 2, 2, 3, 4, 4, 5];
    for (var i = 0; i < array.length; i++) {
      for (var j = i + 1; j < array.length; j++) {
        if (array[i] === array[j]) {
          array.splice(j, 1);
          j--;
        }
      }
    }
    console.log(array);
    
  2. 使用 Set 集合数据结构

    var array = [1, 2, 2, 3, 4, 4, 5];
    var result = [...new Set(array)];
    console.log(result);
    
  3. 使用 Map 哈希数据结构

    var array = [
      { name: "Alex", age: 20 },
      { name: "Bob", age: 25 },
      { name: "Charlie", age: 20 },
    ];
    
    let map = new Map();
    array.forEach((item) => {
      if (!map.has(item.age)) {
        map.set(item.age, [item]);
      } else {
        map.get(item.age).push(item);
      }
    });
    let result = {};
    for (let [key, value] of map) {
      result[key] = value;
    }
    console.log(result);
    
  4. 使用 filter 方法

    var array = [
      { name: "Alex", age: 20 },
      { name: "Bob", age: 25 },
      { name: "Charlie", age: 20 },
    ];
    var result = array.filter((item, index, self) => {
      return self.findIndex((temp) => temp.name === item.name) === index;
    });
    console.log(result);
    
  5. 使用 reduce 方法

    var array = [
      { name: "Alex", age: 20 },
      { name: "Bob", age: 25 },
      { name: "Charlie", age: 20 },
    ];
    var result = array.reduce(function (acc, curr) {
      if (!acc[curr.age]) acc[curr.age] = [];
      acc[curr.age].push(curr);
      return acc;
    }, {});
    console.log(result);
    

Date

  • getDate(): 返回月份中的第几天(从 1 到 31)
  • getDay(): 返回星期几(0 表示周日,1 表示周一)
  • getFullYear(): 返回年份
  • getHours(): 返回小时(从 0 到 23 )
  • getMilliseconds(): 返回毫秒(0 到 999)
  • getMinutes(): 返回分钟(从 0 到 59)
  • getMonth(): 返回月份(从 0 到 11)
  • getSeconds(): 返回秒数(从 0 到 59)
  • getTime(): 返回自1970年1月1日午夜以来的毫秒数
  • getTimezoneOffset(): 返回UTC时间与本地时间之间的时差,以分钟为单位
  • now(): 返回自 1970 年 1 月 1 日午夜以来的毫秒数
  • parse(): 解析日期字符串并返回自 1970 年 1 月 1 日以来的毫秒数
  • setDate(): 设置月份中的某一天
  • setFullYear(): 设置日期对象的年份
  • setHours(): 设置日期对象的小时
  • setMilliseconds(): 设置日期对象的毫秒数
  • setMinutes(): 设置日期对象的分钟数
  • setMonth(): 设置日期对象的月份
  • setSeconds(): 设置日期对象的秒数
  • setTime(): 将日期设置为 1970 年 1 月 1 日之后(之前)的指定毫秒数
  • toDateString(): 将日期对象的日期部分转换为可读字符串
  • toISOString(): 使用 ISO 标准将日期作为字符串返回
  • toJSON(): 以字符串形式返回日期,格式为 JSON 日期
  • toLocaleDateString(): 使用区域设置约定将 Date 对象的日期部分作为字符串返回
  • toLocaleTimeString(): 使用区域设置约定将 Date 对象的时间部分作为字符串返回
  • toLocaleString(): 使用区域设置约定将 Date 对象转换为字符串
  • toString(): 将 Date 对象转换为字符串
  • toTimeString(): 将 Date 对象的时间部分转换为字符串
  • valueOf(): 返回 Date 对象的原始值

RegExp

  • compile():(ES6 开始废弃)重新编译正则表达式

  • exec():执行正则表达式的搜索,返回第一个匹配结果的数组

    var a = 123
    console.log(/^\d+$/.exec(a));	// [ '123', index: 0, input: '123', groups: undefined ]
    
  • test():执行正则表达式的搜索,返回一个布尔值,指示是否找到匹配

    var a = 123
    var b = "123"
    console.log (/^\d+$/.test(a))	// true
    console.log (/^\d+$/.test(b))	// true
    
  • toString():返回表示正则表达式的字符串

    console.log(/^\d+$/.toString());	// /^\d+$/
    
  • flags:返回正则表达式的标志(修饰符)的字符串

  • source:返回正则表达式的模式文本

  • lastIndex:设置或返回正则表达式下次匹配的起始索引

    console.log(/^\d+$/g.flags);		// g
    console.log(/^\d+$/g.source);		// ^\d+$
    console.log(/^\d+$/g.lastIndex);	// 0
    

✅ 事件对象

  • event.preventDefault()阻止事件的默认行为
  • event.stopPropagation()阻止事件继续在 DOM 树上冒泡或捕获,使事件不会传播到其他层级的元素
  • event.stopImmediatePropagation():阻止同一元素上的其他事件处理程序被触发,即使它们在事件队列中等待执行
  • event.target:返回触发事件的元素,即事件的目标
  • event.currentTarget:返回绑定事件处理程序的元素,在事件处理程序内部,this 关键字通常指向 event.currentTarget
  • event.timeStamp:返回事件被触发的时间戳
  • event.isTrusted:返回一个布尔值,指示事件是否由用户而非脚本触发
  • event.type:返回事件的类型,如 clickkeypress
  • event.bubbles:返回一个布尔值,指示事件是否会冒泡
  • event.cancelable:返回一个布尔值,指示事件是否可以被取消
  • event.eventPhase:返回一个整数,表示事件当前处于事件流的哪个阶段(捕获、目标、冒泡)

✅ 原型(proto)与原型链

  • 原型分隐式原型显示原型

    var array = new Array();
    var implicit = array.__proto__;		// 隐式原型
    var explicit = Array.prototype;		// 显式原型
    console.log(implicit, explicit);
    console.log(implicit === explicit);	// true
    
    • 此时,类实例的隐式原型全等于类的显式原型
    • 隐式原型指向显式原型
  • 原型链是指原型中嵌套着原型

    var array = new Array();
    console.log(array.__proto__);
    console.log(array.__proto__.__proto__);
    
  • 可以通过 hasOwnProperty() 方法查看当前实例本身是否具有某个属性,而非去原型链上寻找

    class Calc {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    
    var calc = new Calc(1, 2);
    console.log(calc.hasOwnProperty('x'));	// true
    console.log(calc.hasOwnProperty('z'));	// false
    

✅ 函数

函数类型

  1. 具名函数:通过 function 关键字声明的,具有函数名,可以在其作用域内的任何地方调用

    function func() {}
    
  2. 匿名函数:通常赋值给变量或者作为参数传递给其他函数

    var func = function () {};
    
  3. 箭头函数:ES6 引入的一种新的函数定义方式,提供了更简洁的语法,并且在处理 this 时有所不同

    var func = () => {};
    
  4. 生成器函数:可以暂停执行并在之后恢复执行,通过 function* 关键字定义,并使用 yield 关键字返回值

    function* generator() {
      yield 1;
      yield 2;
      yield 3;
    }
    let g = generator();
    console.log(g.next().value);	// 1
    console.log(g.next().value);	// 2
    console.log(g.next().value);	// 3
    
  5. 构造函数:用于创建对象实例,通常首字母大写,并通过new关键字调用

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    var person = new Person("Alex", 20);
    console.log(person.name, person.age);	// Alex 20
    
  6. 立即执行函数:定义后立即执行,常用于创建私有作用域或避免全局命名空间污染

    (function (name) {
      console.log(name);	// Alex
    })("Alex");
    
  7. 回调函数:回调函数是作为参数传递给另一个函数的函数,通常在某个异步操作完成后被调用

    function func(callback) {
      callback("func");
    }
    func((value) => console.log(value));	// func
    
  8. 闭包函数:闭包是指有权访问另一个函数作用域中变量的函数,通常由一个内部函数引用外部函数的变量形成

    function outer(outerValue) {
      return function inner(innerValue) {
        console.log("outerValue:", outerValue);			// outerValue: out
        console.log("innerValue:", innerValue);			// innerValue: in
      };
    }
    outer("out")("in");
    

箭头函数与普通函数的区别

箭头函数 普通函数
this 绑定 不绑定,捕获上下文的 this 动态绑定,取决于函数的调用方式
arguments 对象 没有自身的 arguments 对象
可以使用剩余参数语法 ...args
有自身的 arguments 对象
包含函数调用时传入的所有参数
构造函数 不可用,不支持 new 可以,支持 new
返回值 单个表达式时可以直接返回表达式结果 必须使用 return 返回
supernew.target 不支持 支持
this.arguments 不支持 支持
特点 快速、简洁 复杂,多场景适用

闭包

  • 闭包 = 内层函数 + 引用外层函数的变量

  • 闭包不一定要有 return

    • 当外层函数需要适使用闭包中的变量时,需要 return

    • 闭包应用:实现数据私有(举例:计数)

      function func() {
        let count = 0;
        return function closure() {
          count++;
          console.log("count", count);
        };
      }
      const res = func();
      res();		// count 1
      res();		// count 2
      
      • 节流与防抖函数
      • Vue 和 React 的 Hooks 钩子函数
  • 闭包不一定有内存泄漏

    • 在上述计数示例中,count 变量在 closure() 中被引用,无法被作为垃圾回收,从而引起内存泄漏
    • 并非所有内存泄漏都需要手动回收

✅ 作用域

全局作用域

  • 可以被局部作用域遮蔽
  • 在浏览器环境中,全局作用域中的变量通常会成为 window 对象的属性

局部作用域

  • 变量或函数只能在特定的代码块内部被访问

块级作用域

  • ES6 引入
  • 允许在代码块内部声明变量和函数,这些变量和函数的作用域被限制在相应的代码块内
  • 通过 letconst 关键字实现

作用域链

  • 用于变量解析的机制
  • 当在函数内部尝试访问一个变量时,如果该变量在当前函数的局部作用域中没有找到,解释器会沿着作用域链向上查找,直至找到该变量或达到全局作用域
  • 确保了变量的私有性封装性,防止了变量名称的冲突

变量提升

  • 变量和函数声明在代码执行之前就被移至其作用域的顶部,但变量的初始化操作保留在原位置

  • 表现为:在变量声明之前引用了变量,会得到 undefined 的值,而非报错

    function func() {
      console.log(a);	// undefined
      var a = 1;
      console.log(a);	// 1
    
      console.log(b);	// 报错:ReferenceError
      let b = 2;
      console.log(b);	// 2
    
      console.log(c);	// 报错:ReferenceError
      const c = 3;
      console.log(c);	// 3
    }
    func();
    

-End-

posted @ 2024-07-16 00:55  SRIGT  阅读(12)  评论(0编辑  收藏  举报