Skip to content

原型相关

原型

每个函数都有 prototype 属性,除了 Function.prototype.bind() 该属性指向原型。

每个对象都有 __proto__ 属性,指向了该对象的构造函数的原型。其实这个属性指向了[[prototype]],但是[[prototype]]是内部属性,我们并不能访问到,所以使用 __proto__来访问

对象可以通过 __proto__ 来寻找不属于该对象的属性,__proto__将对象连接起来组成了原型链

小结

  • Object 是所有对象的爸爸,所有对象都可以通过 proto 找到它
  • Function 是所有函数的爸爸,所有函数都可以通过 proto 找到它
  • Function.prototype 和 Object.prototype 是两个特殊的对象,他们由引擎来创建
  • 除了以上两个特殊对象,其他对象都是通过构造器 new 出来的
  • 函数的 prototype 是一个对象,也就是原型
  • 对象的 proto 指向原型, proto 将对象和原型连接起来组成了原型链

new

  1. 新生成一个对象
  2. 链接到原型
  3. 绑定this
  4. 返回新对象

在调用 new 的过程中发生以上四件事,下面是自己实现的new

js
function myNew() {
  // 创建一个空对象
  let obj = Object.create(null)
  // 获得构造函数
  let con = [].shift.call(arguments)
  // 链接到原型
  obj.__proto__ = con.prototype
  // 绑定this,执行构造函数
  let result = con.apply(obj, arguments)
  // 确保new出来的是个对象
  return typeof result === 'object' ? result : obj
}

对于实例对象来说,都是通过new产生. 对于创建一个对象来说,更推荐使用字面量方式创建(无论是性能还是可读性),因为使用 new Object() 方式创建对象通过作用域链一层层找到Object,但使用字面量方式没这个问题。

instanceof

可正确判断对象的类型,因为内部机制是通过判断对象的原型链中是不是找到类型的prototype


继承

在ES5中,我们可以使用如下方式解决继承问题:

js
function Super() {}
Super.prototype.getNo = function() {return 1}

function Sub() {}
let s = new Sub()
Sub.prototype = Object.create(Super.prototype, {
  constructor: {
    value: Sub,
    enumerable: false,
    writable: true,
    configurable: true
  }
})

以上继承的实现思路就是将子类的原型设置为父类的原型

在ES6中,我们可以通过class语法轻松解决这个问题

js
class MyDate extends Date {
  test() {
    return this.getTime()
  }
}
let myDate = new MyDate()
myDate.test()

共 20 个模块,1301 篇 Markdown 文档。