「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。
一个问题引出JS原型与原型链的处理机制
function Fn(x, y) {
let sum = 10;
this.total = x + y;
this.say = function () {
console.log(`我计算的和是:${this.total}`);
};
}
let f1 = new Fn(10, 20);
console.log(f1.sum);
console.log(f1.total);
- 上面代码,检测某个属性是否为对象的'私有属性'
- f1是Fn类的实例,也是Object这个类的实例
- Object.prototype.hasOwnProperty 这个方法就是用来检测私有属性的
console.log(f1.hasOwnProperty('say')); //=>true 特点:必须是它的一个私有属性才可以「有这个属性,但是不是私有的不行 & 没有这个属性更不行」 console.log(f1.hasOwnProperty('hasOwnProperty')); //=>false - 只想检测是不是他的一个属性[不论是私有还是公有]
console.log('say' in f1); //=>true console.log('hasOwnProperty' in f1); //=>true console.log('sum' in f1); //=>false - 需求:检测这个属性是否为他的公有属性? 方案 -> 是它的属性,但还不能是私有的
function hasPubProperty(obj, attr) {
return (attr in obj) && !obj.hasOwnProperty(attr);
}
console.log(hasPubProperty(f1, 'say')); //=>false
console.log(hasPubProperty(f1, 'hasOwnProperty')); //=>true
console.log(hasPubProperty(f1, 'sum')); //=>false
// toString既是私有的,也是公有的
f1.toString = function () {};
console.log(hasPubProperty(f1, 'toString')); //=>false ? */
//对于toString这个属性来说,该如何检测呢?我们先来引出JS中原型与原型链的机制再来解决这个问题
/* // instanceof:检测当前实例是否为某个类的实例
console.log(f1 instanceof Fn); //=>true
console.log(f1 instanceof Object); //=>true
console.log(f1 instanceof Array); //=>false */
- JS中的原型与原型链处理机制
prototype
大部分“函数数据类型”的值都具备“prototype(原型/显式原型)”属性,属性值本身是一个对象「浏览器会默认为其开辟一个堆内存,用来存储实例可调用的公共的属性和方法」,在浏览器默认开辟的这个堆内存中「原型对象」有一个默认的属性“constructor(构造函数/构造器)”,属性值是当前函数/类本身!!
- 函数数据类型
- 普通函数(实名或者匿名函数)
- 箭头函数
- 构造函数/类「内置类/自定义类」
- 生成器函数 Generator
- ...
- 不具备prototype的函数
- 箭头函数
- 基于ES6给对象某个成员赋值函数值的快捷操作
- ...
__proto__
每一个“对象数据类型”的值都具备一个属性“
__proto__(原型链/隐式原型)”,属性值指向“自己所属类的原型(prototype)”- 对象数据类型值
- 普通对象
- 特殊对象:数组、正则、日期、Math、Error…
- 函数对象
- 实例对象
- 构造函数.prototype
- …
- 以下代码作为运行示例
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();
- Function与Object在原型链中的关系
- 需求:
obj之前如果是数组,我们则创建一个新的数组;如果是正则,则创建一个新的正则;如果是对象,则创建一个新的对象;..obj.constructor正常情况下,获取到的都是obj实列对象所属的类let obj2 = new obj.constructorobj2即为所需对象
- eg:代码分析
function C1(name) {
if (name) {
this.name = name;
}
}
function C2(name) {
this.name = name;
}
function C3(name) {
this.name = name || 'join';
}
C1.prototype.name = 'Tom';
C2.prototype.name = 'Tom';
C3.prototype.name = 'Tom';
alert((new C1().name) + (new C2().name) + (new C3().name));
// 'Tom' + undefined + 'join' => 'Tomundefinedjoin'
- 返回到上面检测公有属性的问题
- 例子:hasPubProperty 不管私有是否存在,我们只看公有中是否有,只要公有中有,则当前属性就是对象的公有属性
- Object.getPrototypeOf(obj) 获取某个对象(实例)的原型:__proto__指向的原型对象
Object.prototype.hasPubProperty = function hasPubProperty(attr){
// this -> obj 要处理的对象
// 找到当前对象的原型,而且一直向上找,直到找到Object.prototype为止;在查找过程中,只要某个原型对象中有ATTR这个属性,则证明这个属性就是对象的公有属性...
let proto = Object.getPrototypeOf(this)
while(proto){
if(proto.hasOwnProperty(attr)) return true
proto = Object.getPrototypeOf(proto)
}
return false
}
let obj = {
name:'obj',
toString(){}
}
obj.hasPubProperty('name') // => false
obj.hasPubProperty('toString') // => true