ES6/2015 中的空安全 属性 访问(和条件赋值)
Null-safe property access (and conditional assignment) in ES6/2015
在 ES6 (ES2015/JavaScript.next/Harmony) 中是否有 null
-安全 属性 访问(空传播/存在)运算符,如 [例如,在 CoffeeScript 中 =15=]?还是计划用于 ES7?
var aThing = getSomething()
...
aThing = possiblyNull?.thing
大致如下:
if (possiblyNull != null) aThing = possiblyNull.thing
理想情况下,如果 possiblyNull
是 null
,解决方案不应分配(甚至 undefined
)到 aThing
没有。您可以在 JavaScript.
中使用 lodash#get 或类似的东西
不,ES6 中没有空传播运算符。您将不得不选择 known patterns.
之一
不过您也许可以使用解构:
({thing: aThing} = possiblyNull);
有很多讨论(例如this) to add such an operator in ES7, but none really took off until several years later when optional chaining syntax在ES2020中被标准化。
安全 属性 访问的香草替代品
(((a.b || {}).c || {}).d || {}).e
最简洁的条件赋值可能是这个
try { b = a.b.c.d.e } catch(e) {}
根据列表 here,目前没有向 Ecmascript 添加安全遍历的提议。所以不仅没有很好的办法做到这一点,而且在可预见的将来也不会添加。
编辑:因为我最初制作这个 post,它实际上被添加到语言中。
不如?。运算符,但要获得类似的结果,您可以这样做:
user && user.address && user.address.postcode
由于 null
和 undefined
都是 falsy 值 (see this reference),[=16 之后的 属性 =] 运算符仅在先例不是 null 或未定义时才被访问。
或者,您可以编写如下函数:
function _try(func, fallbackValue) {
try {
var value = func();
return (value === null || value === undefined) ? fallbackValue : value;
} catch (e) {
return fallbackValue;
}
}
用法:
_try(() => user.address.postcode) // return postcode or undefined
或者,使用回退值:
_try(() => user.address.postcode, "none") // return postcode or a custom string
更新 (2022-01-13):似乎人们仍在寻找这个,这是当前的故事:
- 可选链接现在在规范中 (ES2020) 和 supported by all modern browsers, more in the archived proposal: https://github.com/tc39/proposal-optional-chaining
- babel-preset-env:如果您需要支持没有它的旧环境,这可能就是您想要的 https://babeljs.io/docs/en/babel-preset-env
- Babel v7 插件:https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
更新 (2017-08-01): 如果你想使用官方插件,你可以尝试使用新转换的 Babel 7 alpha 构建。 您的里程可能会有所不同
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
原:
目前处于第 1 阶段的一项功能:可选链接。
https://github.com/tc39/proposal-optional-chaining
如果你今天想使用它,有一个 Babel 插件可以实现。
我认为这个问题需要在 2018 年进行一些更新。这可以在没有任何库使用 Object.defineProperty()
的情况下很好地完成,并且可以按如下方式使用:
myVariable.safeGet('propA.propB.propC');
我认为这是安全的(和 js-ethical),因为 writeable
和 enumerable
定义现在可用于 Object
的 defineProperty
方法,因为documented in MDN
函数定义如下:
Object.defineProperty(Object.prototype, 'safeGet', {
enumerable: false,
writable: false,
value: function(p) {
return p.split('.').reduce((acc, k) => {
if (acc && k in acc) return acc[k];
return undefined;
}, this);
}
});
我将 jsBin 与控制台输出放在一起来演示这一点。请注意,在 jsBin 版本中,我还为空值添加了自定义异常。这是可选的,因此我将其排除在上面的最小定义之外。
欢迎改进
安全的深度获取方法似乎很适合 underscore.js,但问题是避免字符串编程。修改@Felipe 的答案以避免字符串编程(或至少将边缘情况推回调用者):
function safeGet(obj, props) {
return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
}
示例:
var test = {
a: {
b: 'b property value',
c: { }
}
}
safeGet(test, ['a', 'b'])
safeGet(test, "a.b".split('.'))
// Typescript
static nullsafe<T, R>(instance: T, func: (T) => R): R {
return func(instance)
}
// Javascript
function nullsafe(instance, func) {
return func(instance);
};
// use like this
const instance = getSomething();
let thing = nullsafe(instance, t => t.thing0.thing1.thingx);
2020 年解决方案,?.
和 ??
您现在可以直接使用 ?.
(可选链接)内联来安全地测试是否存在。所有现代浏览器都支持它。
??
(Nullish Coalescing)可用于在未定义或 null 时设置默认值。
aThing = possiblyNull ?? aThing
aThing = a?.b?.c ?? possiblyNullFallback ?? aThing
如果 属性 存在,?.
进行下一次检查,或者 return 为有效值。任何故障都会立即短路并 return undefined
.
const example = {a: ["first", {b:3}, false]}
example?.a // ["first", {b:3}, false]
example?.b // undefined
example?.a?.[0] // "first"
example?.a?.[1]?.a // undefined
example?.a?.[1]?.b // 3
domElement?.parentElement?.children?.[3]?.nextElementSibling
null?.() // undefined
validFunction?.() // result
(() => {return 1})?.() // 1
为确保默认定义值,您可以使用??
。如果需要第一个真值,可以使用 ||
.
example?.c ?? "c" // "c"
example?.c || "c" // "c"
example?.a?.[2] ?? 2 // false
example?.a?.[2] || 2 // 2
如果不检查大小写,左边属性一定存在。如果没有,它会抛出异常。
example?.First // undefined
example?.First.Second // Uncaught TypeError: Cannot read property 'Second' of undefined
?.
Browser Support - 92%,2021 年 11 月
??
Browser Support - 92%
--
逻辑无效赋值,2020+ 解决方案
目前正在向浏览器添加新运算符,??=
、||=
和 &&=
。它们并不完全符合您的要求,但可能会导致相同的结果,具体取决于您的代码目标。
NOTE: These are not common in public browser versions yet, but Babel should transpile well. Will update as availability changes.
??=
检查左侧是否未定义或为空,如果已定义则短路。如果不是,则为左侧分配右侧值。 ||=
和 &&=
相似,但基于 ||
和 &&
运算符。
基本示例
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Object/Array 例子
let x = ["foo"]
let y = { foo: "fizz" }
x[0] ??= "bar" // "foo"
x[1] ??= "bar" // "bar"
y.foo ??= "buzz" // "fizz"
y.bar ??= "buzz" // "buzz"
x // Array [ "foo", "bar" ]
y // Object { foo: "fizz", bar: "buzz" }
Browser Support 2021 年 11 月 - 90%
在 ES6 (ES2015/JavaScript.next/Harmony) 中是否有 null
-安全 属性 访问(空传播/存在)运算符,如 [例如,在 CoffeeScript 中 =15=]?还是计划用于 ES7?
var aThing = getSomething()
...
aThing = possiblyNull?.thing
大致如下:
if (possiblyNull != null) aThing = possiblyNull.thing
理想情况下,如果 possiblyNull
是 null
undefined
)到 aThing
没有。您可以在 JavaScript.
中使用 lodash#get 或类似的东西不,ES6 中没有空传播运算符。您将不得不选择 known patterns.
之一不过您也许可以使用解构:
({thing: aThing} = possiblyNull);
有很多讨论(例如this) to add such an operator in ES7, but none really took off until several years later when optional chaining syntax在ES2020中被标准化。
安全 属性 访问的香草替代品
(((a.b || {}).c || {}).d || {}).e
最简洁的条件赋值可能是这个
try { b = a.b.c.d.e } catch(e) {}
根据列表 here,目前没有向 Ecmascript 添加安全遍历的提议。所以不仅没有很好的办法做到这一点,而且在可预见的将来也不会添加。
编辑:因为我最初制作这个 post,它实际上被添加到语言中。
不如?。运算符,但要获得类似的结果,您可以这样做:
user && user.address && user.address.postcode
由于 null
和 undefined
都是 falsy 值 (see this reference),[=16 之后的 属性 =] 运算符仅在先例不是 null 或未定义时才被访问。
或者,您可以编写如下函数:
function _try(func, fallbackValue) {
try {
var value = func();
return (value === null || value === undefined) ? fallbackValue : value;
} catch (e) {
return fallbackValue;
}
}
用法:
_try(() => user.address.postcode) // return postcode or undefined
或者,使用回退值:
_try(() => user.address.postcode, "none") // return postcode or a custom string
更新 (2022-01-13):似乎人们仍在寻找这个,这是当前的故事:
- 可选链接现在在规范中 (ES2020) 和 supported by all modern browsers, more in the archived proposal: https://github.com/tc39/proposal-optional-chaining
- babel-preset-env:如果您需要支持没有它的旧环境,这可能就是您想要的 https://babeljs.io/docs/en/babel-preset-env
- Babel v7 插件:https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
更新 (2017-08-01): 如果你想使用官方插件,你可以尝试使用新转换的 Babel 7 alpha 构建。 您的里程可能会有所不同
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
原:
目前处于第 1 阶段的一项功能:可选链接。
https://github.com/tc39/proposal-optional-chaining
如果你今天想使用它,有一个 Babel 插件可以实现。
我认为这个问题需要在 2018 年进行一些更新。这可以在没有任何库使用 Object.defineProperty()
的情况下很好地完成,并且可以按如下方式使用:
myVariable.safeGet('propA.propB.propC');
我认为这是安全的(和 js-ethical),因为 writeable
和 enumerable
定义现在可用于 Object
的 defineProperty
方法,因为documented in MDN
函数定义如下:
Object.defineProperty(Object.prototype, 'safeGet', {
enumerable: false,
writable: false,
value: function(p) {
return p.split('.').reduce((acc, k) => {
if (acc && k in acc) return acc[k];
return undefined;
}, this);
}
});
我将 jsBin 与控制台输出放在一起来演示这一点。请注意,在 jsBin 版本中,我还为空值添加了自定义异常。这是可选的,因此我将其排除在上面的最小定义之外。
欢迎改进
安全的深度获取方法似乎很适合 underscore.js,但问题是避免字符串编程。修改@Felipe 的答案以避免字符串编程(或至少将边缘情况推回调用者):
function safeGet(obj, props) {
return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
}
示例:
var test = {
a: {
b: 'b property value',
c: { }
}
}
safeGet(test, ['a', 'b'])
safeGet(test, "a.b".split('.'))
// Typescript
static nullsafe<T, R>(instance: T, func: (T) => R): R {
return func(instance)
}
// Javascript
function nullsafe(instance, func) {
return func(instance);
};
// use like this
const instance = getSomething();
let thing = nullsafe(instance, t => t.thing0.thing1.thingx);
2020 年解决方案,?.
和 ??
您现在可以直接使用 ?.
(可选链接)内联来安全地测试是否存在。所有现代浏览器都支持它。
??
(Nullish Coalescing)可用于在未定义或 null 时设置默认值。
aThing = possiblyNull ?? aThing
aThing = a?.b?.c ?? possiblyNullFallback ?? aThing
如果 属性 存在,?.
进行下一次检查,或者 return 为有效值。任何故障都会立即短路并 return undefined
.
const example = {a: ["first", {b:3}, false]}
example?.a // ["first", {b:3}, false]
example?.b // undefined
example?.a?.[0] // "first"
example?.a?.[1]?.a // undefined
example?.a?.[1]?.b // 3
domElement?.parentElement?.children?.[3]?.nextElementSibling
null?.() // undefined
validFunction?.() // result
(() => {return 1})?.() // 1
为确保默认定义值,您可以使用??
。如果需要第一个真值,可以使用 ||
.
example?.c ?? "c" // "c"
example?.c || "c" // "c"
example?.a?.[2] ?? 2 // false
example?.a?.[2] || 2 // 2
如果不检查大小写,左边属性一定存在。如果没有,它会抛出异常。
example?.First // undefined
example?.First.Second // Uncaught TypeError: Cannot read property 'Second' of undefined
?.
Browser Support - 92%,2021 年 11 月
??
Browser Support - 92%
--
逻辑无效赋值,2020+ 解决方案
目前正在向浏览器添加新运算符,??=
、||=
和 &&=
。它们并不完全符合您的要求,但可能会导致相同的结果,具体取决于您的代码目标。
NOTE: These are not common in public browser versions yet, but Babel should transpile well. Will update as availability changes.
??=
检查左侧是否未定义或为空,如果已定义则短路。如果不是,则为左侧分配右侧值。 ||=
和 &&=
相似,但基于 ||
和 &&
运算符。
基本示例
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Object/Array 例子
let x = ["foo"]
let y = { foo: "fizz" }
x[0] ??= "bar" // "foo"
x[1] ??= "bar" // "bar"
y.foo ??= "buzz" // "fizz"
y.bar ??= "buzz" // "buzz"
x // Array [ "foo", "bar" ]
y // Object { foo: "fizz", bar: "buzz" }
Browser Support 2021 年 11 月 - 90%