首页 > 其他分享 >原型与原型链与 new 的模拟实现

原型与原型链与 new 的模拟实现

时间:2022-10-01 17:00:30浏览次数:45  
标签:arr name gender 原型 new prototype 模拟

1. 原型与原型链

1.1 什么是原型

对于任意一个引用类型, 都存在一个属性 [[Prototype]], 这就是我们所说的原型
而对于一个 function, 在存在一个 [[Prototype]] 的基础上, 其还会存在一个 prototype 属性, 这个属性是做什么的呢?

function fn(name, gender) {
  this.name = name
  this.gender = gender
}

let obj = new fn("altria", "female")
console.log(Object.getPrototypeOf(obj) === fn.prototype) //=> true
// obj 的 [[Prototype]] === fn.prototype

由上面的代码, 我们可以发现一个规律: new 构造函数 Fn 所获得的对象 obj, 有 obj 的原型等于 Fn.prototype.
至此, 我们可以说: 一个实例对象的原型和相应构造函数的 prototype 是同一个对象

1.2 什么是原型链

let arr = [1, 2]
arr.push(3)
Array.prototype.val = 233
Object.prototype.v = 55555
console.log(arr) //=> [1, 2, 3]
/*(3) [1, 2, 3]
* 0: 1
* 1: 2
* 2: 3
* length: 3
* [[Prototype]]: Array(0)
* */
console.log(arr.val) //=> 233 (arr -> Array.prototype)
console.log(arr.v) //=> 55555 (arr -> Array.prototype -> Object.prototype)
console.log(arr.push === Array.prototype.push) //=> true (arr -> Array.prototype)

由上面的代码, 我们发现: 在 arr 中, 其并没有 push 方法与 val 属性, 反而倒是其原型 [[Prototype]] 上存在一个 push 方法和 val 属性

  • 通过 arr.push 访问到的 push 方法与 Array.prototype.push 完全一样
  • 通过 arr.val 所获取的值与 Array.prototype.val 也是一模一样
  • 通过 arr.v 所获得的值与 Object.prototype.v 也一样

至此, 我们可以说: 当在一个对象 obj 中访问某一属性 x 时, 若 obj 对象身上并没有 x 属性, 则其会到 obj 的原型 [[Prototype]] 上去寻找, 若再没有找到, 则继续到上一级的原型上去找, 直到没有原型为止, 此时就会返回 undefined
这样一系列的原型连接起来, 就被称为原型链

1.3 JS 中的原型关系

2. new 的模拟实现

function new_re(Fn, ...args) {
  let obj = Object.create(Fn.prototype) 
  // 创建一个原型为 Fn.prototype 的对象
  let res = Fn.call(obj, ...args) 
  // 执行构造函数时, 将 this 指向新实例对象
  return (typeof res === "object" && res != null || typeof res === "function") ? res : obj 
  // 若构造函数返回的结果为引用类型, 则 new 出来的结果为该引用类型
  // 若构造函数返回的结果为基础类型, 则 new 出来的结果为 Fn 的实例对象
}

new_re 的测试

function fn(name, gender) {
  this.name = name
  this.gender = gender
}
function f(name, gender) {
  this.name = name
  this.gender = gender
  return function() {}
}

let o1 = new fn("altria", "female")
let o2 = new f("berserker", "male")

let oo1 = new_re(fn, "altria", "female")
let oo2 = new_re(f, "berserker", "male")

console.log(o1) //=> fn {name: 'altria', gender: 'female'}
console.log(oo1) //=> fn {name: 'altria', gender: 'female'}
console.log(o2) //=> ƒ () {}
console.log(oo2) //=> ƒ () {}

标签:arr,name,gender,原型,new,prototype,模拟
From: https://www.cnblogs.com/suzukaze/p/prototype-new.html

相关文章