JavaScript中左侧的可选链接链。

60

在 Javascript 中,能否在赋值符号 = 的左侧使用 可选链式操作符

const building = {}
building?.floor?.apartment?.number = 3; // Is this possible?

7
不,这是不可能的。 - Philipp Meissner
1
从文档中并不清楚。文档说“允许读取...”,这并不意味着不允许赋值。 - Ma Jerez
1
但是,我想要赋值,我该怎么做呢? passwordErr?.confirmation_password = "test" - Nam Lê Quý
6个回答

38
有一个提案(处于第一阶段)支持它:https://github.com/nicolo-ribaudo/proposal-optional-chaining-assignment
很抱歉,这是不可能的。
为了提供一个权威答案:MDN文档对此并没有明确说明,但你可以阅读GitHub上的提案README获取更多信息。它说道

尽管有一些使用情况,但以下内容不受支持;请参考Issue #18进行讨论:

  • 可选属性赋值:a?.b = c
在相关问题中的评论如下1

好的,在这个帖子中似乎已经达成了初步共识,第一次迭代不会处理写入的情况。

而且2

我们在TC39也讨论过这个问题,委员会似乎对添加这个功能不太感兴趣。

所以我猜这个功能不太可能很快实现。

希望能帮到你,祝好运!


8

我自己也在研究这个问题,但遗憾的是,正如其他评论者已经指出的那样,在撰写本文时,使用可选链进行赋值似乎在TypeScript中是不可能实现的,这确实会导致解析器警告:

赋值表达式的左侧不能是可选属性访问。

当尝试类似于以下代码时:

class A{
    b?: string;
}

var a = new A();
a?.b = "foo";

但是由于有时候可选的任务很有用,因此仍然可以使用旧式单行if查询的方法:

class A{
    b?: string;
}

try{a.b = "foo0"} // throws TypeError
catch(e){console.log(e.toString())} // a is undefined

if(a) a.b = "foo1"; // skips
console.log(a); // a is undefined

var a: any;
if(a) a.b = "foo2"; // skips
console.log(a); // a is undefined

a = null;
if(a) a.b = "foo3"; // skips
console.log(a); // a is null

a = undefined;
if(a) a.b = "foo4"; // skips
console.log(a); // a is undefined

a = new A();
if(a) a.b = "foo5"; // runs
console.log(a); // a is A: {"b": "foo5"}

if(null) console.log("bar0"); // skips
if(undefined) console.log("bar1"); // skips
if({}) console.log("bar2"); // runs
if({something: "there"}) console.log("bar3"); // runs
if([]) console.log("bar4"); // runs
if(["not empty"]) console.log("bar5"); // runs

为了演示一个实际可行的例子,这里是一段 Kotlin 代码片段:

要演示一个确实可以的例子,这里是一个 Kotlin 代码片段:

class A{
    var b: B? = null;
    var title: String? = null;
    override fun toString():String = "Instance of class A with title: ${this.title} and b of value: ${this.b.toString()}";
}

class B{
    var title: String? = null;
    override fun toString():String = "Instance of class B with title: ${this.title}";
}

fun main() {
    var a:A? = null;
    println(a); // null
    
    try{a!!.title = "foo0"} catch(e:Exception){println(e)} // NPE
    
    a?.title = "foo1";
    println(a); // null
    
    a = A();
    println(a); // Instance of class A with title: null and b of value: null
    
    a?.title = "foo2";
    println(a); // Instance of class A with title: foo2 and b of value: null
    
    try{a!!.b!!.title = "bar0"} catch(e:Exception){println(e)} // NPE
    
    a?.b?.title = "bar1";
    println(a); // Instance of class A with title: foo2 and b of value: null
    
    a?.b = B();
    println(a); // Instance of class A with title: foo2 and b of value: Instance of class B with title: null
    
    a?.b?.title = "bar2";
    println(a); // Instance of class A with title: foo2 and b of value: Instance of class B with title: bar2

    a?.b?.let{it.title = "bar3"}
    println(a); // Instance of class A with title: foo2 and b of value: Instance of class B with title: bar3
}

我并不是在争论哪种语言比另一种更好,而是不同的目的和哲学需要不同的设计选择,这些选择决定了工具的形状,最终任何编程或脚本语言都是如此。同时我也有点生气,因为我无法在 TypeScript 中给一个可选链赋值。

编辑:我使用了以下这些Playground网站来测试这些内容:


3
现在还不可能,但你可以尝试其他方法。
例如1:
let a = {x: {y: {z: 2}}} as {x?: {y?: {z?: number}}};
a?.x?.y?.z ? a.x.y.z = 1 : null;

例2:使用lodash

let a = {}
_.set(a, 'x.y.z', 1);
_.get(a, 'x.y.z');

0
我在Chrome Canary上尝试过这个(因为浏览器兼容性),但它没有起作用: 输入图像描述

3
无论在哪里都不行,这不是规范的一部分。 - Kewin Dousse

0
不,这是不可能的。 文档清楚地说明了

可选链操作符?.允许读取连接对象链中深处的属性值,而无需明确验证链中每个引用是否有效。


0
不,但你可以做以下的事情:
(((building ?? {}).floor ?? {}).apartment ?? {}).number = 3;

将会将分配还原为临时对象,如果导致它的所有对象实际上不存在,则会有效地丢弃该分配。
请注意,右侧将始终执行,即使左侧是临时的。为了避免这种情况,请在分配之前使用条件。
if (building?.floor?.apartment)
    building.floor.apartment.number = 3;

(该条件假设公寓存在的话,必须是一个对象...)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接