什么是原型?

image.png
遍历对象属性,一般是不会显示这个属性的

并不是说它就是 prototype 这个名字,早期ECMA标准里面是没有规范如何查看这个属性,因此某些浏览器为了方便开发,在浏览器内部给对象都添加了一个属性:proto
image.png image.png image.png

由于是浏览器添加的,因此可能会有的浏览器的对象有这个属性:proto,有的浏览器没有。因此为了适配各个浏览器,不建议直接使用这个属性,实际上开发也用的少。

有什么用?

image.png

简单地说,就是通过一个函数创建出来的实例,都有一个祖先,并继承这个祖先的属性,且这些祖先的属性是多个实例共享的

  1. let Person = function() {};
  2. // 或
  3. function Person() {}
  4. // 给函数的原型设置对象属性
  5. Person.prototype.name = "Nicholas";
  6. Person.prototype.age = 29;
  7. Person.prototype.job = "Software Engineer";
  8. Person.prototype.sayName = function() {
  9. console.log(this.name);
  10. };
  11. // 实例化
  12. let person1 = new Person();
  13. person1.sayName(); // "Nicholas" ,这里先检查person1是否有自己的属性,有就使用;没有就访问它的原型里面找
  14. let person2 = new Person();
  15. person2.sayName(); // "Nicholas" ,这里先检查person1是否有自己的属性,有就使用;没有就访问它的原型里面找
  16. // 相同是因为都是同一个原型,可以理解为都是一个祖先传下来的基因
  17. console.log(person1.sayName == person2.sayName); // true

内存表现:
image.png

通过这样的设计,可以把一些通用的属性一级一级继承下去。
就比如 toString() 方法,这个方法是Object对象原型上的方法,因此只要是对象,都可以直接用这个方法

因此,可以给这个原型添加一些公共的属性和方法,让它的后代都能共享这些属性和方法。
但不建议在开发中这样操作,可能会导致某个后代修改了公共的这些属性,导致其他后代出现不可预料的问题。

image.png(大家都有公共的方法eating 和 running)
切记这里用到了this,因此不能用箭头函数

================

函数也有原型 prototype

函数都有一个属性:prototype,默认是个空对象 { },这个属性只有函数有,对象是没有的。
image.png
查看一下这个属性的特性,如下,有个constructor(构造器的意思)的属性,值是函数自己(循环引用自己),可以写入,不可以遍历,可以修改和删除
image.png

当这个函数被new 后,创建的对象的原型属性 proto,就是这个函数的 prototype 属性
image.pngtrue

这种被new的函数,就叫构造函数。是用来构造对象的函数

修改原型

直接把原型属性,指向另一个对象就可以了
image.png

但是这里有个问题,这个新的对象没有constructor这个属性

  1. let f1 = new foo()
  2. console.log(f1) // {}

此时加一个属性即可

  1. function foo(){}
  2. foo.prototype = {
  3. constructorfoo
  4. }
  5. // 但最好通过Object.defineProperty 的方式添加
  6. Object.defineProperty(foo.prototype,"constructor",{
  7. value: foo,
  8. configurable:true,
  9. Enumerable:false, // 不可遍历
  10. Writable:true
  11. })

================

原型链

原型链,就是原型像链条一样连起来引用。当访问对象属性,如果当前这个对象没有这个属性,就会沿着这个链条上的对象,一个一个去找。

如下图,打印 obj.address,本身它自己没有这个属性,因此会默认向它的原型对象里面查找;
它的原型对象没有,就往它的原型对象的原型对象查找;
最终找到顶层,如果还没有,就报undefined,找到就返回;
image.png
(上图的 proto 属性,是浏览器为了方便开发添加的,不同浏览器可能实现方法不同,比如可能某些浏览器压根没有这个,因此不建议这样使用)

原型链的顶层对象

image.png
NodeJS 最顶层的原型
image.png

谷歌浏览器最顶层的原型
image.png

这个操作相当于,把内置对象Object的原型,赋值给了所有字面量对象的 proto 属性,也就是最顶层的

  1. var obj = {}
  2. // 相当于 var obj = new Object()
  3. // 然后有 obj.__proto__ = Object.prototype;

image.png true

里面有什么

这个对象看上去是空的,为什么?实际上里面有很多内置的方法,但是都是设置了不可遍历的,所以才看不见

那要怎么查看?可以通过如下方法
image.png
image.png
里面有包括toString方法、valueOf方法等等
image.png

Object是所有类的父类

image.png

================