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
上下文。具体步骤如下:
-
首先,通过
context
参数来指定要设置为函数内部this
的上下文。如果没有传递context
参数,它将默认为全局对象window
。 -
在传递的上下文对象(
context
)中创建了一个临时属性fn
,并将当前调用mycall
方法的函数(即调用mycall
的函数)赋值给这个属性。这样可以在上下文中调用函数,而且函数内部的this
将会指向上下文对象。 -
通过将剩余的参数(除了第一个参数
context
之外)转换为数组,然后使用展开运算符...
调用函数。这些参数将作为函数的参数传递给函数。 -
执行函数后,删除临时属性
fn
,以避免污染传递的上下文对象。 -
最后,返回函数执行的结果。
这样,使用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
上下文,同时传递一个参数数组。
具体步骤如下:
-
首先,将传递给
myapply
的第一个参数作为函数内部的上下文。如果没有传递参数,将默认使用全局对象window
作为上下文。 -
在传递的上下文对象(
content
)中创建了一个临时属性fn
,并将当前调用myapply
方法的函数(即调用myapply
的函数)赋值给这个属性。这样可以在上下文中调用函数,而且函数内部的this
将会指向上下文对象。 -
使用
arguments[1]
来获取传递给myapply
的第二个参数,它应该是一个数组或类似数组的对象,其中包含要传递给函数的参数。如果存在第二个参数,就使用展开运算符(...
)来将参数数组传递给函数;否则,直接调用函数。 -
执行函数后,删除临时属性
fn
,以避免污染传递的上下文对象。 -
最后,返回函数执行的结果。
这样,使用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
)。具体步骤如下:
-
首先,检查当前函数是否为一个函数。如果不是函数,则抛出一个错误。
-
保存当前函数的引用,以备后续使用,因为在返回的新函数中需要使用原函数。
-
提取除了第一个参数(
content
)之外的其他参数,这些参数将会在新函数被调用时传递给原函数。 -
返回一个新的函数
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
操作符的行为,它接受任意数量的参数,并执行以下步骤:
-
创建一个空对象
obj
,它将成为构造函数的实例。 -
使用
[].shift.call(arguments)
从传递给myNew
的参数中获取第一个参数,这通常应该是一个构造函数。这将在后续步骤中用于创建对象实例。 -
将
obj
的原型对象 (__proto__
属性) 设置为构造函数的prototype
属性,以建立原型链。这是为了确保新创建的对象可以继承构造函数原型上的属性和方法。 -
使用
Constructor.apply(obj, arguments)
调用构造函数,将obj
作为this
关键字绑定到构造函数内部,同时传递剩余的参数给构造函数。这样构造函数内部的代码可以对obj
进行初始化操作。 -
最后,根据构造函数的执行结果,决定返回的对象。如果构造函数显式返回一个对象,那么就返回该对象;否则,返回创建的
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