手写查找公有属性的方法

233 阅读2分钟

检测某属性是否属于某实例(不论私有还是公有),[属性] in [对象]
检测某属性是否属于某实例的私有属性[对象].hasOwnProperty([属性])

  • [属性] in [对象]:基于原型链机制查找,在当前对象中查找到的为私有属性,基于__proto__查找的属于公有属性(公有、私有针对[对象]而言)
    • 先查找当前对象是否存在此属性,若存在,返回true;
    • 若不存在会基于[对象]的原型链__proto__查找到其所属类的原型prototype上的属性(对[对象]来说为公共属性),存在返回true;
    • 若还不存在,还会基于此原型prototype的__proto__查找(不是被new出来的prototype属于对象类),直至找到Object.prototype位置,存在则返回true,不存在返回false;
  • [对象].hasOwnProperty([属性]):在[对象]地址空间中查找[属性],若存在返回true;不存在返回false;(查找到的是[对象]的私有属性)

问题:检测某个[属性]是否为这个[对象]的公有属性

//此方法思想:属性attr是对象obj的一个属性,并且属性attr不是对象obj的私有属性,那么属性attr就是公有属性
const hasPubProperty = function hasPubProperty(obj, attr) {
    return (attr in obj) && !obj.hasOwnProperty(attr);
};
//此方法有瑕疵:如果attr既是对象obj的私有属性也是对象obj的公有属性呢,这个方法就会返回false,但是属性attr是对象obj的公有方法啊

上述方法的缺陷,详看下图:

  • 对于对象a1,方法m1属于其私有方法,方法M1既是a1的私有方法也是a1的公有方法;方法M2是a1的公有方法;
  • 对于对象a2,方法m2是a2的私有方法,方法M1和M2的a2的公有方法;
classDiagram
类A的prototype属性 <|-- 实例a1
类A的prototype属性 <|-- 实例a2
类A的prototype属性 : +...
类A的prototype属性 : +...
类A的prototype属性: +供所属实例调用的公共属性和方法M1()
类A的prototype属性: +供所属实例调用的公共属性和方法M2()
class 实例a1{
+...
+私有方法m1()
+私有方法M1()
}
class 实例a2{
-...
-私有方法m2()
}

解决方法:

  • 不论私有中是否存在此属性,只要在其原型链中存在的属性就为公有属性
  • 首先获取当前实例this(obj)的原型对象A,看A中是否存在attr这个属性,
    • 存在则直接返回true,说明attr是它的一个公有属性;
    • 如果不存在,则找A的原型对象...直到找到Object.prototype;
    • 如果整个过程中都没有找到对应的属性,则说明attr不是他的公有属性,返回false即可;
  • Object.getPrototypeOf(实例):获取某个实例的原型对象;
  • 把检测其公有属性的方法拓展到对象类的原型上【基类的原型上Object.prototype】
Object.prototype.hasPubProperty = function  hasPubProperty(attr){
       //获取当前对象的原型
       let proto = Object.getPrototypeOf(this);
       //截止到基类原型上的原型链,就停止循环,Object.prototype.__proto__=null;null转换为布尔类型为false
       while (proto) {
            //找到属性就返回true
            if (proto.hasOwnProperty(attr)) return true;
            //没有找到属性,就继续往上级原型找
            proto = Object.getPrototypeOf(proto);
      }
      //一直找不到就返回false
      return false;
};