面试题答案
一键面试call、apply 和 bind 对属性访问、方法调用及原型链关系的影响
- 属性访问:
call
、apply
和bind
主要用于改变函数调用时this
的指向,对属性访问本身并没有直接影响。但改变this
指向后,在函数内部通过this
访问属性时,会根据新的this
指向去查找属性。例如,如果this
被改变为一个具有特定属性的对象,那么对属性的访问就基于这个新对象。
- 方法调用:
call
和apply
方法可以立即调用一个函数,并将函数内部的this
指向指定的对象。它们的区别在于传递参数的方式,call
是逐个传递参数,apply
是传递一个参数数组。bind
方法会创建一个新的函数,新函数内部的this
被绑定到指定的对象,但是不会立即调用函数。当调用这个新函数时,this
始终是绑定的对象。- 对于继承体系,这些方法可以让子类对象调用父类的方法,并将
this
正确地指向子类对象,从而实现方法的复用和扩展。
- 原型链关系:
call
、apply
和bind
不会改变原型链本身。原型链是基于构造函数的prototype
属性建立的,而这三个方法主要操作函数调用时的this
指向。不过,通过正确使用它们来调用父类方法,可以确保在子类对象上按照原型链查找方法和属性。
代码示例
function C() {
this.cProp = 'C property';
this.cMethod = function() {
return 'C method';
};
}
function B() {
this.bProp = 'B property';
this.bMethod = function() {
return 'B method';
};
}
B.prototype = new C();
function A() {
this.aProp = 'A property';
this.aMethod = function() {
return 'A method';
};
}
A.prototype = new B();
// 使用 call 实现特殊继承
A.prototype.callCMethod = function() {
return C.prototype.cMethod.call(this);
};
// 使用 apply 实现特殊继承
A.prototype.applyCMethod = function() {
return C.prototype.cMethod.apply(this);
};
// 使用 bind 实现特殊继承
A.prototype.bindCMethod = function() {
return C.prototype.cMethod.bind(this)();
};
let a = new A();
console.log(a.callCMethod()); // 输出: C method
console.log(a.applyCMethod()); // 输出: C method
console.log(a.bindCMethod()); // 输出: C method
在上述代码中,A
类继承自 B
类,B
类继承自 C
类。通过 call
、apply
和 bind
方法,A
类的实例可以调用 C
类的方法,并将 this
正确地指向 A
类的实例,实现了特殊的继承需求。这种方式在需要复用父类方法但又要确保 this
指向正确对象时非常有用。