谈谈你对原型链的理解?

1,407 阅读4分钟

前言

过了一遍原型链坚持有收获有产出 谈谈你对原型链的理解?面试中如果是前端主管面试90%会问到这个.“橘生淮南则为橘,橘生淮北则为枳”可能在工作中用不到这些但是面试问到了支支吾吾半天崩不出一个字那么就会大大减分了,为了面试才看这些?结果当然是否定的原型模式不仅是一种设计模式,它还是一种编程范式(programming paradigm),是 JavaScript 面向对象系统实现的根基。

什么是原型链?

// Object 的 ___proto___ 的 ___proto___ .... 这条链 就是原型链

image.png

使用原型链的好处是什么?

继承,层层继承 先看下js给我们的例子

 let obj = {};
 console.log(obj.__proto__ === Object.prototype);
 // true
 let arr = [];
 console.log(arr.__proto__ === Array.prototype);
 // true
 let str = "hello world";
 console.log(str.__proto__ === String.prototype);
 // true
 let reg = /[0-9]/g;
 console.log(reg.__proto__ === RegExp.prototype);
 // true
 let bool = true;
 console.log(bool.__proto__ === Boolean.prototype);
  // true
 let bigint = BigInt(99);
 console.log(bigint.__proto__ === BigInt.prototype);
  // true
 let map = new Map();
 console.log(map.__proto__ === Map.prototype);
   // true
   ...
 
 
 // true
 console.log(Boolean.prototype.__proto__ === Object.prototype);
 // true
 console.log(Array.prototype.__proto__ === Object.prototype);
 // true
 console.log(String.prototype.__proto__ === Object.prototype);
 // true
 console.log(RegExp.prototype.__proto__ === Object.prototype);
 // true
 console.log(Boolean.prototype.__proto__ === Object.prototype);
 // true
 console.log(BigInt.prototype.__proto__ === Object.prototype);
 // true
 console.log(new Map().__proto__.__proto__ === Object.prototype);
 // true
 ...

所有的基本类型除了nullundefined,都是由newfunction出来的,以及他们的方法

image.png

注:其中__proto__是浏览器获取原型对象的方法,但是在js中他是不标准的,js提供给我们获取对象的原型方法是Object.getPrototypeOf

等等.. 其中null为空指针原型链的尽头(啥都没有)undefined表示为缺少值,变量定义了未赋值给默认undefined 把原型链的一层看做是父亲在一层就是父亲的父亲那么顶层为nullObject对象延伸出了Boolean,Array,String,RegExp,Boolean,BigInt,他们各自有各自的方法,数组原型方法有map,push,some,every等等,在比如es6中扩展的BigInt,Map,Set都是Object类型的扩展

好处是什么?可继承,易扩展 通过以上代码,数组构造函数的__proto__定义了很多方法,function没new后,是不能直接访问prototype数据和函数里this定义的数据

继承可以用来做什么?

 function animal() {}
      animal.prototype.name = "动物";
      animal.prototype.foot = "4只";
      animal.prototype.hasTail = true
      var dog = new animal();
      console.log(dog.foot);
      // 4只
      var cat = new animal();
      console.log(cat.foot);
      // 4只

猫和狗都属于动物,这时候定义一个animal类,狗,猫它们都语属于等物大类,有4只爪子,有尾巴,即他们可以继承animal类,当然他们也有不同


dog.call = "汪汪汪";
      dog.classification = "犬科";
      console.log(dog.call);
      // 汪汪汪
      console.log(dog.classification);
      // 犬科
      cat.call = "喵喵喵";
      dog.classification = "猫科";
      console.log(cat.call);
      // 喵喵喵
      console.log(dog.classification);
      // 猫科

狗是属于犬科,猫是属于猫科,狗叫声是汪汪汪,猫的叫声是喵喵喵 当然他们也有共同的祖先生物,动物也属于生物,生物的特点是什么? 生长、繁衍、生存 如何继承?动物类继承即可

 // 生物类
      function organism() {
        this.grow = true; // 可以生长
        this.reproduction = true; // 繁衍
        this.existence = true; // 生存
      }
      function animal() {}
      animal.prototype = new organism();
      // constructor构造函数指向animal不会对organism污染
      animal.prototype.constructor = animal;
      animal.prototype.name = "动物";
      animal.prototype.foot = "4只";
      animal.prototype.hasTail = false;
      var dog = new animal();
      var cat = new animal();
      // 是否可以繁衍
      console.log(dog.reproduction);
      // true
    console.dir(new organism());

image.png

如果有一天小黑做了绝育手术,就不能繁衍了,但是他还可以生存生长,还是属于生物类如何处理?

var XH = new animal();
      XH.reproduction = false; // 做了绝育
      console.log(XH.reproduction);
      //  false

image.png 当然生物类还是没有改,只是小黑不能繁衍了,值得查找是按照原型链层层查找本层查到了就不会在往下查找了

易错小tips

 function animal() {
   this.name = "this动物";
 }
 animal.name = "animal动物";
 animal.prototype.name = "prototype动物";
 console.log(animal.name);

打印结果是什么?? 答案:animal,name是函数对象的一个特殊属性,该属性是不可写的即writable = false,所以animal.name就算赋值也是无效的,打印的animal.name始终是function后面的标识符

image.png

 function animal() {}
      animal.price = 1000;
      animal.prototype.price = 20;
      var dog = function () {};
      dog.prototype = new animal();
      var cat = animal;
      var tidy = new dog();
      //    下面两行分别输出什么?
      console.dir(tidy.price);
      console.log(cat.price);

答案: 20 1000

20值解析

tidy的构造函数是dog,dog的prototype是new animal() 执行new操作符会生产对象,将prototype对象挂到__proto__下,换句话说prototype.price被继承了

1000值解析

// 1000
dog.prototype = new animal();

进行了new操作,new函数成为了构造函数,new操作符可以创建对象把对象里面的值赋值给对象,将prototype的值继承也就是说animal.prototype整个对象被继承了所以price 20这个值也被继承了,而animal.price = 1000被放在了constructor里

console.dir(dog.prototype.constructor.price);
// 1000