JS-原型和原型链的面试常考题

224 阅读3分钟

前言

本篇文章是作者在准备春招时,学习JS原型链的感悟。假如您也和我一样,在准备春招。欢迎加我微信shunwuyu ,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!”

1.对原型、原型链的理解

什么是原型

在JavaScript中每一个构造函数都有一个prototype属性,它的属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。 当使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。

ES5 中可以通过Object.getPrototypeOf()来获取对象的原型。

什么是原型链

当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。

原型链的尽头一般来说都是 Object.prototype 所以这就是新建的对象为什么能够使用 toString() 等方法的原因。

2.对原型修改

function Person(name) {
    this.name = name
}

// 修改原型
Person.prototype.getName = function() {}
var p = new Person('hello')

console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true

// 重写原型
Person.prototype = {
    getName: function() {}
}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype)        // true
console.log(p.__proto__ === p.constructor.prototype) // false

可以看到修改原型的时候p的构造函数不是指向Person了,因为直接给Person的原型对象直接用对象赋值时,它的构造函数指向的了根构造函数Object,所以这时候p.constructor === Object ,而不是p.constructor === Person。要想成立,就要用constructor指回来:

Person.prototype = {
    getName: function() {}
}
var p = new Person('hello')
p.constructor = Person
console.log(p.__proto__ === Person.prototype)        // true
console.log(p.__proto__ === p.constructor.prototype) // true

3.原型链指向

p.__proto__  // Person.prototype
Person.prototype.__proto__  // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor  // Person

4.原型链的终点是什么?

由于Object是构造函数,原型链终点是Object.prototype.__proto__

Object.prototype.__proto__=== null // true,所以,原型链的终点是null

原型链上的所有原型都是对象,所有的对象最终都是由Object构造的,而Object.prototype的下一级是Object.prototype.__proto__

5.原型与继承

原型链的机制使得 JavaScript 具有了基于原型的继承方式,这种继承方式相对于传统的基于类的继承更为灵活。通过原型,一个对象可以直接继承另一个对象的属性和方法,而不必事先定义类。

示例:

function Animal() {}
Animal.prototype.eat = function() {
    console.log('Animal is eating');
};

function Dog() {}
Dog.prototype = Object.create(Animal.prototype);

let dog = new Dog();
dog.eat(); // 输出: "Animal is eating"

在这个例子中,Dog 函数通过 Object.create() 方法继承了 Animal.prototype 的属性和方法,实现了 Dog 对象对 Animal 对象的继承。

6.如何获得对象非原型链上的属性?

使用后hasOwnProperty()方法来判断属性是否属于原型链的属性:

function iterate(obj){
   var res=[];
   for(var key in obj){
        if(obj.hasOwnProperty(key))
           res.push(key+': '+obj[key]);
   }
   return res;
}