js常考的面试题重新整理

// call

Function.prototype.mycall = function(context) {
  // 1. 将传递给mycall的第一个参数作为函数内部的上下文,如果没有传递参数,则默认为全局对象window。
  context = context || window;

  // 2. 在传递的上下文对象中创建一个临时属性fn,并将当前函数(即调用mycall的函数)赋值给这个属性。
  content.fn = this;

  // 3. 通过将剩余的参数(除了第一个参数context之外)转换为数组,然后使用展开运算符(...)调用函数。
  let arg = [...arguments].slice(1);
  let result = content.fn(...arg);

  // 4. 删除临时属性fn,以避免污染传递的上下文对象。
  delete content.fn;

  // 5. 返回函数执行的结果。
  return result;
}

  

这段代码的主要作用是将一个函数作为方法调用,同时自定义了函数内部的this上下文。具体步骤如下:

  1. 首先,通过context参数来指定要设置为函数内部this的上下文。如果没有传递context参数,它将默认为全局对象window

  2. 在传递的上下文对象(context)中创建了一个临时属性fn,并将当前调用mycall方法的函数(即调用mycall的函数)赋值给这个属性。这样可以在上下文中调用函数,而且函数内部的this将会指向上下文对象。

  3. 通过将剩余的参数(除了第一个参数context之外)转换为数组,然后使用展开运算符...调用函数。这些参数将作为函数的参数传递给函数。

  4. 执行函数后,删除临时属性fn,以避免污染传递的上下文对象。

  5. 最后,返回函数执行的结果。

这样,使用mycall方法可以实现自定义的call功能,允许您调用函数并指定函数内部的this上下文,同时传递参数。例如:

function greet(message) {
  console.log(message + ", " + this.name);
}

const person = { name: "Alice" };

greet.mycall(person, "Hello"); // 输出 "Hello, Alice"

  实现apply

Function.prototype.myapply = function(content) {
  // 1. 将传递给myapply的第一个参数作为函数内部的上下文,如果没有传递参数,则默认为全局对象window。
  content = content || window;

  // 2. 在传递的上下文对象中创建一个临时属性fn,并将当前函数(即调用myapply的函数)赋值给这个属性。
  content.fn = this;

  // 3. 使用arguments[1]来获取传递给myapply的第二个参数,它应该是一个数组或类似数组的对象,其中包含要传递给函数的参数。
  let result;
  if (arguments[1]) {
    result = content.fn(...arguments[1]);
  } else {
    result = content.fn();
  }

  // 4. 删除临时属性fn,以避免污染传递的上下文对象。
  delete content.fn;

  // 5. 返回函数执行的结果。
  return result;
}

  

这段代码的主要作用是允许您调用函数,并指定函数内部的this上下文,同时传递一个参数数组。

具体步骤如下:

  1. 首先,将传递给myapply的第一个参数作为函数内部的上下文。如果没有传递参数,将默认使用全局对象window作为上下文。

  2. 在传递的上下文对象(content)中创建了一个临时属性fn,并将当前调用myapply方法的函数(即调用myapply的函数)赋值给这个属性。这样可以在上下文中调用函数,而且函数内部的this将会指向上下文对象。

  3. 使用arguments[1]来获取传递给myapply的第二个参数,它应该是一个数组或类似数组的对象,其中包含要传递给函数的参数。如果存在第二个参数,就使用展开运算符(...)来将参数数组传递给函数;否则,直接调用函数。

  4. 执行函数后,删除临时属性fn,以避免污染传递的上下文对象。

  5. 最后,返回函数执行的结果。

这样,使用myapply方法可以模拟apply方法的行为,允许您在调用函数时指定上下文并传递参数数组。例如:

function greet(message) {
  console.log(message + ", " + this.name);
}

const person = { name: "Alice" };

greet.myapply(person, ["Hello"]); // 输出 "Hello, Alice"

//bind

Function.prototype.mybind = function(content) {
  // 1. 首先,检查当前函数是否为一个函数。
  if (typeof this !== 'function') {
    throw new Error('not a function');
  }

  // 2. 保存当前函数的引用,以备后续使用。
  let _this = this;

  // 3. 提取除了第一个参数(content)之外的其他参数,这些参数将会在新函数被调用时传递给原函数。
  let arg = [...arguments].slice(1);

  // 4. 返回一个新函数F,它可以根据如下规则调用原函数:
  return function F() {
    // 5. 如果新函数F通过构造函数方式调用(即使用new关键字),则会将原函数当作构造函数来调用,创建一个新对象并返回。
    if (this instanceof F) {
      return new _this(...arg, ...arguments);
    }
    // 6. 如果新函数F通过普通函数调用(即不使用new关键字),则将原函数作为方法调用,并传递上下文和参数。
    return _this.apply(content, arg.concat(...arguments));
  }
}

这段代码的主要作用是创建一个新函数,该新函数在调用时会根据上下文对象(content)来调用原函数(this)。具体步骤如下:

  1. 首先,检查当前函数是否为一个函数。如果不是函数,则抛出一个错误。

  2. 保存当前函数的引用,以备后续使用,因为在返回的新函数中需要使用原函数。

  3. 提取除了第一个参数(content)之外的其他参数,这些参数将会在新函数被调用时传递给原函数。

  4. 返回一个新的函数F,它可以根据如下规则调用原函数:

    • 如果新函数F通过构造函数方式调用(即使用new关键字),则会将原函数当作构造函数来调用,创建一个新对象并返回。这样可以确保this关键字在原函数内部指向新对象。

    • 如果新函数F通过普通函数调用(即不使用new关键字),则将原函数作为方法调用,并传递上下文对象(content)和参数。这里使用apply方法来调用原函数。

通过这种方式,mybind方法创建了一个新函数,该新函数具有永久性的上下文绑定,并且可以在需要时传递参数。例如:

 
function greet(message) {
  console.log(message + ", " + this.name);
}

const person = { name: "Alice" };

const boundGreet = greet.mybind(person, "Hello");
boundGreet(); // 输出 "Hello, Alice"

// new

function myNew() {
  // 1. 创建一个空对象obj。
  let obj = {};

  // 2. 从参数中取出第一个参数(通常是构造函数),并将其赋值给Constructor变量。
  let Constructor = [].shift.call(arguments);

  // 3. 将obj的原型对象(__proto__属性)设置为构造函数的prototype属性,以建立原型链。
  obj.__proto__ = Constructor.prototype;

  // 4. 使用apply方法调用构造函数,并将obj作为this关键字绑定到构造函数内部。
  let result = Constructor.apply(obj, arguments);

  // 5. 返回根据构造函数执行的结果决定的对象。如果构造函数显式返回一个对象,则返回该对象,否则返回创建的obj对象。
  return typeof result === 'object' ? result : obj;
}

这段代码的主要作用是模拟new操作符的行为,它接受任意数量的参数,并执行以下步骤:

  1. 创建一个空对象 obj,它将成为构造函数的实例。

  2. 使用 [].shift.call(arguments) 从传递给 myNew 的参数中获取第一个参数,这通常应该是一个构造函数。这将在后续步骤中用于创建对象实例。

  3. obj 的原型对象 (__proto__ 属性) 设置为构造函数的 prototype 属性,以建立原型链。这是为了确保新创建的对象可以继承构造函数原型上的属性和方法。

  4. 使用 Constructor.apply(obj, arguments) 调用构造函数,将 obj 作为 this 关键字绑定到构造函数内部,同时传递剩余的参数给构造函数。这样构造函数内部的代码可以对 obj 进行初始化操作。

  5. 最后,根据构造函数的执行结果,决定返回的对象。如果构造函数显式返回一个对象,那么就返回该对象;否则,返回创建的 obj 对象。

这样,myNew 函数模拟了 new 操作符的行为,可以用来创建对象实例,就像使用 new 一样。例如:

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

const person = myNew(Person, "Alice", 30);
console.log(person.name); // 输出 "Alice"
console.log(person.age);  // 输出 30

 

posted @ 2023-09-11 18:04  科比net  阅读(9)  评论(0编辑  收藏  举报