JavaScript의 정적 변수


716

Javascript에서 정적 변수를 작성하는 방법


"dispaly : none"스타일 속성으로 레이블 또는 다른 html 태그를 정의하고이 값에 대한 변수 값과이 값에 대한 조작을 설정할 수 있습니다. 열심히하지 말자
— asghar 2019

내가 찾은 가장 간단한 해결책 : 클래스에서 정적 변수를 전혀 정의하지 마십시오. 정적 변수를 사용하려는 경우, 단지 예를 들어, 다음 거기를 정의하고 someFunc = () => { MyClass.myStaticVariable = 1; }. 그런 다음 정적 메소드를 작성하여 정적 멤버를 리턴하십시오 (예 :) static getStatic() { return MyClass.myStaticVariable; }. 그런 다음 MyClass.getStatic()클래스 외부에서 호출 하여 정적 데이터를 유지할 수 있습니다!
— 픽셀

답변:


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는 함수를 일급 객체 로 취급 하므로 객체 이므로 속성을 함수에 할당 할 수 있습니다.

업데이트 : 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
아마도 privilegedMethodMyClass 인스턴스에서 호출 될 수있는 것처럼 보이기 때문에 OO의 개인 메소드와 같지 않을까요? 액세스 할 수 있기 때문에 권한이 있음을 의미 privateVariable합니까?
— Dónal

3
this.constructor"인스턴스 메소드"에서 정적 변수에 액세스하는 데 사용할 수 없습니까 ? 그렇다면 대답에 추가 할 가치가 있습니다.
— Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

1
예제에서 정적 함수 를 언급 할 수도 있습니다 .
— David Rodrigues

18
안녕하세요, 나는이 줄에 동의하지 않습니다 // 모든 인스턴스가 공유하는 정적 변수 'MyClass.staticProperty = "baz";' 에 관해서는 저 를 추론 당신이 'myInstance.staticProperty'에서 바즈 찾을 수 있다고하는 과정의 당신은 할 수 없습니다.
— fullstacklife

5
아마도 MyClass.prototype.staticProperty = "baz";정적 속성은 실제로 익명 함수로 정의되어 MyClass.prototype.staticProperty = function () {return staticVar;}모든 변수가 단일 변수에 액세스하여 세터로 변경할 수 있도록 OO 원칙을 읽 거나 훨씬 더 정확해야합니다 .
— 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에서 정적 변수를 사용하는 Trick :

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;정적 변수가 거짓이 아닌 경우 (false, 0, null 또는 빈 문자열)
— Kip

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검사는 다른 몇 가지 이상한 강압에가는거야.
— dewd

@SonySantos 테스트 쇼 파이어 폭스 (40)에 대한 반대
— BARTOLO-otrit

96

IIFE (즉시 호출 된 함수 표현식)를 통해 수행합니다.

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

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

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

21
이것이 JavaScript에서 가장 관용적 인 방법이라고 말하고 싶습니다. 다른 언어를 사용하는 사람들이 선호하는 다른 방법 덕분에 너무 많은 공짜를 얻지 못합니다.

1
'IIFE'가 아닌 'closure'를 사용하여 문구를 바꾸겠습니다.
— zendka

39

arguments.callee를 사용하여 "정적"변수를 저장할 수 있습니다 (익명 함수에서도 유용함).

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

3
내가 이해할 수있는 한,이 방법은 pascal MARTIN의 방법에 비해 하나의 장점 만 있습니다. 익명 함수에서 사용할 수 있습니다. 이에 대한 예가 좋을 것입니다
— Dan

27
arguments.callee더 이상 사용되지 않습니다.
— Quolonel Questions

나는 항상 거의 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에 대한 참조가 함수 내에서 유지됩니다.

getter와 setter를 정의 할 수도 있습니다 . 이 코드 스 니펫을 살펴보십시오 ( 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

'new'문은 새로운 객체를 생성하고 모든 속성과 메소드를 복사합니다.

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에 따라 생성자 함수 의 명령문 을 사용 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. 게양
  6. 자동 세미콜론 삽입
  7. 정적 속성 및 방법

참고 것을 자동 세미콜론 삽입 (6.에서 언급 한) 자바 스크립트의 "기능"매우 자주 코드에서 이상한 문제의 원인에 대한 책임이있다. 따라서 기능보다는 버그로 간주합니다.

자세한 내용을 보려면 여기 에 이러한 주제에 대한 흥미로운 MSDN 기사 가 있으며 그중 일부는 더 자세한 내용을 제공합니다.

무엇이다 읽는 재미 (또한 주제는 위에서 언급 한 커버)로부터 그 기사입니다뿐만 아니라 MDN 자바 스크립트 가이드 :

JavaScript 에서 c # out매개 변수 를 에뮬레이트 하는 방법을 알고 싶다면 여기에서 샘플 코드를DateTime.TryParse(str, out result) 찾을 수 있습니다.


당신의 그들을 IE 작업 (사용 개발자 도구를 엽니 다하지 않는 자바 스크립트에 대한 콘솔이없는 F12다음을 찾을 수 콘솔 탭을 엽니 다)는 유용 니펫을. console.log(msg);위의 예에서 사용 된 대로 사용할 수 있습니다 . Podcast기능 전에 삽입하십시오 .

편의를 위해 하나의 완전한 단일 코드 스 니펫에 위의 코드가 있습니다.


노트:

  • JavaScript 프로그래밍에 대한 몇 가지 유용한 팁, 힌트 및 권장 사항은 일반적으로 여기 (JavaScript 모범 사례) 와 여기 ( 'var'대 'let')에서 찾을 수 있습니다. 또한 암시 적 타입 캐스트 (강제)에 대한 이 기사도 권장됩니다 .

  • 클래스를 사용하고 JavaScript로 컴파일하는 편리한 방법은 TypeScript입니다. 작동 방식을 보여주는 예제를 찾을 수 있는 놀이터 가 있습니다. 현재 TypeScript를 사용하지 않더라도 TypeScript를 JavaScript 결과와 나란히 볼 수 있기 때문에 살펴볼 수 있습니다. 대부분의 예제는 간단하지만 즉시 시도 할 수있는 Raytracer 예제도 있습니다. 특히 "클래스 사용", "상속 사용"및 "제네릭 사용"예제를 콤보 상자에서 선택하여 살펴 보는 것이 좋습니다. JavaScript에서 즉시 사용할 수있는 멋진 템플릿입니다. Typescript는 Angular 와 함께 사용됩니다 .

  • 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파일 에 넣을 수 있습니다 . 이것은 예제를 짧게 유지하기 위해 인라인으로 작성되었습니다.

자체 호출 기능 (IIFE = 즉시 호출 된 함수 표현이라고도 함)은 여기에보다 자세히 설명되어 있습니다 .


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

FooJavaScript 함수는 객체이므로 속성에 할당 할 수 있습니다 .


Foo.bar;주석이 암시하는 것처럼 함수가 반환 한 문자열이 아니라 할당 된 함수를 반환합니다.

두 예제에서 정적 값을 설정 (덮어 쓰기)하는 방법에 대한 정보를 추가 할 수 있습니까?
— Wilt

1
@Wilt 두 경우 모두 "정적"속성은 함수의 속성 일 뿐이므로 JavaScript의 다른 속성과 마찬가지로 설정하고 덮어 씁니다. 두 경우 모두 설정할 수 bar의 속성을 Foo하기 위해 3이 같은Foo.bar = 3;
— 최대 Heiber


16

다음 예제와 설명은 Nicholas Zakas의 책 전문 웹 개발자를위한 전문 JavaScript 2 판입니다. 이것은 내가 찾고있는 대답이므로 여기에 추가하는 것이 도움이 될 것이라고 생각했습니다.

(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
이렇게하면 Person 개체가 전역 네임 스페이스에 배치됩니다. 내가 권장하는 해결책이 아닙니다.
— 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에서 정적 변수를 효과적으로 만듭니다.


정적 유틸리티 클래스를 빌드 할 때 유용합니다!
— Indolering

1
그러나 이제 문제는 어떻게 값을 유지하고 세터를 사용하여 값을 변경할 수 있는지입니다. 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와 함께 ClassName. var신택스 :

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

나머지 외에도 현재 ECMA 제안서 에 초안 ( 2 단계 제안서 )이 있어 수업에 공개 필드 를 소개 합니다. ( 비공개 분야 고려 )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}; function 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의 값은 1000 밀리 초마다 1 씩 증가합니다.
1,2,3 등을 인쇄합니다.


2
다른 경우입니다. 귀하의 예는 범위에 관한 것입니다.
— challet

4

이 스레드를 탐색 한 후 요구 사항을 해결하는 또 다른 접근법이 있습니다. "정적 변수"를 사용하여 정확히 달성하려는 대상에 따라 다릅니다.

전역 속성 sessionStorage 또는 localStorage를 사용하면 세션 수명 동안 또는 명시 적으로 지울 때까지 무기한 더 오랜 기간 동안 데이터를 저장할 수 있습니다. 이를 통해 페이지 / 앱의 모든 창, 프레임, 탭 패널, 팝업 등에서 데이터를 공유 할 수 있으며 하나의 코드 세그먼트에서 간단한 "정적 / 전역 변수"보다 훨씬 강력합니다.

최상위 전역 변수, 즉 Window.myglobal의 범위, 수명, 의미, 역학 등 모든 번거 로움을 피합니다. 그것이 얼마나 효율적인지 모르지만, 적당한 속도로 액세스하는 적당한 양의 데이터에는 중요하지 않습니다.

"sessionStorage.mydata = anything"로 쉽게 액세스하고 유사하게 검색합니다. "JavaScript : 결정적인 안내서, 6 판", David Flanagan, ISBN : 978-0-596-80552-4, 20 장, 섹션 20.1을 참조하십시오. 이것은 간단한 검색 또는 O'Reilly Safaribooks 구독 (무게가 금으로 표시됨)을 통해 PDF로 쉽게 다운로드 할 수 있습니다.


2

함수 / 클래스는 객체 범위에 단일 생성자 만 허용합니다. Function Hoisting, declarations & expressions

  • Function 생성자로 생성 된 함수는 해당 생성 컨텍스트에 대한 클로저를 생성하지 않습니다. 그들은 항상 글로벌 범위에서 만들어집니다.

      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)

클로저 -클로저의 복사본은 보존 된 데이터로 작동합니다.

  • 각 클로저의 사본은 자체 자유 값 또는 참조가있는 함수에 작성됩니다. 다른 함수 내에서 함수를 사용할 때마다 클로저가 사용됩니다.
  • 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, Attributes)를 사용합니다

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

Javascript에서 함수 로컬 정적 변수를 에뮬레이트하는 방법에는 4 가지가 있습니다.

방법 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

이 글을 쓰는 시점에서 여전히 클래스 내에서 정적 속성 (함수 이외의)을 정의 할 수는 없습니다. 정적 속성은 여전히 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 () result로 설정됩니다.

그런 다음 다음을 수행 할 수 있습니다.

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

창 수준 변수는 직접 참조를 사용할 수 있다는 점에서 정적과 비슷하며 앱의 모든 부분에서 사용할 수 있습니다


3
이러한 변수에 대한 훨씬 더 나은 설명은 정적이 아니라 '전역'입니다.
— Patrick M

0

Javascript에는 정적 변수와 같은 것이 없습니다. 이 언어는 프로토 타입 기반 객체를 지향하므로 클래스는 없지만 객체가 "복사"하는 프로토 타입은 없습니다.

전역 변수 또는 프로토 타입을 사용하여 프로토 타입에 속성을 추가하여 시뮬레이션 할 수 있습니다.

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

이 방법은 효과적이지만 Function.prototype
— Dan

@ Dan : 이것이 기능이 아닌 서클을위한 것임을 이해합니다. 적어도 그것이 크롬이 말하려는 것입니다. function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(그것이 당신이 의도 한 것이라면)
— Aktau

0

jQuery를 사용하는 MVC 웹 사이트를 사용하면서 특정 이벤트 핸들러 내의 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.