primers
To acquire a deep object, for everyone is a routine thing. Like their own package, third-party libraries and ES2020 to provide, in short, share and discuss
Get the city address of the user
const user = {
name: 'xxx'.
address: {
city: 'hangzhou'
}
};
Copy the code
The most direct
const ctiy = user && user.address && user.address.city;
// or
constcity = ! user ?undefined : !user.address ? undefined : user.address.city;
Copy the code
Every time I add a line to the object, I need another layer to determine whether I can write a parsed function to get the value of user.name.address.city if I know the path
Manual implementation
var user = {
name: 'xxx'.
address: {
city: 'hangzhou'
}
};
const str = 'address.city';
const get = (obj, path, defaultValue) => {
let result = obj, i = 0;
const paths = path.split('. ');
while (i < paths.length) {
result = Object(result)[paths[i]];
if (result === undefined) {
return defaultValue;
}
i++
}
return result;
};
console.log(get(user, str), '--');
// hangzhou
Copy the code
So we’re actually going to add, and it’s going to be easy to add one line to each of the array subscripts
Optimized version
var user = {
name: 'xxx'.
address: {
cities: [{city: 'hangzhou'}]
}
};
const str = 'address.cities[0].city';
const get = (obj, path, defaultValue) => {
let result = obj, i = 0;
// Add this line ————————————————————————————
const paths = path.replace(/\[(\d+)\]/g.'$1').split('. ')
console.log(paths, The '-')
while (i < paths.length) {
result = Object(result)[paths[i]];
if (result === undefined) {
return defaultValue;
}
i++;
}
return result;
};
console.log(get(user, str), '--');
/ / hangzhou
Copy the code
Big guy one line version
var mb=p=>o=>p.map(c=>o=(o||{})[c])&&o
There’s a guy who wrote a mb.js line that implements get as an array
var getHello = mb(["a"."b".0."hello"]);
var getHelloLength = mb(["a"."b".0."hello"."length"]);
var obj1 = {
a: {
b: [{ hello: "world" }]
}
};
var obj2 = {
c: {
d: "e"
}
};
getHello(obj1); // world
getHelloLength(obj1); / / 5
getHello(obj2); // undefined
getHelloLength(obj2); // undefined
Copy the code
All of the above operations can be implemented if you define your own parser
lodash/get
const city = get(user, 'address.cities[0].city'))
Copy the code
Let’s take a look at the source./get.js
import baseGet from './.internal/baseGet.js'
function get(object, path, defaultValue) {
// the procedure is simple. DefaultValue is the defaultValue of undefined. All values are in the 'baseGet' module.
const result = object == null ? undefined : baseGet(object, path)
return result === undefined ? defaultValue : result
}
export default get
Copy the code
See baseGet. Js
import castPath from './castPath.js'
import toKey from './toKey.js'
function baseGet(object, path) {
// All paths are converted to arrays
path = castPath(path, object)
let index = 0
const length = path.length
while(object ! =null && index < length) {
// The key is changed to a unique key
object = object[toKey(path[index++])]
}
// Check the key array
return (index && index == length) ? object : undefined
}
export default baseGet
/ * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// Split castpath.js
import isKey from './isKey.js'
import stringToPath from './stringToPath.js'
function castPath(value, object) {
if (Array.isArray(value)) {
return value
}
// Convert to a key array
return isKey(value, object) ? [value] : stringToPath(value)
}
export default castPath
// isKey.js
function isKey(value, object) {
if (isArray(value)) { // Array, return false
return false;
}
if (type == 'number' || type == 'symbol' || type == 'boolean' ||
value == null || isSymbol(value)) {
return true;
}
returnreIsPlainProp.test(value) || ! reIsDeepProp.test(value) ||
(object ! =null && value in Object(object));
}
Copy the code
IsKey (value, object) is used to determine whether a value is the key of an object, like object[value]
Ramda
Ramda is a one-two punch. After all, Ramda is a functional programming library. Let’s take a look at the implementation
// The one-step version, which has no default option
const city = R.path(['address'.'cities'.0.'city'])(user)
// Version with default parameters
R.pathOr([], ['user'.'posts'.0.'comments'])
/ /
const city = R.compose(
R.prop('city'),
R.path(['address, cities'.0,])(user)
Copy the code
Kind of the way
const user = {
address: {
city: 'hangzhou'
}
}
class GetValue {
constructor(val) {
this.__val = val;
}
static set(val) {
return new GetValue(val);
}
isNothing() {
return this.__val === null || this.__val === undefined;
}
map(f) {
return this.isNothing() ? new GetValue(null) : new GetValue(f(this.__val));
}
}
const prop = key= > obj= > obj[key]
const city = GetValue.set(user).map(prop('address')).map(prop('city'))
console.log(city, 'city')
// GetValue { __val: 'hangzhou' } city
Copy the code
We’ve been doing this for so long, but ES2020 has already provided a new way to do it for us
Optional Chaining operators
Optional chain we do not need to nullate in various ways when querying multi-layer objects
constcity = address? .cities[0]? .city
Copy the code
When the left is empty, the right value is taken, otherwise the left value is taken. Null refers to null and undefined, which is different from false values and the difference between using null operators and logical or operators
compatibility
precondition
- Nodejs v > = 14.0.0
- The TypeScript v > = 3.7
- Babel plug-in support
// install
yarn add @babel/plugin-proposal-optional-chaining
--dev / / optional link chain
yarn add @babel/plugin-proposal-nullish-coalescing-operato --save / / double question mark
// use
{
"plugins": ["@ Babel/plugin - proposal - optional - chaining"].
"@babel/plugin-proposal-nullish-coalescing-operator"
}
Copy the code
- The framework does not primarily support vue templates
More 🌰
Dynamic key
const obj = { a: { b: 'b'}}
const name = 'b'
constb = obj? .a? .[name]
Copy the code
Three yuan
const city = user ? user.name : 'xxx' / / before
constcity = user ? .name ??'xxx' / / after
Copy the code
After I use it, my code becomes a question mark
The last
Although we have been working on this for so long, we are probably only writing crawler scenes with relatively deep objects. If you come across such a deep data structure from the back end of your work, you should spray it, do not use these useless