@[toc]
0 / 两句话
JS中面向对象的底层处理机制:
第一句话:
=> 每一个(除了三种特例,以外的)函数数据类型,都天生自带一个属性:<u>prototype原型属性</u>,其属性值是:<u>一个对象</u>(Function.prototype除外)
=> 这个prototye原型对象中天生自带一个属性:<u>constructor</u>,其属性值是:<u>当前构造函数本身</u>
第二句话:
=> 每一个对象数据类型值,都天生自带一个属性:\proto 原型链属性(或者叫:隐式原型),其属性值指向:<u>所属类的原型对象prototype</u> 可以找到所属类原型上的公共方法
△ 请大声朗读10遍~
函数数据类型,没有原型属性的特例:
① 箭头函数
② let obj = {say(){}};
这种写法的obj.say()
③ Function.prototype
没有原型属性,不能使用 new 关键字
△ 图1.1_三个没有原型的函数数据类型,不能使用new关键字
函数数据类型:
① 普通函数、箭头函数、生成器函数
② 构造函数(自定义类)
③ 内置类(内置构造函数)
④ ……
prototype
原型对象,针对 <u>类</u> 有用,对于普通函数来说没啥用
对象数据类型:
① 普通对象、数组对象、正则对象、日期对象……
② 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句话
来来来,根据上面的 <u>2句话</u> 来一一验证这些问题~
上 菜 图
△ 图1_一张图
f1
和 f2
是 new Fn;
创建出来的实例对象
那么,Fn.prototype
原型对象是谁new出来的?
咱不知道是谁的实例对象时候,那就找Object
去吧~
Object
是一个内置类、类、类、类,是个构造函数
△ 图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 隐式原型),其指向所属类的原型
先把这个练熟了,后面再加的内容才更容易接受~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。