[软件构造] reading 2: basic typescript

reading 2: basic typescript

快照图,同一语句有多种详细程度的表现形式,根据要求灵活选择。

双圈箭头表示此变量是const, 双圈对象表示此对象是immutable。

 

变量s 被定义为string类型,其值为"abc"。实际这是定义了一个变量s,s指向一个string对象"abc",这个"abc"对象是immutable的,也就是说这个对象永远是"abc",其内容不能改变。

s.concat("123")调用了string对象中的concat方法,这个方法创建了一个新字符串("abc123"),并且返回这个字符串。但是,之前已有的字符串"abc"不会被这个concat方法的调用影响到,因为string是immutable的。

而且,由于并没有一个变量来接收concat方法的返回值,此方法新创建的字符串"abc123",在被创建后就被丢弃了。

综上,s.concat("123") 语句没有改变变量s 或 "abc"对象的内容。(变量s的内容可以看作它指向的东西,它指向哪里没有变,指向的对象"abc"本身也没有变。)

 

reassigning a parameter inside a method does not reassign a variable in the caller. Here, reassigning n does not reassign i. The only way to communicate back to the caller through a parameter is to mutate the object that the parameter points to.

关于call-by-value的阅读材料:

This kind of parameter-passing behavior is referred to as call-by-value, because the parameter receives an initial value from the caller, but then the parameter can be freely reassigned without affecting the caller. Most programming languages, not only TypeScript/JavaScript but also Python, Java, and C, use exclusively call-by-value. A few languages, notably C++ and C#, also offer call-by-reference semantics, where the parameter n could become an alias for the passed-in variable i, so that reassigning n also reassigns i. But this is unusual; call-by-value is by far the norm.

我的解析:执行f前,为:

t:"a"

tarr:["a"]

执行f后,由于是按值调用,t、tarr不变。

t:"a"

tarr:["a"] // 错误原因是简单地认为按值调用就是开一个副本,原来的数据和副本互不相通,对副本的操作完全不影响。没有深刻理解immutable和mutable带来的差异。

答案:

解析:

初始化:

Let’s run through the execution of this larger example, using snapshot diagrams to visualize what’s going on. It’s good to form pictures like this in your head when you’re mentally executing code.

let t:string = "a" declares a new variable t that points to a string object "a". This object is immutable, it will always represent the character sequence "a".

let tarr:Array<string> = [t] declares a new variable tarr that points to a new array value, whose first element points to the current value of t, specifically "a". This array object is mutable, so it might change its value internally when methods are later called on it.

f函数:

f(t, tarr) calls the function f and instantiates new parameter variables s and arr pointing to the string and array object values that we passed, respectively. Now we enter the body of f.

s.concat("b") calls the concatmethod on the string object. As in the 1st exercise in this sequence, the method creates a fresh string object for "ab" and returns it, but that return value is not assigned to anything, and the new object is discarded. Strings are immutable, so the existing string "a" cannot be affected by this method call, and this statement has no effect on any of the existing variables or objects.

注意这里按值调用的实质:并不是创建一个变量和一个新的对象(和原来对象值相同),而是创建一个新的变量,指向原来那个对象。其实这里的“按值调用”更类似于C语言中的传递地址+写权限的有无:新建一个指针,指向原来的地址,通过设置属性为immutable或mutable来决定写权限的有无。若无写权限,则在别处开辟一块新空间,写入新的数据;若有写权限,则直接修改相应地址处的数据。

总结:如果指向的对象是immutable,那么在调用到可能会修改对象值的方法时,保留原来的对象不变,创建一个新的经方法修改后的对象,并让原来的变量指向这个新的对象。而如果是mutable,在碰到可能会修改对象值的方法时,会直接修改这个对象。

s+="c":

s += "c" implicitly calls concat to produce a fresh string object with "ac", and then assigns it to s. The variable t is not affected by this assignment.

由于string是immutable,s+="c"时,调用到可能会修改对象值的方法时,保留原来的对象不变,创建一个新的经方法修改后的对象,并让原来的变量指向这个新的对象。

arr.push("d"):

arr.push("d") calls the push method on the array object, and as we saw in the previous section, this method mutates the array object to add a new element "d". The variabletarris affected by this assignment, because it points to the object that was mutated.

Now we return from the method call, and examine the values of t and tarr, to find that t still points to the original string "a", while tarr points to the original array object, whose contents are now ["a","d"].

As in the 2nd exercise in this sequence, reassigning a parameter inside a method does not reassign a variable in the caller. Here, reassigning s does not reassign t. But we can mutate the object that the parameter points to, and that is how arr affected tarr.

由于Array是mutable,在arr.push("d")时,会直接修改这个对象。

迭代时,加const,防止在循环体执行过程中循环变量的值被不小心改变了。

posted @ 2022-05-30 21:08  Matrix_250  阅读(30)  评论(0编辑  收藏  举报