手写实现js类/方法【改变this、map、Object、发布订阅、promise】

目录

改变this

call

typeof this !== 'function'

context = context || window

context._this = this

delete context._this

bind: return _this.apply(context, [...arguments].slice(1));

 Object

Object.create 

Object.freeze 

Object for of

*instance of

map

订阅发布,取消,一次订阅

promise A+、catch、finally、all、allsettled、any、race​​​​​​​

改变this

call

  1. typeof this !== 'function'

  2. context = context || window

  3. context._this = this

  4. 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,核心步骤有:

  1. 创建一个临时函数
  2. 将该临时函数的原型指向对象参数
  3. 返回该临时对象的实例

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:

  1. Object.getOwnPropertyNames/Symbol
  2. forEach
  3. Object.defineProperty:configurable,writable
  4. 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

  1. 获取首个对象参数的原型对象
  2. 获取Fn函数的原型对象
  3. 进入死循环,当两个参数的原型对象相等时返回true
  4. 当两个参数的原型对象不相等时获取首个对象参数原型的原型并且循环该步骤直到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();

promise A+、catch、finally、all、allsettled、any、race

猜你喜欢

转载自blog.csdn.net/qq_28838891/article/details/134399610