目录
bind: return _this.apply(context, [...arguments].slice(1));
promise A+、catch、finally、all、allsettled、any、race
改变this
call
-
typeof this !== 'function'
-
context = context || window
-
context._this = this
-
delete context._this
// 给function的原型上面添加一个 _call 方法
Function.prototype._call = function (context) {
// 判断调用者是否是一个函数 this 就是调用者
if (typeof this !== 'function') {
throw new TypeError('what is to be a function')
}
// 如果有 context 传参就是传参者 没有就是window
context = context || window
// 保存当前调用的函数
context._this = this
// 截取传过来的参数
/*
arguments
a: 1
fn: ƒ fns()
*/
// 通过 slice 来截取传过来的参数
const local = [...arguments].slice(1)
// 传入参数调用函数
let result = context._this(...local)
// 删属性
delete context._this
return result
}
let obj = { a: 1 }
function fns(a, b) {
console.log(a, b);
console.log(this)
}
fns._call(obj, 23, 555)
bind: return _this.apply(context, [...arguments].slice(1));
Object
Object.create
该函数创建一个新对象,使用现有的对象来提供新创建的对象的proto,核心步骤有:
- 创建一个临时函数
- 将该临时函数的原型指向对象参数
- 返回该临时对象的实例
Object.create法创建一个新对象,使用现有的对象来提供新创建的对象的proto。
const _objectCreate = proto => {
if(typeof proto !== 'object' || proto === null) return
const fn = function() {}
fn.prototype = proto
return new fn()
}
Object.freeze
Object.freeze = writable: false + Object.seal = writable: false + Object.preventExtensions + configable: false
- Symbol 类型作为 key 值的情况,也要冻结
- 只冻结对象自有的属性(使用 for ... in 会把原型链上的可枚举属性遍历出来)。
- 注意不可扩展性(不能添加新属性,使用 Object.preventExtensions() 或 Object.seal() 实现,同时也相当于把原型链冻结)。
key:
- Object.getOwnPropertyNames/Symbol
- forEach
- Object.defineProperty:configurable,writable
- Object.preventExtensions(object)
const _objectFreeze = object => {
if(typeof object !== 'object' || object === null) {
throw new TypeError(`the ${object} is not a object`)
}
const keys = Object.getOwnPropertyNames(object);
const symbols = Object.getOwnPropertySymbols(object);
[...keys, ...symbols].forEach(key => {
Object.defineProperty(object, key, {
configurable: false,
writable: false,
})
})
Object.preventExtensions(object)
}
Object for of
// 创建一个构造函数
function MyObject() {
// 为构造函数的实例对象添加两个属性
this.prop1 = 'Value 1';
this.prop2 = 'Value 2';
}
// 在原型上添加一个自定义的迭代器方法
MyObject.prototype[Symbol.iterator] = function () {
// 获取实例对象的所有属性名并存储在数组 keys 中
const keys = Object.keys(this);
let index = 0;
// 返回一个迭代器对象,包含 next 方法
return {
next: () => {
// 如果还有属性未遍历完
if (index < keys.length) {
// 获取当前属性名 key,并递增索引 index
const key = keys[index++];
// 返回包含当前属性名和对应值的对象,并设置 done 为 false 表示未遍历完
return { value: [key, this[key]], done: false };
} else {
// 如果所有属性都已遍历完,返回 done 为 true 表示遍历结束
return { done: true };
}
},
};
};
// 创建一个实例对象
const instance = new MyObject();
// 使用 for...of 遍历实例对象的属性
for (const [key, value] of instance) {
// 打印属性名和对应值
console.log(key, value);
}
*instance of
- 获取首个对象参数的原型对象
- 获取Fn函数的原型对象
- 进入死循环,当两个参数的原型对象相等时返回true
- 当两个参数的原型对象不相等时获取首个对象参数原型的原型并且循环该步骤直到null时返回false
const _instanceof = (target, Fn) => {
let proto = target.__proto__
let prototype = Fn.prototype
while(true) {
if(proto === Fn.prototype) return true
if(proto === null) return false
proto = proto.__proto__
}
}
const _instanceof = (target, Fn) => {
return Fn.prototype.isPrototypeOf(target);
}
map
splice(start[, deleteCount, item...])
function CustomMap() {
this.keyValuePairs = [];
}
CustomMap.prototype.set = function(key, value) {
// 检查键是否已经存在,如果存在则更新值,否则添加新的键值对
const existingPair = this.keyValuePairs.find(pair => isEqual(pair.key, key));
if (existingPair) {
existingPair.value = value;
} else {
this.keyValuePairs.push({ key, value });
}
};
CustomMap.prototype.get = function(key) {
const pair = this.keyValuePairs.find(pair => isEqual(pair.key, key));
return pair ? pair.value : undefined;
};
CustomMap.prototype.delete = function(key) {
const index = this.keyValuePairs.findIndex(pair => isEqual(pair.key, key));
if (index !== -1) {
this.keyValuePairs.splice(index, 1);
}
};
// 一个简单的辅助函数,用于比较键的相等性
function isEqual(a, b) {
if (typeof a === 'object' && typeof b === 'object') {
// 深度比较对象
return JSON.stringify(a) === JSON.stringify(b);
}
return a === b;
}
// 示例使用
const myMap = new CustomMap();
// 使用对象作为键
const objKey = { name: 'John' };
myMap.set(objKey, 'Value for John');
console.log(myMap.get(objKey)); // 输出: Value for John
// 使用字符串作为键
myMap.set('stringKey', 'Value for stringKey');
console.log(myMap.get('stringKey')); // 输出: Value for stringKey
订阅发布,取消,一次订阅
class PubSub {
constructor() {
this.subscribers = {};
}
// 订阅方法
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
const index = this.subscribers[event].length - 1;
// 返回取消订阅的函数
return () => {
this.subscribers[event].splice(index, 1);
};
}
// 发布方法
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => {
callback(data);
});
}
}
// 取消订阅方法
unsubscribe(event, callback) {
if (this.subscribers[event]) {
const index = this.subscribers[event].indexOf(callback);
if (index > -1) {
this.subscribers[event].splice(index, 1);
}
}
}
// 一次性订阅方法
subscribeOnce(event, callback) {
const wrapper = (data) => {
callback(data);
this.unsubscribe(event, wrapper);
};
this.subscribe(event, wrapper);
}
}
// 使用示例
const pubSub = new PubSub();
// 订阅
const subscription = pubSub.subscribe('myEvent', data => {
console.log(`Received: ${data}`);
});
// 一次性订阅
pubSub.subscribeOnce('myEvent', data => {
console.log(`Received once: ${data}`);
});
// 发布
pubSub.publish('myEvent', 'Hello World!'); // Both subscribers will be notified
pubSub.publish('myEvent', 'Hello again!'); // Only the first subscriber will be notified
// 取消订阅
subscription();