JavaScript에서 '새'키워드는 무엇입니까?


1744

new사람들이 JavaScript를 객체 지향 프로그래밍 언어가 아니라고 생각하는 경향이 있기 때문에 JavaScript 의 키워드는 처음 접했을 때 상당히 혼란 스러울 수 있습니다.

  • 무엇입니까?
  • 어떤 문제가 해결됩니까?
  • 적절한시기와시기는?


답변:


2144

그것은 5 가지 일을한다 :

  1. 새 객체를 만듭니다. 이 객체의 타입은 단순히 object 입니다.
  2. 이 새로운 객체의 접근 불가능한 내부 [[prototype]] (예 : __proto__ ) 속성을 생성자 함수의 외부의 접근 가능한 프로토 타입 객체로 설정합니다 (모든 함수 객체에는 자동으로 프로토 타입 속성이 있음).
  3. 그것은하게 this새로 만든 객체에 변수 지점을.
  4. this언급 될 때마다 새로 작성된 객체를 사용하여 생성자 함수를 실행합니다 .
  5. 생성자 함수가 null객체 가 아닌 참조를 반환하지 않으면 새로 만든 객체를 반환합니다 . 이 경우 해당 객체 참조가 대신 반환됩니다.

참고 : 생성자 함수 는 다음과 같이 new키워드 뒤의 함수를 나타냅니다 .

new ConstructorFunction(arg1, arg2)

이 작업이 완료되면 새 객체의 정의되지 않은 속성이 요청되면 스크립트는 대신 객체의 [[prototype]] 객체에서 속성을 확인합니다. 이것은 JavaScript에서 전통적인 클래스 상속과 비슷한 것을 얻는 방법입니다.

이것에 대해 가장 어려운 부분은 포인트 번호 2입니다. 모든 객체 (함수 포함)에는 [[prototype]] 이라는 내부 속성이 있습니다. new 를 사용 하거나 Object.create 를 사용하거나 리터럴을 기준으로 오브젝트 작성시 에만 설정할 수 있습니다 (함수 기본값은 Function.prototype, 숫자는 Number.prototype 등). Object.getPrototypeOf (someObject) 로만 읽을 수 있습니다 . 이 값을 설정하거나 읽는 다른 방법 은 없습니다 .

기능, 숨겨진 외에도 [[프로토 타입]] 속성도라는 속성이 프로토 타입을 , 그리고 당신이 액세스 할 수있는이 있다는 것입니다, 수정은 당신이 할 객체에 대한 상속 된 속성 및 방법을 제공 할 수 있습니다.


예를 들면 다음과 같습니다.

ObjMaker = function() {this.a = 'first';};
// ObjMaker is just a function, there's nothing special about it that makes 
// it a constructor.

ObjMaker.prototype.b = 'second';
// like all functions, ObjMaker has an accessible prototype property that 
// we can alter. I just added a property called 'b' to it. Like 
// all objects, ObjMaker also has an inaccessible [[prototype]] property
// that we can't do anything with

obj1 = new ObjMaker();
// 3 things just happened.
// A new, empty object was created called obj1.  At first obj1 was the same
// as {}. The [[prototype]] property of obj1 was then set to the current
// object value of the ObjMaker.prototype (if ObjMaker.prototype is later
// assigned a new object value, obj1's [[prototype]] will not change, but you
// can alter the properties of ObjMaker.prototype to add to both the
// prototype and [[prototype]]). The ObjMaker function was executed, with
// obj1 in place of this... so obj1.a was set to 'first'.

obj1.a;
// returns 'first'
obj1.b;
// obj1 doesn't have a property called 'b', so JavaScript checks 
// its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype
// ObjMaker.prototype has a property called 'b' with value 'second'
// returns 'second'

사용하는 모든 객체 new ObjMaker()가 'b'속성을 상속받은 것처럼 보이기 때문에 클래스 상속과 같습니다 .

서브 클래스와 같은 것을 원한다면 다음을 수행하십시오.

SubObjMaker = function () {};
SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
// Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
// is now set to the object value of ObjMaker.prototype.
// The modern way to do this is with Object.create(), which was added in ECMAScript 5:
// SubObjMaker.prototype = Object.create(ObjMaker.prototype);

SubObjMaker.prototype.c = 'third';  
obj2 = new SubObjMaker();
// [[prototype]] property of obj2 is now set to SubObjMaker.prototype
// Remember that the [[prototype]] property of SubObjMaker.prototype
// is ObjMaker.prototype. So now obj2 has a prototype chain!
// obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype

obj2.c;
// returns 'third', from SubObjMaker.prototype

obj2.b;
// returns 'second', from ObjMaker.prototype

obj2.a;
// returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype 
// was created with the ObjMaker function, which assigned a for us

마지막 으로이 페이지를 찾기 전에이 주제에 대해 많은 쓰레기를 읽었습니다. 이 페이지 는 멋진 다이어그램으로 잘 설명되어 있습니다.


47
그냥 추가하고 싶었습니다. 실제로 __proto__에 의해 내부 [[prototype]]에 액세스하는 방법이 있습니다. 그러나 이것은 비표준이며 비교적 새로운 브라우저에서만 지원됩니다 (모두가 아님). 표준화 된 방법, 즉 Object.getPrototypeOf (obj)가 있지만 Ecmascript3.1이며 새 브라우저에서만 다시 지원됩니다. 일반적으로 그 속성을 사용하지 않는 것이 좋습니다. 내부에서 물건이 빨리 복잡해집니다.
Blub

9
질문 : ObjMaker값을 반환하는 함수로 정의 된 경우 어떻게 달라 집니까?
Jim Blackler

13
@LonelyPixel new이 존재 하므로 함수 / 객체를 구성 / 복사하기 위해 팩토리 메소드를 작성할 필요가 없습니다 . "이것을 복사하여 부모 '클래스'와 동일하게 만들고 효율적이고 정확하게 수행하며 내부적으로 JS 만 액세스 할 수있는 상속 정보를 저장합니다"라는 의미입니다. 그렇게하기 위해, 접근 불가능한 prototype새로운 객체의 내부 를 수정하여 상속 된 멤버를 불투명하게 캡슐화하여 기존 OO 상속 체인 (런타임 수정 불가능)을 모방합니다. 없이이를 시뮬레이션 할 수 new있지만 상속은 런타임 수정 가능합니다. 좋은? 나쁜? 당신에게 달려 있습니다.
엔지니어

11
추가 할 작은 점 : new 키워드가 앞에 올 때 생성자에 대한 호출은 생성 된 객체를 자동으로 반환합니다. 생성자 내에서 명시 적으로 반환 할 필요가 없습니다.
찰리 로버츠

7
라는 메모가 Notice that this pattern is deprecated!있습니다. 클래스의 프로토 타입을 설정하는 올바른 최신 패턴은 무엇입니까?
Tom Pažourek

400

이 기능이 있다고 가정하십시오.

var Foo = function(){
  this.A = 1;
  this.B = 2;
};

이것을 독립형 함수로 호출하면 다음과 같습니다.

Foo();

이 함수를 실행하면 window객체 ( AB) 에 두 가지 속성이 추가됩니다 . 받는 사람이 추가합니다 window때문에이 window당신이 그런 식으로 그것을 실행할 때 함수를 호출하는 객체이며, this함수의 기능이라고하는 객체입니다. 적어도 자바 스크립트에서.

이제 다음과 같이 호출하십시오 new.

var bar = new Foo();

new함수 호출에 추가 하면 새 객체가 생성되고 (just var bar = new Object()) this함수 내에서 함수를 호출 한 객체가 아니라 방금 생성 한 새 객체가 함수 내부를 가리키는 Object것입니다. 그래서 bar지금의 속성을 가진 객체입니다 AB. 모든 함수는 생성자가 될 수 있으며 항상 의미가있는 것은 아닙니다.


7
실행 컨텍스트에 따라 다릅니다. 제 경우에는 (Qt 스크립팅) 전역 객체 일뿐입니다.
Maxym

2
더 많은 메모리 사용이 발생합니까?
Jürgen Paul

2
window는 함수를 호출 한 객체 이기 때문에 다음과 같아야합니다. window는 함수 를 포함 하는 객체입니다 .
Dávid Horváth

1
@Taurus 웹 브라우저에서 비 메서드 함수는 window암시 적 으로 방법입니다 . 비록 익명이라도 폐쇄. 그러나이 예에서는 Foo();=> [default context].Foo();=> 창에서 간단한 메소드 호출입니다 window.Foo();. 이 표현 window에는 문맥 ( 호출자 뿐만 아니라 중요하지 않음)이 있습니다.
Dávid Horváth

1
@Taurus 기본적으로 그렇습니다. 그러나 ECMA 6 및 7에서는 상황이 더 복잡합니다 (람다, 클래스 등 참조).
Dávid Horváth

164

Daniel Howard의 답변 외에도 다음과 같은 기능이 있습니다 new.

function New(func) {
    var res = {};
    if (func.prototype !== null) {
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
    return res;
}

동안

var obj = New(A, 1, 2);

에 해당

var obj = new A(1, 2);

73
V : 그 자바 스크립트가 영어보다 이해하기 쉽게 발견
damphat

훌륭한 답변입니다. 작은 질문이 하나 있습니다. 어떻게 될 func.prototypenull있습니까? 좀 더 자세히 설명해 주시겠습니까?
Tom Pažourek

6
@tomp 단순히 쓰기 만하면 프로토 타입 속성을 재정의 할 수 있습니다 A.prototype = null;.이 경우 new A()오브젝트가 생성되고 내부 프로토 타입이 Object오브젝트를 가리 킵니다 . jsfiddle.net/Mk42Z
basilikum

2
호스트 개체가 "개체"또는 "기능"과 다른 것을 생성 할 수 있기 때문에 검사 ​​유형이 잘못되었을 수 있습니다. 무언가가 물체인지 테스트하려면을 선호합니다 Object(ret) === ret.
Oriol

2
의견을 보내 주셔서 감사합니다. 당신이 말하는 것은 사실이며 실제 테스트는 더 강력한 방식으로 수행되어야합니다. 그러나 나는이 개념적인 대답에 대해 typeof테스트를 통해 배후에서 무슨 일이 일어나고 있는지 쉽게 이해할 수 있다고 생각 합니다.
basilikum

109

초보자가 더 잘 이해할 수 있도록

브라우저 콘솔에서 다음 코드를 시도하십시오.

function Foo() { 
    return this; 
}

var a = Foo();       //returns window object
var b = new Foo();   //returns empty object of foo

a instanceof Window;  // true
a instanceof Foo;     // false

b instanceof Window;  // false
b instanceof Foo;     // true

이제 커뮤니티 위키 답변을 읽을 수 있습니다 :)


4
좋은 대답입니다. 또한-생략 return this;하면 동일한 출력이 생성됩니다.
Nelu

37

따라서 아마도 객체의 인스턴스를 생성하기위한 것이 아닙니다.

그것을 위해 정확하게 사용됩니다. 다음과 같이 함수 생성자를 정의하십시오.

function Person(name) {
    this.name = name;
}

var john = new Person('John');

그러나 ECMAScript의 추가 이점은 .prototype속성을 사용하여 확장 할 수 있으므로 다음과 같은 작업을 수행 할 수 있다는 것입니다.

Person.prototype.getName = function() { return this.name; }

이 생성자에서 생성 된 모든 객체는 이제 getName액세스 할 수있는 프로토 타입 체인 으로 인해 생성됩니다 .


6
함수 생성자는 클래스처럼 사용되며 class키워드 는 없지만 거의 같은 일을 할 수 있습니다.
meder omuraliev

종류 키워드가 있습니다-클래스는 나중에 사용하기 위해 예약되어 있습니다
Greg

11
우연히 .class가 아닌 .className을 사용하여 CSS 클래스를 설정하는 이유
Greg

23
컨벤션에 의해 대문자로 표시되어야합니다.
eomeroff

27

JavaScript 객체 지향 프로그래밍 언어이며 인스턴스 작성에 정확하게 사용됩니다. 클래스 기반이 아니라 프로토 타입 기반이지만 객체 지향적이지 않다는 의미는 아닙니다.


6
JavaScript는 모든 클래스 기반 언어보다 객체 지향적이라고 생각합니다. JavaScript에서는 즉시 작성하는 모든 것이 객체가되지만 클래스 기반 언어에서는 먼저 선언을 작성하고 나중에 클래스의 특정 인스턴스 (객체)를 작성합니다. 그리고 JavaScript 프로토 타입은 클래스 기반 언어를위한 모든 VTABLE 요소를 모호하게 생각 나게합니다.
JustAMartin

14

Javascript는 객체 지향 프로그래밍 패러다임을 지원하는 동적 프로그래밍 언어이며 객체의 새 인스턴스를 만드는 데 사용됩니다.

객체에는 클래스가 필요하지 않습니다. Javascript는 프로토 타입 기반 언어입니다.


12

이미 훌륭한 답변이 있지만 아래의 사례 III 에 대한 관찰을 강조하기 위해 새로운 답변을 게시하고 있습니다 new. 아래 사례를 살펴보십시오.

사례 I :

var Foo = function(){
  this.A = 1; 
  this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1

위의가 가리키는 익명 함수를 호출하는 일반적인 경우입니다 Foo. 이 함수를 호출하면가 반환 undefined됩니다. 명시적인 return 문이 없으므로 JavaScript 인터프리터 return undefined;는 함수 끝에 명령문을 강제로 삽입 합니다. 여기서 window는 thisnew AB속성 을 가져 오는 호출 객체 (contextual )입니다 .

사례 II :

var Foo = function(){
  this.A = 1;
  this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1

new키워드를 보는 JavaScript 인터프리터 는에서 this가리키는 익명 함수 의 호출 객체 (컨텍스트 ) 역할을하는 새 객체를 만듭니다 Foo. 이 경우 AB새로 생성 된 객체가 될 속성 (window 객체 대신에). 명시적인 return 문이 없으므로 JavaScript 인터프리터는 new키워드 사용으로 인해 생성 된 새 객체를 반환하기 위해 return 문을 강제로 삽입 합니다.

사례 III :

var Foo = function(){
  this.A = 1;
  this.B = 2;
  return {C:20,D:30}; 
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.

여기서 new키워드를 보는 JavaScript 인터프리터 는에서 this가리키는 익명 함수 의 호출 객체 (컨텍스트 ) 역할을하는 새 객체를 만듭니다 Foo. 다시, A그리고 B새로 생성 된 객체의 속성이된다. 그러나 이번에는 명시적인 return 문이 있으므로 JavaScript 인터프리터는 자체적으로 아무것도 하지 않습니다 .

III 번의 경우주의해야 할 점은 new키워드 로 인해 생성 된 객체가 레이더에서 손실 되었다는 것입니다 . bar실제로 new키워드 로 인해 JavaScript 인터프리터가 만든 것이 아닌 완전히 다른 객체를 가리키고 있습니다.

JavaScripit : David Flanagan 인용 : 결정적인 안내서 (6 판), Ch. 4, 페이지 62 :

객체 생성 표현식이 평가되면 JavaScript는 먼저 객체 이니셜 라이저 {}에 의해 생성 된 객체와 같은 빈 객체를 새로 만듭니다. 다음으로 지정된 인수를 사용하여 지정된 함수를 호출하고 this 키워드의 값으로 새 객체를 전달합니다. 그런 다음이 함수를 사용하여 새로 만든 객체의 속성을 초기화 할 수 있습니다. 생성자로 사용하기 위해 작성된 함수는 값을 반환하지 않으며 객체 생성 표현식의 값은 새로 생성되고 초기화 된 객체입니다. 생성자가 객체 값을 반환하면 해당 값은 객체 생성 표현식의 값이되고 새로 생성 된 객체는 삭제됩니다.

--- 추가 정보 ---

위의 코드 스 니펫에 사용되는 함수는 JS 세계에서 다음과 같이 특별한 이름을 갖습니다.

사례 I 및 II- 생성자 함수

사례 III- 공장 기능. 팩토리 함수 new 현재 스레드에서 개념을 설명하기 위해 수행 한 키워드 와 함께 사용 해서는 안됩니다 .

스레드 에서 차이점에 대해 읽을 수 있습니다 .


귀하의 사례 3은 gr8 관찰입니다
appu

5

때로는 코드가 단어보다 쉽습니다.

var func1 = function (x) { this.x = x; }                    // used with 'new' only
var func2 = function (x) { var z={}; z.x = x; return z; }   // used both ways
func1.prototype.y = 11;
func2.prototype.y = 12;

A1 = new func1(1);      // has A1.x  AND  A1.y
A2 =     func1(1);      // undefined ('this' refers to 'window')
B1 = new func2(2);      // has B1.x  ONLY
B2 =     func2(2);      // has B2.x  ONLY

필자는 프로토 타입을 사용하지 않는 한 func2 스타일을 사용하여 함수 내부 및 외부에서 약간의 유연성을 제공합니다.


3
B1 = new func2(2); <-왜 이것이 B1.y 없을까요?
sunny_dev

@sunny_dev JS 전문가는 아니지만 func2 가 내부 값으로 작업 / 반환하는 대신 값 (z 객체)을 직접 반환 하기 때문에 (아마 )
Eagle

5

new키워드는 함수가 실행되고있는 아래의 상황을 변경하고 해당 컨텍스트에 대한 포인터를 반환한다.

new키워드를 사용하지 않으면 함수 Vehicle()가 실행되는 컨텍스트는 Vehicle함수를 호출하는 컨텍스트와 동일 합니다. this키워드는 같은 컨텍스트를 참조한다. 을 사용 new Vehicle()하면 새 컨텍스트가 작성되므로 this함수 내의 키워드 가 새 컨텍스트를 참조합니다. 당신이 얻는 것은 새로 작성된 컨텍스트입니다.


그것은 범위 측면에서 매우 통찰력있는 답변입니다. 답변에 Gr8 추가.
appu 2016 년

3

new키워드는 새 개체 인스턴스를 생성합니다. Javascript는 동적 프로그래밍 언어이며 객체 지향 프로그래밍 패러다임을 지원합니다. 객체 이름 지정에 대한 규칙은 항상 새 키워드로 인스턴스화해야하는 객체에 대문자를 사용하는 것입니다.

obj = new Element();

2

요약:

new키워드는 생성자 함수에서 객체를 생성하는 자바 스크립트에 사용됩니다. new키워드는 생성자 함수를 호출하기 전에 배치하는 다음과 같은 일을 할 것입니다 :

  1. 새로운 객체를 생성
  2. 이 객체의 프로토 타입을 생성자 함수의 prototype 속성으로 설정합니다.
  3. this키워드를 새로 만든 객체에 바인딩하고 생성자 함수를 실행합니다
  4. 새로 만든 객체를 반환

예:

function Dog (age) {
  this.age = age;
}

const doggie = new Dog(12);

console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true

정확히 무슨 일이 :

  1. const doggie 말한다 : 우리는 변수를 선언하기 위해 메모리가 필요합니다.
  2. 어설 션 연산자 =는 다음과 같이 말합니다.=
  3. 표현은 new Dog(12)입니다. JS 엔진은 새 키워드를보고 새 개체를 만들고 프로토 타입을 Dog.prototype으로 설정합니다.
  4. 생성자 함수는 this새 객체로 설정된 값으로 실행됩니다 . 이 단계에서는 새로 만든 강아지 개체에 연령이 할당됩니다.
  5. 새로 작성된 오브젝트가 리턴되어 변수 doggie에 지정됩니다.

1

new키워드는 생성자 등의 기능을 사용하여 개체의 인스턴스를 생성합니다. 예를 들어 :

var Foo = function() {};
Foo.prototype.bar = 'bar';

var foo = new Foo();
foo instanceof Foo; // true

인스턴스 prototype는 생성자 함수 에서 상속됩니다 . 위의 예를 들어 ...

foo.bar; // 'bar'

2
new 키워드는 기본적으로 함수를 생성자로 이미 연결합니다. 당신은 아무것도 반환 할 필요가 없습니다. 다음과 같이하면됩니다 : function foo (x) {this.bar = x; } var obj = 새로운 foo (10); 경고 (obj.bar);
reko_t

특별히 의도하지 않는 한 생성자 함수에서 객체를 반환 할 필요는 없습니다. 예를 들어, 어떤 이유로 든 매번 새 객체를 생성하는 대신 특정 객체 인스턴스를 반환해야하는 경우. 그러나 귀하의 예에서는 완전히 불필요합니다.
Chetan Sastry

글쎄, 예입니다. 객체 반환 있습니다 . 이 시나리오에는 여러 가지 패턴이 사용되었는데, 예를 들어 "예"라는 단어를 제공했기 때문에 "예"라는 단어를 제공했습니다.
eyelidlessness

1

JavaScript는 항상 원본 사양 EcmaScript의 구현이므로 플랫폼마다 크게 다를 수 있습니다.

어쨌든 EcmaScript 사양을 따르는 모든 JavaScript 구현은 구현과는 별도로 Object Oriented Language를 제공합니다. ES 표준에 따르면 :

ECMAScript는 호스트 환경 내에서 계산을 수행하고 계산 객체를 조작하기위한 객체 지향 프로그래밍 언어입니다.

이제 JavaScript가 EcmaScript의 구현이므로 객체 지향 언어라는 데 동의했습니다. new모든 객체 지향 언어로 작업을 정의 하면 이러한 키워드는 특정 유형의 클래스 (C #과 같은 경우 익명 유형 포함)에서 객체 인스턴스를 만드는 데 사용됩니다.

EcmaScript에서는 스펙에서 읽을 수있는 클래스를 사용하지 않습니다.

ECMAScript는 C ++, Smalltalk 또는 Java와 같은 클래스를 사용하지 않습니다. 대신 객체는 리터럴 표기법 또는 객체를 생성 한 다음 생성자를 통해 속성을 초기화하여 코드의 전체 또는 일부를 초기화하는 생성자를 통해 다양한 방법으로 생성 될 수 있습니다. 각 생성자는 프로토 타입 기반 상속 및 공유 속성을 구현하는 데 사용되는“prototype”이라는 속성을 가진 함수입니다. 객체는
새로운 표현식에서 생성자를 사용하여 생성됩니다 . 예를 들어 new Date (2009,11)는 새 ​​Date 객체를 만듭니다. new를 사용하지 않고 생성자를 호출하면 생성자에 따라 결과가 달라집니다. 예를 들어, Date ()는 객체가 아닌 현재 날짜와 시간의 문자열 표현을 생성합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.