19.原型链

110 阅读3分钟
function Fn() {
  this.x = 100;
  this.y = 200;
  this.getX = function () {
    console.log(this.x)
  }
}
Fn.prototype.getX = function () {
  console.log(this.x)
}
Fn.prototype.getY = function () {
  console.log(this.y)
}
let f1 = new Fn
let f2 = new Fn
console.log(f1.getX === f2.getX)
console.log(f1.getY === f2.getY)
console.log(f1.__proto__.getY === Fn.__proto__.getY)
console.log(f1.__proto__.getX === f2.getX)
console.log(f1.getX === Fn.__proto__.getX)
console.log(f1.constructor)
console.log(Fn.prototype.__proto__.constructor)
f1.getX()
f1.__proto__.getX()
f2.getY()
Fn.prototype.getY()
/**
 * EC(G)
 * vo
 * 0x000 Fn函数堆内存
 * ”代码字符串“
 * prototype =》
 *  0x001 Fn.prototype (当前类的)原型对象
 *    constructor:Fn(自身)
 *    =》
 *    getX: function...
 *    getY: function...
 *    __proto__
 *    
 * 详解:
 * 原型上的getX和getY
 *  相对于f1/f2两个实例来讲是其公共的属性和方法
 *  
 * 
 * 属性是私有还是公有-》是相对的
 * 
 * 
 *    
 * 
 * 
 * 0x002 let f1 = new Fn
 * 实例对象
 * x = 100
 * y = 200
 * getX:function...
 * 
 * 
 * 0x003 let f2 = new Fn
 * 实例对象
 * x = 100
 * y = 200
 * getX:function...
 */
function Fn() {
  this.x = 100;
  this.y = 200;
  this.getX = function () {
    console.log(this.x)
  }
}
Fn.prototype.getX = function () {
  console.log(this.x)
}
Fn.prototype.getY = function () {
  console.log(this.y)
}
let f1 = new Fn
let f2 = new Fn
console.log(f1.getX === f2.getX) // => false
console.log(f1.getY === f2.getY) // => true
console.log(f1.__proto__.getY === Fn.prototype.getY) // true
console.log(f1.__proto__.getX === f2.getX) // false
console.log(f1.getX === Fn.__proto__.getX) // false
console.log(f1.constructor) // Fn
console.log(Fn.prototype.__proto__.constructor) // Object
f1.getX() // 100
f1.__proto__.getX() // undefined
f2.getY() // 200
Fn.prototype.getY() // undefined

/**
 * JS中面向对象的底层处理机制
 *  =》存储当前类所属实例调用的公用属性和方法
 *  1.每一个(除箭头函数外的)函数数据类型,都天生自带一个属性:prototype原型属性,属性值是一个对象(Function.prototype除外),并且原型对象中自带一个属性:constructor,属性值是当前构造函数
 *    1.普通函数、箭头函数、生成器函数
 *    2.构造函数「一般指自定义类」
 *    3.内置类「内置构造函数」
 *    2&3 prototype 针对类游泳,对于普通函数来讲没啥用
 *    ...
 *  =》 为了找到所属类原型上的公用方法
 *  2.每一个对象数据类型值,都天生自带一个属性:__proto__原型链属性(隐式原型)属性值指向所属类的原型对象prototype
 *    普通对象,数组对象,正则对象、日期对象...
 *    prototype原型对象
 *    实例对象
 *    函数也是对象
 *    ...
 *    * 所有对象都是Object内置类的实例
 */

/**
 * Object 内置类 「函数类型」
 * ”【native code】“
 * ------------------
 * prototype => 0x000
 *
 *
 * 0x000 Object.prototype 原型对象
 * constructor:Object
 * ------------------
 * hasOwnPrpperty
 * isPrototypeof
 * toStringOf
 * ...
 * ----------------------------------------------------------------
 * __proto__: null ***注意:为啥是null,原因:Object.prototype原型对象也是Object对象类的一个实例,__proto__如果要指向,就指向自己了,这样没有意义:所以作为基类原型上的__proto__是null即可!!
 *
 *
 *
 * 成员访问「不论是遍历还是直接访问等」
 *  f1.x -> 首先找自己私有的属性,私有中存在操作的就是私有的,私有的不存在,则默认基于__proto__找所属类prototype上的。如果还没有,则基于prototype上的__proto__继续向上查找...直到找到Object.prototype位置「我们把这个套查找机制,称之为原型链」
 *
 * 「公有属性」
 *    每个实例都可以基于__proto__找到
 *
 * f1.__proto__.getX -> 跳过私有属性的查找,直接找所属类原型上的公有属性和方法「__proto__在Ie中不兼容,浏览器把他起来了,不让用」
 * f1.getX() -> 实例先找到对应的方法「基于原型链」,再把方法执行,如果遇到this,则分析this是谁「函数执行看点前面是谁」
 *    找到的是私有getX,this -> f1
 *      console.log(this.x) -> console.log(f1.x) => 100
 * f1.__proto__.getX()
 *    公共的getX,this -> f1.__proto__
 *    console.log(this.x) => console.log(f1.__proto__.x) => undefined
 * f2.getY()
 *    公共的getY, this->f2
 *    console.log(this,y) => console.log(f2,y) => 200
 *
 * Fn.prototype.getY()
 *    原型上的getY, this -> Fn.prototype
 *    console.log(this,y) => console.log(Fn.prototype,y) =>undefined
 *
 */

/**
 * f1 instanceof 检测某个实例是否属于这个类
 *
 * 我也不知道new谁出来的
 * Fn.prototype  一定 不是Fn的实例
 * 一般只有new Fn出来的才是他的实例
 *
 *
 */