Skip to content

谈谈你对原型的理解

查看详情

在 JavaScript 中,原型(prototype)是实现对象继承和共享属性的基础机制。通过原型,JavaScript 对象可以继承其他对象的属性和方法,从而实现代码的复用和对象的扩展。

原型链解决的是什么问题?什么是原型链?

查看详情
  • 原型链解决的主要是继承问题
  • 当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象( object )都有一个私有属性(称之为 __proto__ )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象( __proto__ ) ,层层向上直到一个对象的原型对象为 null。

prototype 和__proto__区别是什么?

查看详情
  • prototype 是构造函数的属性
  • __proto__是每个实例都有的属性
  • 实例的__proto__与其构造函数的 prototype 指向的是同一个对象

ES5 继承的方法有哪些?

查看详情
  • 组合继承
javascript
function SuperType(name) {
  this.name = name;
  this.colors = ['red', 'green', 'blue'];
}
SuperType.prototype.sayName = function () {
  console.log(this.name);
};

function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

SubType.prototype.sayAge = function () {
  console.log(this.age);
};

ES5/ES6 的继承的区别

查看详情
  • 写法不同
    • ES5
    • ES6 通过 extends 关键字继承父类
  • ES6 子类可以通过__proto__寻找到父类,而 ES5 函数通过__proto__找到的是Function.prototype
javascript
class Super {}
class Sub extends Super {}
Sub.__proto__ === Super;

function Super() {}
function Sub() {}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
Sub.__proto__ === Function.prototype;
  • this生成的顺序不同
    • ES5 的继承先生成子类的实例,在调用父类的构造函数修饰子类实例
    • ES6 的继承先生成父类实例,再调用子类的构造函数修饰父类的实例,这个差别使得 ES6 可以继承内置对象

ES6 继承的时候父类的哪些东西能否继承

查看详情
  • 实例属性和方法:通过 super() 调用父类构造函数继承。
  • 静态属性和方法:通过 extends 关键字继承。
  • 访问器(getters 和 setters):可以直接继承父类定义的访问器方法。
  • Symbol 属性:子类可以继承父类定义的 Symbol 属性和方法。
  • 父类的构造函数:子类必须调用 super() 来调用父类的构造函数。

谈谈 JS 执行上下文栈和作用域链的理解

查看详情
  • 执行上下文就是 JavaScript 代码被解析和执行时所在环境
    • JavaScript 执行在单线程上,所有的代码都是排队执行,代码运行时创建的所有执行上下文被存储在执行栈(调用栈),遵循后进先出的规则
    • 执行上下文有三种:
      • 全局执行上下文:这是一个基础的上下文,任何不在函数内部的代码都会在全局上下文中。一个程序只有一个全局上下文,浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部,在关闭浏览器的时候出栈
      • 函数执行上下文:当函数被调用的时候,会为函数创建一个新的上下文环境,并且把它压入执行栈的顶部。当函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收机制回收
      • eval 函数执行上下文
  • 作用域链:在使用变量的时候会从当前的作用域开始查找,如果没有找到,就会向上级作用域继续查找,每次上升一个作用域,一直找到全局作用域为止

new 的原理是什么?通过 new 的方式创建对象和通过字面量创建对象有什么区别?

查看详情
  • 原理
    • 创建一个空的简单 JavaScript 对象(即{})
    • 将函数的 prototype 赋值给对象的 __proto__属性
    • 调用函数,并将步骤 1 新创建的对象作为函数的 this 上下文
    • 如果该函数没有返回值或者返回值不是对象,则返回创建的对象,如果返回值是对象,则直接返回该对象。
javascript
function _new() {
  let target = {};
  let [constructor, ...args] = [...arguments];
  target.__proto__ = constructor.prototype;
  let result = constructor.apply(target, args);
  if (result && (typeof result === 'object' || typeof result === 'function')) {
    return result;
  }
  return target;
}
  • 区别
    • 字面量创建对象不会调用 Object 构造函数,简洁且性能更好
    • new Object()方法创建对象本质上是方法调用,涉及到在 proto 联众遍历该方法,当找到该方法后,又会生产方法调用必须的堆栈信息,方法调用结束后,还要释放该堆栈,性能不如字面量的方式。