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_指向该对象的原型 - 实例原型也是一个对象
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 // 返回克隆对象
}