0%

检测公有属性的封装

检测属性方法

in

  • 检测当前对象是否存在某个属性,不论是公有还是私有,只要有,返回 true

    [attr] in [object]

1
2
3
4
5
6
7
8
function Fn() {
this.age = 14;
this.name = "lion";
}
Fn.prototype.category = "animal";
let f = new Fn();
console.log("name" in f); // true
console.log("category" in f); // true

hasOwnProperty

  • 检测一个属性是不是这个对象的私有属性,如果是,返回true

    [object].hasOwnProperty([attr])

1
2
3
4
5
6
7
8
function Fn() {
this.age = 14;
this.name = "lion";
}
Fn.prototype.category = "animal";
let f = new Fn();
console.log(f.hasOwnProperty("name")); // true
console.log(f.hasOwnProperty("category")); // false

尝试封装检测公有属性

  • 了解了 inhasOwnProperty 之后我们可以尝试封装检测公有属性的方法

写出来大概是如下这样:

1
2
3
Object.prototype.hasPubProperty = function (attr) {
return attr in obj && !obj.hasOwnProperty(attr);
}
  • 但是这个是有弊端的,比如:某个属性既是私有的,也是公有的,就检测不出来了
1
2
3
4
5
6
7
8
9
10
11
12
13
Object.prototype.hasPubProperty = function (attr) {
return attr in this && !this.hasOwnProperty(attr);
}
function Fn() {
this.age = 14;
this.name = "lion";
}
Fn.prototype.category = "animal";
Fn.prototype.name = "bird";
let f = new Fn();
// name既是公有的也是私有的
console.log(f.hasPubProperty("name")); // false
console.log(f.hasPubProperty("category")); // true

这样肯定不行,有没有什么方法可以避免这个问题,接下来需要看一下 Object 的其它几个方法

检测公有属性

  • 期望结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Fn() {
this.age = 14;
this[A] = 100;
this.name = "lion";
}
let A = Symbol("a");
Fn.prototype.name = "bird";
Fn.prototype[A] = 200;
let f = new Fn();

// age是私有方法
console.log(f.hasPubProperty("age")); // false
// name既是公有的也是私有的
console.log(f.hasPubProperty("name")); // true
// A(Symbol)既是公有的也是私有的
console.log(f.hasPubProperty(A)); // true

Object.getPrototypeOf

如果了解前置知识,可直接跳到封装方法处

前置知识

ES5新增方法

  • Object.getPrototypeOf([object]) 方法返回指定对象自身的原型
1
Fn.prototype === Object.getPrototypeOf(f); // true

封装方法

  • 借用原型链查找公有属性
1
2
3
4
5
6
7
8
9
10
11
Object.prototype.hasPubProperty = function (attr) {
let self = this,
prototype = Object.getPrototypeOf(self);
while (prototype) {
// 检测是否存在attr这个属性
if (prototype.hasOwnProperty(attr)) return true;
// 一直按照原型链查找
prototype = Object.getPrototypeOf(prototype);
}
return false
}
  • 因为用到了 hasOwnProperty,它不仅能检测可枚举属性还可以检测内置属性
1
2
console.log(f.hasPubProperty("toString")); // true
console.log(f.hasPubProperty("valueOf")); // true

Object.keys

如果了解前置知识,可直接跳到封装方法处

前置知识

ES5新增方法

  • Object.keys([object]) 方法会返回一个数组,数组里面存放指定对象自身的可枚举属性
  • Object.keys([object]) 方法返回非 Symbol 私有属性的数组
1
2
3
4
5
6
7
8
9
Object.prototype.xx = "xx";
let obj = {
name: "lion",
age: 12,
3: 200,
0: 100,
[Symbol("a")]: function () {}
}
console.log(Object.keys(obj)); // [ '0', '3', 'name', 'age' ]
  • 如果想获取 Symbol 私有属性,可以使用 Object.getOwnPropertySymbols(obj)
1
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(a) ]
  • 如果想获取所有私有属性(包括Symbol)到一个数组中,可以这么写
1
2
[...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
// ['0', '3', 'name', 'age', Symbol(a)]

封装方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Object.prototype.hasPubProperty = function (attr) {
var self = this,
prototype = Object.getPrototypeOf(self);
while (prototype) {
// 检测是否存在attr这个属性
var keys = Object.keys(prototype);
// 检测浏览器是否支持Symbol
if (typeof Symbol !== "undefined") {
// 如果支持,把Symbol属性合并到数组中
keys = keys.concat(Object.getOwnPropertySymbols(prototype));
}
// 一直按照原型链查找
prototype = Object.getPrototypeOf(prototype);
}
return false
}
  • 注意:内置属性不可以枚举,Object.keys([object]) 方法检测不到内置属性
1
2
console.log(f.hasPubProperty("toString")); // false
console.log(f.hasPubProperty("valueOf")); // false