Operation of properties
In JavaScript, adding a property to an object is very simple, just call the property and assign it a value.
const obj = {};
obj.name = 'Tom';
console.log(obj);
/**
* 输出:
* {name: 'Tom'}
*/
Properties added in this way can be manipulated at will:
- Can be modified
- enumerable
- can be deleted
Can be modified:
// 可修改
+ obj.name = 'Jim';
+ console.log(obj.name);
/**
* 输出:
* 'Jim'
*/
Enumerable:
// 可枚举
+ for (let key in obj) {
+ console.log(`${key} : ${obj[key]}`);
+ }
/**
* 输出:
* name : Jim
*/
Can be deleted:
// 可删除
+ delete obj.name;
+ console.log(obj);
/**
* 输出:
* {}
*/
If you want to achieve the above function through Object.defineProperty
, you can use the following code:
- obj.name = 'Tom';
+ Object.defineProperty(obj, 'name', {
+ value: 'Tom',
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ });
function signature
Before going deep into Object.defineProperty
, let's have an understanding of this method signature:
Object.defineProperty(obj, prop, descriptor);
As you can see from the function signature, defineProperty
is a static method on Object
that can pass three parameters:
-
obj
The object whose properties are to be defined -
prop
Name of the attribute to be defined or modified -
descriptor
Descriptor to define or modify the attribute
The return value is the object passed to the function, which is the first argument obj
.
The descriptor can have the following optional values:
-
configurable
-
enumerable
-
value
-
writable
-
get
-
set
Descriptor
Define a property for the object by Object.defineProperty
.
const obj = {};
Object.defineProperty(obj, 'name', {});
console.log(obj);
/**
* 输出:
* {name: undefined}
*/
As can be seen from the output, an attribute ---ae28d79bdcef2d8669227efc91155674 obj
name
, but its value is undefined
.
value
If you want to assign a value to an attribute, you can use the value
attribute in the descriptor.
- Object.defineProperty(obj, 'name', {});
+ Object.defineProperty(obj, 'name', {
+ value: 'Tom',
+ });
/**
* 输出:
* {name: 'Tom'}
*/
writable
In general, to modify the property value in an object, you can use the form of obj.name = 'Jim'
.
+ obj.name = 'Jim';
+ console.log(obj);
/**
* 输出:
* {name: 'Tom'}
*/
It can be seen from the output that the modification was not successful. If you want to modify the attribute value, you can set writable
in the descriptor to true
.
Object.defineProperty(obj, 'name', {
value: 'Tom',
+ writable: true,
});
enumerable
To enumerate the properties of an object, you can use for...in
.
+ for (let key in obj) {
+ console.log(`${key} : ${obj[key]}`);
+ }
Strangely enough, executing the above code does not output any information.
If you want to enumerate the properties of the object normally, you can set the enumerable
value in the descriptor to true
.
Object.defineProperty(obj, 'name', {
value: 'Tom',
writable: true,
+ enumerable: true,
});
configurable
When this property is not needed, it can be removed by delete
.
+ delete obj.name;
+ console.log(obj);
/**
* 输出:
* {name: 'Jim'}
*/
It can be seen from the output results that the expected effect has not been achieved. If you want to delete the attribute from the object normally, you can set configurable
in the descriptor to true
.
Object.defineProperty(obj, 'name', {
value: 'Tom',
writable: true,
enumerable: true,
+ configurable: true,
});
get
If you need to get the value of the object, you can use get
in the descriptor.
const obj = {};
let _tmpName = 'Tom';
Object.defineProperty(obj, 'name', {
get() {
return _tmpName;
},
});
console.log(obj.name);
/**
* 输出:
* {name: 'Tom'}
*/
set
If you need to set the value of the object, you can use set
in the descriptor, which needs to pass a parameter, which is the modified value.
Object.defineProperty(obj, 'name', {
get() {
return _tmpName;
},
+ set(newVal) {
+ _tmpName = newVal;
+ },
});
+ obj.name = 'Jim';
+ console.log(obj.name);
/**
* 输出:
* {name: 'Jim'}
*/
Precautions
In the operator object, if there is any one or more of ---20b6fc783d85af198b8150e7d2d165ae value
or writable
51639160c99a6a50e02b4d8663bde2df---, it cannot exist get
or set
.
const obj = {};
Object.defineProperty(obj, 'name', {
value: 1,
get() {
return 2;
},
});
The error message is as follows:
Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
In order to facilitate later reference, summarize the mutual exclusion situation:
-
value
andget
mutually exclusive -
value
andset
mutually exclusive -
value
andset
+get
mutually exclusive -
writable
andget
mutually exclusive -
writable
andset
mutually exclusive -
writable
andset
+get
mutually exclusive
scenes to be used
Object.defineProperty()
method will define a new property directly on an object, or modify an existing property of an object, and return the object. This method allows precise addition or modification of object properties.
This method is a relatively low-level method in JavaScript, and is mainly used to add or modify object properties on objects.
Simple application
Use of base modifiers
Suppose there is now a requirement to achieve the following effects:
const obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
obj[key] += 1;
}
console.log(obj);
/*
输出:
{ a: 3, b: 3, c: 5 }
*/
Object.defineProperty()
Not only can define attributes, but also modify attributes. At this time, you can use the method of modifying the properties to achieve the above requirements.
for (let key in obj) {
Object.defineProperty(obj, key, {
enumerable: true,
value: ++obj[key],
writable: key !== 'b',
});
}
use of get
Use Object.defineProperty
in get
to output the information in console.log
normally.
if (num === 1 && num === 2 && num === 3) {
console.log('you win ...');
}
As can be seen from the title, num
cannot be equal to 1
and 2
, and also equal to 3
. If you want to achieve this effect, you must automatically increase the value of num
at the same time.
To achieve a variable value and auto-increment, you need to use Object.defineProperty
in get
. num
is used directly. In the browser, only the attributes mounted on the window
object can be used directly.
let _tmpNum = 0;
Object.defineProperty(window, 'num', {
get() {
return ++_tmpNum;
},
});
Suppose there is a requirement now, to achieve the following effects:
_ // a
_ + _ // ab
_ + _ + _ // abc
This requirement is actually to mount a _
attribute on the window
object. Each time _
is called, the ASCII code will be incremented automatically.
Object.defineProperty(window, '_', {
get() {
// 获取字母 a 的 ASCII 码
const aAsciiCode = 'a'.charCodeAt(0);
// 获取字母 z 的 ASCII 码
const zAsciiCode = 'z'.charCodeAt(0);
// 如果 _code 不存在,将其赋值为 a 的 ASCII 码
this._code = this._code || aAsciiCode;
// 如果 _code 的范围超出了小写字母的范围,直接返回
if (this._code > zAsciiCode) return;
// 获取当前 ASCII 码对应的字母
const _char = String.fromCharCode(this._code);
// 每调用一次自增一次
this._code++;
// 返回
return _char;
},
});
If you want to print out a combination of 26 letters, you can traverse it.
let resStr = '';
for (let i = 0; i < 26; i++) {
resStr += _;
}
console.log(resStr);
use of set
If you assign a string to 'Object'
, print the string output {type: 'Object', length: 6}
; if you assign a string to 'Object'
, print this string output {type: 'Array', length: 5}
; If you assign the string to another value, the program will report an error TypeError: This type is invalid.
.
Analyzing this topic, when printing, it is actually the process of taking values. You need to use the get
operator, type
is the value of the current string, length
is the current value The length of the string.
let _tmpStr = '';
Object.defineProperty(window, 'str', {
get() {
return { type: _tmpStr, length: _tmpStr.length };
},
});
When assigning a value to a string, when the value of the string is 'Object'
or 'Array'
, the value is assigned normally, and the other cases throw an error directly. This operation needs to be implemented in the operator set
.
Object.defineProperty(window, 'str', {
get() {
return { type: _tmpStr, length: _tmpStr.length };
},
set(newVal) {
+ if (newVal === 'Object' || newVal === 'Array') {
+ _tmpStr = newVal;
+ } else {
+ throw new TypeError('This type is invalid.');
+ }
},
});
Verify the execution of the code:
str = 'Object';
console.log(str);
/*
输出:
{type: 'Object', length: 6}
*/
str = 'Array';
console.log(str);
/*
输出:
{type: 'Array', length: 5}
*/
str = '123';
console.log(str);
/*
输出:
TypeError: This type is invalid.
*/
complex application
Requirement: There is an input box on the page and a display area below it. When the content of the input box changes, the content in the display area changes synchronously. When the page is refreshed, the information in the page remains the same as before the refresh.
First, draw the page information in index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div><input type="text" placeholder="输入信息" id="idInfo" /></div>
<div id="idShowInfo"></div>
<script type="module" src="./js/index.js"></script>
</body>
</html>
Simple implementation
The easiest way to implement it is to get data from the cache when entering the page, and assign values to the input box and display area when you can get it; at the same time, monitor the input event of the input box, and write the corresponding information into the cache and display area.
function init() {
const eleInfo = document.getElementById('idInfo');
const eleShowInfo = document.getElementById('idShowInfo');
const _storageInfo = JSON.parse(localStorage.getItem('storageInfo') || '{}');
if (_storageInfo.info) {
eleInfo.value = _storageInfo.info;
}
eleShowInfo.innerHTML = eleInfo.value;
eleInfo.addEventListener(
'input',
function () {
localStorage.setItem(
'storageInfo',
JSON.stringify({ info: eleInfo.value || '' }),
);
eleShowInfo.innerHTML = eleInfo.value;
},
false,
);
}
init();
Object.defineProperty implementation
The above implementation method is relatively straightforward and simple, but the encapsulation of the code is relatively poor, and the data coupling is relatively high. If you use Object.defineProperty
you can organize the code better.
First write the code of the entry file js/index.js
:
import { observer } from './observer.js';
const eleInfo = document.getElementById('idInfo');
const eleShowInfo = document.getElementById('idShowInfo');
const infoObj = observer({ info: '' }, eleInfo, eleShowInfo);
function init() {
bindEvent(eleInfo);
}
function bindEvent(ele) {
ele.addEventListener('input', handleInput, false);
}
function handleInput(event) {
const _info = event.target.value || '';
infoObj.info = _info;
}
init();
Next, write the code in js/observer.js
:
export function observer(infoObj, inputDom, viewDom) {
const _storageInfo = JSON.parse(localStorage.getItem('storageInfo') || '{}');
const _resInfo = {};
init(_storageInfo, infoObj, _resInfo, inputDom, viewDom);
return _resInfo;
}
function init(storageInfo, infoObj, resInfo, inputDom, viewDom) {
initData(storageInfo, infoObj, resInfo, inputDom, viewDom);
initDom(resInfo, inputDom, viewDom);
}
function initData(storageInfo, infoObj, resInfo, inputDom, viewDom) {
for (let key in storageInfo) {
infoObj[key] = storageInfo[key];
}
for (let key in infoObj) {
(function (key) {
Object.defineProperty(resInfo, key, {
get() {
return infoObj[key];
},
set(newVal) {
infoObj[key] = newVal;
localStorage.setItem('storageInfo', JSON.stringify(infoObj));
initDom(resInfo, inputDom, viewDom);
},
});
})(key);
}
}
function initDom(resInfo, inputDom, viewDom) {
inputDom.value = resInfo.info;
viewDom.innerHTML = resInfo.info;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。