JS基础复习

98 阅读4分钟

JS的数据类型

  • 原始类型(NNUSB + symbol + bigint
    • number
    • null
    • undefined
    • string
    • boolean
    • symbol
    • bigint

原始数据类型:直接存储在栈(stack)内存中;原始数据类型是不可变(immutable)的,每一次赋值实际上都是创建新值;

  • 引用类型
    • Date
    • Object
    • Function
    • Array
    • ...

引用数据类型:存储在堆(heap)中,指针存储在栈(stack)中,指针指向堆中地址;简单的赋值只是把两个变量指向同一个堆地址;

Map和Set

相同点:

  • 存储不重复的值

不同点:

  • Set是[value,value]形式存储,Map是[key,value]形式存储
  • Set成员唯一,

Map(字典)

Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者基本类型)都可以作为一个键或一个值。

操作方法:

  • set(key, value):向字典中添加新元素。
  • get(key):通过键查找特定的数值并返回。
  • has(key):判断字典中是否存在键key。
  • delete(key):通过键 key 从字典中移除对应的数据。
  • clear():将这个字典中的所有元素删除。

遍历方法:

  • Keys():将字典中包含的所有键名以迭代器形式返回。
  • values():将字典中包含的所有数值以迭代器形式返回。
  • entries():返回所有成员的迭代器。
  • forEach():遍历字典的所有成员。

Set(集合)

  • Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
  • 数组去重:[...new Set(arr)]
  • 在Set中,5'5'是不相等的
  • NaN 和 undefined 都可以被存储在 Set 中,NaN 之间被视为相同的值(NaN 被认为是相同的,尽管 NaN !== NaN)
  • WeakSet 是弱引用,不会影响垃圾回收

操作方法:

  • add(value):新增,相当于 array里的push。
  • delete(value):存在即删除集合中value。
  • has(value):判断集合中是否存在 value。
  • clear():清空集合。

遍历方法:遍历方法(遍历顺序为插入顺序)

  • keys():返回一个包含集合中所有键的迭代器。
  • values():返回一个包含集合中所有值得迭代器。
  • entries():返回一个包含Set对象中所有元素得键值对迭代器。
  • forEach(callbackFn, thisArg):用于对集合成员执行callbackFn操作,如果提供了 thisArg 参数,回调中的this会是这个参数,没有返回值。

原型和原型链

  • 函数的prototype 指向实例原型
  • JavaScript 对象上的 _proto_ 指向该对象的原型
  • 实例原型也是一个对象

image.png

this指向

当函数独立调用的时候,在严格模式下它的this指向undefined,在非严格模式下,当this指向undefined的时候,自动指向全局对象(浏览器中就是window)

箭头函数会捕获其所在上下文的 this 值,作为自己的 this 值,也就是说箭头函数的this在词法层面就完成了绑定。apply,call方法只是传入参数,却改不了this。

判断技巧:

  • 对象调用,this 指向该对象(前边谁调用 this 就指向谁)
  • 直接调用的函数,this 指向的是全局 window 对象
  • 通过 new 的方式,this 永远被绑定在新创建的对象上,任何方式都改变不了 this 的指向
  • 方法是绑定在原型上,this 指向 window ;方法绑定在实例上, this 指向实例对象

new做了什么事

  • 创建一个临时对象
  • 给临时对象绑定原型
  • 给临时对象对应属性赋值
  • 将临时对象return
function Fun() {
  //new做的事情
  var obj = {};
  obj.__proto__ = Fun.prototype;//Base为构造函数
  obj.name = 'Damonare';
  ...//一系列赋值以及更多的事
  return obj
}

call,apply,bind

function print() {
    console.log(this.name)
}

var obj = {
    name: 'moxie'
}

print.call(obj, 1, 2, 3);

print.apply(obj, [1, 2, 3]);

var fn1 = print.bind(obj, 1, 2, 3);
var fn2 = print.bind(obj, [1, 2, 3]);
fn1();
fn2();

共同点:

  • 都能改变 this 指向,方法的第一个参数都是 this 指向的对象
  • 都采用后续传参的形式

不同点:

  • call, apply 都是直接执行的;bind 是返回一个函数
  • call 的 arguments 是一个一个传递;apply, bind 是以数组形式传递

深拷贝与浅拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的

浅拷贝:

  • [ ...arr ] or { ...obj }
  • Object.assign({}, obj)
  • Array.prototype.slice()

深拷贝:

  • JSON.parse(JSON.stringify())

有局限性,Function 无法被转换为 JSON ,只能对 Object 、Array 进行深拷贝

  • lodash 中的 cloneDeep
  • 手写递归
// 简单版本
function deepClone (target) {
  if (typeof target !== 'object') { // 如果是原始类型,无需继续拷贝,直接返回
    return target
  }
  // 如果是引用类型,递归实现每一层的拷贝
  const cloneTarget = {} // 定义一个克隆对象
  for (const key in target) { // 遍历原对象
    cloneTarget[key] = deepClone(target[key]) // 递归拷贝每一层
  }
  return cloneTarget // 返回克隆对象
}