2022年元旦,我终于搞懂了原型和原型链

3,484 阅读3分钟

前言

如果你对原型和原型链的了解还停留在一个很浅的、模棱两可的阶段,不妨来看看我的这篇文章,它应该能对你能有所帮助,如果对你有那么一丢丢帮助的话,欢迎点赞评论加转发。有问题和疑惑的话也可以在评论区留言,我会第一时间回复大家,如果觉得我的文章哪里有知识点错误的话,也恳请能够告知,把错的东西理解成对的,对我们这个行业来说,是致命的。

之前虽然也经常刷原型方面的面试题,但是总是停留在一个很浅的、对知识点模棱两可的阶段,而且经常忘记(这点相信大伙也是这样,哈哈哈),趁着元旦假期的最后一天(终于摸起了键盘),跟着b站一个视频过了下相关方面的知识,对此终于有了一个整体的理解。这里对其进行了一个整理和归纳。

呜呜呜,本猿在这里立誓,未来一周,不管多忙,都需要回顾一遍本文,
否则
否则
掘金永远抽bug 😣😣😣。

先知道对应关系

  1. js中,对象分为普通对象函数对象
  2. 每个对象都有__proto__属性,它的值是一个对象,保存着对象构造函数的prototype
  3. prototype是函数对象(箭头函数么有)的一个属性,保存着函数的构造函数constructor2023.05.11注:Array.prototype是个数组
  4. 所有函数对象的__proto__都指向Function.prototype,包括Function()本身
  5. Function.prototype位于所有函数的原型链上,所有的函数既是Function的实例又是Object的实例,Function.prototype是个函数对象;
  6. Function.prototype.__proto__指向Object.prototype

The Function prototype object is specified to be a function object to ensure compatibility with ECMAScript code that was created prior to the ECMAScript 2015 specification. 大家经常忽略忘记的一点:Object是个方法(构造函数),new Object是个实例对象!!!

console.log(Object) //typeof Object ==='function'
console.log(new Object) //typeof new Object ==='object'

这是基础数据,先执行。

function Test() {}
let test=new Test() //new完之后 test是个实例对象了

constructor

constructor就是实例化对象的构造函数,constructor允许被更改,所以通过constructor判断数据类型,是一种不安全的做法。

//test.constructor -> 实例化test对象的构造函数 Test
console.log(test.__proto__.constructor===Test) //true

console.log(test.constructor.prototype.constructor===Test) //true
console.log(test.constructor.prototype.constructor.prototype.constructor===Test) //true

function Test2() {
    this.name='pig'
}
test.constructor=Test2
console.log(test) //Test {name: 1, constructor: ƒ Test2()}

原型

Test.prototype也是一个对象,所以它也有__proto__

Test.prototype.__proto__ // {constructor: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}

对象的__proto__保存着对象构造函数的prototype

test.__proto__===Test.prototype  //true
Test.prototype.__proto__===Object.prototype //true  

能不能描述一下原型链

对象的__proto__保存着对象的构造函数的prototypeprototype又是个对象,所以也有自己的__proto__,这样一直走到终点Object.__proto__,这样就形成了一根链条, 即为原型链。

test{
      __proto__:Test.prototype={
          __proto__:Object.prototype={
              __proto__:null
          }
      }
 }

原型链的终点

test.__proto__===Test.prototype
test.__proto__.__proto__.__proto__=null

特殊的函数对象

javaScript中,万物皆是对象,底层引擎规定Function.prototype.__proto__指向Object.prototype , 所以所有的函数既是Function的实例又是Object的实例,并分别从这两个内置对象继承了很多属性和方法。

// 所有函数对象的__proto__都指向Function.prototype,包括Function()本身,
// Function.prototype处于所有函数的原型链上。
Test.__proto__===Function.prototype  //true
Function.__proto__===Function.prototype //true
String.__proto__===Function.prototype //true

//Function.prototype又通过__proto__指向Object.prototype,所以会有
Function.prototype.__proto__===Object.prototype //true 最终还是指向了Object

//所有的函数既是`Function`的实例又是`Object`的实例
Test.prototype.__proto__===Object.prototype //true

这里可以证明Function的原型链最后走到了Object.prototype
Object.prototype.exp=1
Function.exp //1  Function

关系比较乱,发现有些无厘头的设定,一开始可能看不懂,先从左侧new Foo()开始看

image.png

hasOwnProperty和in

hasOwnProperty

hasOwnProperty用来判断是否是对象自身的属性(非原型链继承过来的)

let test={
    a:1,
    b:2
}
Object.prototype.c=3
console.log(test.hasOwnProperty('a')) //true
console.log(test.hasOwnProperty('b')) //true
console.log(test.hasOwnProperty('c')) //false

in

in用来检查对象是是否包含某个属性(包含原型链上的属性)

console.log('a' in test) //true
console.log('b' in test) //true
console.log('c' in test) //true
console.log('toString' in test) //true
console.log('d' in test) //false

引用

快速搞懂『原型、原型链』
Function.prototype是什么?
MDN
首发于istao