JavaScript中是否有指针?

82

我以前使用过C++,发现指针非常有用。在Javascript中是否有类似指针的东西?Javascript有指针吗?当我想要使用如下内容时,我喜欢使用指针:

var a = 1;
var b = "a";
document.getElementById(/* value pointed by b */).innerHTML="Pointers";

我知道这只是一个非常简单的例子,我可以直接使用a标签,但是在一些更复杂的例子中,我会发现指针非常有用。有什么建议吗?


6
嗯...一般情况下你不需要指针。你能否给出一个你遇到过指针有帮助的现实世界例子? - Ry-
可能是JavaScript中的指针?的重复问题。 - Dan Dascalescu
@Ry- 如果ab是引用的话,这是正确的 :) 我的意思是你不能在另一个函数中交换原始类型的值(比如数字),但是在C语言中你可以很容易地通过指针来实现。 - undefined
@EzioMercer:我的意思是没有函数的情况下。你可以用[a, b] = [b, a]来代替swap(a, b)。(不过,行为不取决于ab的内容。) - undefined
@Ry- 如果我表达不清楚,对不起。是的,我可以在任何地方写 [a, b] = [b, a]。我的意思是我不能在某个函数 swap 中写这个。例如,在 C 中,添加关于交换两个变量值的额外日志是没有成本的,但在 JS 中,每次交换两个变量的值时,我都必须在每个地方写这个额外的日志。 - undefined
显示剩余2条评论
7个回答

125

不,JS没有指针。

通过传递引用的副本来传递对象。程序员无法访问任何类似于C语言中表示对象地址的“值”。

在函数内部,可以通过该引用更改传递的对象的内容,但是您不能修改调用者拥有的引用,因为您的引用只是一份副本:

var foo = {'bar': 1};

function tryToMungeReference(obj) {
    obj = {'bar': 2};  // won't change caller's object
}

function mungeContents(obj) {
    obj.bar = 2;       // changes _contents_ of caller's object
}

tryToMungeReference(foo);
foo.bar === 1;   // true - foo still references original object

mungeContents(foo);
foo.bar === 2;  // true - object referenced by foo has been modified

1
什么是引用的副本,它是否可以像指针一样使用,我该如何使用它? - Dylan Vander Berg
3
参考是对象的名称,复制基本上是指向同一地址的新名称。 - Mataniko
“引用的副本” 占用多少内存?它基本上只是一个地址,指向实际对象的位置,还是会在内存中分配另一个空间来复制对象? - Frank
我认为在代码 var a = {}; var b = { c:a }; 中,可以安全地说 b.c 不持有 a 的副本,而是持有一个代表 a 在内存中位置的值。在这种情况下,会在内存中分配三个空间:一个类型为 Object 的 a,一个类型为 Object 的 b,以及一个类型为 Int 的 b.c,它保存着 a 在内存中的位置值。 - Frank
3
即使对象是通过传递引用的副本来传递的,它仍然被认为是指针吗?不是我们直接访问它的指针,而是指它是一个对对象内存位置的引用,JavaScript确实具有这种引用。也许重新构造第一句会更好,改成"不,JS没有类似于C的指针"之类的话可能更好一些。 因为从技术上讲,在JS中对象仍然是指针。那函数指针/引用呢? - Aeternus
显示剩余2条评论

63

当然有指针在JavaScript中;对象就是指针。

//this will make object1 point to the memory location that object2 is pointing at
object1 = object2;

//this will make object2 point to the memory location that object1 is pointing at 
function myfunc(object2){}
myfunc(object1);

如果一个内存位置不再被指向,那里的数据就会丢失。

与C语言不同,你无法看到指针的实际地址或实际值,只能对其进行解引用(获取它所指向地址上的值)。


1
Javascript在传递对象到函数方面有点有趣。如果函数一次只更改一个对象成员,则是按引用传递。但是,如果您尝试使用花括号完全更改对象,则似乎是按值传递。我猜这是因为Javascript自动认为您在创建新对象时使用= {...},基本上是创建一个具有与参数相同名称的局部变量。 - user3015682
1
实际上,这并不是关于创建一个新对象,正如你明确所说的那样。我学到的是始终传递引用:当你执行objX = {..}时,你实际上是将引用传递给一个新创建的对象。当你执行objX = objY时,你传递的是对已经存在的objY对象的引用。但是,=操作符始终传递右侧对象所在地址(无论它是新创建的还是已经存在的——赋值运算符的右侧先解析)。 - Tyler
6
不,JavaScript 是按值传递而不是按引用传递。JavaScript 在底层确实有“指针”。指针只是存储对象地址的变量。它们按值传递。因此,您可以修改指向的对象,但无法通过将其传递到函数来强制对象指向其他内容。 - Aleksandr Hovhannisyan
1
这些最多只是伪指针。无法将它们用作对象的键,而这将非常有帮助。 - Eggon
1
许多人似乎混淆指针和引用的概念。引用只是相同内存地址的别名。指针是保存实际对象内存地址(或类似标识符)的变量。即使您无法显式访问指针中存储的地址/标识符,也并不意味着它们不是指针。 - tweekz
显示剩余3条评论

6

我刚做了一件奇怪的事情,但它也很有效。

与其传递指针,不如传递一个函数,将其参数填入目标变量中。

var myTarget;

class dial{
  constructor(target){
    this.target = target;
    this.target(99);
  }
}
var myDial = new dial((v)=>{myTarget = v;});

看起来可能有点奇怪,但效果还不错。在这个例子中,我创建了一个通用的旋钮,可以通过这个小函数“(v)=>{target = v}”指定任何目标。不知道它在性能方面表现如何,但它的操作非常流畅。


3
由于JS传递对象的性质,如果引用的对象被完全更改,则按值传递(只传递值),如果引用对象的字段被更改,则按引用传递。因此,无法完全替换引用对象。
但是,让我们利用现有的东西:替换引用对象的单个字段。通过这样做,以下函数可以实现您所要求的功能:
“由于JS传递对象的性质,如果引用的对象被完全更改,则按值传递(只传递值),如果引用对象的字段被更改,则按引用传递。因此,无法完全替换引用对象。
但是,让我们利用现有的东西:替换引用对象的单个字段。通过这样做,以下函数可以实现您所要求的功能:”将原始答案替换为“最初的回答”。
function replaceReferencedObj(refObj, newObj) {
    let keysR = Object.keys(refObj);
    let keysN = Object.keys(newObj);
    for (let i = 0; i < keysR.length; i++) {
        delete refObj[keysR[i]];
    }
    for (let i = 0; i < keysN.length; i++) {
        refObj[keysN[i]] = newObj[keysN[i]];
    }
}

对于用户3015682提供的示例,您可以按如下方式使用此函数:

Original Answer翻译成:“最初的回答”

replaceReferencedObj(foo, {'bar': 2})

0

引用赋值和数组。

let pizza = [4,4,4];
let kebab = pizza;  // both variables are references to shared value
kebab.push(4);
console.log(kebab); //[4,4,4,4]
console.log(pizza); //[4,4,4,4]

由于原始值未被修改,因此不会创建新的引用。

kebab = [6,6,6,6];  // value is reassigned
console.log(kebab); //[6,6,6,6]
console.log(pizza); //[4,4,4,4]

当变量中的复合值被重新分配时,会创建一个新的引用。


0
是的,事实上,所有的对象和数组都是指针。 如果我必须按照你的例子字面意思来理解的话,那么你只需要将变量转换为对象类型即可,例如。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pointers</title>
</head>
<body>
    <h1>Asynchronous JavaScript</h1>

<!--the pointer with class b--->
    <p>Our City</p>
    <p id="variableA" >Minnesota</p>

    <script src="pointers.js" ></script>
</body>
</html>

然后是 pointers.js 文件:
var a = {name: "todos", data: {pointerOne: 'Minnesota', pointerTwo: 'NewYork'}};
var b = a;//pointer to a

setTimeout(()=>{
//using timeout to see our pointer at work!

b.data.pointerOne = 'Nairobi';
document.getElementById('variableA').innerHTML = a.data.pointerOne;

}, 3000);

JavaScript的主要区别在于指针的表示方式,或者说没有直接的方法来标识指针。在C、Golang和C#中,使用'&'运算符来创建指针。
这是基础。在理解了这个概念之后,你可以进一步发展成函数指针、链表,或者像结构体一样使用它;并且以C++的方式来编写JavaScript。 不过,我建议你在命名变量时使用当前的JavaScript约定。 即:
const a = {name: "todos", data: {pointerOne: 'Minnesota', pointerTwo: 'NewYork'}};
const b = a;//pointer to a

-8

从技术上讲,JS没有指针,但我发现了一种模仿它们行为的方法 ;)

var car = {
    make: 'Tesla',
    nav: {
       lat: undefined,
       lng: undefined
    }
};

var coords: {
    center: {
       get lat() { return car.nav.lat; }, // pointer LOL
       get lng() { return car.nav.lng; }  // pointer LOL
    }   
};

car.nav.lat = 555;
car.nav.lng = 777;

console.log('*** coords: ', coords.center.lat); // 555
console.log('*** coords: ', coords.center.lng); // 777

8
你只需要返回 car 的属性。这与指针或模拟无关,被称为“作用域”。 - Dimitri L.
1
从技术上讲,JS只是指针。但是你只能取消引用它们,而不能操作指针本身。 - RickyA

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