首页 > 其他分享 >js常考的面试题重新整理

js常考的面试题重新整理

时间:2023-09-11 18:11:59浏览次数:32  
标签:content 面试题 函数 常考 传递 重新整理 参数 上下文 构造函数

// 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

 

标签:content,面试题,函数,常考,传递,重新整理,参数,上下文,构造函数
From: https://www.cnblogs.com/kbnet/p/17694166.html

相关文章

  • Spring面试题
    谈谈SpringIOC的理解,原理与实现?控制反转:理论思想,原来的对象是由使用者来控制,有了Spring之后,可以把整个对象交给Spring来帮我们进行管理。DI:依赖注入,把对应的属性的值注入到具体的对象中。容器:存储对象,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存......
  • 【大厂面试题】如何设计一个秒杀系统?
    学习:https://www.bilibili.com/video/BV1KS4y147Yc/?spm_id_from=333.788.recommend_more_video.-1&vd_source=46d50b5d646b50dcb2a208d3946b1598......
  • Java基础知识面试题系列五:41~50题
    Java基础知识面试题系列三:41~50题41.值传递与引用传递有哪些区别42.不同数据类型的转换有哪些规则43.强制类型转换的注意事项有哪些44.Math类中round、ceil和floor方法的功能是什么45.++i与i++有什么区别46."<<"运算符与">>"运算符有什么异同47.char型变量中是否可以存储一个中文汉......
  • Java基础知识面试题系列三:21~30题
    Java基础知识面试题系列三:21~30题21.抽象类(abstractclass)与接口(interface)有什么异同22.内部类有哪些23.如何获取父类的类名24.this与super有什么区别25.break、continue以及return有什么区别26.final、finally和finalize有什么区别27.JDK中哪些类是不能继承的28.assert有什么......
  • Java基础知识面试题系列四:31~40题
    Java基础知识面试题系列三:31~40题31.static与final结合使用表示什么意思32.使用switch时有哪些注意事项33.volatile有什么作用34.instanceof有什么作用35.strictfp有什么作用36.Java提供了哪些基本数据类型37.在Java语言中null值时什么?在内存中null是什么38.如何理解赋值语句String......
  • Java基础知识面试题系列七:61~70题
    Java基础知识面试题系列七:61~70题61、JavaIO流的实现机制是什么62、管理文件和目录的类是什么63、如何列出某个目录下的所有目录和文件64、JavaSocket是什么65.用Socket实现客户端和服务器端的通信,要求客户发送数据后能够回显相同的数据66.JavaNIO是什么67.什么是Java序列化68.......
  • Java基础知识面试题系列六:51~60题
    Java基础知识面试题系列六:51~60题51."=="、equals和hashCode有什么区别52.String、StringBuffer、StringBuilder和StringTokenizer有什么区别53.Java中数组是不是对象54.数组的初始化方式有哪几种55.length属性与length()方法有什么区别56.异常处理的原理是什么57.运行时异常和普通......
  • Java基础知识面试题系列八:81~90题
    Java基础知识面试题系列七:81~90题81.JavaCollections框架是什么82.什么是迭代器83.Iterator与ListIterator有什么区别84.ArrayList、Vector和LinkedList有什么区别85.ArrayList、Vector和LinkedList容器使用场景选择86.HashMap、Hashtable、TreeMap和WeakHashMap有哪些区别87.Hash......
  • JVM调优篇:探索Java性能优化的必备种子面试题
    JVM内存模型首先面试官会询问你在进行JVM调优之前,是否了解JVM内存模型的基础知识。这是一个重要的入门问题。JVM内存模型主要包括程序计数器、堆、本地方法栈、Java栈和方法区(1.7之后更改为元空间,并直接使用系统内存)。正常堆内存又分为年轻代和老年代。在Java虚拟机中,年轻代用于存......
  • 代码随想录算法训练营第四天| 24. 两两交换链表中的节点, 19.删除链表的倒数第N个结点
    24.两两交换链表中的节点mydemo(超时)/***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode():val(0),next(nullptr){}*ListNode(intx):val(x),next(nullptr){}*ListNode(intx,Lis......