自学内容网 自学内容网

前端面试宝典【Javascript篇】【4】

在这里插入图片描述

欢迎来到《前端面试宝典》,这里是你通往互联网大厂的专属通道,专为渴望在前端领域大放异彩的你量身定制。通过本专栏的学习,无论是一线大厂还是初创企业的面试,都能自信满满地展现你的实力。

核心特色:

  • 独家实战案例:每一期专栏都将深入剖析真实的前端面试案例,从基础知识到前沿技术,从算法挑战到框架运用,让你在实战中迅速成长。
  • 深度技术解析:不再只是表面文章,我们将带你深入技术的核心,理解每一个知识点背后的原理与- - 应用场景,让你在面试中不仅知其然,更知其所以然。
  • 高质量内容保证:每一期内容都经过精心策划与打磨,确保信息的准确性和实用性,拒绝泛泛而谈,只提供真正有价值的内容。
  • 持续更新迭代:持续关注前端领域的最新动态,及时更新专栏内容,确保你始终站在技术的最前沿。

10. 介绍一下JavaScript中的原型链

JavaScript中的原型链是实现继承和属性查找机制的基础。在JavaScript中,每个对象都有一个原型对象,这个原型对象可以是另一个对象的实例或者是Object.prototype。原型链就是一系列的原型对象,它们通过Object.getPrototypeOf(obj)获取obj这个对象的原型对象,同样的方法获取原型对象的原型对象,形成一个链式结构。

原型对象

每个函数在创建时都会自动获得一个prototype属性,这是一个对象,用于初始化由该构造函数创建的对象的原型。当我们使用构造函数创建新对象时,新对象的原型对象将指向构造函数的prototype对象。

原型链工作原理

当试图访问一个对象的属性或方法时,如果该对象自身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到该属性或方法为止。如果在原型链的末端(通常是Object.prototype)都没有找到,那么查找失败,返回undefined。

示例:

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

Person.prototype.greet = function() {
    console.log("Hello, my name is " + this.name);
};

const john = new Person("John");

john.greet(); // 输出: Hello, my name is John

console.log(john.hasOwnProperty('greet')); // 输出: false
console.log(Object.getPrototypeOf(john).hasOwnProperty('greet')); // 输出: true

在这个例子中,john对象没有自身的greet方法,但是Object.getPrototypeOf(john)指向了Person.prototype,而Person.prototype有greet方法,因此john.greet()可以正常工作。

原型链的顶端

原型链的最顶端是Object.prototype,它是所有对象的原型。Object.prototype也有一个原型对象(即Object.getPrototypeOf(Object.prototype)),但它指向null,表示原型链的终点。

原型链与继承

原型链还用于实现继承。当一个对象没有某个属性或方法时,它会沿着原型链查找,如果在某个原型对象中找到了,那么就可以使用这个属性或方法,这就是继承的实现方式。

总结

原型链是JavaScript中对象属性查找和继承的基础,了解它是理解和编写复杂JavaScript代码的关键。通过原型链,JavaScript实现了动态的属性查找和灵活的继承机制。

原型链是js的核心内容,理解其原理非常重要,因为篇幅问题介绍的没那么详细,想了解更多的朋友可以查看MDN官方文档,介绍的非常详全面

11. ES5有几种方式可以实现继承?分别有哪些优缺点?

在ES5中,实现继承主要有六种方式,它们分别是:

  1. 原型链继承
  • 实现方式:通过将子类的prototype属性设置为父类的一个实例,来实现继承。
  • 优点:
    • 简单易懂,实现容易。
    • 子类可以复用父类的所有方法。
  • 缺点:
    • 每个子类实例会共享父类的引用类型属性。
    • 创建子类实例时,不能向父类构造函数传递参数。
    • 父类的构造函数会被调用多次,一次是在创建父类实例时,另一次是在创建子类实例时。
function Parent() {
    this.name = 'parent';
}

Parent.prototype.getName = function() {
    return this.name;
};

function Child() {}

// 继承
Child.prototype = new Parent();

var child = new Child();
console.log(child.getName()); // "parent"

  1. 构造函数继承
  • 实现方式:在子类构造函数中调用父类构造函数,并使用apply或call方法改变this指向。
  • 优点:
    • 可以为子类实例添加独立的属性。
    • 可以在创建子类实例时向父类构造函数传递参数。
  • 缺点:
    • 无法实现函数复用,每个子类实例都会拥有父类方法的副本。
    • 父类中定义的方法不会被子类继承。
function Parent() {
    this.name = 'parent';
}

function Child() {
    Parent.call(this); // 调用父类构造函数
}

var child = new Child();
console.log(child.name); // "parent"

  1. 组合继承(经典继承)
  • 实现方式:结合原型链继承和构造函数继承的优点,既能在子类实例中复用父类的方法,也能为子类实例添加独立的属性。
  • 优点:
    • 解决了原型链继承和构造函数继承的缺点。
  • 缺点:
    • 父类的构造函数会被调用两次,一次在原型链继承中,另一次在构造函数继承中。
function Parent() {
    this.name = 'parent';
}

function Child() {
    Parent.call(this); // 调用父类构造函数
}

var child = new Child();
console.log(child.name); // "parent"

  1. 寄生继承
  • 实现方式:创建一个仅用于继承其他对象的函数,然后将这个函数的返回值赋给新的对象。
  • 优点:
    • 可以增强对象,同时不会影响到原型链。
  • 缺点:
    • 相比其他方式较为复杂,使用较少。
function createObj(o) {
    var F = function() {};
    F.prototype = o;
    return new F();
}

function Parent() {
    this.name = 'parent';
}

function Child() {
    this.name = createObj(new Parent()).name;
}

var child = new Child();
console.log(child.name); // "parent"

  1. 寄生组合继承
  • 实现方式:组合继承的优化版本,通过借用构造函数和原型链,避免了父类构造函数被调用两次的问题。
  • 优点:
    • 避免了组合继承的缺点,只调用一次父类构造函数。
  • 缺点:
    • 实现稍微复杂一些。
function inheritPrototype(subType, superType) {
    var prototype = createObj(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

function Parent() {
    this.name = 'parent';
}

Parent.prototype.getName = function() {
    return this.name;
};

function Child() {
    Parent.call(this);
}

inheritPrototype(Child, Parent);

var child = new Child();
console.log(child.getName()); // "parent"

  1. 使用Object.create()
  • 实现方式:使用Object.create()方法指定原型对象,创建一个新的对象。
  • 优点:
    • 更加规范和清晰,避免了原型链的污染。
  • 缺点:
    • 不能向父类构造函数传递参数。
function Parent() {
    this.name = 'parent';
}

Parent.prototype.getName = function() {
    return this.name;
};

function Child() {
    this.name = 'child';
}

// 继承
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

var child = new Child();
console.log(child.getName()); // "parent"


原文地址:https://blog.csdn.net/BDawn/article/details/140671008

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!