2句话,1道题,1张图:带你捋清楚【原型和原型链】

274 阅读3分钟

0 / 两句话

JS中面向对象的底层处理机制

第一句话

=> 每一个(除了三种特例,以外的函数数据类型,都天生自带一个属性:prototype原型属性,其属性值是:一个对象(Function.prototype除外

=> 这个prototye原型对象中天生自带一个属性:constructor,其属性值是:当前构造函数本身

第二句话

=> 每一个对象数据类型值,都天生自带一个属性:_proto_ 原型链属性(或者叫:隐式原型),其属性值指向:所属类的原型对象prototype 可以找到所属类原型上的公共方法

△ 请大声朗读10遍~

函数数据类型,没有原型属性的特例:

① 箭头函数

let obj = {say(){}}; 这种写法的obj.say()

③ Function.prototype

没有原型属性,不能使用 new 关键字

公众号:朝霞的光影笔记ID:zhaoxiajingjing

△ 图1.1_三个没有原型的函数数据类型,不能使用new关键字

函数数据类型

① 普通函数、箭头函数、生成器函数

② 构造函数(自定义类)

③ 内置类(内置构造函数)

④ ……

prototype 原型对象,针对 类 有用,对于普通函数来说没啥用

对象数据类型

① 普通对象、数组对象、正则对象、日期对象……

② prototype 原型对象

③ 实例对象

④ 函数也是对象 后面再细说~

⑤ ……

所有对象都是Object内置类的一个实例

1 / 一道题 and 一张图

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.prototype.getY);
console.log(f1.__proto__.getX === f2.getX);
console.log(f1.getX === Fn.prototype.getX);
console.log(f1.constructor);
console.log(Fn.prototype.__proto__.constructor);
f1.getX();
f1.__proto__.getX();
f2.getY();
Fn.prototype.getY();

△ 通过这道题来理解上面的2句话

来来来,根据上面的 2句话 来一一验证这些问题~

公众号:朝霞的光影笔记ID:zhaoxiajingjing

△ 图1_一张图

f1 f2new Fn; 创建出来的实例对象

那么,Fn.prototype 原型对象是谁new出来的?

咱不知道是谁的实例对象时候,那就找Object去吧~

Object 是一个内置类、类、类、类,是个构造函数

公众号:朝霞的光影笔记ID:zhaoxiajingjing

△ 图2_Object 是个内置类

Fn.prototype 原型对象上的 getX 和 getY:

① 相对于 实例 f1 和 f2 来说是公共属性和方法 f1.hasOwnProperty('getY') => false

② 但相对于Fn.prototype 对象自己来说,就是私有属性

Fn.prototype.hasOwnProperty('getY') => true

属性是私有还是公有=>相对来说的,看参照物是谁

成员访问:不论是遍历还是直接访问

=> 点表示法 f1.x

=> 括号表示法 f1['x']

f1.x

① 首先找自己私有的属性,私有中存在,那么操作的就是私有的

② 私有中不存在,则默认基于_proto_ 找所属类的原型prototype上的

③ 如果还没有,则基于prototype上的__proto__继续向上查找……

④ 一直找到 Object.prototype 为止

把这套查找机制,称为:原型链查找机制

f1._proto_.getX

跳过私有属性查找,直接找到所属类的原型上 的公共属性和方法

注意:在IE浏览器中不兼容_proto_,浏览器保护起来了,不让咱用啊~

但是,咱可以用 Object.getPrototypeOf(f1).getX

f1.getX()

① 实例先找到对应的方法基于原型链查找机制

② 再把方法执行

③ 如果遇到this,则分析this是谁【函数执行看“点”前面是谁】

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.prototype.getX); //=> false
console.log(f1.constructor); //=>function Fn(){...} 自定义类
console.log(Fn.prototype.__proto__.constructor); //=> function Object(){...} 内置类

△ 看图说话

f1.getX();

=> 调用getX函数,有点:this->f1

=> f1实例对象上有自己的:私有方法getX

=> console.log(this.x);

=>** f1.x ->100**

f1.__proto__.getX();

=> 调用getX函数,前面有点:this->f1._proto_->Fn.prototype

=> 公共的getX方法

=> console.log(this.x);

=> Fn.prototype.x ->undefined

f2.getY();

=> 调用getY函数,有点:this->f2

=> 在f2实例上没有找到getY方法,那么就沿着原型链f2.__proto__找到所属类的原型Fn.prototype身上,找到了getY方法

=> 公共的getY方法

=> console.log(this.y);

=> f2.y ->200

Fn.prototype.getY();

=> 原型上的getY方法

=> this->Fn.prototype

=> console.log(this.y);

=> Fn.prototype.y => undefined

- end -

2句话,1道题,1张图:捋清楚【原型和原型链】~

第一句话

=> 每一个函数数据类型,天生自带一个prototype原型属性,其属性值是一个对象 注意:有特例

=> 这个prototype原型对象上,天生自带一个属性constructor,其属性值是类/构造函数本身

第二句话

=> 一个对象数据类型,天生自带一个 _proto_ 原型链属性(or 隐式原型),其指向所属类的原型

先把这个练熟了,后面再加的内容才更容易接受~