以下是关于“JS面试必备之手写call/apply/bind/new”的完整攻略。
手写call和apply
call和apply是JavaScript原生的方法,可以改变函数的this指向。下面是手写实现call和apply的步骤:
call
- 将函数作为对象的一个属性。
- 将函数的this指向当前对象。
- 执行该函数。
- 将对象上的函数删除。
Function.prototype.myCall = function (context = window, ...args) {
let fn = Symbol();
context[fn] = this;
let result = context[fn](...args);
delete context[fn];
return result;
}
apply
- 将函数作为对象的一个属性。
- 将函数的this指向当前对象。
- 执行该函数。
- 将对象上的函数删除。
Function.prototype.myApply = function (context = window, args) {
let fn = Symbol();
context[fn] = this;
let result = context[fn](...args);
delete context[fn];
return result;
}
代码中的context是传入的上下文对象,如果不传入则默认为window。
示例:
let obj = {
name: '小明'
}
function sayHi(age, gender) {
console.log(`我叫${this.name},我今年${age}岁了,我是${gender}。`);
}
sayHi.myCall(obj, 18, '男'); // 我叫小明,我今年18岁了,我是男。
sayHi.myApply(obj, [18, '男']); // 我叫小明,我今年18岁了,我是男。
手写bind
bind方法可以创建一个新的函数,将原函数的this指向指定对象,并返回该新函数。下面是手写实现bind方法的步骤:
- 返回一个新函数。
- 将新函数的this指向传入的对象。
- 将新函数的参数传递给原函数。
- 如果新函数被实例化,需要将原函数的原型链赋值给新函数,以保证原函数的属性和方法可以被继承。
Function.prototype.myBind = function (context = window, ...args) {
let self = this;
return function (...newArgs) {
if (this instanceof self) {
self.apply(this, [...args, ...newArgs]);
} else {
context[self.name] = self;
context[self.name](...args, ...newArgs);
delete context[self.name];
}
}
}
示例:
let obj1 = {
name: '小明',
sayHi(age) {
console.log(`我叫${this.name},我今年${age}岁了。`);
}
}
let obj2 = {
name: '小红'
}
let sayHi = obj1.sayHi.myBind(obj2, 18);
sayHi(); // 我叫小红,我今年18岁了。
let person = new sayHi(); // person.sayHi is not a function
手写new
new操作符主要实现以下几步操作:
- 创建一个新对象。
- 将该新对象的原型链指向构造函数的prototype。
- 将构造函数的this指向该新对象。
- 执行构造函数,获得返回值。
- 如果构造函数返回值为基本类型,则返回新创建的对象,否则返回构造函数的返回值。
function myNew() {
let obj = new Object();
let Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
let result = Constructor.apply(obj, arguments);
return typeof result === 'object' ? result || obj : obj;
}
示例:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log(`我叫${this.name},我今年${this.age}岁了。`);
}
let person1 = myNew(Person, '小明', 18);
let person2 = new Person('小红', 19);
person1.sayHi(); // 我叫小明,我今年18岁了。
person2.sayHi(); // 我叫小红,我今年19岁了。
总结:通过手写call、apply、bind和new的实现,不仅可以帮助我们更好地理解和掌握这些方法的使用,同时也可以在面试中展示我们的js基础知识和编程技能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS面试必备之手写call/apply/bind/new - Python技术站