차이점은 무엇입니까
var A = function () {
this.x = function () {
//do something
};
};
과
var A = function () { };
A.prototype.x = function () {
//do something
};
답변
예제의 결과는 매우 다릅니다.
차이점을 살펴보기 전에 다음 사항에 유의해야합니다.
- 생성자의 프로토 타입 은 인스턴스의 private
[[Prototype]]
속성을 통해 인스턴스간에 메서드와 값을 공유하는 방법을 제공 합니다. - 함수입니다 이이 함수가 호출되는 방법 또는를 사용하여 설정 바인드 (여기서 논의하지 않음). 함수는 객체 (예를 들면 호출되는 경우
myObj.method()
그 다음) 이 있어서 참조 내의 개체. 어디 이이 호출 또는 사용으로 설정되지 않습니다 바인딩 , 그것은 (브라우저의 창) 전역 객체에 대한 기본값 또는 엄격 모드는 정의되지 않은 상태로 유지됩니다. - JavaScript는 객체 지향 언어입니다. 즉, 대부분의 값은 함수를 포함한 객체입니다. (문자열, 숫자 및 부울은 객체 가 아닙니다 .)
문제의 스 니펫은 다음과 같습니다.
var A = function () {
this.x = function () {
//do something
};
};
이 경우 변수 A
에는 함수에 대한 참조 인 값이 할당됩니다. 이 기능을 사용하여 호출 할 때 A()
, 함수의 이이 그것 전역 객체에 대한 기본값과 표현하도록 호출에 의해 설정되지 않은 this.x
효과가있다 window.x
. 결과적으로 오른쪽의 함수 표현식에 대한 참조가에 지정됩니다 window.x
.
다음의 경우 :
var A = function () { };
A.prototype.x = function () {
//do something
};
매우 다른 일이 일어납니다. 첫 번째 줄에서 변수 A
에는 함수에 대한 참조가 할당됩니다. JavaScript에서 모든 함수 객체에는 기본적으로 프로토 타입 속성이 있으므로 A.prototype 객체 를 만드는 별도의 코드가 없습니다 .
두 번째 줄에서 A.prototype.x 에는 함수에 대한 참조가 할당됩니다. x 속성이 없으면 새 속성 을 만들 거나 새 속성이 있으면 새 값을 할당합니다. 따라서 객체의 x 속성이 표현식에 포함 된 첫 번째 예제와의 차이점입니다 .
다른 예는 다음과 같습니다. 그것은 첫 번째 것과 비슷합니다 (아마도 당신이 묻고 싶었던 것) :
var A = new function () {
this.x = function () {
//do something
};
};
이 예제에서는 new
함수가 생성자로 호출되도록 연산자가 함수 표현식 앞에 추가되었습니다. 호출 할 때 new
함수이다 이것은 누구의 개인 새로운 객체 참조로 설정되어 [[Prototype]]
특성 생성자의 공용 참조하도록 설정되어 프로토 타입을 . 대 입문 x
에서이 새 객체에 속성이 생성됩니다. 생성자로 호출되면 함수는 기본적 으로이 객체를 반환 하므로 별도의 return this;
명령문이 필요하지 않습니다 .
A 에 x 속성 이 있는지 확인하려면
console.log(A.x) // function () {
// //do something
// };
생성자를 참조하는 유일한 방법은 A.constructor 를 통하는 것이므로 new를 일반적으로 사용하지 않습니다 . 수행하는 것이 훨씬 일반적입니다.
var A = function () {
this.x = function () {
//do something
};
};
var a = new A();
비슷한 결과를 얻는 또 다른 방법은 즉시 호출 된 함수 표현식을 사용하는 것입니다.
var A = (function () {
this.x = function () {
//do something
};
}());
이 경우 A
오른쪽에서 함수 호출의 반환 값을 할당했습니다. 때문에 여기서 다시, 이것은 호출에 설정되어 있지 않은, 그것은 전역 객체를 참조하는 것 this.x
효과적입니다 window.x
. 이 함수는 아무것도 반환하지 않으므로 A
값은 undefined
입니다.
Javascript 객체를 JSON으로 직렬화하거나 직렬화 해제하는 경우 두 접근 방식 간의 이러한 차이점도 나타납니다. 오브젝트의 프로토 타입에 정의 된 메소드는 오브젝트를 직렬화 할 때 직렬화되지 않습니다. 예를 들어 오브젝트의 데이터 부분 만 직렬화하려고하지만 메소드는 아닙니다.
var A = function () {
this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance));
// {"objectsOwnProperties":"are serialized"}
관련 질문 :
참고 : 두 접근 방식간에 메모리를 크게 절약 할 수는 없지만 프로토 타입을 사용하여 메소드와 속성을 공유하면 각 사본이있는 각 인스턴스보다 적은 메모리를 사용하게됩니다.
JavaScript는 저수준 언어가 아닙니다. 프로토 타입 또는 다른 상속 패턴을 메모리 할당 방식을 명시 적으로 변경하는 방법으로 생각하는 것은 그리 가치가 없을 수 있습니다.
답변
다른 사람들이 첫 번째 버전을 말했듯이, “this”를 사용하면 클래스 A의 모든 인스턴스에 독자적인 함수 메소드 “x”의 사본이 있습니다. “prototype”을 사용한다는 것은 클래스 A의 각 인스턴스가 동일한 방법 “x”의 사본을 사용한다는 것을 의미합니다.
이 미묘한 차이를 보여주는 코드는 다음과 같습니다.
// x is a method assigned to the object using "this"
var A = function () {
this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
this.x = function() { alert( value ); }
};
var a1 = new A();
var a2 = new A();
a1.x(); // Displays 'A'
a2.x(); // Also displays 'A'
a1.updateX('Z');
a1.x(); // Displays 'Z'
a2.x(); // Still displays 'A'
// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };
B.prototype.updateX = function( value ) {
B.prototype.x = function() { alert( value ); }
}
var b1 = new B();
var b2 = new B();
b1.x(); // Displays 'B'
b2.x(); // Also displays 'B'
b1.updateX('Y');
b1.x(); // Displays 'Y'
b2.x(); // Also displays 'Y' because by using prototype we have changed it for all instances
다른 사람들이 언급했듯이 한 가지 방법을 선택해야하는 여러 가지 이유가 있습니다. 내 샘플은 차이점을 명확하게 보여주기위한 것입니다.
답변
이 두 가지 예를 보자.
var A = function() { this.hey = function() { alert('from A') } };
vs.
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
여기에있는 대부분의 사람들 (특히 최고 답변)은 WHY를 설명하지 않고 어떻게 다른지 설명하려고했습니다. 나는 이것이 잘못되었다고 생각하고 기초를 먼저 이해하면 그 차이가 분명해질 것입니다. 기본 사항을 먼저 설명해 봅시다 …
a) 함수는 JavaScript의 객체입니다. 자바 스크립트의 모든 객체 (의미, 당신은, 다른 속성처럼 액세스 크롬 등의 브라우저에서 어쩌면 제외시켰다 없습니다) 내부 속성을 가져옵니다 종종라고 __proto__
(실제로 입력 할 수 있습니다 anyObject.__proto__
무엇을 참조를 볼 크롬에.이 단지이다 , 속성, 그 밖의 것 없음 JavaScript의 속성 = 객체 안의 변수, 그 밖의 것 없음 변수는 무엇을 하는가?
이 __proto__
속성 은 무엇을 가리 킵니까? 글쎄, 일반적으로 다른 객체입니다 (나중에 이유를 설명하겠습니다). __proto__
속성의 JavaScript 가 다른 객체를 가리 키지 않도록 하는 유일한 방법 은을 사용하는 것 var newObj = Object.create(null)
입니다. 이렇게해도 __proto__
STILL 속성은 객체의 속성으로 존재하며 다른 객체를 가리 키지 않고를 가리 킵니다 null
.
대부분의 사람들이 혼란스러워하는 부분은 다음과 같습니다.
JavaScript에서 새 함수 (객체이기도 함을 기억 하는가?)를 작성할 때, 정의 된 순간 JavaScript는 해당 함수에이라는 새 특성을 자동으로 작성합니다 prototype
. 시도 해봐:
var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined
A.prototype
__proto__
속성과 완전히 다릅니다 . 이 예에서 ‘A’에는 이제 ‘prototype’및이라는 두 가지 속성이 __proto__
있습니다. 이것은 사람들에게 큰 혼란입니다. prototype
및 __proto__
특성과 관련된 어떠한 방식으로, 그들은 별도의 값을 가리키는 별도의 일을 것입니다.
궁금 할 수도 있습니다. 왜 __proto__
모든 객체에 JavaScript가 속성을 생성합니까? 한마디 : 위임 . 객체에서 속성을 호출 할 때 객체에 속성이없는 경우 JavaScript는 참조 된 객체를 찾아 해당 객체 __proto__
가 있는지 확인합니다. 그것이 없다면, 그 객체의 __proto__
속성 등을보고 … 체인이 끝날 때까지. 따라서 이름 프로토 타입 체인 입니다. 물론 __proto__
객체를 가리 키지 않고 대신 null
운이 좋은 운임을 가리키면 JavaScript가이를 인식 undefined
하고 속성을 반환합니다 .
prototype
함수를 정의 할 때 JavaScript가 함수에 대한 속성을 작성하는 이유가 궁금 할 수도 있습니다. 그것은 당신을 속이려고하기 때문에, 클래스 기반 언어처럼 작동한다는 것을 속이십시오 .
예제로 넘어 가서 “object”를 만들어 봅시다 A
:
var a1 = new A();
이 일이 발생했을 때 백그라운드에서 무언가가 발생했습니다. a1
새로운 빈 객체에 할당 된 일반 변수입니다.
new
함수 호출 전에 연산자를 사용했다는 사실 A()
은 백그라운드에서 추가 작업을 수행했습니다. new
키워드는 이제 참조를 새로운 객체를 생성 a1
하고 그 객체가 비어 있습니다. 추가로 일어나는 일은 다음과 같습니다.
우리는 각 함수 정의에 prototype
( __proto__
프로퍼티 와 달리 액세스 할 수 있는) 새로운 프로퍼티가 생성되었다고 말했 습니까? 그 속성은 현재 사용되고 있습니다.
이제 우리는 갓 구운 빈 a1
물건 이있는 지점에 있습니다 . 우리는 JavaScript의 모든 객체 가 null이든 다른 객체이든 __proto__
무언가를 가리키는 내부 속성을 가지고 있다고 말했습니다 a1
. 무엇 new
운영자가하는 것은 그 설정이다 __proto__
함수의에 지점 속성을 prototype
속성입니다. 다시 읽어보세요. 기본적으로 이것입니다 :
a1.__proto__ = A.prototype;
우리는 A.prototype
그것을 정의하기 전에 다른 것으로 변경하지 않는 한 빈 객체에 지나지 않는다고 말했습니다 a1
. 이제는 기본적으로 a1.__proto__
같은 A.prototype
빈 객체를 가리 킵니다. 그들은이 줄이 발생할 때 만들어진 동일한 객체를 가리 킵니다.
A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}
이제 var a1 = new A()
진술이 처리 될 때 또 다른 일이 발생 합니다. 기본적 A()
으로 실행되고 A가 다음과 같은 경우 :
var A = function() { this.hey = function() { alert('from A') } };
내부의 모든 것들이 function() { }
실행될 것입니다. this.hey..
라인에 도달하면 this
로 변경되고 다음 a1
과 같은 결과가 나타납니다.
a1.hey = function() { alert('from A') }
this
변경 이유 를 다루지는a1
않지만 자세한 내용 은이 답변 을 참조하십시오.
요약 var a1 = new A()
하면 백그라운드에서 3 가지 일이 발생합니다.
- 완전히 새로운 빈 객체가 생성되어에 할당됩니다
a1
.a1 = {}
-
a1.__proto__
속성은A.prototype
(또 다른 빈 객체 {}) 를 가리키는 것과 동일한 것을 가리 키도록 할당됩니다. -
1 단계에서 생성 된 새로운 빈 객체
A()
로this
설정하여 함수 를 실행 중입니다 (위에서 내가 왜this
변경 했는지에 대한 대답을 읽으십시오a1
)
이제 다른 객체를 만들어 봅시다 :
var a2 = new A();
1,2,3 단계가 반복됩니다. 당신은 뭔가를 알아? 핵심 단어는 반복입니다. 1 단계 : a2
새로운 빈 객체가 될 것입니다 .2 단계 : __proto__
속성이 같은 것을 A.prototype
가리키고 가장 중요하게 A()
는 3 단계 : 함수 가 다시 실행 a2
됩니다. 즉, 함수 가 hey
포함 된 속성을 얻습니다 . a1
및 a2
라는 두 개의 별도의 속성이 hey
이 개 별도의 기능을 가리! 우리는 이제 같은 일을하는 동일한 두 개의 다른 객체에 중복 함수를 new A
가지고 있습니다. 우리는 이것을 어떻게 방지합니까?
왜 __proto__
모든 개체에 속성이 존재 하는지 기억 하십니까? yoMan
속성 을 검색하면 a1
(존재하지 않는) __proto__
속성이 참조되며, 속성이 객체 (대부분의 경우) 인 경우 속성이 포함되어 있는지 확인 yoMan
하고 그렇지 않은 경우 해당 객체 __proto__
등 을 참조 할 것입니다 . 그렇다면 해당 속성 값을 가져 와서 표시합니다.
그래서 누군가 가이 사실 +을 만들 때 a1
그 __proto__
속성이 동일한 (빈) 객체를 A.prototype
가리키고 이것을 수행한다는 사실을 사용하기로 결정했습니다 .
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
멋있는! 이제 생성 할 때 a1
위의 3 단계를 모두 거치고 3 단계에서는 아무것도 수행하지 않으므로 아무것도하지 않습니다 function A()
. 그리고 우리가 할 경우 :
a1.hey
그것은 그 볼 a1
이 포함되어 있지 않습니다 hey
및 그것 확인합니다 __proto__
그것이 어떤 경우인지, 그것을 가지고 있는지 확인하기 위해 속성 개체를.
이 방법을 사용하면 3 단계에서 각각의 새 객체 생성시 함수가 복제되는 부분을 제거합니다. 대신에 a1
와 a2
별도 가지는 hey
속성을, 지금 그들 중 누구도 그것을이 없습니다. 당신이 지금까지 알아 낸 것 같아요. 좋은 점입니다. 이해 __proto__
하고 Function.prototype
있다면 이와 같은 질문은 매우 분명합니다.
참고 : 일부 사람들은 내부 프로토 타입 속성을로 부르지 않는 경향 __proto__
이 있습니다.이 게시물을 통해이 이름을 사용 Functional.prototype
하여 두 가지 다른 속성으로 속성을 명확하게 구분했습니다 .
답변
대부분의 경우 기본적으로 동일하지만 두 번째 버전은 각 객체에 대해 별도의 함수 대신 하나의 함수 인스턴스 만 있기 때문에 메모리를 절약합니다.
첫 번째 양식을 사용하는 이유는 “개인 구성원”에 액세스하기위한 것입니다. 예를 들면 다음과 같습니다.
var A = function () {
var private_var = ...;
this.x = function () {
return private_var;
};
this.setX = function (new_x) {
private_var = new_x;
};
};
javascript의 범위 지정 규칙으로 인해 private_var는 this.x에 지정된 함수에 사용할 수 있지만 객체 외부에서는 사용할 수 없습니다.
답변
첫 번째 예는 해당 객체의 인터페이스 만 변경합니다. 두 번째 예는 해당 클래스의 모든 객체에 대한 인터페이스를 변경합니다.
답변
this
대신에 사용 하는 데있어 궁극적 인 문제 prototype
는 메소드를 대체 할 때 기본 클래스의 생성자가 여전히 대체 된 메소드를 참조한다는 것입니다. 이걸 고려하세요:
BaseClass = function() {
var text = null;
this.setText = function(value) {
text = value + " BaseClass!";
};
this.getText = function() {
return text;
};
this.setText("Hello"); // This always calls BaseClass.setText()
};
SubClass = function() {
// setText is not overridden yet,
// so the constructor calls the superclass' method
BaseClass.call(this);
// Keeping a reference to the superclass' method
var super_setText = this.setText;
// Overriding
this.setText = function(value) {
super_setText.call(this, "SubClass says: " + value);
};
};
SubClass.prototype = new BaseClass();
var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!
subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
대:
BaseClass = function() {
this.setText("Hello"); // This calls the overridden method
};
BaseClass.prototype.setText = function(value) {
this.text = value + " BaseClass!";
};
BaseClass.prototype.getText = function() {
return this.text;
};
SubClass = function() {
// setText is already overridden, so this works as expected
BaseClass.call(this);
};
SubClass.prototype = new BaseClass();
SubClass.prototype.setText = function(value) {
BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};
var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
이것이 문제가 아니라고 생각한다면, 그것은 사적 변수없이 살 수 있는지, 그리고 누수를 볼 때 누수를 알기에 충분한 경험이 있는지에 달려 있습니다. 또한 메소드 정의 후에 생성자 논리를 넣어야하는 것이 불편합니다.
var A = function (param1) {
var privateVar = null; // Private variable
// Calling this.setPrivateVar(param1) here would be an error
this.setPrivateVar = function (value) {
privateVar = value;
console.log("setPrivateVar value set to: " + value);
// param1 is still here, possible memory leak
console.log("setPrivateVar has param1: " + param1);
};
// The constructor logic starts here possibly after
// many lines of code that define methods
this.setPrivateVar(param1); // This is valid
};
var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0
a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0
대:
var A = function (param1) {
this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
this.publicVar = value; // No private variable
};
var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1
답변
모든 객체는 프로토 타입 객체에 연결됩니다. 존재하지 않는 속성에 액세스하려고하면 JavaScript는 해당 속성에 대한 객체의 프로토 타입 객체를 찾아 해당 속성이있는 경우이를 반환합니다.
prototype
함수 생성자 의 속성은를 사용할 때 해당 함수로 생성 된 모든 인스턴스의 프로토 타입 객체를 나타냅니다 new
.
첫 번째 예에서는 함수로 x
만든 각 인스턴스에 속성 을 추가 A
합니다.
var A = function () {
this.x = function () {
//do something
};
};
var a = new A(); // constructor function gets executed
// newly created object gets an 'x' property
// which is a function
a.x(); // and can be called like this
두 번째 예에서는 모든 인스턴스가 A
가리키는 프로토 타입 객체에 속성을 추가합니다 .
var A = function () { };
A.prototype.x = function () {
//do something
};
var a = new A(); // constructor function gets executed
// which does nothing in this example
a.x(); // you are trying to access the 'x' property of an instance of 'A'
// which does not exist
// so JavaScript looks for that property in the prototype object
// that was defined using the 'prototype' property of the constructor
결론적으로, 첫 번째 예 에서는 함수의 사본이 각 인스턴스에 할당됩니다 . 두 번째 예 에서 함수의 단일 사본은 모든 인스턴스에서 공유됩니다 .