การอ้างอิงตัวแปร javascript / นามแฝง


89

เป็นไปได้ไหมใน javascript ที่จะกำหนดนามแฝง / การอ้างอิงให้กับ local var someway?

ฉันหมายถึงสิ่งที่เหมือน C:

function foo() {
  var x = 1;
  var y = &x;
  y++;
  alert(x); // prints 2 
}

= แก้ไข =

เป็นไปได้ไหมที่จะใช้นามแฝง arguments.callee ในรหัสนี้:

function foo() {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 0;
  arguments.callee.myStaticVar++;
  return arguments.callee.myStaticVar;
}

5
คำตอบง่ายๆคือไม่ แต่ฉันรู้สึกว่ามีคนใน SO จะมาแฮ็คเพื่อทำสิ่งนี้ :)
Amarghosh

คำตอบ:


173

ใน JavaScript ประเภทดั้งเดิมเช่นจำนวนเต็มและสตริงจะถูกส่งผ่านโดยค่าในขณะที่ออบเจ็กต์ถูกส่งผ่านโดยการอ้างอิง ดังนั้นเพื่อให้บรรลุสิ่งนี้คุณต้องใช้วัตถุ:

// declare an object with property x
var obj = { x: 1 };
var aliasToObj = obj;
aliasToObj.x ++;
alert( obj.x ); // displays 2

นั่นเร็ว =) ฉันต้องการสร้างนามแฝงให้กับ arguments.callee ในฟังก์ชันของฉัน (เพื่อหลีกเลี่ยงการพิมพ์ arguments.callee ทุกครั้ง) วิธีนี้เป็นไปได้หรือไม่ ถ้าฉันเข้าใจฉันสามารถใช้นามแฝงว่า "อาร์กิวเมนต์" ได้ แต่ฉันก็ยังต้องเขียน "callee" อยู่ดีใช่ไหม
gpilotino

9
@ ดาริน: นี่มันเกินไปหน่อย เป็นประเภทที่ไม่เปลี่ยนรูปและไม่สามารถเปลี่ยนแปลงได้แทนที่จะเป็นประเภทดั้งเดิมเทียบกับวัตถุ ใน JavaScript ทุกอย่างเป็นวัตถุในบางรูปแบบ
Crescent Fresh

7
ใน JS การอ้างอิงจะถูกส่งผ่านด้วยค่า มีความแตกต่างระหว่าง "การส่งผ่านโดยการอ้างอิง" และ "การส่งผ่านการอ้างอิงโดยค่า" ใน Javascript การส่งผ่านพารามิเตอร์โดยการอ้างอิงไม่ได้รับการสนับสนุน
Corneliu

15

ในระดับหนึ่งคุณสามารถสร้างนามแฝงให้กับตัวแปรโดยใช้การปิด:

Function.prototype.toString = function() {
    return this();
}

var x = 1;
var y = function() { return x }
x++;
alert(y); // prints 2, no need for () because of toString redefinition 

1
ฉันเชื่อว่า "alert (y); // พิมพ์ 2" ควรเป็น: "alert (y ()); // พิมพ์ 2" คุณต้องเรียกใช้ฟังก์ชันเพื่อให้ได้ผลลัพธ์ แย่มากเนื่องจากไวยากรณ์ที่แนะนำจะเป็นประโยชน์ในบางสถานการณ์
Nathan Labenz

3
คำจำกัดความใหม่ของ toString นั้นมีเหตุผลดังนั้นจึงalert(y)ถูกต้อง แม้ว่าการกำหนดวิธีการต้นแบบฟังก์ชันใหม่จะเป็นรูปแบบที่แย่มาก แต่เดี๋ยวก่อนมันได้ผล!
metalim

8

คุณสามารถใช้นามแฝงบางอย่างได้หรือไม่นั้นขึ้นอยู่กับประเภทข้อมูล ออบเจ็กต์อาร์เรย์และฟังก์ชันต่างๆจะได้รับการจัดการโดยการอ้างอิงและการใช้นามแฝงเป็นไปได้ ประเภทอื่น ๆ เป็นพื้นฐานของปรมาณูและตัวแปรจะเก็บค่ามากกว่าการอ้างอิงถึงค่า

arguments.callee เป็นฟังก์ชันดังนั้นคุณสามารถมีการอ้างอิงและแก้ไขอ็อบเจ็กต์ที่แชร์นั้นได้

function foo() {
  var self = arguments.callee;
  self.myStaticVar = self.myStaticVar || 0;
  self.myStaticVar++;
  return self.myStaticVar;
}

โปรดทราบว่าถ้าในโค้ดข้างต้นคุณจะพูดself = function() {return 42;};แล้วselfก็จะหมายถึงวัตถุที่แตกต่างกันกว่าซึ่งยังคงมีการอ้างอิงถึงarguments.callee fooเมื่อคุณมีวัตถุผสมตัวดำเนินการกำหนดจะแทนที่การอ้างอิงโดยจะไม่เปลี่ยนวัตถุที่อ้างอิง ด้วยค่าอะตอมเคส like y++จะเทียบเท่ากับy = y + 1ซึ่งกำลังกำหนดจำนวนเต็ม 'ใหม่' ให้กับตัวแปร


ไม่ต้องพูดถึงว่าarguments.calleeมีนามแฝงอยู่แล้วซึ่งเป็นชื่อของฟังก์ชัน ในตัวอย่างนี้คุณสามารถใช้ได้foo.myStaticVar(อาจจะไม่ใช่กรณีย้อนกลับไปในปี 2009?)
aljgom


1

แก้ไขคำตอบก่อนหน้าของฉัน: หากคุณต้องการนับการเรียกใช้ฟังก์ชันคุณอาจต้องการลอง:

var countMe = ( function() {
  var c = 0;

  return function() {
    c++;
    return c;
  }
})();

alert(countMe()); // Alerts "1"
alert(countMe()); // Alerts "2"

ที่นี่ c ทำหน้าที่เป็นตัวนับและคุณไม่จำเป็นต้องใช้ arguments.callee


หรือคุณสามารถใช้ตัวแปรคงที่ countMe = function f(){ return ++f.c || (f.c = 1); }
aljgom

1

ในปี 2019 ฉันจำเป็นต้องเขียนปลั๊กอิน jquery ที่ย่อขนาดดังนั้นฉันจึงต้องการมันด้วยนามแฝงนี้ดังนั้นการทดสอบตัวอย่างเหล่านี้และอื่น ๆ จากแหล่งอื่น ๆ ฉันพบวิธีที่ไม่มีการคัดลอกในหน่วยความจำของวัตถุทั้งหมด แต่สร้างเฉพาะข้อมูลอ้างอิงเท่านั้น ฉันทดสอบสิ่งนี้แล้วกับ firefox และดูหน่วยความจำแท็บของตัวจัดการงานบน firefox มาก่อน รหัสคือ:

var {p: d} ={p: document};
console.log(d.body);

สิ่งนี้ไม่ผ่านการอ้างอิงใด ๆ คุณสามารถส่งผ่านเอกสารได้โดยตรง (ซึ่งเป็นการอ้างอิงถึงวัตถุอยู่แล้วและถูกส่งผ่านด้วยค่า) การทำลายโครงสร้างไม่ได้สร้างนามแฝง
จำ Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.