乐趣区

关于javascript:在JavaScript中给函数调用的参数是一个值而不是一个引用

思考的问题:为什么他能够工作以及他是如何工作的,为什么他能够工作

function getLogger(arg){function logger(){console.log(arg)
   }
    return logger
}

let fruit='raspberry'
const logFruit=getLogger(fruit)

logFruit() // 'raspberry'
fruit='peach'
logFruit()// 'raspberry'  这里打印进去的内容为什么不是 peach  大家心里有这个纳闷吗 

首先,来说下下面这个代码块的执行产生了什么,我建设一个 fruit 的变量并且给他赋值了 ’rasberry’, 而后我传递给此函数,在创立并返回一个名字叫 logger,当其被调用时会打印出 fruit 这个变量的函数。我首次调用这个函数,咱们能够看到控制台打印出咱们所期待的 ’rapberry’ 值。


然而当我给 fruit 变量从新赋值为 ’peach’,而后再次调用 logger 函数时。然而控制台 log 进去的数据不是我刚刚赋的新值,而是一个之前第一次赋的值。


我能够解决这问题,咱们能够再次调用 getLogger 这个函数失去一个新的 logger:

const LogFruit2=getLogger(fruit)
logFruit2()  // 'peach'

然而为什么我只能是扭转变量的值并且失去一个新的 logger 函数后能力 log 出一个最新的值?


起因是在 JavaScript 中,当你调用一个带有参数的函数时。这个参数会被当做是一个 value 传递,不是一个援用。上面用代码来简略的形容这里到底是如何运行的:

function getLogger(arg){function logger(){console.log(arg)
  }
  return logger
}

当 getLogger 函数被调用时,这个 logger 的函数被创立了。他就是一个新的函数,当一个新的函数被创立时,这个看起来所有可能拜访的变量造成一个敞开的状态这样局势被称为一个闭包。这象征只有这个 logger 函数存在,他将拜访到变量在他的父级函数或者其余模块级别的函数变量。


因而什么变量 logger 函数被创立之后就可能被拜访?咱们再来看一下这个例子,它可能拜访到 fruit,getLogger,arg 和 logger,这些变量对于代码为何是如此运行有着至关重要的作用。你能够发现,arg 和 fruit 都被列举进去了,只管他们是一样的值。


只是因为两个变量都被赋上雷同的值,然而并不意味着他们是同一个变量。上面是一个简略的的例子对于这个概念:

let a=1
let b=a
console.log(a,b) // 1,1
a=2
console.log(a,b) //2 1

留神到只管咱们将变量 b 指向一个变量 a 的值,咱们能够试着去扭转变量 a 而变量 b 的指针指向却不会扭转。这是因为咱们不能将变量 b 指向 a 自身,咱们只是将变量 b 过后的值指向了变量 a


我更偏向认为变量是一个指向电脑内存区域的一个指针标记。因而当咱们写下 let a =1 时,其实就是:你好 JavaScript 引擎,我想要创立一块内存用于存储这个值为 1 而后创立了一个指向对应内存地位的指针 a。
然而当咱们写下 let b =a,就相当于在通知 js 引擎,此刻我想要创立一个名叫 b 的指针指向与 a 指针指向同一块内存区域。
也就是说,当咱们调用一个函数时,js 引擎将会创立一个新的变量为了函数的参数。在下面提到的例子中,咱们调用了 getLogger(fruit),而后 js 引擎基本上做了如下的操作。


let arg = fruit

因而当咱们之后对于 fruit 从新赋值为 peach 的时候,它并不会有任何的影响对于 arg 参数而言,因为他们两个是一个齐全不同的变量。


无论你认为只是一种限度还是一个性能,实际上这是他的一种工作形式。如果你想要放弃这两个变量实时的相互彼此更新,上面这种形式能够做到这一点。咱们能够扭转变量指向地位,而不是去扭转指针,如下:

let a={current:1}
let b=a
console.log(a.current,b.current) //1 1
a.current=2
console.log(a.current,b.current) //2 2

在下面这个例子中,咱们并没有给 a 从新赋值,而是扭转变量 a 所指向的值。而且因为恰好变量 b 是指向同一个对象,所以他们都会一起更新。
因而,咱们能够利用这个计划解决 logger 函数 log 值的问题:

function getLastestLogger(argRef){function logger(){console.log(argRef)
  }
  return logger
}
const fruitRef={current:'raspberry'}
const latestLogger=getLastestLogger(fruitRef)

latestLogger()// 'raspberry'

fruitRef.current='peach'
latestLogger() //'peacch'

这个 Ref 的后缀对于援用单词的缩写,也就是变量的值只是用来援用另一个值(然而在咱们的例子当中,current 只是一个对象的属性)。


论断

这是一个利弊衡量的问题,然而很快乐 JavaScript 的标准规范更偏向于传递值而不是一个援用对象在调用函数时。然而这个解决办法也不是很麻烦,当你真正有需要的时候 (这个其实是十分常见,因为可变性和动态性将会使得程序变得难以了解)。

写在最初

本文翻译与外国认为开发工程师的文章,如有不正确的中央,欢送斧正。
原文地址

退出移动版