Js 使用 Object.defineProperty 新增或修改对象方法
最近工作和学习中,了解到一个十分有用的 Object.defineProperty 方法。其实在我们工作面试的时候,有些面试官就会问到:你知道Vue数据双向绑定的原理嘛?没错,这底层逻辑实现的方式就是先借助 Object.defineProperty 的 get 、set 方法监听修改和读取,通过 数据劫持结合发布者-订阅者模式 的方式来实现数据双向绑定。
语法:
Object.defineProperty(obj
, prop
, descriptor
)
参数:
obj
要定义属性的对象。
prop
要定义或修改的属性的名称或 Symbol 。
descriptor
要定义或修改的属性描述符。
描述:
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。
数据描述符:
configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为 false。
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 默认为 false。
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined。
writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。 默认为 false。
存取描述符:
get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined。
set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined。
案例:
这次用String的endsWith方法为例,若endsWith不存在,使用Object.defineProperty为String新增个endsWith方法。
if (!String.prototype.endsWith) {
const endsWith = function (searchStr, strLen) {
if (strLen === undefined || strLen > this.length) {
strLen = this.length;
}
return this.substring(strLen - searchStr.length, strLen) === searchStr;
};
if (Object.defineProperty) {
Object.defineProperty(String.prototype, 'endsWith', {
'value': endsWith,
'configurable': true,
'writable': true
});
} else {
String.prototype.endsWith= endsWith;
}
}
用Array的at方法为例。
if (!Array.prototype.at) {
const atFunc = function (idx) {
idx = Math.trunc(idx) || 0;
if (idx < 0) idx += this.length;
if (idx < 0 || idx >= this.length) return undefined;
return this[idx];
}
if (Object.defineProperty) {
Object.defineProperty(Array.prototype, "at", {
'value': atFunc,
'configurable': false,
'writable': false,
'configurable': true,
});
} else {
Array.prototype.at = atFunc;
}
}