原型链是 JavaScript 中的一个重要概念,面试中经常会被问到。以下是一些常见的面试题:
-
解释什么是原型链? 这个问题是为了测试你是否理解原型链的基本概念。你可以解释原型链是 JavaScript 实现对象间继承的主要机制,每个对象都有一个指向其原型(即创建该对象的构造函数的 prototype 属性)的内部链接。
详解:原型链是 JavaScript 中实现对象间继承的主要机制。每个对象都有一个指向其原型(即创建该对象的构造函数的 prototype 属性)的内部链接,这个链接被称为 [[Prototype]]
。原型对象也可能有自己的原型,形成了一个原型链。当试图访问一个对象的属性时,如果对象自身没有这个属性,那么 JavaScript 会沿着原型链去查找。如果沿着原型链都找不到这个属性,那么返回 undefined
。
function Person() {}
Person.prototype.sayHello = function() {
return 'Hello, World!';
}
let person1 = new Person();
console.log(person1.sayHello()); // 输出 "Hello, World!"
在这个例子中,person1
对象没有 sayHello
方法,但是它的原型 Person.prototype
有这个方法,所以 person1.sayHello()
可以正确地执行。
2.如何通过原型链实现继承? 这个问题是为了测试你是否知道如何使用原型链来实现继承。你可以解释使用构造函数和 prototype 属性来实现继承,或者使用 Object.create 方法。
在 JavaScript 中,我们可以通过原型链来实现继承。每个对象都有一个 [[Prototype]]
属性,这个属性链接到它的原型对象。当我们试图访问一个对象的属性时,如果对象自身没有这个属性,那么 JavaScript 会沿着原型链去查找。
为了通过原型链实现继承,我们可以将子类的原型设置为父类的实例。这样,子类的实例就可以访问父类原型上的属性和方法。同时,我们还需要在子类的构造函数中调用父类的构造函数,以继承父类的实例属性。
function Parent() {
this.name = 'parent';
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child() {
Parent.call(this);
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
let child = new Child();
child.sayName(); // 输出 "parent"
在这个例子中,Child
通过 Parent.call(this)
继承了 Parent
的实例属性,通过 Child.prototype = new Parent()
继承了 Parent
的原型方法。这就是如何通过原型链实现继承。
需要注意的是,这只是一种基本的实现方式,实际上还有很多其他的方式可以实现继承,例如使用 Object.create
方法等。
3.原型链查找属性或方法时,如果找不到会发生什么? 这个问题是为了测试你是否理解原型链的工作原理。你可以解释,当试图访问一个对象的属性或方法时,如果对象自身没有这个属性或方法,那么 JavaScript 会沿着原型链去查找。如果沿着原型链都找不到这个属性或方法,那么返回 undefined。
4.什么是原型污染? 这个问题是为了测试你是否理解原型链的一些潜在问题。你可以解释,原型污染是指通过修改原型添加或修改属性或方法,导致所有继承自该原型的对象都被改变。
原型污染,也被称为原型污染攻击或原型覆盖,是一种 JavaScript 的安全漏洞。它发生在当恶意代码通过修改原型添加或修改属性或方法,导致所有继承自该原型的对象都被改变。
Object.prototype.foo = "bar";
这段代码添加了一个新的属性 foo
到 Object.prototype
。由于几乎所有的 JavaScript 对象都是从 Object.prototype
继承的,这意味着几乎所有的对象现在都有了这个新的 foo
属性。这就是原型污染。
原型污染可能会导致各种问题,包括数据泄露、应用崩溃或其他未预期的行为。因此,我们应该避免修改内置对象的原型,除非我们完全理解可能的后果。
5.解释 __proto__
和 prototype
的区别? 这个问题是为了测试你是否理解这两个属性的区别。你可以解释,__proto__
是每个实例对象(Object)都具有的属性,指向它的构造函数的原型对象(prototype)。prototype
是构造函数的属性,指向实例对象的原型对象。
__proto__
和 prototype
是 JavaScript 中的两个属性,它们都与原型链和继承有关,但是它们的用途和含义是不同的。
-
__proto__
:这是每个对象都有的一个属性,它指向了创建该对象的构造函数的原型。也就是说,obj.__proto__
就是创建obj
对象的构造函数的prototype
。这个属性是 JavaScript 的内部机制,虽然在很多浏览器中可以直接访问,但在 ES6 之前并不是标准的一部分。在 ES6 中,__proto__
被包含在了语言规范中,主要是为了保持向后兼容。 -
prototype
:这是函数才有的一个属性。当一个函数被用作构造函数来创建实例时,这个函数的prototype
就会成为实例对象的原型。也就是说,如果我们有let obj = new SomeConstructor()
,那么SomeConstructor.prototype
就是obj
的原型。
总的来说,__proto__
是对象的属性,指向了对象的原型,而 prototype
是函数的属性,当函数被用作构造函数创建实例时,函数的 prototype
就会成为实例的原型。