【整合】实现JavaScript方法

114 阅读2分钟

数组

1. 实现数组的push方法

Array.prototype.customPush = function (...items){

  for (const item of items) {
    this[this.length] = item;
  }

  return this.length;
};

const arr = [1, 2, 3];
arr.customPush(4, 5, 6);
console.log(arr);

2. 实现数组的pop方法

Array.prototype.customPop = function () {
  const len = this.length - 1;
  const popValue = this[len];
  delete this[len];
  this.length = len;

  return popValue;
};

const arr = [1, 2, 3];
arr.customPop();
console.log(arr);

3. 实现数组的filter方法

Array.prototype.customFilter = function (callback, context) {
  if (typeof callback !== "function")
    throw new Error("The first parameter must be a function!");

  const self = this,
    newArr = [];

  self.forEach((item, index, self) => {
    if (context) {
      if (callback.call(context, item, index, self)) newArr.push(item);
    } else {
      if (callback(item, index, self)) newArr.push(item);
    }
  });

  return newArr;
};

const arr = [1, 6, 3, 5, 4];
const newArr = arr.customFilter(function (item) {
  return item <= 3;
});
console.log(newArr);

4. 实现数组的reduce方法

Array.prototype.customReduce = function (fn, initialValue) {
  for (let i = 0; i < this.length; i++) {
    if (typeof initialValue === "undefined") {
      initialValue = fn(this[i], this[i + 1], i + 1, this);
      ++i;
    } else {
      initialValue = fn(initialValue, this[i], i, this);
    }
  }
  return initialValue;
};

const arr = [1, 2, 3, 4];
const newArr = arr.customReduce((res, curr) => {
  return res + curr;
});
console.log(newArr);

函数

1. 实现函数的bind方法

Function.prototype.customBind = function (obj, ...args) {
  if (!isCallable(this)) {
    throw new TypeError(
      "Function.prototype.bind called on incompatible" + this
    );
  }

  let self = this;
  let binder = function (...restArgs) {
    if (typeof new.target !== undefined) {
      let result = self.apply(this, [...args, ...restArgs]);
      if (Object(result) === result) {
        return result;
      }
      return this;
    } else {
      return self.apply(obj, [...args, ...restArgs]);
    }
  };

  return binder;
};

const info = {
  firstName: "charlotte",
  lastName: "lai",
};

const printInfo = function (city, country) {
  this.city = city;
  this.country = country;
  console.log(
    `I am ${this.firstName} ${this.lastName} from ${city} ${country}`
  );
};

let callPrintInfo = printInfo.customBind(info, "xiamen");
let newResult = new callPrintInfo("china");
console.log(newResult);

2. 实现函数的call方法

Function.prototype.customCall = function (context, ...args) {
  context = context ? new Object(context) : globalThis;
  const fnKey = Symbol()
  context[fnKey] = this
  const res = context[fnKey](...args)
  delete context[fnKey]

  return res
};

const info = {
  firstName: "charlotte",
  lastName: "lai",
};

const printInfo = function (city, country) {
  console.log(
    `I am ${this.firstName} ${this.lastName} from ${city} ${country}`
  );
};

printInfo.customCall(info, 'xiamen', 'china');

3. 实现函数的apply方法

Function.prototype.customApply = function (context, arg) {
  context = context ? new Object(context) : globalThis;
  const fnKey = Symbol();
  context[fnKey] = this;
  const res = context[fnKey](...arg);
  delete context[fnKey];

  return res;
};

const info = {
  firstName: "charlotte",
  lastName: "lai",
};

const printInfo = function (city, country) {
  console.log(
    `I am ${this.firstName} ${this.lastName} from ${city} ${country}`
  );
};

printInfo.customApply(info, ["xiamen", "china"]);

操作符

  1. 实现new操作符
function customNew(constructor, ...args) {
  const newObj = new Object();
  newObj.__proto__ = constructor.prototype;

  const res = constructor.call(newObj, ...args);

  return res instanceof Object ? res : newObj;
}

function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person1 = customNew(Person, "lucy", 15);
console.log(person1);

基于发布订阅模式的js事件处理中心

class EventEmitter {
  constructor() {
    this.subscribers = {};
  }

  on(eventName, callback) {
    const callbacks = this.subscribers[eventName] || [];
    callbacks.push(callback);
    this.subscribers[eventName] = callbacks;
  }

  emit(eventName, ...args) {
    const callbacks = this.subscribers[eventName] || [];
    callbacks.forEach((cb) => cb(...args));
  }

  off(eventName, callback) {
    const callbacks = this.subscribers[eventName] || [];
    const filteredCbs = callbacks.filter((cb) => cb !== callback);
    this.subscribers[eventName] = filteredCbs;
  }
  
  once(eventName, callback) {
    const one = (...args) => {
      callback(...args)
      this.off(eventName, one)
    }

    this.on(eventName, one)
  }
}

const subscribers = new EventEmitter();

subscribers.on("message", function (message) {
  console.log(`Message: ${message}`);
});

subscribers.emit("message", "It is going to rain.");

Promise.all()

function myPromiseAll(iterable){
  return new Promise((resolve, reject)=>{
    const promises = Array.from(iterable)
    const result = []
    let count = 0
    for (let i=0; i < promises.length; i++){
      Promise.resolve(promises[i]).then(res => {
        result[i] = res;
        count++;
        if (count === promises.length) {
          resolve(result)
        }
      }).catch(err => reject(err))
    }
  })
}


function asyncOperation(id, delay) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`Operation ${id} completed after ${delay}ms`);
      resolve(id);
    }, delay);
  });
}

const promises = [
  asyncOperation(1, 2000),
  asyncOperation(2, 1000),
  asyncOperation(3, 1500)
];

myPromiseAll(promises).then(results => {
  console.log("All operations completed:", results);
})