ตัวแปรสแตติกใน JavaScript


716

ฉันจะสร้างตัวแปรสแตติกใน Javascript ได้อย่างไร


เราสามารถกำหนดป้ายกำกับหรือแท็ก html อื่น ๆ ด้วยแอตทริบิวต์สไตล์ "dispaly: none" และตั้งค่าตัวแปรสำหรับค่านี้และการดำเนินการกับค่านี้ อย่าเอาแรง
asghar

ทางออกที่ง่ายที่สุดที่ฉันพบ: ไม่ได้กำหนดตัวแปรแบบคงที่ในคลาสเลย someFunc = () => { MyClass.myStaticVariable = 1; }เมื่อคุณต้องการที่จะใช้ตัวแปรคงที่เพียงแค่กำหนดมันมีแล้วเช่น static getStatic() { return MyClass.myStaticVariable; }จากนั้นเพียงแค่สร้างวิธีการแบบคงที่จะกลับสมาชิกคงเช่น จากนั้นคุณสามารถโทรMyClass.getStatic()จากนอกห้องเรียนเพื่อรับข้อมูลคงที่!
Pixel

คำตอบ:


863

หากคุณมาจากภาษาเชิงวัตถุที่เน้นประเภทคลาส(เช่น Java, C ++ หรือ C #)ฉันคิดว่าคุณกำลังพยายามสร้างตัวแปรหรือวิธีการที่เกี่ยวข้องกับ "ประเภท" แต่ไม่ใช่อินสแตนซ์

ตัวอย่างการใช้วิธี "แบบคลาสสิก" ด้วยฟังก์ชั่นคอนสตรัคเตอร์อาจช่วยให้คุณได้รับแนวคิดของ OO JavaScript พื้นฐาน:

function MyClass () { // constructor function
  var privateVariable = "foo";  // Private variable 

  this.publicVariable = "bar";  // Public variable 

  this.privilegedMethod = function () {  // Public Method
    alert(privateVariable);
  };
}

// Instance method will be available to all instances but only load once in memory 
MyClass.prototype.publicMethod = function () {    
  alert(this.publicVariable);
};

// Static variable shared by all instances
MyClass.staticProperty = "baz";

var myInstance = new MyClass();

staticPropertyถูกกำหนดไว้ในวัตถุ MyClass (ซึ่งเป็นฟังก์ชั่น) และไม่มีส่วนเกี่ยวข้องกับอินสแตนซ์ที่สร้างขึ้น JavaScript จะถือว่าฟังก์ชั่นเป็นวัตถุชั้นหนึ่งดังนั้นในฐานะที่เป็นวัตถุคุณสามารถกำหนดคุณสมบัติให้กับฟังก์ชันได้

UPDATE: ES6 แนะนำความสามารถในการประกาศคลาสผ่านclassคีย์เวิร์ด เป็นซินแท็กซ์น้ำตาลที่สืบทอดมาจากต้นแบบที่มีอยู่เดิม

staticคำหลักที่ช่วยให้คุณสามารถกำหนดคุณสมบัติคงที่หรือวิธีการในชั้นเรียน

มาดูตัวอย่างด้านบนที่ใช้กับคลาส ES6:

class MyClass {
  // class constructor, equivalent to
  // the function body of a constructor
  constructor() {
    const privateVariable = 'private value'; // Private variable at the constructor scope
    this.publicVariable = 'public value'; // Public property

    this.privilegedMethod = function() {
      // Public Method with access to the constructor scope variables
      console.log(privateVariable);
    };
  }

  // Prototype methods:
  publicMethod() {
    console.log(this.publicVariable);
  }

  // Static properties shared by all instances
  static staticProperty = 'static value';

  static staticMethod() {
    console.log(this.staticProperty);
  }
}

// We can add properties to the class prototype
MyClass.prototype.additionalMethod = function() {
  console.log(this.publicVariable);
};

var myInstance = new MyClass();
myInstance.publicMethod();       // "public value"
myInstance.additionalMethod(); // "public value"
myInstance.privilegedMethod(); // "private value"
MyClass.staticMethod();             // "static value"


5
สันนิษฐานว่าprivilegedMethodไม่เทียบเท่ากับวิธีการส่วนตัวใน OO เพราะดูเหมือนว่าจะสามารถเรียกใช้ในอินสแตนซ์ของ MyClass ได้? คุณหมายความว่าเป็นสิทธิพิเศษเพราะสามารถเข้าถึงได้privateVariableหรือไม่
Dónal

3
ไม่this.constructorสามารถใช้เพื่อเข้าถึงตัวแปรคงที่จาก "วิธีการแบบอินสแตนซ์" ได้หรือไม่ ถ้าใช่มันคุ้มค่าที่จะเพิ่มเข้าไปในคำตอบ
Ciro Santilli 冠状病毒审查六四事件法轮功

1
คุณสามารถพูดถึงฟังก์ชั่นคงที่ในตัวอย่างของคุณ
David Rodrigues

18
สวัสดีฉันไม่แน่ใจว่าฉันเห็นด้วยกับบรรทัดนี้ // ตัวแปรแบบคงที่ที่ใช้ร่วมกันโดยอินสแตนซ์ทั้งหมด 'MyClass.staticProperty = "baz";' สำหรับฉันที่ infers ที่คุณสามารถหา baz จาก 'myInstance.staticProperty' ซึ่งแน่นอนคุณไม่สามารถ
fullstacklife

5
บางทีมันควรจะอ่านMyClass.prototype.staticProperty = "baz";หรือแก้ไขเพิ่มเติมให้ถูกต้องตามหลักการ OO คุณสมบัติคงที่ควรถูกกำหนดให้เป็นฟังก์ชั่นที่ไม่ระบุชื่อMyClass.prototype.staticProperty = function () {return staticVar;}และเพื่อให้ทุกกรณีเข้าถึงตัวแปรเดียวซึ่งสามารถเปลี่ยนแปลงได้ด้วย setter
lindsaymacvean

535

คุณอาจใช้ประโยชน์จากความจริงที่ว่าฟังก์ชั่น JS ยังเป็นวัตถุ - ซึ่งหมายความว่าพวกเขาสามารถมีคุณสมบัติ

ตัวอย่างเช่นการอ้างถึงตัวอย่างที่ให้ไว้ในบทความ (ตอนนี้หายไป) ตัวแปรคงที่ใน Javascript :

function countMyself() {
    // Check to see if the counter has been initialized
    if ( typeof countMyself.counter == 'undefined' ) {
        // It has not... perform the initialization
        countMyself.counter = 0;
    }

    // Do something stupid to indicate the value
    alert(++countMyself.counter);
}

หากคุณเรียกใช้ฟังก์ชันนั้นหลายครั้งคุณจะเห็นตัวนับกำลังเพิ่มขึ้น

และนี่อาจเป็นทางออกที่ดีกว่าการกำหนดเนมสเปซส่วนกลางด้วยตัวแปรโกลบอล


และนี่คือวิธีแก้ปัญหาอื่นที่เป็นไปได้โดยอ้างอิงจากการปิด: เคล็ดลับในการใช้ตัวแปรแบบคงที่ใน javascript :

var uniqueID = (function() {
   var id = 0; // This is the private persistent value
   // The outer function returns a nested function that has access
   // to the persistent value.  It is this nested function we're storing
   // in the variable uniqueID above.
   return function() { return id++; };  // Return and increment
})(); // Invoke the outer function after defining it.

สิ่งใดที่ทำให้คุณได้รับผลลัพธ์ชนิดเดียวกัน - ยกเว้นเวลานี้ค่าที่เพิ่มขึ้นจะถูกส่งคืนแทนที่จะแสดง


50
เป็นทางลัดคุณก็สามารถทำได้countMyself.counter = countMyself.counter || initial_value;ถ้าตัวแปรคงที่จะไม่เคยไปจะ falsey (false, 0, โมฆะหรือสตริงว่างเปล่า)
กีบ

3
สั้นและชัดขึ้นเล็กน้อย: (function () {var id = 0; function uniqueID () {return id ++;};}) ()
Tom Robinson

3
ตัวนับการปิดจะเร็วกว่าในชั้นเรียนใน Firefox jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos

ใช้===สำหรับการtypeofตรวจสอบอื่นคุณจะได้รับการข่มขู่แปลก ๆ เกิดขึ้น
น้ำค้าง

@SonySantos การทดสอบของคุณแสดงถึงสิ่งที่ตรงกันข้ามสำหรับ Firefox 40
bartolo-otrit

96

คุณทำผ่าน IIFE (ฟังก์ชั่นการแสดงออกทันที):

var incr = (function () {
    var i = 1;

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

incr(); // returns 1
incr(); // returns 2

21
ฉันจะบอกว่านี่เป็นวิธีที่ง่ายที่สุดใน JavaScript น่าเสียดายที่มันไม่ได้มี upvotes มากเกินไปด้วยวิธีการอื่น ๆ ที่น่าพอใจสำหรับคนที่มาจากภาษาอื่น

1
ฉันใช้ถ้อยคำใหม่โดยใช้ 'การปิด' มากกว่าแค่ 'IIFE'
zendka

39

คุณสามารถใช้ arguments.callee เพื่อเก็บตัวแปร "คงที่" (ซึ่งมีประโยชน์ในฟังก์ชั่นที่ไม่ระบุชื่อด้วย):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}

3
เท่าที่ฉันเข้าใจวิธีนี้มีข้อได้เปรียบเพียงทางเดียว (ทางเดียวเท่านั้น) เหนือปาสกาลมาร์ติน: คุณสามารถใช้มันกับฟังก์ชั่นนิรนาม ตัวอย่างนี้จะดีมาก
ด่าน

27
arguments.calleeเลิกใช้แล้ว
คำถามของ Quolonel

ฉันค่อนข้างเยาะเย้ย JS ตลอดเวลา แต่calleeดูเหมือนจะเป็นสิ่งที่ดี ฉันสงสัยว่าทำไมแฮ็คจึงตัดสินใจเลิกใช้สิ่งนี้ ... : |
user2173353

35

ฉันเห็นคำตอบที่คล้ายกันสองสามข้อ แต่ฉันต้องการพูดถึงว่าโพสต์นี้อธิบายได้ดีที่สุดดังนั้นฉันจึงต้องการแบ่งปันกับคุณ

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

นอกจากนี้ยังตอบคำถามของคุณ:

function Podcast() {

    // private variables
    var _somePrivateVariable = 123;

    // object properties (read/write)
    this.title = 'Astronomy Cast';
    this.description = 'A fact-based journey through the galaxy.';
    this.link = 'http://www.astronomycast.com';

    // for read access to _somePrivateVariable via immutableProp 
    this.immutableProp = function() {
        return _somePrivateVariable;
    }

    // object function
    this.toString = function() {
       return 'Title: ' + this.title;
    }
};

// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
    console.log('Downloading ' + podcast + ' ...');
};

จากตัวอย่างนั้นคุณสามารถเข้าถึงคุณสมบัติ / ฟังก์ชั่นแบบคงที่ดังต่อไปนี้:

// access static properties/functions
console.log(Podcast.FILE_EXTENSION);   // 'mp3'
Podcast.download('Astronomy cast');    // 'Downloading Astronomy cast ...'

และคุณสมบัติวัตถุ / ฟังก์ชั่นเพียงแค่เป็น:

// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString());       // Title: The Simpsons
console.log(podcast.immutableProp());  // 123

โปรดทราบว่าใน podcast.immutableProp () เรามีการปิด :การอ้างอิงถึง _somePrivateVariable จะถูกเก็บไว้ในฟังก์ชัน

คุณยังสามารถกำหนดgetters และ setters ดูตัวอย่างโค้ดนี้ (ซึ่งdเป็นต้นแบบของวัตถุที่คุณต้องการประกาศคุณสมบัติyเป็นตัวแปรส่วนตัวที่มองไม่เห็นนอกตัวสร้าง):

// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
    get: function() {return this.getFullYear() },
    set: function(y) { this.setFullYear(y) }
});

มันกำหนดคุณสมบัติd.yearผ่านgetและsetฟังก์ชั่น - ถ้าคุณไม่ได้ระบุsetคุณสมบัตินั้นเป็นแบบอ่านอย่างเดียวและไม่สามารถแก้ไขได้ (โปรดทราบว่าคุณจะไม่ได้รับข้อผิดพลาดหากคุณพยายามตั้งค่า แต่ไม่มีผล) สถานที่ให้บริการแต่ละคนมีคุณสมบัติwritable, configurable(อนุญาตให้มีการเปลี่ยนแปลงหลังจากการประกาศ) และenumerable(อนุญาตที่จะใช้เป็นตัวแจงนับ) falseซึ่งเป็นราคาต่อค่าเริ่มต้น คุณสามารถตั้งค่าผ่านทางdefinePropertyในพารามิเตอร์ที่ 3 enumerable: trueเช่น

สิ่งที่ถูกต้องก็คือไวยากรณ์นี้:

// getters and setters - alternative syntax
var obj = { a: 7, 
            get b() {return this.a + 1;}, 
            set c(x) {this.a = x / 2}
        };

ซึ่งกำหนดคุณสมบัติอ่าน / เขียนได้คุณสมบัติaอ่านได้อย่างเดียวbและคุณสมบัติเขียนอย่างเดียวcผ่านคุณสมบัติที่aสามารถเข้าถึงได้

การใช้งาน:

console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21

หมายเหตุ:

เพื่อหลีกเลี่ยงพฤติกรรมที่ไม่คาดคิดในกรณีที่คุณลืมnewคำหลักฉันแนะนำให้คุณเพิ่มสิ่งต่อไปนี้ในฟังก์ชั่นPodcast:

// instantiation helper
function Podcast() {
    if(false === (this instanceof Podcast)) {
        return new Podcast();
    }
// [... same as above ...]
};

ตอนนี้ทั้งสองอินสแตนซ์ต่อไปนี้จะทำงานตามที่คาดไว้:

var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast();     // you can omit the new keyword because of the helper

คำสั่ง 'ใหม่' สร้างวัตถุใหม่และคัดลอกคุณสมบัติและวิธีการทั้งหมดเช่น

var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"

โปรดทราบด้วยว่าในบางสถานการณ์การใช้returnคำสั่งในฟังก์ชั่น Constructor Podcastเพื่อส่งกลับฟังก์ชั่นการปกป้องวัตถุที่กำหนดเองนั้นจะต้องอาศัยคลาสภายในซึ่งต้องมีการเปิดเผย นี่คือคำอธิบายเพิ่มเติมในบทที่ 2 (วัตถุ) ของชุดบทความ

คุณสามารถพูดได้ว่าaและสืบทอดมาจากb Podcastทีนี้จะเกิดอะไรขึ้นถ้าคุณต้องการเพิ่มวิธีการในพอดคาสต์ที่ใช้กับพวกเขาทั้งหมดหลังจากนั้นaและbได้รับการเปิดตัวแล้ว? ในกรณีนี้ใช้.prototypeดังต่อไปนี้:

Podcast.prototype.titleAndLink = function() {
    return this.title + " [" + this.link + "]";
};

ตอนนี้โทรaและbอีกครั้ง:

console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"

คุณสามารถค้นหารายละเอียดเพิ่มเติมเกี่ยวกับต้นแบบที่นี่ หากคุณต้องการที่จะทำมรดกผมขอแนะนำให้มองเข้าไปในนี้


บทความชุดที่ผมได้กล่าวมาข้างต้นจะขอแนะนำให้อ่านพวกเขารวมถึงยังหัวข้อต่อไปนี้:

  1. ฟังก์ชั่น
  2. วัตถุ
  3. ต้นแบบ
  4. การบังคับใช้สิ่งใหม่บนฟังก์ชันตัวสร้าง
  5. hoisting
  6. การแทรกเครื่องหมายอัฒภาคอัตโนมัติ
  7. คุณสมบัติและวิธีการแบบคงที่

โปรดทราบว่า"คุณสมบัติ" การแทรกเครื่องหมายอัฒภาคอัตโนมัติของ JavaScript (ดังที่กล่าวไว้ใน 6) มักรับผิดชอบในการทำให้เกิดปัญหาที่แปลกในรหัสของคุณ ดังนั้นฉันค่อนข้างจะถือว่าเป็นข้อบกพร่องมากกว่าเป็นคุณสมบัติ

หากคุณต้องการอ่านเพิ่มเติมนี่เป็นบทความ MSDN ที่น่าสนใจทีเดียวเกี่ยวกับหัวข้อเหล่านี้บางหัวข้อที่อธิบายไว้มีรายละเอียดเพิ่มเติม

สิ่งที่น่าสนใจที่จะอ่านเช่นกัน (รวมถึงหัวข้อที่กล่าวถึงด้านบน) คือบทความเหล่านั้นจากคู่มือMDN JavaScript :

หากคุณต้องการทราบวิธีจำลองoutพารามิเตอร์c # (เหมือนในDateTime.TryParse(str, out result)) ใน JavaScript คุณสามารถค้นหาโค้ดตัวอย่างได้ที่นี่


ผู้ที่ทำงานกับ IE (ซึ่งไม่มีคอนโซลสำหรับ JavaScript ยกเว้นว่าคุณเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ที่ใช้F12และเปิดแท็บคอนโซล) อาจพบว่าข้อมูลโค้ดต่อไปนี้มีประโยชน์ อนุญาตให้คุณใช้console.log(msg);ตามที่ใช้ในตัวอย่างด้านบน เพียงแค่ใส่ก่อนPodcastฟังก์ชั่น

เพื่อความสะดวกของคุณนี่คือรหัสข้างต้นในตัวอย่างโค้ดเดี่ยวที่สมบูรณ์แบบ:


หมายเหตุ:

  • เคล็ดลับที่ดีคำแนะนำและข้อเสนอแนะเกี่ยวกับการเขียนโปรแกรม JavaScript ในทั่วไปที่คุณสามารถหาได้ที่นี่ (จาวาปฏิบัติที่ดีที่สุด)และมี ( 'var' กับ 'ให้') นอกจากนี้ยังแนะนำคือบทความนี้ เกี่ยวกับ typecasts นัย (บังคับ)

  • วิธีที่สะดวกในการใช้คลาสและคอมไพล์ลงใน JavaScript คือTypeScript นี่คือสนามเด็กเล่นที่คุณสามารถค้นหาตัวอย่างแสดงวิธีการทำงานของมัน แม้ว่าคุณจะไม่ได้ใช้ TypeScript ในขณะนี้คุณสามารถดูได้เพราะคุณสามารถเปรียบเทียบ TypeScript กับผลลัพธ์ JavaScript ในมุมมองแบบเคียงข้างกัน ตัวอย่างส่วนใหญ่นั้นเรียบง่าย แต่ก็มีตัวอย่างของ Raytracer ที่คุณสามารถลองใช้ได้ทันที ฉันขอแนะนำให้ดูเป็นพิเศษในตัวอย่าง "การใช้คลาส", "การใช้การสืบทอด" และ "การใช้ Generics" โดยการเลือกใน Combobox ซึ่งเป็นเทมเพลตที่ดีที่คุณสามารถใช้ใน JavaScript ได้ทันที typescript จะใช้กับเชิงมุม

  • เพื่อให้บรรลุการห่อหุ้มของตัวแปรท้องถิ่นฟังก์ชั่นอื่น ๆ ใน JavaScript ผมแนะนำให้ใช้รูปแบบดังต่อไปนี้ (JQuery ใช้เทคนิคเดียวกัน):

<html>
<head></head>
<body><script>
    'use strict';
    // module pattern (self invoked function)
    const myModule = (function(context) { 
    // to allow replacement of the function, use 'var' otherwise keep 'const'

      // put variables and function with local module scope here:
      var print = function(str) {
        if (str !== undefined) context.document.write(str);
        context.document.write("<br/><br/>");
        return;
      }
      // ... more variables ...

      // main method
      var _main = function(title) {

        if (title !== undefined) print(title);
        print("<b>last modified:&nbsp;</b>" + context.document.lastModified + "<br/>");        
        // ... more code ...
      }

      // public methods
      return {
        Main: _main
        // ... more public methods, properties ...
      };

    })(this);

    // use module
    myModule.Main("<b>Module demo</b>");
</script></body>
</html>

แน่นอนคุณสามารถ - และควร - ใส่รหัสสคริปต์ใน*.jsไฟล์แยกต่างหาก นี่เป็นเพียงการเขียนแบบอินไลน์เพื่อให้ตัวอย่างสั้น

ฟังก์ชั่นตัวเอง invocing (ยังเป็นที่รู้จักในฐานะ IIFE = Expression ฟังก์ชั่นเรียกทันที) จะอธิบายในรายละเอียดเพิ่มเติมได้ที่นี่


28
function Person(){
  if(Person.count == undefined){
    Person.count = 1;
  }
  else{
    Person.count ++;
  }
  console.log(Person.count);
}

var p1 = new Person();
var p2 = new Person();
var p3 = new Person();

28

คำตอบที่อัปเดต:

ในECMAScript 6คุณสามารถสร้างฟังก์ชั่นคงที่โดยใช้staticคำหลัก:

class Foo {

  static bar() {return 'I am static.'}

}

//`bar` is a property of the class
Foo.bar() // returns 'I am static.'

//`bar` is not a property of instances of the class
var foo = new Foo()
foo.bar() //-> throws TypeError

คลาส ES6 ไม่แนะนำความหมายใหม่ใด ๆ สำหรับสถิตศาสตร์ คุณสามารถทำสิ่งเดียวกันใน ES5 เช่นนี้:

//constructor
var Foo = function() {}

Foo.bar = function() {
    return 'I am static.'
}

Foo.bar() // returns 'I am static.'

var foo = new Foo()
foo.bar() // throws TypeError

คุณสามารถกำหนดให้กับคุณสมบัติของFooเพราะในฟังก์ชั่นจาวาสคริปต์เป็นวัตถุ


Foo.bar;ส่งคืนฟังก์ชั่นที่ได้รับมอบหมายไม่ใช่สตริงที่ส่งคืนโดยฟังก์ชันเนื่องจากความคิดเห็นของคุณหมายถึง

คุณสามารถเพิ่มข้อมูลเกี่ยวกับวิธีการตั้งค่า (เขียนทับ) ค่าคงที่ในตัวอย่างทั้งสองได้หรือไม่
Wilt

1
@ ทั้งสองกรณีคุณสมบัติ "คงที่" เป็นเพียงคุณสมบัติในฟังก์ชันดังนั้นคุณจึงตั้งค่าและเขียนทับเช่นเดียวกับคุณสมบัติอื่น ๆ ใน JavaScript ในทั้งสองกรณีคุณสามารถตั้งค่าbarคุณสมบัติFooเป็น3ดังนี้:Foo.bar = 3;
Max Heiber


16

ตัวอย่างและคำอธิบายต่อไปนี้มาจากหนังสือ JavaScript ระดับมืออาชีพสำหรับนักพัฒนาเว็บรุ่นที่ 2 โดย Nicholas Zakas นี่คือคำตอบที่ฉันกำลังมองหาดังนั้นฉันคิดว่ามันจะมีประโยชน์ที่จะเพิ่มที่นี่

(function () {
    var name = '';
    Person = function (value) {
        name = value;
    };
    Person.prototype.getName = function () {
        return name;
    };
    Person.prototype.setName = function (value) {
        name = value;
    };
}());
var person1 = new Person('Nate');
console.log(person1.getName()); // Nate
person1.setName('James');
console.log(person1.getName()); // James
person1.name = 'Mark';
console.log(person1.name); // Mark
console.log(person1.getName()); // James
var person2 = new Person('Danielle');
console.log(person1.getName()); // Danielle
console.log(person2.getName()); // Danielle

ตัวPersonสร้างในตัวอย่างนี้มีการเข้าถึงชื่อตัวแปรส่วนตัวเช่นเดียวกับวิธีการgetName()และ setName()เมื่อใช้รูปแบบนี้ตัวแปรชื่อจะเป็นแบบสแตติกและจะถูกใช้ในทุกกรณี ซึ่งหมายถึงการโทรหาsetName()อินสแตนซ์หนึ่งมีผลต่ออินสแตนซ์อื่นทั้งหมด การโทรsetName()หรือสร้างPersonอินสแตนซ์ใหม่ตั้งค่าตัวแปรชื่อเป็นค่าใหม่ สิ่งนี้ทำให้อินสแตนซ์ทั้งหมดส่งคืนค่าเดียวกัน


ดูนวกรรมิก + ต้นแบบ (ไฮบริด)
Ganesh Kumar

2
สิ่งนี้วางวัตถุบุคคลใน namespace ส่วนกลาง ไม่ใช่วิธีที่ฉันอยากจะแนะนำ
Ghola

ฉันไม่คิดว่านี่เป็นตัวแปรคงที่ที่แท้จริงเพราะมันถูกสร้างอินสแตนซ์ที่แตกต่างกับแต่ละวัตถุใหม่ วัตถุคงที่ควรสอดคล้องกันในทุกวัตถุที่สืบทอดมาจากต้นแบบต้น?
lindsaymacvean

1
@Ghola ความตั้งใจที่นี่เพื่ออธิบายวิธีการสร้างตัวแปรแบบคงที่ การกำหนดระยะห่างที่เหมาะสมและหลีกเลี่ยงการกลมกลืนเป็นหัวข้อแยกต่างหากซึ่งอาจเพิ่มความซับซ้อนของคำตอบ ขึ้นอยู่กับผู้ใช้ในการพิจารณาว่าจะแนบตัวสร้างโดยไม่ก่อให้เกิดมลพิษ ถ้ามันดีพอสำหรับนิโคลัสซากาสมันก็ดีพอสำหรับฉัน
Nate

@lindsaymacvean มันเป็นตัวแปรแบบคงที่เพราะค่าเดียวจะถูกแชร์ในทุกกรณี ไม่เป็นไรสำหรับค่าที่จะเปลี่ยน หากหนึ่งอินสแตนซ์เปลี่ยนค่าอินสแตนซ์ทั้งหมดจะได้รับผลกระทบ ไม่น่าเป็นไปได้ว่ามันจะถูกใช้เหมือนกับตัวอย่างด้านบน การอนุญาตให้ตั้งค่าระหว่างการสร้างอินสแตนซ์เป็นเพียงการแสดงว่าเป็นไปได้ กรณีการใช้งานที่เป็นไปได้มากกว่านั้นคือมีแค่ getter และ setter หรืออย่างน้อยก็ตรวจสอบเพื่อให้แน่ใจว่ามันถูกตั้งค่าเป็นอย่างอื่นที่ไม่ได้กำหนดไว้
Nate

15

หากคุณใช้ไวยากรณ์คลาสใหม่จากนั้นคุณสามารถทำสิ่งต่อไปนี้:

    class MyClass {
      static get myStaticVariable() {
        return "some static variable";
      }
    }

    console.log(MyClass.myStaticVariable);

    aMyClass = new MyClass();
    console.log(aMyClass.myStaticVariable, "is undefined");

สิ่งนี้จะสร้างตัวแปรแบบคงที่ใน JavaScript ได้อย่างมีประสิทธิภาพ


สิ่งนี้มีประโยชน์เมื่อสร้างคลาสยูทิลิตี้คงที่!
พอใจ

1
แต่ตอนนี้คำถามคือคุณยังคงมีค่าและอนุญาตการเปลี่ยนแปลงกับ setter ได้อย่างไร จะต้องมีการปิดหรือคุณสมบัติที่MyClassกำหนดไว้ด้านนอกของการสร้างชั้นเรียน
trincot


8

หากคุณต้องการประกาศตัวแปรแบบคงที่สำหรับการสร้างค่าคงที่ในแอปพลิเคชันของคุณฉันก็พบว่าวิธีต่อไปนี้ง่ายที่สุด

ColorConstants = (function()
{
    var obj = {};
    obj.RED = 'red';
    obj.GREEN = 'green';
    obj.BLUE = 'blue';
    obj.ALL = [obj.RED, obj.GREEN, obj.BLUE];
    return obj;
})();

//Example usage.
var redColor = ColorConstants.RED;

8

เกี่ยวกับclassECMAScript 2015 ที่นำเสนอคำตอบอื่น ๆ ยังไม่ชัดเจน

นี่คือตัวอย่างที่แสดงให้เห็นถึงวิธีการสร้าง var คงที่ด้วยstaticVar synthax:ClassNamevar

class MyClass {
    constructor(val) {
        this.instanceVar = val;
        MyClass.staticVar = 10;
    }
}

var class1 = new MyClass(1);
console.log(class1.instanceVar);      // 1
console.log(class1.constructor.staticVar); // 10

// New instance of MyClass with another value
var class2 = new MyClass(3);
console.log(class1.instanceVar);      // 1
console.log(class2.instanceVar);      // 3

ในการเข้าถึงตัวแปรสแตติกเราใช้.constructorคุณสมบัติที่ส่งคืนการอ้างอิงไปยังฟังก์ชันตัวสร้างวัตถุที่สร้างคลาส เราสามารถเรียกมันบนสองอินสแตนซ์ที่สร้างขึ้น:

MyClass.staticVar = 11;
console.log(class1.constructor.staticVar); // 11
console.log(class2.constructor.staticVar); // 11 <-- yes it's static! :)

MyClass.staticVar = 12;
console.log(class1.constructor.staticVar); // 12
console.log(class2.constructor.staticVar); // 12

7

มีคำตอบอื่น ๆ ที่คล้ายกัน แต่ไม่มีใครสนใจฉันเลย นี่คือสิ่งที่ฉันลงเอยด้วย:

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();

7

นอกจากส่วนที่เหลือปัจจุบันมีร่าง ( ข้อเสนอขั้นที่ 2 ) ในข้อเสนอ ECMAที่แนะนำเขตข้อมูลstatic สาธารณะในชั้นเรียน ( เขตข้อมูลส่วนตัวได้รับการพิจารณา )

ใช้ตัวอย่างจากข้อเสนอstaticไวยากรณ์ที่เสนอจะมีลักษณะดังนี้:

class CustomDate {
  // ...
  static epoch = new CustomDate(0);
}

และเทียบเท่ากับสิ่งต่อไปนี้ที่ผู้อื่นเน้นไว้:

class CustomDate {
  // ...
}
CustomDate.epoch = new CustomDate(0);

CustomDate.epochจากนั้นคุณสามารถเข้าถึงได้ผ่านทาง

คุณสามารถติดตามข้อเสนอใหม่proposal-static-class-featuresได้


ขณะนี้ babel รองรับคุณสมบัตินี้ด้วยปลั๊กอินเปลี่ยนคุณสมบัติคลาสซึ่งคุณสามารถใช้ได้ นอกจากนี้แม้ว่าจะยังคงอยู่ในความคืบหน้าอยู่ในการดำเนินการนั้นV8


6

คุณสามารถสร้างตัวแปรคงที่ใน JavaScript เช่นนี้ด้านล่าง นี่countคือตัวแปรแบบคงที่

var Person = function(name) {
  this.name = name;
  // first time Person.count is undefined, so it is initialized with 1
  // next time the function is called, the value of count is incremented by 1
  Person.count = Person.count ? Person.count + 1 : 1;
}

var p1 = new Person('User p1');
console.log(p1.constructor.count);   // prints 1
var p2 = new Person('User p2');
console.log(p2.constructor.count);   // prints 2

คุณสามารถกำหนดค่าให้กับตัวแปรแบบสแตติกโดยใช้Personฟังก์ชันหรืออินสแตนซ์ใด ๆ :

// set static variable using instance of Person
p1.constructor.count = 10;         // this change is seen in all the instances of Person
console.log(p2.constructor.count); // prints 10

// set static variable using Person
Person.count = 20;
console.log(p1.constructor.count); // prints 20

นี่เป็นหนึ่งในวิธีที่ดีในการประกาศตัวแปรแบบคงที่และเข้าถึงใน JavaScript
ArunDhwaj IIITH

5

หากคุณต้องการสร้างตัวแปรสแตติกโกลบอล:

var my_id = 123;

แทนที่ตัวแปรด้วยด้านล่าง:

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});

4

สิ่งที่ใกล้เคียงที่สุดใน JavaScript ไปยังตัวแปรแบบคงที่คือตัวแปรทั่วโลก - นี่เป็นเพียงตัวแปรที่ประกาศนอกขอบเขตของฟังก์ชันหรือวัตถุตามตัวอักษร:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

สิ่งอื่นที่คุณสามารถทำได้คือเก็บตัวแปรทั่วโลกไว้ในวัตถุตามตัวอักษรเช่นนี้

var foo = { bar : 1 }

และจากนั้นเข้าถึง variabels foo.barเช่นนี้


อันนี้ช่วยให้ฉันอัปโหลดหลายไฟล์ ..... var foo = {counter: 1}; ฟังก์ชั่น moreFiles () {fileName = "ไฟล์" + foo.counter; foo.counter = foo.counter + 1;
veer7

4

หากต้องการรวมแนวคิดของคลาสทั้งหมดที่นี่ให้ทดสอบสิ่งนี้:

var Test = function() {
  // "super private" variable, accessible only here in constructor. There are no real private variables
  //if as 'private' we intend variables accessible only by the class that defines the member and NOT by child classes
  var test_var = "super private";

  //the only way to access the "super private" test_var is from here
  this.privileged = function(){
    console.log(test_var);
  }();

  Test.test_var = 'protected';//protected variable: accessible only form inherited methods (prototype) AND child/inherited classes

  this.init();
};//end constructor

Test.test_var = "static";//static variable: accessible everywhere (I mean, even out of prototype, see domready below)

Test.prototype = {

 init:function(){
   console.log('in',Test.test_var);
 }

};//end prototype/class


//for example:
$(document).ready(function() {

 console.log('out',Test.test_var);

 var Jake = function(){}

 Jake.prototype = new Test();

 Jake.prototype.test = function(){
   console.log('jake', Test.test_var);
 }

 var jake = new Jake();

 jake.test();//output: "protected"

});//end domready

อีกวิธีหนึ่งในการดูแนวปฏิบัติที่ดีที่สุดในสิ่งเหล่านี้คือเพื่อดูว่ากาแฟแปลแนวคิดเหล่านี้อย่างไร

#this is coffeescript
class Test
 #static
 @prop = "static"

 #instance
 constructor:(prop) ->
   @prop = prop
   console.log(@prop)

 t = new Test('inst_prop');

 console.log(Test.prop);


//this is how the above is translated in plain js by the CS compiler
  Test = (function() {
    Test.prop = "static";

    function Test(prop) {
     this.prop = prop;
     console.log(this.prop);
    }

    return Test;

  })();

  t = new Test('inst_prop');

  console.log(Test.prop);

4

ในตัวแปร JavaScript จะเป็นค่าคงที่ตามค่าเริ่มต้น ตัวอย่าง :

var x = 0;

function draw() {
    alert(x); //
    x+=1;
}

setInterval(draw, 1000);

ค่าของ x จะเพิ่มขึ้น 1 ทุก ๆ 1,000 มิลลิวินาที
มันจะพิมพ์ 1,2,3 เรื่อย ๆ


2
เป็นกรณีที่แตกต่างกัน ตัวอย่างของคุณเกี่ยวกับขอบเขต
challet

4

มีวิธีอื่นที่แก้ไขความต้องการของฉันหลังจากเรียกดูกระทู้นี้ ขึ้นอยู่กับสิ่งที่คุณต้องการบรรลุด้วย "ตัวแปรคงที่"

global property sessionStorage หรือ localStorage ช่วยให้สามารถจัดเก็บข้อมูลสำหรับอายุการใช้งานของเซสชันหรือสำหรับช่วงเวลาที่ยาวกว่าโดยไม่ จำกัด จนกว่าจะล้างอย่างชัดเจนตามลำดับ ซึ่งช่วยให้สามารถแบ่งปันข้อมูลระหว่าง windows, frame, tab panels, popups ฯลฯ ของหน้า / แอพของคุณและมีประสิทธิภาพมากกว่า "ตัวแปร static / global" ในรหัสเดียว

มันหลีกเลี่ยงความยุ่งยากทั้งหมดกับขอบเขตอายุการใช้งานความหมายพลวัตและอื่น ๆ ของตัวแปรระดับโลกระดับบนสุดเช่น Window.myglobal ไม่ทราบว่ามันมีประสิทธิภาพเพียงใด แต่นั่นไม่สำคัญสำหรับปริมาณข้อมูลขนาดเล็กที่เข้าถึงได้ในอัตราที่ปานกลาง

เข้าถึงได้อย่างง่ายดายเป็น "sessionStorage.mydata = Anything" และดึงข้อมูลในทำนองเดียวกัน ดูที่ "JavaScript: The Definitive Guide, Sixth Edition", David Flanagan, ISBN: 978-0-596-80552-4, บทที่ 20, ส่วนที่ 20.1 นี้สามารถดาวน์โหลดได้อย่างง่ายดายในรูปแบบ PDF โดยการค้นหาง่าย ๆ หรือในการสมัครสมาชิก O'Reilly Safaribooks ของคุณ (คุ้มค่ากับน้ำหนักด้วยทองคำ)


2

Function / คลาสของ Function อนุญาตให้มีคอนสตรัคเตอร์เดียวสำหรับขอบเขตของวัตถุ Function Hoisting, declarations & expressions

  • ฟังก์ชั่นที่สร้างขึ้นด้วยตัวสร้างฟังก์ชั่นไม่ได้สร้างการปิดกับบริบทการสร้างของพวกเขา; พวกเขามักจะถูกสร้างขึ้นในขอบเขตส่วนกลาง

      var functionClass = function ( ) {
            var currentClass = Shape;
            _inherits(currentClass, superClass);
            function functionClass() { superClass.call(this); // Linking with SuperClass Constructor.
                // Instance Variables list.
                this.id = id;   return this;
            }
        }(SuperClass)

Closures - สำเนาของ closure เป็นฟังก์ชันที่มีข้อมูลที่สงวนไว้

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

      function closureFun( args ) {
            // Local variable that ends up within closure
            var num = args;
            num++;
            return function() { console.log(num); }
        }
        var closure1 = closureFun( 5 );
        var closure2 = closureFun( 777 );
        closure1(); // 5
        closure2(); // 777
        closure2(); // 778
        closure1(); // 6

คลาสฟังก์ชัน ES5 : ใช้Object.defineProperty (O, P, คุณสมบัติ)

กระบวนการObject.defineProperty ()วิธีการกำหนดคุณสมบัติใหม่โดยตรงบนวัตถุหรือปรับเปลี่ยนคุณสมบัติที่มีอยู่บนวัตถุและส่งกลับวัตถุ

สร้างวิธีการบางอย่างโดยใช้``เพื่อให้ทุกคนสามารถเข้าใจคลาสฟังก์ชันได้อย่างง่ายดาย

'use strict';
var Shape = function ( superClass ) {
    var currentClass = Shape;
    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.
        // Instance Variables list.
        this.id = id;   return this;
    }
    var staticVariablesJOSN = { "parent_S_V" : 777 };
    staticVariable( currentClass, staticVariablesJOSN );

    // Setters, Getters, instanceMethods. [{}, {}];
    var instanceFunctions = [
        {
            key: 'uniqueID',
            get: function get() { return this.id; },
            set: function set(changeVal) { this.id = changeVal; }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Object);

var Rectangle = function ( superClass ) {
    var currentClass = Rectangle;

    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.

        this.width = width;
        this.height = height;   return this;
    }

    var staticVariablesJOSN = { "_staticVar" : 77777 };
    staticVariable( currentClass, staticVariablesJOSN );

    var staticFunctions = [
        {
            key: 'println',
            value: function println() { console.log('Static Method'); }
        }
    ];
    staticMethods(currentClass, staticFunctions);

    var instanceFunctions = [
        {
            key: 'setStaticVar',
            value: function setStaticVar(staticVal) {
                currentClass.parent_S_V = staticVal;
                console.log('SET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
            }
        }, {
            key: 'getStaticVar',
            value: function getStaticVar() {
                console.log('GET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
                return currentClass.parent_S_V;
            }
        }, {
            key: 'area',
            get: function get() {
                console.log('Area : ', this.width * this.height);
                return this.width * this.height;
                }
        }, {
            key: 'globalValue',
            get: function get() {
                console.log('GET ID : ', currentClass._staticVar);
                return currentClass._staticVar;
            },
            set: function set(value) {
                currentClass._staticVar = value;
                console.log('SET ID : ', currentClass._staticVar);
            }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Shape);

// ===== ES5 Class Conversion Supported Functions =====
function defineProperties(target, props) {
    console.log(target, ' : ', props);
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function staticMethods( currentClass, staticProps ) {
    defineProperties(currentClass, staticProps);
};
function instanceMethods( currentClass, protoProps ) {
    defineProperties(currentClass.prototype, protoProps);
};
function staticVariable( currentClass, staticVariales ) {
    // Get Key Set and get its corresponding value.
    // currentClass.key = value;
    for( var prop in staticVariales ) {
        console.log('Keys : Values');
        if( staticVariales.hasOwnProperty( prop ) ) {
            console.log(prop, ' : ', staticVariales[ prop ] );
            currentClass[ prop ] = staticVariales[ prop ];
        }
    }
};
function _inherits(subClass, superClass) {
    console.log( subClass, ' : extends : ', superClass );
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, 
            { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
    if (superClass)
        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

ตัวอย่างโค้ดด้านล่างคือการทดสอบเกี่ยวกับแต่ละอินสแตนซ์มีสำเนาของสมาชิกอินสแตนซ์และสมาชิกแบบคงที่ทั่วไป

var objTest = new Rectangle('Yash_777', 8, 7);
console.dir(objTest);

var obj1 = new Rectangle('R_1', 50, 20);
Rectangle.println(); // Static Method
console.log( obj1 );    // Rectangle {id: "R_1", width: 50, height: 20}
obj1.area;              // Area :  1000
obj1.globalValue;       // GET ID :  77777
obj1.globalValue = 88;  // SET ID :  88
obj1.globalValue;       // GET ID :  88  

var obj2 = new Rectangle('R_2', 5, 70);
console.log( obj2 );    // Rectangle {id: "R_2", width: 5, height: 70}
obj2.area;              // Area :  350    
obj2.globalValue;       // GET ID :  88
obj2.globalValue = 999; // SET ID :  999
obj2.globalValue;       // GET ID :  999

console.log('Static Variable Actions.');
obj1.globalValue;        // GET ID :  999

console.log('Parent Class Static variables');
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  777
obj1.setStaticVar(7);   // SET Instance Method Parent Class Static Value :  7
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  7

การเรียกเมธอดแบบสแตติกทำบนคลาสโดยตรงและไม่สามารถเรียกใช้บนอินสแตนซ์ของคลาสได้ แต่คุณสามารถรับสายสำหรับสมาชิกแบบสแตติกได้จากภายในอินสแตนซ์

ใช้ไวยากรณ์:

   this.constructor.staticfunctionName();
class MyClass {
    constructor() {}
    static staticMethod() {
        console.log('Static Method');
    }
}
MyClass.staticVar = 777;

var myInstance = new MyClass();
// calling from instance
myInstance.constructor.staticMethod();
console.log('From Inside Class : ',myInstance.constructor.staticVar);

// calling from class
MyClass.staticMethod();
console.log('Class : ', MyClass.staticVar);

คลาส ES6: คลาส ES2015 เป็นน้ำตาลแบบง่ายเหนือรูปแบบ OO ต้นแบบ การมีรูปแบบการประกาศที่แสนสะดวกทำให้รูปแบบการเรียนง่ายขึ้นและกระตุ้นให้เกิดการทำงานร่วมกัน คลาสสนับสนุนการสืบทอดที่อิงต้นแบบการเรียกใช้ขั้นสูงอินสแตนซ์และวิธีการคงที่และตัวสร้าง

ตัวอย่าง : อ้างอิงโพสต์ก่อนหน้าของฉัน


2

มี 4 วิธีในการจำลองตัวแปรคงที่ฟังก์ชั่นท้องถิ่นใน Javascript

วิธีที่ 1: การใช้คุณสมบัติวัตถุของฟังก์ชัน (รองรับในเบราว์เซอร์รุ่นเก่า)

function someFunc1(){
    if( !('staticVar' in someFunc1) )
        someFunc1.staticVar = 0 ;
    alert(++someFunc1.staticVar) ;
}

someFunc1() ; //prints 1
someFunc1() ; //prints 2
someFunc1() ; //prints 3

วิธีที่ 2: ใช้การปิดชุดตัวเลือกที่ 1 (รองรับในเบราว์เซอร์รุ่นเก่า)

var someFunc2 = (function(){
    var staticVar = 0 ;
    return function(){
        alert(++staticVar) ;
    }
})()

someFunc2() ; //prints 1
someFunc2() ; //prints 2
someFunc2() ; //prints 3

วิธีที่ 3: ใช้การปิดชุดตัวเลือก 2 (รองรับในเบราว์เซอร์เก่าด้วย)

var someFunc3 ;
with({staticVar:0})
    var someFunc3 = function(){
        alert(++staticVar) ;
    }

someFunc3() ; //prints 1
someFunc3() ; //prints 2
someFunc3() ; //prints 3

วิธีที่ 4: ใช้การปิดชุดตัวเลือก 3 (ต้องการการสนับสนุนสำหรับ EcmaScript 2015)

{
    let staticVar = 0 ;
    function someFunc4(){
        alert(++staticVar) ;
    }
}

someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3

2

คุณสามารถกำหนดฟังก์ชั่นคงที่ใน JavaScriptโดยใช้staticคำหลัก:

class MyClass {
  static myStaticFunction() {
    return 42;
  }
}

MyClass.myStaticFunction(); // 42

จากการเขียนนี้คุณยังไม่สามารถกำหนดคุณสมบัติคงที่ (นอกเหนือจากฟังก์ชั่น) ภายในชั้นเรียน คุณสมบัติสแตติกยังคงเป็นข้อเสนอ Stage 3ซึ่งหมายความว่าพวกเขายังไม่ได้เป็นส่วนหนึ่งของ JavaScript อย่างไรก็ตามไม่มีอะไรหยุดคุณจากการมอบหมายให้คลาสเหมือนกับที่คุณทำกับวัตถุอื่น:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

หมายเหตุสุดท้าย: ระวังการใช้วัตถุคงที่กับการสืบทอด - คลาสที่สืบทอดทั้งหมดจะใช้สำเนาของวัตถุเดียวกัน


1

ใน JavaScript ไม่มีคำหรือคำหลักคงที่ แต่เราสามารถใส่ข้อมูลดังกล่าวลงในฟังก์ชั่นวัตถุโดยตรง (เช่นในวัตถุอื่น ๆ )

function f() {
    f.count = ++f.count || 1 // f.count is undefined at first
    alert("Call No " + f.count)
}

f(); // Call No 1

f(); // Call No 2

1

ฉันใช้ตัวแปรฟังก์ชั่นสแตติกจำนวนมากและเป็นความอัปยศที่แท้จริง JS ไม่มีกลไกในตัวสำหรับสิ่งนั้น บ่อยครั้งที่ฉันเห็นโค้ดที่ตัวแปรและฟังก์ชั่นถูกกำหนดไว้ในขอบเขตด้านนอกแม้ว่าพวกเขาจะใช้ภายในฟังก์ชันเดียว นี่เป็นสิ่งที่น่าเกลียดข้อผิดพลาดได้ง่ายและขอเพียงปัญหา ...

ฉันคิดวิธีต่อไปนี้ขึ้นมา:

if (typeof Function.prototype.statics === 'undefined') {
  Function.prototype.statics = function(init) {
    if (!this._statics) this._statics = init ? init() : {};
    return this._statics;
  }
}

นี่เป็นการเพิ่มเมธอด 'statics' ให้กับทุกฟังก์ชั่น (ใช่เพียงแค่ผ่อนคลายเกี่ยวกับมัน) เมื่อถูกเรียกมันจะเพิ่มวัตถุว่างเปล่า (_statics) ลงในฟังก์ชั่นของวัตถุและส่งคืนมัน หากฟังก์ชั่น init ได้รับการจัดหา _statics จะถูกตั้งค่าเป็นผลลัพธ์ init ()

จากนั้นคุณสามารถทำได้:

function f() {
  const _s = f.statics(() => ({ v1=3, v2=somefunc() });

  if (_s.v1==3) { ++_s.v1; _s.v2(_s.v1); }
} 

การเปรียบเทียบสิ่งนี้กับ IIFE ซึ่งเป็นคำตอบที่ถูกต้องอื่น ๆ นี้มีข้อเสียของการเพิ่มหนึ่งการมอบหมายและหนึ่งถ้าในทุกฟังก์ชั่นการโทรและการเพิ่มสมาชิก '_statics' ไปยังฟังก์ชั่น ด้านบนไม่ได้อยู่ในฟังก์ชั่นภายในการใช้ 'คงที่' ในรหัสฟังก์ชั่นภายในอย่างชัดเจนด้วย '_s.' คำนำหน้าและโดยรวมง่ายกว่าที่จะมองและเข้าใจ


1

สรุป:

ในES6/ ES 2015 classมีการใช้staticคำหลักพร้อมกับคำหลักที่มาพร้อม โปรดทราบว่านี่คือน้ำตาลเชิงประโยคมากกว่ารูปแบบการถ่ายทอดทางพันธุกรรมต้นแบบซึ่ง javavscript คาดเดา staticคำหลักที่ทำงานในวิธีต่อไปนี้สำหรับวิธีการ:

class Dog {

  static bark () {console.log('woof');}
  // classes are function objects under the hood
  // bark method is located on the Dog function object
  
  makeSound () { console.log('bark'); }
  // makeSound is located on the Dog.prototype object

}

// to create static variables just create a property on the prototype of the class
Dog.prototype.breed = 'Pitbull';
// So to define a static property we don't need the `static` keyword.

const fluffy = new Dog();
const vicky = new Dog();
console.log(fluffy.breed, vicky.breed);

// changing the static variable changes it on all the objects
Dog.prototype.breed = 'Terrier';
console.log(fluffy.breed, vicky.breed);


2
เขากำลังขอตัวแปรคงไม่ใช่ฟังก์ชันคงที่
Konrad Höffner

1

ฉันใช้ต้นแบบและวิธีการทำงาน:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }
}

Cat.COLLECTION_NAME = "cats";

หรือใช้ทะเยอทะยานแบบคงที่:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }

  static get COLLECTION_NAME() {
    return "cats"
  }
}

0

vars ระดับหน้าต่างเป็น sorta เหมือนสถิตยศาสตร์ในแง่ที่คุณสามารถใช้การอ้างอิงโดยตรงและสิ่งเหล่านี้สามารถใช้ได้กับทุกส่วนของแอปของคุณ


3
คำอธิบายที่ดีกว่าของ vars ดังกล่าวคือ 'ทั่วโลก' แทนที่จะเป็นแบบคงที่
Patrick M

0

ไม่มีสิ่งดังกล่าวเป็นตัวแปรคงที่ใน Javascript ภาษานี้เป็นวัตถุต้นแบบที่วางแนวดังนั้นจึงไม่มีคลาส แต่ต้นแบบจากที่วัตถุ "คัดลอก" ตัวเอง

คุณสามารถจำลองพวกมันด้วยตัวแปรโกลบอลหรือด้วยการสร้างต้นแบบ (การเพิ่มคุณสมบัติให้กับต้นแบบ):

function circle(){
}
circle.prototype.pi=3.14159

วิธีนี้ใช้งานได้ แต่คุณกำลังทำการสำรวจFunction.prototype
Dan

@ ด่าน: มันเป็นความเข้าใจของฉันนี่จะเป็นวงกลมและไม่ใช่ฟังก์ชั่น อย่างน้อยนั่นคือสิ่งที่ Chrome พยายามบอกฉัน: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(ถ้านั่นคือสิ่งที่คุณหมายถึง)
Aktau

0

การทำงานกับเว็บไซต์ MVC ที่ใช้ jQuery ฉันต้องการตรวจสอบให้แน่ใจว่าการดำเนินการ AJAX ภายในตัวจัดการเหตุการณ์บางอย่างสามารถดำเนินการได้เมื่อคำขอก่อนหน้านี้เสร็จสมบูรณ์ ฉันใช้ตัวแปรวัตถุ jqXHR "คงที่" เพื่อให้บรรลุนี้

รับปุ่มต่อไปนี้:

<button type="button" onclick="ajaxAction(this, { url: '/SomeController/SomeAction' })">Action!</button>

โดยทั่วไปฉันใช้ IIFE เช่นนี้สำหรับตัวจัดการคลิกของฉัน:

var ajaxAction = (function (jqXHR) {
    return function (sender, args) {
        if (!jqXHR || jqXHR.readyState == 0 || jqXHR.readyState == 4) {
            jqXHR = $.ajax({
                url: args.url,
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify($(sender).closest('form').serialize()),
                success: function (data) {
                    // Do something here with the data.
                }
            });
        }
    };
})(null);

0

หากคุณต้องการใช้ต้นแบบนั้นมีวิธี

var p = function Person() {
    this.x = 10;
    this.y = 20;
}
p.prototype.counter = 0;
var person1 = new p();
person1.prototype = p.prototype;
console.log(person1.counter);
person1.prototype.counter++;
var person2 = new p();
person2.prototype = p.prototype;
console.log(person2.counter);
console.log(person1.counter);

การทำเช่นนี้คุณจะสามารถเข้าถึงตัวแปรตัวนับจากอินสแตนซ์ใดก็ได้และการเปลี่ยนแปลงใด ๆ ในคุณสมบัติจะสะท้อนทันที !!

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