질문자 :John Leidegren
저는 동적 프로그래밍 언어에 익숙하지 않지만 JavaScript 코드를 상당 부분 작성했습니다. 저는 이 프로토타입 기반 프로그래밍에 대해 전혀 머리를 쓰지 못했습니다. 이것이 어떻게 작동하는지 아는 사람이 있습니까?
var obj = new Object(); obj.prototype.test = function() { alert('Hello?'); }; var obj2 = new obj(); obj2.test();
나는 얼마 전에 사람들과 많은 토론을 했던 것을 기억합니다(제가 무엇을 하는지 정확히 모르겠습니다). 그러나 제가 이해하기로는 수업에 대한 개념이 없습니다. 그것은 단지 개체이고 그 개체의 인스턴스는 원본의 클론입니다. 그렇죠?
그러나 JavaScript에서 이 ".prototype" 속성의 정확한 목적은 무엇입니까? 객체를 인스턴스화하는 것과 어떤 관련이 있습니까?
업데이트: 올바른 방법
var obj = new Object(); // not a functional object obj.prototype.test = function() { alert('Hello?'); }; // this is wrong! function MyObject() {} // a first class functional object MyObject.prototype.test = function() { alert('OK'); } // OK
또한 이 슬라이드는 정말 많은 도움이 되었습니다.
Java, C# 또는 C++와 같은 고전적 상속을 구현하는 언어에서는 객체에 대한 청사진인 클래스를 생성하여 시작한 다음 해당 클래스에서 새 객체를 생성하거나 클래스를 확장하여 확장하는 새 클래스를 정의할 수 있습니다. 원래 수업.
JavaScript에서는 먼저 객체(클래스 개념 없음)를 만든 다음 자신의 객체를 보강하거나 이 객체에서 새 객체를 만들 수 있습니다. 어렵지는 않지만 고전적인 방식에 익숙한 사람에게는 약간 생소하고 대사하기 어렵습니다.
예시:
//Define a functional object to hold persons in JavaScript var Person = function(name) { this.name = name; }; //Add dynamically to the already defined object a new getter Person.prototype.getName = function() { return this.name; }; //Create a new object of type Person var john = new Person("John"); //Try the getter alert(john.getName()); //If now I modify person, also John gets the updates Person.prototype.sayMyName = function() { alert('Hello, my name is ' + this.getName()); }; //Call the new method on john john.sayMyName();
지금까지 기본 개체를 확장해 왔으며 이제 다른 개체를 만든 다음 Person에서 상속합니다.
//Create a new object of type Customer by defining its constructor. It's not //related to Person for now. var Customer = function(name) { this.name = name; }; //Now I link the objects and to do so, we link the prototype of Customer to //a new instance of Person. The prototype is the base that will be used to //construct all new instances and also, will modify dynamically all already //constructed objects because in JavaScript objects retain a pointer to the //prototype Customer.prototype = new Person(); //Now I can call the methods of Person on the Customer, let's try, first //I need to create a Customer. var myCustomer = new Customer('Dream Inc.'); myCustomer.sayMyName(); //If I add new methods to Person, they will be added to Customer, but if I //add new methods to Customer they won't be added to Person. Example: Customer.prototype.setAmountDue = function(amountDue) { this.amountDue = amountDue; }; Customer.prototype.getAmountDue = function() { return this.amountDue; }; //Let's try: myCustomer.setAmountDue(2000); alert(myCustomer.getAmountDue());
var Person = function (name) { this.name = name; }; Person.prototype.getName = function () { return this.name; }; var john = new Person("John"); alert(john.getName()); Person.prototype.sayMyName = function () { alert('Hello, my name is ' + this.getName()); }; john.sayMyName(); var Customer = function (name) { this.name = name; }; Customer.prototype = new Person(); var myCustomer = new Customer('Dream Inc.'); myCustomer.sayMyName(); Customer.prototype.setAmountDue = function (amountDue) { this.amountDue = amountDue; }; Customer.prototype.getAmountDue = function () { return this.amountDue; }; myCustomer.setAmountDue(2000); alert(myCustomer.getAmountDue());
말했듯이 나는 사람에 대해 setAmountDue(), getAmountDue()를 호출할 수 없습니다.
//The following statement generates an error. john.setAmountDue(1000);
stivlo모든 JavaScript 개체에는 값이 null
또는 object
[[Prototype]]
이라는 내부 "슬롯" 이 있습니다. 슬롯은 작성하는 코드에서 숨겨진 JavaScript 엔진 내부의 객체 속성으로 생각할 수 있습니다. [[Prototype]]
주위의 대괄호는 의도적이며 내부 슬롯을 나타내는 ECMAScript 사양 규칙입니다.
[[Prototype]]
이 가리키는 값은 구어체로 "해당 객체의 프로토타입"으로 알려져 있습니다.
obj.propName
) 또는 대괄호( obj['propName']
) 표기법을 통해 속성에 액세스하고 객체에 직접 이러한 속성이 없는 경우(즉, 자체 속성 obj.hasOwnProperty('propName')
통해 확인할 수 있음) obj.hasOwnProperty('propName')
), 런타임은 대신 [[Prototype]]
에서 참조하는 개체에서 해당 이름을 가진 속성을 찾습니다. [[Prototype]]
에도 이러한 속성이 없으면 [[Prototype]]
이 차례로 확인되는 식입니다. 이런 식으로 원본 개체의 프로토타입 체인 은 일치하는 항목을 찾거나 끝 부분에 도달할 때까지 진행됩니다. 프로토타입 체인의 맨 위에는 null
값이 있습니다.
최신 JavaScript 구현은 다음과 같은 방식으로 [[Prototype]]
에 대한 읽기 및/또는 쓰기 액세스를 허용합니다.
-
new
연산자(생성자 함수에서 반환된 기본 개체에 대한 프로토타입 체인 구성), -
extends
키워드(클래스 구문을 사용할 때 프로토타입 체인 구성), -
Object.create
는 제공된 인수를 [[Prototype]]
으로 설정합니다. -
Object.getPrototypeOf
및 Object.setPrototypeOf
(객체 생성 후 [[Prototype]]
가져오기/설정) 및 -
__proto__
라는 표준화된 접근자(예: getter/setter) 속성(4와 유사)
Object.getPrototypeOf
및 Object.setPrototypeOf
__proto__
보다 선호됩니다. 부분적으로 null
프로토타입이 있을 때 o.__proto__
의 동작이 비정상적 이기 때문입니다.
개체의 [[Prototype]]
은 개체 생성 중에 초기에 설정됩니다.
new Func()
를 통해 새 객체를 생성하는 경우 객체의 [[Prototype]]
Func.prototype
참조하는 객체로 설정됩니다.
따라서 new
연산자와 함께 사용할 수 있는 모든 함수에는 자체 [[Prototype]]
내부 슬롯 .prototype
이라는 속성이 있습니다. "프로토타입"이라는 단어의 이중 사용은 언어를 처음 접하는 사람들 사이에서 끝없는 혼란의 근원입니다.
new
를 사용하면 JavaScript에서 고전 상속을 시뮬레이션할 수 있습니다. JavaScript의 상속 시스템은 우리가 보았듯이 클래스 기반이 아니라 프로토타입입니다.
JavaScript에 클래스 구문이 도입되기 전에는 생성자 함수가 클래스를 시뮬레이션하는 유일한 방법이었습니다. 생성자 함수의 .prototype 속성이 참조하는 객체의 속성을 공유 멤버로 .prototype
즉. 각 인스턴스에 대해 동일한 구성원입니다. 클래스 기반 시스템에서 메서드는 각 인스턴스에 대해 동일한 방식으로 구현되므로 메서드는 개념적으로 .prototype
속성에 추가됩니다. 그러나 개체의 필드는 인스턴스에 따라 다르므로 구성 중에 개체 자체에 추가됩니다.
클래스 구문이 없으면 개발자는 수동으로 프로토타입 체인을 구성하여 클래식 상속과 유사한 기능을 구현해야 했습니다. 이로 인해 이를 달성하기 위한 다양한 방법이 우세했습니다.
한 가지 방법은 다음과 같습니다.
function Child() {} function Parent() {} Parent.prototype.inheritedMethod = function () { return 'this is inherited' } function inherit(child, parent) { child.prototype = Object.create(parent.prototype) child.prototype.constructor = child return child; } Child = inherit(Child, Parent) const o = new Child console.log(o.inheritedMethod()) // 'this is inherited'
...또 다른 방법이 있습니다.
function Child() {} function Parent() {} Parent.prototype.inheritedMethod = function () { return 'this is inherited' } function inherit(child, parent) { function tmp() {} tmp.prototype = parent.prototype const proto = new tmp() proto.constructor = child child.prototype = proto return child } Child = inherit(Child, Parent) const o = new Child console.log(o.inheritedMethod()) // 'this is inherited'
ES2015에 도입된 클래스 구문은 JavaScript에서 고전적인 상속을 시뮬레이션하기 위해 프로토타입 체인을 구성하는 "단 하나의 진정한 방법"으로 extends
따라서 위의 코드와 유사하게 클래스 구문을 사용하여 다음과 같이 새 객체를 생성하는 경우:
class Parent { inheritedMethod() { return 'this is inherited' } } class Child extends Parent {} const o = new Child console.log(o.inheritedMethod()) // 'this is inherited'
...결과 객체의 [[Prototype]]
[[Prototype]]
이 Parent.prototype
인 Parent
의 인스턴스로 설정됩니다.
Object.create(foo)
를 통해 새 객체를 생성하면 결과 객체의 [[Prototype]]
foo
로 설정됩니다.
Christoph이것은 설명 중에 샘플로 간주되는 매우 간단한 프로토타입 기반 개체 모델이며 아직 설명이 없습니다.
function Person(name){ this.name = name; } Person.prototype.getName = function(){ console.log(this.name); } var person = new Person("George");
프로토타입 개념을 살펴보기 전에 고려해야 할 몇 가지 중요한 사항이 있습니다.
1- JavaScript 기능이 실제로 작동하는 방식:
첫 번째 단계를 밟기 위해 우리는 JavaScript 함수가 실제로 어떻게 작동 this
키워드를 사용하는 클래스와 같은 클래스 또는 인수가 있는 일반 함수로서 수행하는 작업과 반환하는 내용을 파악해야 합니다.
Person
객체 모델을 만들고 싶다고 가정해 봅시다. 하지만 이 단계에서 나는 prototype
과 new
키워드를 사용하지 않고 똑같은 일을 하려고 할 것입니다.
따라서 이 단계에서는 functions
, objects
및 this
키워드만 있으면 됩니다.
첫 번째 질문은 this
new
키워드를 사용하지 않고 어떻게 유용할 수 있느냐는 것입니다.
따라서 빈 객체가 있고 다음과 같은 두 가지 기능이 있다고 가정해 보겠습니다.
var person = {}; function Person(name){ this.name = name; } function getName(){ console.log(this.name); }
이제 new
키워드를 사용하지 않고 이러한 기능을 어떻게 사용할 수 있는지 알아보겠습니다. 따라서 JavaScript에는 이를 수행하는 3가지 다른 방법이 있습니다.
NS. 첫 번째 방법은 함수를 일반 함수로 호출하는 것입니다.
Person("George"); getName();//would print the "George" in the console
이 경우 현재 컨텍스트 객체가 됩니다. 일반적으로 window
객체 또는 Node.js
GLOBAL
입니다. 이는 "George"를 값으로 하여 브라우저에 window.name을, Node.js에 GLOBAL.name을 가질 수 있음을 의미합니다.
NS. 우리는 그것들을 속성으로 객체에 붙일 수 있습니다
- 이를 수행 하는 가장 쉬운 방법 person
개체를 수정하는 것입니다.
person.Person = Person; person.getName = getName;
이렇게 하면 다음과 같이 호출할 수 있습니다.
person.Person("George"); person.getName();// -->"George"
이제 person
객체는 다음과 같습니다.
Object {Person: function, getName: function, name: "George"}
- 객체에 속성을 추가하는 다른 방법 __proto__
라는 이름의 JavaScript 객체에서 찾을 수 있는 해당 객체 prototype
을 사용하는 것이며 요약 부분에서 약간 설명하려고 했습니다. 따라서 다음을 수행하여 비슷한 결과를 얻을 수 있습니다.
person.__proto__.Person = Person; person.__proto__.getName = getName;
그러나 이런 식으로 우리가 실제로 하고 있는 것은 Object.prototype
{ ... }
)을 사용하여 JavaScript 객체를 생성할 때마다 Object.prototype
기반으로 생성되기 때문에 새로 생성된 객체에 첨부된다는 의미입니다. __proto__
라는 속성으로 변경하면 이전 코드 스니펫에서 수행한 것처럼 모든 JavaScript 개체가 변경되지만 좋은 방법은 아닙니다. 이제 더 나은 방법은 무엇입니까?
person.__proto__ = { Person: Person, getName: getName };
이제 다른 개체는 평화롭지만 여전히 좋은 습관은 아닌 것 같습니다. 그래서 아직 하나의 솔루션이 더 있지만 이 솔루션을 사용하려면 person
객체가 생성된 var person = {};
)로 돌아가서 다음과 같이 변경해야 합니다.
var propertiesObject = { Person: Person, getName: getName }; var person = Object.create(propertiesObject);
그것이 하는 일은 새로운 JavaScript Object
propertiesObject
를 __proto__
속성에 첨부하는 것입니다. 따라서 다음을 수행할 수 있습니다.
console.log(person.__proto__===propertiesObject); //true
person
객체의 첫 번째 수준 __proto__
에 정의된 모든 속성에 액세스할 수 있다는 것입니다(자세한 내용은 요약 부분 참조).
이 두 가지 방법 중 하나를 사용하는 것을 볼 수 있듯이 this
person
객체를 가리킬 것입니다.
씨. JavaScript에는 함수를 호출하기 위해 호출 또는 적용 을 사용하는 this
와 함께 함수를 제공하는 또 다른 방법이 있습니다.
apply() 메서드는 주어진 this 값과 배열(또는 배열과 유사한 객체)로 제공된 인수로 함수를 호출합니다.
그리고
call() 메소드는 주어진 이 값과 개별적으로 제공된 인수로 함수를 호출합니다.
내가 가장 좋아하는 이 방법으로 다음과 같은 함수를 쉽게 호출할 수 있습니다.
Person.call(person, "George");
또는
//apply is more useful when params count is not fixed Person.apply(person, ["George"]); getName.call(person); getName.apply(person);
이 3가지 방법은 .prototype 기능을 파악하기 위한 중요한 초기 단계입니다.
new
키워드는 어떻게 작동합니까?
.prototype
기능을 이해하는 두 번째 단계입니다. 이것이 제가 프로세스를 시뮬레이션하는 데 사용하는 것입니다.
function Person(name){ this.name = name; } my_person_prototype = { getName: function(){ console.log(this.name); } };
이 부분에서 나는 사용하지 않고, 자바 스크립트가 수행하는 모든 조치를 취하려고 할거야 new
키워드 및 prototype
사용할 때, new
키워드를. new Person("George")
을 수행할 때 Person
함수는 생성자 역할을 합니다. JavaScript가 하나씩 수행하는 작업은 다음과 같습니다.
NS. 우선 다음과 같은 빈 객체, 기본적으로 빈 해시를 만듭니다.
var newObject = {};
NS. JavaScript가 취하는 다음 단계는 모든 프로토타입 객체를 새로 생성된 객체 에 첨부하는 것입니다.
여기에 프로토타입 객체와 유사한 my_person_prototype
for(var key in my_person_prototype){ newObject[key] = my_person_prototype[key]; }
JavaScript가 프로토타입에 정의된 속성을 실제로 첨부하는 방식이 아닙니다. 실제 방법은 프로토타입 체인 개념과 관련이 있습니다.
NS. & NS. 이 두 단계 대신 다음을 수행하여 똑같은 결과를 얻을 수 있습니다.
var newObject = Object.create(my_person_prototype); //here you can check out the __proto__ attribute console.log(newObject.__proto__ === my_person_prototype); //true //and also check if you have access to your desired properties console.log(typeof newObject.getName);//"function"
my_person_prototype
getName
함수를 호출할 수 있습니다.
newObject.getName();
씨. 그런 다음 해당 객체를 생성자에 제공합니다.
다음과 같은 샘플로 이 작업을 수행할 수 있습니다.
Person.call(newObject, "George");
또는
Person.apply(newObject, ["George"]);
그러면 생성자는 원하는 모든 작업을 수행할 수 있습니다. 해당 생성자 내부의 this 는 방금 생성된 객체이기 때문입니다.
이제 다른 단계를 시뮬레이션하기 전의 최종 결과: Object {name: "George"}
요약:
기본적으로 함수에서 new 키워드를 사용하면 해당 함수를 호출하고 해당 함수가 생성자 역할을 하므로 다음과 같이 말할 수 있습니다.
new FunctionName()
JavaScript는 내부적으로 객체, 즉 빈 해시를 만든 다음 해당 객체를 생성자에 제공합니다. 그러면 생성자는 원하는 모든 작업을 수행할 수 있습니다. 해당 생성자 내부의 this 는 방금 생성된 객체이고 물론 해당 객체를 제공하기 때문입니다. 함수에서 return 문을 사용하지 않았거나 return undefined;
함수 본문의 끝에서.
따라서 JavaScript가 객체의 속성을 조회할 때 가장 먼저 하는 일은 해당 객체에서 조회하는 것입니다. 그리고 비밀 속성 [[prototype]]
이 있습니다. 일반적으로 __proto__
와 같은 속성을 가지고 있으며 그 속성은 JavaScript가 다음에 살펴보는 것입니다. __proto__
통해 볼 때 또 다른 JavaScript 객체인 한 자체 __proto__
__proto__
가 null인 지점에 도달할 때까지 계속 올라갑니다. 요점은 JavaScript에서 __proto__
속성이 null인 Object.prototype
객체라는 것입니다.
console.log(Object.prototype.__proto__===null);//true
이것이 JavaScript에서 상속이 작동하는 방식입니다.
다시 말해서, 함수에 대한 프로토타입 속성이 있고 그것에 대해 new를 호출하면 JavaScript가 속성에 대해 새로 생성된 객체를 살펴본 후 함수의 .prototype
살펴보고 이 객체가 자체 내부 프로토타입이 있습니다. 등등.
Mehran Hatami프로토타입의 일곱 Koans
Ciro San이 깊은 명상을 한 후 Mount Fire Fox를 내려왔을 때 그의 마음은 깨끗하고 평화로웠습니다.
그러나 그의 손은 쉬지 않고 스스로 붓을 잡고 다음과 같은 메모를 적었다.
0) 두 가지 다른 것을 "프로토타입"이라고 부를 수 있습니다.
obj.prototype
에서와 같이 프로토타입 속성
프로토타입 내부 속성, ES5에서 [[Prototype]]
으로 표시됩니다.
Object.getPrototypeOf()
를 통해 검색할 수 있습니다.
Firefox는 확장으로 __proto__
속성을 통해 액세스할 수 있도록 합니다. ES6은 이제 __proto__
대한 몇 가지 선택적 요구 사항을 언급합니다.
1) 이러한 개념은 다음 질문에 답하기 위해 존재합니다.
obj.property
할 때 .property
어디에서 찾습니까?
직관적으로 클래식 상속은 속성 조회에 영향을 미칩니다.
2)
-
__proto__
는 점에 사용됩니다 .
obj.property
에서와 같이 속성 조회. -
.prototype
은 조회에 직접 사용되지 않고 new
로 객체 생성 시 __proto__
를 결정하기 때문에 간접적으로만 사용됩니다.
조회 순서는 다음과 같습니다.
-
obj.p = ...
또는 Object.defineProperty(obj, ...)
추가된 obj
-
obj.__proto__
속성 -
obj.__proto__.__proto__
속성 등 - 일부
__proto__
가 null
undefined
반환합니다.
이것이 이른바 프로토타입 체인 입니다.
피할 수 있습니다 .
obj.hasOwnProperty('key')
및 Object.getOwnPropertyNames(f)
조회
3) obj.__proto__
를 설정하는 두 가지 주요 방법이 있습니다.
new
:
var F = function() {} var f = new F()
그런 다음 new
가 설정했습니다.
f.__proto__ === F.prototype
여기 에서 .prototype
이 사용됩니다.
Object.create
:
f = Object.create(proto)
세트:
f.__proto__ === proto
4) 코드:
var F = function(i) { this.i = i } var f = new F(1)
다음 다이어그램에 해당합니다(일부 Number
은 생략됨).
(Function) ( F ) (f)----->(1) | ^ | | ^ | i | | | | | | | | | | | | +-------------------------+ | | | |constructor | | | | | | | | +--------------+ | | | | | | | | | | | | | | | | | |[[Prototype]] |[[Prototype]] |prototype |constructor |[[Prototype]] | | | | | | | | | | | | | | | | | | +----------+ | | | | | | | | | | | | | | +-----------------------+ | | | | | | | | v | vv | v | (Function.prototype) (F.prototype) | | | | | | | |[[Prototype]] |[[Prototype]] [[Prototype]]| | | | | | | | +-------------------------------+ | | | | vvv (Object.prototype) (Number.prototype) | | ^ | | | | | +---------------------------+ | | | | +--------------+ | | | | | | | |[[Prototype]] |constructor |prototype | | | | | | | | -------------+ | | | vv | (null) (Object)
이 다이어그램은 사전 정의된 많은 언어 개체 노드를 보여줍니다.
-
null
-
Object
-
Object.prototype
-
Function
-
Function.prototype
-
1
-
Number.prototype
(1).__proto__
에서 찾을 수 있으며, 구문을 충족하려면 괄호가 필수임)
2줄의 코드는 다음과 같은 새 객체만 생성했습니다.
i
f
의 속성입니다. 왜냐하면 당신이 할 때:
var f = new F(1)
그 평가 F
가진 this
그 가치 new
다음 지정된 도착 반환, f
.
5) .constructor
일반적에서 오는 F.prototype
관통 .
조회:
f.constructor === F !f.hasOwnProperty('constructor') Object.getPrototypeOf(f) === F.prototype F.prototype.hasOwnProperty('constructor') F.prototype.constructor === f.constructor
f.constructor
를 작성할 때 JavaScript는 .
다음과 같이 조회:
-
f
.constructor
가 없습니다. -
f.__proto__ === F.prototype
에는 .constructor === F
가 있으므로 가져오세요.
f.constructor == F
결과는 직관적으로 정확합니다. F
는 고전적인 OOP 언어에서와 같이 필드를 설정하는 것과 같이 f
를 구성하는 데 사용되기 때문입니다.
6) 프로토타입 체인을 조작하여 고전적인 상속 구문을 얻을 수 있습니다.
ES6은 이전에 가능했던 프로토타입 조작 광기에 대한 대부분의 구문 설탕인 class
추가하고 extends
class C { constructor(i) { this.i = i } inc() { return this.i + 1 } } class D extends C { constructor(i) { super(i) } inc2() { return this.i + 2 } }
// Inheritance syntax works as expected. c = new C(1) c.inc() === 2 (new D(1)).inc() === 2 (new D(1)).inc2() === 3
// "Classes" are just function objects. C.constructor === Function C.__proto__ === Function.prototype D.constructor === Function // D is a function "indirectly" through the chain. D.__proto__ === C D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class // lookups will work as expected var d = new D(1) d.__proto__ === D.prototype D.prototype.__proto__ === C.prototype // This is what `d.inc` actually does. d.__proto__.__proto__.inc === C.prototype.inc
// Class variables // No ES6 syntax sugar apparently: // http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives Cc = 1 Cc === 1 // Because `D.__proto__ === C`. Dc === 1 // Nothing makes this work. dc === undefined
사전 정의된 모든 개체가 없는 단순화된 다이어그램:
(c)----->(1) | i | | |[[Prototype]] | | v __proto__ (C)<--------------(D) (d) | | | | | | | | | |prototype |prototype |[[Prototype]] | | | | | | | | | | | +---------+ | | | | | | | | | | vv |[[Prototype]] (D.prototype)--------> (inc2 function object) | | | inc2 | | | | | |[[Prototype]] | | | | | | | | +--------------+ | | | | | | | vv | (C.prototype)------->(inc function object) | inc v Function.prototype
다음이 어떻게 작동하는지 잠시 살펴보겠습니다.
c = new C(1) c.inc() === 2
첫 번째 줄은 "4)"에서 설명한 대로 ci
를 1
두 번째 줄에서 다음을 수행합니다.
c.inc()
-
.inc
[[Prototype]]
체인을 통해 찾을 수 있습니다 c
-> C
-> C.prototype
-> inc
- 자바스크립트에서 함수를
XY()
로 호출하면 자바스크립트는 자동으로 Y()
함수 호출 내에서 this
X
와 동일하게 설정합니다!
똑같은 논리로 d.inc
와 d.inc2
도 설명합니다.
이 기사 https://javascript.info/class#not-just-a-syntax-sugar 는 알 가치가 class
추가 효과에 대해 언급합니다. class
키워드 없이는 달성할 수 없습니다(TODO 확인):
-
[[FunctionKind]]:"classConstructor"
, new로 생성자를 강제로 호출: ES6 클래스 생성자를 일반 함수로 호출할 수 없는 이유는 무엇입니까? - 클래스 메서드는 열거할 수 없습니다.
Object.defineProperty
로 수행할 수 있습니다. - 클래스는 항상
use strict
. use strict
를 명시적으로 사용하여 수행할 수 있습니다. 이는 확실히 지루합니다.
Ciro Santilli 新疆再教育营六四事件法轮功郝海东prototype
사용하면 클래스를 만들 수 있습니다. prototype
을 사용하지 않으면 정적이 됩니다.
다음은 짧은 예입니다.
var obj = new Object(); obj.test = function() { alert('Hello?'); };
위의 경우 정적 함수 호출 테스트가 있습니다. 이 함수는 obj가 클래스라고 상상할 수 있는 obj.test에서만 액세스할 수 있습니다.
아래 코드에서와 같이
function obj() { } obj.prototype.test = function() { alert('Hello?'); }; var obj2 = new obj(); obj2.test();
obj는 이제 인스턴스화할 수 있는 클래스가 되었습니다. obj의 여러 인스턴스가 존재할 수 있으며 모두 test
기능이 있습니다.
이상은 제 이해입니다. 나는 그것을 커뮤니티 위키로 만들고 있으므로 사람들이 내가 틀렸다면 나를 고칠 수 있습니다.
Community Wiki이 스레드를 읽은 후 JavaScript Prototype Chain과 혼동을 느끼다가 이 차트를 찾았습니다.
http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance
Prototype Chain에 의한 JavaScript 상속을 보여주는 명확한 차트입니다.
그리고
http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/
여기에는 코드와 몇 가지 멋진 다이어그램이 포함된 예제가 포함되어 있습니다.
프로토타입 체인은 궁극적으로 Object.prototype으로 대체됩니다.
프로토타입 체인은 하위 클래스의 프로토타입을 상위 클래스의 객체와 동일하게 설정하여 매번 원하는 만큼 기술적으로 확장할 수 있습니다.
JavaScript Prototype Chain을 이해하는 데에도 도움이 되길 바랍니다.
rockXrock모든 객체에는 내부 속성 [[Prototype]] 이 있으며 이를 다른 객체에 연결합니다.
object [[Prototype]] → anotherObject
전통적인 자바스크립트에서 연결된 객체는 prototype
속성입니다.
object [[Prototype]] → aFunction.prototype
일부 환경에서는 [[Prototype]] 을 __proto__
로 노출합니다.
anObject.__proto__ === anotherObject
객체를 생성할 때 [[Prototype]] 링크를 생성합니다.
// (1) Object.create: var object = Object.create(anotherObject) // object.__proto__ = anotherObject // (2) ES6 object initializer: var object = { __proto__: anotherObject }; // object.__proto__ = anotherObject // (3) Traditional JavaScript: var object = new aFunction; // object.__proto__ = aFunction.prototype
따라서 다음 명령문은 동일합니다.
var object = Object.create(Object.prototype); var object = { __proto__: Object.prototype }; // ES6 only var object = new Object;
실제로 새 문에서 링크 대상( Object.prototype
)을 볼 수 없습니다. 대신 대상은 생성자( Object
)에 의해 암시됩니다.
기억하다:
- 모든 객체에는 [[Prototype]] 링크가 있으며 때로는 __proto__ 로 표시 됩니다.
- 모든 함수에는
prototype
속성이 있으며 처음에는 빈 객체를 보유합니다. - new 로 생성된 객체는 생성자
prototype
속성에 연결됩니다. - 함수가 생성자
prototype
속성이 사용되지 않습니다. - 생성자가 필요하지 않다면
new
대신 Object.create 를 사용하세요.
samJavascript는 일반적인 의미에서 상속이 없지만 프로토타입 체인이 있습니다.
프로토타입 체인
개체의 구성원이 개체에서 찾을 수 없으면 프로토타입 체인에서 찾습니다. 체인은 다른 개체로 구성됩니다. 주어진 인스턴스의 프로토타입은 __proto__
변수를 사용하여 액세스할 수 있습니다. 자바스크립트에서 클래스와 인스턴스 간에 차이가 없기 때문에 모든 객체에는 하나가 있습니다.
프로토타입에 함수/변수를 추가할 때의 이점은 모든 인스턴스가 아니라 한 번만 메모리에 있어야 한다는 것입니다.
프로토타입 체인은 다른 많은 객체로 구성될 수 있기 때문에 상속에도 유용합니다.
Georg Schölly글이 깁니다. 그러나 JavaScript 상속의 "프로토타입" 특성에 대한 대부분의 질문이 해결될 것이라고 확신합니다. 그리고 더. 전체 기사를 읽으십시오.
JavaScript에는 기본적으로 두 가지 종류의 데이터 유형이 있습니다.
비 객체
다음은 비 객체 데이터 유형입니다.
- 끈
- 숫자(NaN 및 무한대 포함)
- 부울 값(true, false)
- 찾으시는 주소가 없습니다
이러한 데이터 유형은 typeof 연산자를 사용할 때 다음을 반환합니다.
typeof "문자열 리터럴" (또는 문자열 리터럴을 포함하는 변수) === '문자열'
typeof 5 (또는 숫자 리터럴 또는 숫자 리터럴 또는 NaN 또는 Infynity를 포함하는 변수) === '숫자'
typeof true (또는 false 또는 true 또는 false를 포함하는 변수) === 'boolean'
typeof undefined (또는 undefined 변수 또는 undefined 를 포함하는 변수) === 'undefined'
string , number 및 boolean 데이터 유형은 객체 및 비 객체 로 모두 표시될 수 있습니다. 객체로 표시될 때 해당 유형은 항상 === '객체'입니다. 객체 데이터 유형을 이해하면 이 문제로 다시 돌아올 것입니다.
사물
객체 데이터 유형은 두 가지 유형으로 더 나눌 수 있습니다.
- 함수 유형 객체
- 비 함수 유형 객체
함수 유형 객체 는 typeof 연산자와 함께 문자열 'function' 을 반환하는 객체입니다. new 연산자를 사용하여 새로운 객체를 생성할 수 있는 모든 사용자 정의 함수 및 모든 JavaScript 내장 객체가 이 범주에 속합니다. 예를 들어
- 물체
- 끈
- 숫자
- 부울
- 정렬
- 유형이 지정된 배열
- 정규 표현식
- 기능
- new 연산자를 사용하여 새 객체를 생성할 수 있는 다른 모든 내장 객체
- function UserDefinedFunction (){ /*사용자 정의 코드 */ }
따라서 typeof(Object) === typeof(String) === typeof(Number) === typeof(Boolean) === typeof(Array) === typeof(RegExp) === typeof(Function) == = typeof(UserDefinedFunction) === '함수'
모든 Function 유형 객체 는 실제로 내장 JavaScript 객체 Function 의 인스턴스입니다(Function 객체 포함, 즉 재귀적으로 정의됨). 이러한 객체는 다음과 같이 정의된 것과 같습니다.
var Object= new Function ([native code for object Object]) var String= new Function ([native code for object String]) var Number= new Function ([native code for object Number]) var Boolean= new Function ([native code for object Boolean]) var Array= new Function ([native code for object Array]) var RegExp= new Function ([native code for object RegExp]) var Function= new Function ([native code for object Function]) var UserDefinedFunction= new Function ("user defined code")
언급했듯이 Function 유형 객체 는 new 연산자를 사용하여 새 객체를 추가로 생성할 수 있습니다. 예를 들어 Object , String , Number , Boolean , Array , RegExp 또는 UserDefinedFunction 유형의 개체는 다음을 사용하여 만들 수 있습니다.
var a=new Object() or var a=Object() or var a={} //Create object of type Object var a=new String() //Create object of type String var a=new Number() //Create object of type Number var a=new Boolean() //Create object of type Boolean var a=new Array() or var a=Array() or var a=[] //Create object of type Array var a=new RegExp() or var a=RegExp() //Create object of type RegExp var a=new UserDefinedFunction()
이렇게 생성된 객체는 모두 Non Function 유형 객체 이며 해당 typeof === 'object' 를 반환합니다. 이 모든 경우에 개체 "a"는 new 연산자를 사용하여 개체를 더 이상 만들 수 없습니다. 그래서 다음은 틀리다.
var b=new a() //error. a is not typeof==='function'
내장 객체 Math 는 typeof === 'object' 입니다. 따라서 Math 유형의 새 객체는 new 연산자로 생성할 수 없습니다.
var b=new Math() //error. Math is not typeof==='function'
또한 Object , Array 및 RegExp 함수는 new 연산자를 사용하지 않고도 새 객체를 생성할 수 있습니다. 그러나 다음은 그렇지 않습니다.
var a=String() // Create a new Non Object string. returns a typeof==='string' var a=Number() // Create a new Non Object Number. returns a typeof==='number' var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'
사용자 정의 함수는 특별한 경우입니다.
var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.
Function 유형 객체 는 새 객체를 생성할 수 있으므로 생성자 라고도 합니다.
모든 생성자/함수 (내장 또는 사용자 정의)는 자동으로 정의될 때 값이 기본적으로 객체로 설정되는 "prototype"이라는 속성을 갖습니다. 이 객체 자체에는 기본적으로 Constructor/Function을 다시 참조하는 "constructor" 라는 속성이 있습니다.
예를 들어 함수를 정의할 때
function UserDefinedFunction() { }
다음은 자동으로 발생합니다
UserDefinedFunction.prototype={constructor:UserDefinedFunction}
이 "prototype" 속성 은 Function 유형 객체 에만 존재합니다( Non Function 유형 객체에는 없음 ).
이는 새 객체가 생성될 때(new 연산자를 사용하여) 생성자 함수의 현재 프로토타입 객체에서 모든 속성과 메서드를 상속하기 때문입니다. 즉, 생성자 함수의 현재 프로토타입 객체가 참조하는 객체를 참조하는 새로 생성된 객체에 내부 참조가 생성되기 때문입니다.
상속된 속성을 참조하기 위해 개체에서 생성되는 이 "내부 참조" 는 개체의 프로토타입 으로 알려져 있습니다(이는 생성자의 "prototype" 속성에서 참조하지만 다른 개체를 참조함). 모든 객체(Function 또는 Non Function)에 대해 Object.getPrototypeOf() 메서드를 사용하여 검색할 수 있습니다. 이 방법을 사용하면 객체의 프로토타입 체인을 추적할 수 있습니다.
또한 생성되는 모든 객체 ( 함수 유형 또는 비함수 유형 )에는 생성자 함수의 프로토타입 속성에서 참조하는 객체에서 상속되는 "생성자" 속성이 있습니다. 기본적으로 이 "생성자" 속성은 이를 생성 한 생성자 함수 를 참조합니다(생성자 함수의 기본 "프로토타입"이 변경되지 않은 경우).
모든 함수 유형 객체의 경우 생성자 함수는 항상 function Function(){}
비 함수 유형 객체 (예: Javascript Built in Math 객체)의 경우 생성자 함수는 이를 생성한 함수입니다. Math 객체의 경우 function Object(){} 입니다.
위에서 설명한 모든 개념은 지원 코드 없이는 이해하기 어려울 수 있습니다. 개념을 이해하기 위해 다음 코드를 한 줄씩 살펴보십시오. 더 나은 이해를 위해 그것을 실행하십시오.
function UserDefinedFunction() { } /* creating the above function automatically does the following as mentioned earlier UserDefinedFunction.prototype={constructor:UserDefinedFunction} */ var newObj_1=new UserDefinedFunction() alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays true alert(newObj_1.constructor) //Displays function UserDefinedFunction //Create a new property in UserDefinedFunction.prototype object UserDefinedFunction.prototype.TestProperty="test" alert(newObj_1.TestProperty) //Displays "test" alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test" //Create a new Object var objA = { property1 : "Property1", constructor:Array } //assign a new object to UserDefinedFunction.prototype UserDefinedFunction.prototype=objA alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays false. The object referenced by UserDefinedFunction.prototype has changed //The internal reference does not change alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction alert(newObj_1.TestProperty) //This shall still Display "test" alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test" //Create another object of type UserDefinedFunction var newObj_2= new UserDefinedFunction(); alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true. alert(newObj_2.constructor) //Displays function Array() alert(newObj_2.property1) //Displays "Property1" alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1" //Create a new property in objA objA.property2="property2" alert(objA.property2) //Displays "Property2" alert(UserDefinedFunction.prototype.property2) //Displays "Property2" alert(newObj_2.property2) // Displays Property2 alert(Object.getPrototypeOf(newObj_2).property2) //Displays "Property2"
모든 객체의 프로토타입 체인은 궁극적으로 Object.prototype(자체에는 프로토타입 객체가 없음)으로 추적됩니다. 다음 코드는 개체의 프로토타입 체인을 추적하는 데 사용할 수 있습니다.
var o=Starting object; do { alert(o + "\n" + Object.getOwnPropertyNames(o)) }while(o=Object.getPrototypeOf(o))
다양한 객체에 대한 프로토타입 체인은 다음과 같이 작동합니다.
- 모든 Function 객체(내장 Function 객체 포함)-> Function.prototype -> Object.prototype -> null
- 단순 객체(내장 Math 객체를 포함하여 new Object() 또는 {}에 의해 생성됨)-> Object.prototype -> null
- new 또는 Object.create -> 하나 이상의 프로토타입 체인 -> Object.prototype -> null로 생성된 객체
프로토타입 없이 객체를 생성하려면 다음을 사용하십시오.
var o=Object.create(null) alert(Object.getPrototypeOf(o)) //Displays null
생성자의 프로토타입 속성을 null로 설정하면 null 프로토타입이 있는 객체가 생성된다고 생각할 수도 있습니다. 그러나 이러한 경우 새로 생성된 객체의 프로토타입은 Object.prototype으로 설정되고 생성자는 함수 객체로 설정됩니다. 이것은 다음 코드로 증명됩니다.
function UserDefinedFunction(){} UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.) var o=new UserDefinedFunction() alert(Object.getPrototypeOf(o)==Object.prototype) //Displays true alert(o.constructor) //Displays Function Object
이 기사의 요약에 따르면
- 객체에는 기능 유형 과 비 기능 유형 의 두 가지 유형이 있습니다.
함수 유형 객체 만 new 연산자를 사용하여 새 객체를 생성할 수 있습니다. 이렇게 생성된 객체는 Non Function 유형 객체입니다. 비 함수 유형 객체 는 new 연산자를 사용하여 더 이상 객체를 생성할 수 없습니다.
모든 함수 유형 개체 에는 기본적으로 "프로토타입" 속성이 있습니다. 이 "프로토타입" 속성은 기본적으로 함수 유형 개체 자체를 참조하는 "생성자" 속성이 있는 개체를 참조합니다.
모든 객체( 함수 유형 및 비 함수 유형 )에는 기본적으로 이를 생성 한 함수 유형 객체 / 생성자 를 참조하는 "생성자" 속성이 있습니다.
생성되는 모든 객체는 내부적으로 생성한 생성자의 "prototype" 속성에서 참조하는 객체를 참조합니다. 이 객체는 생성된 객체의 프로토타입 으로 알려져 있습니다(참조하는 Function 유형 객체 "prototype" 속성과 다름). 이렇게 하면 생성된 객체는 생성자의 "prototype" 속성이 참조하는 객체에 정의된 메서드와 속성에 직접 액세스할 수 있습니다(객체 생성 시).
객체의 프로토타입 (따라서 상속된 속성 이름)은 Object.getPrototypeOf() 메서드를 사용하여 검색할 수 있습니다. 사실 이 방법은 개체의 전체 프로토타입 체인을 탐색하는 데 사용할 수 있습니다.
모든 객체의 프로토타입 체인은 궁극적으로 Object.prototype으로 다시 추적됩니다(객체가 프로토타입이 없는 경우 Object.create(null)을 사용하여 객체를 생성하지 않는 한).
typeof(new Array())==='object' 는 언어의 설계에 의한 것이며 Douglas Crockford가 지적한 실수가 아닙니다.
생성자의 프로토타입 속성을 null(또는 undefined,number,true,false,string)로 설정하면 null 프로토타입이 있는 개체가 생성되지 않습니다. 이러한 경우 새로 생성된 객체의 프로토타입은 Object.prototype으로 설정되고 생성자는 함수 객체로 설정됩니다.
도움이 되었기를 바랍니다.
Arup Horeprototypal
상속의 개념은 많은 개발자에게 가장 복잡한 개념 중 하나입니다. prototypal inheritance
더 잘 이해하기 위해 문제의 근원을 이해하려고 노력합시다. plain
함수로 시작합시다.
Tree function
new
연산자를 사용하는 경우 constructor
함수로 호출합니다.
모든 JavaScript
함수에는 prototype
있습니다. Tree.prototype
을 기록하면 다음을 얻습니다.
위의 console.log()
Tree.prototype
의 생성자 속성과 __proto__
속성도 볼 수 있습니다. __proto__
는 이 function
기반 prototype
inheritance
설정되지 않은 JavaScript function
이므로 JavaScript에 내장된 Object prototype
을 나타냅니다...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
.toString, .toValue, .hasOwnProperty
등과 같은 것들이 있습니다.
__proto__
는 더 이상 사용되지 않으며 Object.getPrototypeOf
object's prototype
을 가져옵니다.
Object.getPrototypeOf(Tree.prototype); // Object {}
Tree
prototype
메서드를 추가해 보겠습니다.
Root
수정하고 거기에 function
분기를 추가했습니다.
Tree
instance
를 만들 때 branch
메서드를 호출할 수 있습니다.
Prototype
primitives
나 objects
를 추가할 수도 있습니다.
Tree
child-tree
를 추가해 보겠습니다.
여기서 Child
prototype
을 상속합니다. 여기서 우리가 하는 것은 Object.create()
메서드를 사용하여 전달한 내용을 기반으로 새 개체를 만드는 것입니다 Tree.prototype
입니다. 이 경우 우리가 하고 있는 것은 Child의 프로토타입을 Tree
프로토타입과 동일하게 보이는 새 객체로 설정하는 것입니다. Child's constructor to Child
로 설정하고, 그렇지 않으면 Tree()
가리킵니다.
Child
에는 자체 prototype
이 있고 __proto__
는 Tree
Tree's prototype
은 기본 Object
가리킵니다.
Child | \ \ Tree.prototype - branch | | \ \ Object.prototype -toString -valueOf -etc., etc.
Tree
에서 사용할 수 있는 Child
instance
를 만들고 branch
를 호출합니다. 우리는 실제로 Child prototype
에 branch
를 정의하지 않았습니다. 그러나 Child가 상속 Root prototype
JS에서는 모든 것이 객체가 아니며 모든 것이 객체처럼 작동할 수 있습니다.
Javascript
strings, number, booleans, undefined, null.
과 같은 기본 요소가 있습니다. 그것들은 object(ie reference types)
object
처럼 작동할 수 있습니다. 여기에서 예를 살펴보겠습니다.
이 목록의 첫 번째 줄에서 primitive
문자열 값이 이름에 할당됩니다. 두 번째 줄은 name을 object
처럼 취급하고 점 표기법을 사용하여 charAt(0)
을 호출합니다.
이것은 배후에서 일어나는 일입니다: // JavaScript
엔진이 하는 일
String object
는 소멸되기 전에 하나의 명령문에 대해서만 존재합니다( autoboxing
이라고 하는 프로세스). prototypal
inheritance
돌아가 보겠습니다.
-
Javascript
prototypes
기반으로 하는 delegation
통한 상속을 지원합니다. - 각
Function
에는 다른 객체를 참조 prototype
-
properties/functions
는 object
자체에서 또는 존재하지 않는 경우 prototype
prototype
JS의 객체입니다 yields
다른 사람의 부모를 object
. [ie..delegation] Delegation
이란 자신이 할 수 없는 일을 다른 사람에게 대신 하도록 하는 것을 의미합니다.
https://jsfiddle.net/say0tzpL/1/
위의 바이올린을 조회하면 dog는 toString
Object.prototype
위임하는 프로토타입 체인을 통해 사용할 수 있습니다.
아래를 보면 function
에서 사용할 수 call
방식에 접근하려고 합니다.
https://jsfiddle.net/rknffckc/
위의 바이올린을 찾아보면 Profile
Function은 call
Function.prototype
위임하는 프로토타입 체인을 통해 사용할 수 있습니다.
참고: prototype
은 함수 생성자의 속성인 반면 __proto__
는 함수 생성자에서 생성된 객체의 속성입니다. 모든 함수에는 값이 빈 object
prototype
속성이 있습니다. 함수의 인스턴스를 만들 때 constructor
의 프로토타입인 [[Prototype]]
또는 __proto__
를 얻습니다.
prototype chaining
작동하는 방식에 대한 전체 그림을 보여줍니다. 천천히 살펴보겠습니다.
두 개의 인스턴스 b1
과 b2
가 있습니다. 생성자는 Bar
이고 부모는 Foo이며 프로토타입 체인의 두 가지 메서드가 있으며 Bar
및 Foo
를 통해 identify
하고 speak
https://jsfiddle.net/kbp7jr7n/
위의 코드를 찾아보면 identify()
메소드 Foo
생성자와 speak
메소드 Bar
생성자가 있습니다. 부모 유형이 Foo
인 두 개의 Bar
인스턴스 b1
및 b2
를 만듭니다. Bar
speak
메소드를 호출 prototype
체인을 통해 speak를 호출한 사람을 식별할 수 있습니다.
Bar
prototype
정의된 Foo
모든 메서드를 갖습니다. Object.prototype
과 Function.prototype
, 그리고 그것들이 어떻게 관련되어 있는지 더 자세히 알아보자. Foo
의 생성자를 조회하면 Bar
와 Object
는 Function constructor
입니다.
prototype
의 Bar
있다 Foo
, prototype
의 Foo
입니다 Object
당신이 자세히 보면 경우 prototype
의 Foo
관련이 Object.prototype
.
이 글을 마무리하기 전에 위의 모든 내용 을 요약하기 위해 여기에 작은 코드 조각을 넣어 보겠습니다. 여기에서 instanceof
연산자를 사용하여 object
의 prototype
체인에 constructor
prototype
속성이 있는지 확인하고 아래에 전체 큰 다이어그램이 요약되어 있습니다.
나는 이 추가 정보가 약간의 정보가 되기를 바랍니다. 나는 이것이 이해하기 어려울 수 있다는 것을 압니다... 간단히 말해서 그것은 개체에 연결된 개체일 뿐입니다!!!!
Thalaivar프로토타입 체인을 두 가지 범주로 분류하는 데 도움이 될 수 있습니다.
생성자를 고려하십시오.
function Person() {}
Object.getPrototypeOf(Person)
의 값은 함수입니다. 사실, 그것은 Function.prototype
입니다. Person
은 함수로 생성되었기 때문에 모든 함수가 가지고 있는 동일한 프로토타입 함수 객체를 공유합니다. Person.__proto__
와 동일하지만 해당 속성을 사용하면 안 됩니다. 어쨌든 Object.getPrototypeOf(Person)
를 사용하면 프로토타입 체인이라는 사다리를 효과적으로 올라갈 수 있습니다.
위쪽 방향의 체인은 다음과 같습니다.
Person
→ Function.prototype
→ Object.prototype
(종료점)
Person
이 구성 할 수 있는 객체와 거의 관련이 없다는 것입니다. 생성된 객체에는 고유한 프로토타입 체인이 있으며 이 체인에는 위에서 언급한 것과 공통적으로 가까운 조상이 없을 수 있습니다.
다음 객체를 예로 들어 보겠습니다.
var p = new Person();
p 는 Person 과 직접적인 프로토타입 체인 관계가 없습니다. 그들의 관계는 다릅니다. 객체 p 에는 자체 프로토타입 체인이 있습니다. Object.getPrototypeOf
사용하면 다음과 같은 체인을 찾을 수 있습니다.
p
→ Person.prototype
→ Object.prototype
(종료점)
이 체인에는 함수 개체가 없습니다(있을 수 있지만).
따라서 Person
은 자신의 삶을 사는 두 종류의 사슬과 관련이 있는 것 같습니다. 한 체인에서 다른 체인으로 "점프"하려면 다음을 사용합니다.
.prototype
: 생성자의 체인에서 생성된 객체의 체인으로 이동합니다. 따라서 이 속성은 함수 개체에 대해서만 정의됩니다( new
는 함수에만 사용할 수 있음).
.constructor
: 생성된 객체의 체인에서 생성자의 체인으로 이동합니다.
다음은 관련된 두 가지 프로토타입 체인을 열로 표시한 시각적 표현입니다.
요약하자면:
prototype
속성은 주체의 프로토타입 체인에 대한 정보를 제공하지 않지만 주체에 의해 생성된 객체에 대한 정보를 제공합니다.
prototype
의 이름이 혼동을 일으킬 수 있다는 것은 놀라운 일이 아닙니다. prototypeOfConstructedInstances
또는 그 라인을 따라 이름이 지정되었다면 더 명확했을 것입니다.
두 프로토타입 체인 사이를 앞뒤로 이동할 수 있습니다.
Person.prototype.constructor === Person
prototype
속성에 다른 객체를 명시적으로 할당하여 깨뜨릴 수 있습니다(나중에 자세히 설명).
하나의 함수를 만들고 두 개의 객체를 가져옵니다
Person.prototype
Person
함수가 생성될 때 생성된 객체입니다. 해당 생성자가 실제로 아직 실행되지 않았음에도 불구하고 Person
따라서 두 개의 객체가 동시에 생성됩니다.
- 기능
Person
자체 - 함수가 생성자로 호출될 때 프로토타입으로 작동할 객체
둘 다 객체이지만 역할이 다릅니다. 함수 객체가 생성 하는 반면 다른 객체는 함수가 생성할 객체의 프로토타입을 나타냅니다. 프로토타입 객체는 프로토타입 체인에서 생성된 객체의 부모가 됩니다.
함수도 객체이기 때문에 자체 프로토타입 체인에 자체 부모도 있지만 이 두 체인은 서로 다른 점을 기억하십시오.
다음은 문제를 파악하는 데 도움이 될 수 있는 몇 가지 평등입니다. 이 모든 것이 true
인쇄됩니다.
function Person() {}; // This is prototype chain info for the constructor (the function object): console.log(Object.getPrototypeOf(Person) === Function.prototype); // Step further up in the same hierarchy: console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype); console.log(Object.getPrototypeOf(Object.prototype) === null); console.log(Person.__proto__ === Function.prototype); // Here we swap lanes, and look at the constructor of the constructor console.log(Person.constructor === Function); console.log(Person instanceof Function); // Person.prototype was created by Person (at the time of its creation) // Here we swap lanes back and forth: console.log(Person.prototype.constructor === Person); // Although it is not an instance of it: console.log(!(Person.prototype instanceof Person)); // Instances are objects created by the constructor: var p = new Person(); // Similarly to what was shown for the constructor, here we have // the same for the object created by the constructor: console.log(Object.getPrototypeOf(p) === Person.prototype); console.log(p.__proto__ === Person.prototype); // Here we swap lanes, and look at the constructor console.log(p.constructor === Person); console.log(p instanceof Person);
프로토타입 체인에 레벨 추가
프로토타입 객체는 생성자 함수를 생성할 때 생성되지만 해당 객체를 무시하고 해당 생성자가 생성한 후속 인스턴스의 프로토타입으로 사용해야 하는 다른 객체를 할당할 수 있습니다.
예를 들어:
function Thief() { } var p = new Person(); Thief.prototype = p; // this determines the prototype for any new Thief objects: var t = new Thief();
이제 t 의 프로토타입 체인 은 p 의 프로토타입 체인보다 한 단계 더 깁니다.
t
→ p
→ Person.prototype
→ Object.prototype
(종료점)
다른 프로토타입 체인은 더 이상 없습니다. Thief
와 Person
은 프로토타입 체인에서 동일한 부모를 공유하는 형제입니다.
Person
}
Thief
} → Function.prototype
→ Object.prototype
(종료점)
이전에 제시된 그래픽은 다음으로 확장될 수 있습니다(원래 Thief.prototype
은 생략됨).
파란색 선은 프로토타입 체인을 나타내고 다른 색 선은 다른 관계를 나타냅니다.
- 객체와 생성자 사이
- 생성자와 객체 생성에 사용될 프로토타입 객체 사이
trincot이 ".prototype" 속성의 정확한 목적은 무엇입니까?
표준 클래스에 대한 인터페이스를 확장할 수 있습니다. 예를 들어 Array
클래스를 사용 중이고 모든 배열 개체에 대한 사용자 지정 직렬 변환기도 추가해야 합니다. 하위 클래스를 코딩하는 데 시간을 할애하거나 구성을 사용하거나 ... 프로토타입 속성은 사용자가 클래스에서 사용할 수 있는 정확한 멤버/메서드 집합을 제어할 수 있도록 하여 이 문제를 해결합니다.
프로토타입을 추가 vtable 포인터로 생각하십시오. 원래 클래스에서 일부 멤버가 누락된 경우 런타임 시 프로토타입이 조회됩니다.
dirkgently객체 지향 JavaScript에 대한 확실한 가이드 - 질문에 대한 매우 간결하고 명확한 ~30분 비디오 설명(Prototypal Inheritance 주제는 5:45 부터 시작하지만 전체 비디오를 듣고 싶습니다). 이 영상의 작가는 자바스크립트 객체 시각화 웹사이트 http://www.objectplayground.com/ 도 만들었습니다.
Badobj_n.prop_X
가 참조될 때 "프로토타입 체인"을 재귀 규칙으로 설명하는 것이 도움이 된다는 것을 알았습니다.
obj_n.prop_X
가 존재하지 않으면 obj_n+1.prop_X
확인하십시오. 여기서 obj_n+1 = obj_n.[[prototype]]
k번째 프로토타입 객체에서 prop_X
가 마침내 발견되면
obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X
여기에서 속성별로 Javascript 객체의 관계 그래프를 찾을 수 있습니다.
http://jsobjects.org
B M생성자가 개체를 만들 때 해당 개체는 속성 참조를 확인하기 위해 생성자의 "프로토타입" 속성을 암시적으로 참조합니다. 생성자의 "prototype" 속성은 프로그램 표현식 constructor.prototype에 의해 참조될 수 있으며 개체의 프로토타입에 추가된 속성은 상속을 통해 프로토타입을 공유하는 모든 개체에서 공유됩니다.
Tom여기에 설명이 필요한 두 가지 별개의 관련 엔터티가 있습니다.
- 함수의
.prototype
속성입니다. - 모든 객체의
[[Prototype]]
[1] 속성 [2] .
이것은 두 가지 다른 것입니다.
[[Prototype]]
속성:
이것은 모든 [2] 객체에 존재하는 속성입니다.
여기에 저장된 것은 또 다른 객체로, 객체 자체로서 다른 객체를 가리키는 자체 [[Prototype]]
그 다른 개체에는 [[Prototype]]
자체가 있습니다. .toString
와 같은)에서 액세스할 수 있는 메서드를 제공하는 프로토타입 객체에 도달할 때까지 계속됩니다.
[[Prototype]]
[[Prototype]]
체인을 구성하는 부분입니다. [[Prototype]]
객체 체인은 예를 들어 객체에 대해 [[Get]]
또는 [[Set]]
작업이 수행될 때 검사되는 것입니다.
var obj = {} obj.a // [[Get]] consults prototype chain obj.b = 20 // [[Set]] consults prototype chain
.prototype
속성:
이것은 함수에서만 볼 수 있는 속성입니다. 매우 간단한 기능 사용:
function Bar(){};
.prototype
속성 var b = new Bar
를 수행할 때 b.[[Prototype]]
할당될 객체를 보유합니다 . 다음과 같이 쉽게 검사할 수 있습니다.
// Both assign Bar.prototype to b1/b2[[Prototype]] var b = new Bar; // Object.getPrototypeOf grabs the objects [[Prototype]] console.log(Object.getPrototypeOf(b) === Bar.prototype) // true
.prototype
중 하나는 Object
함수 입니다. [[Prototype]]
체인이 포함하는 프로토타입 객체를 보유합니다. 여기에 새 개체에 사용할 수 있는 모든 메서드가 정의됩니다.
// Get properties that are defined on this object console.log(Object.getOwnPropertyDescriptors(Object.prototype))
이제 .prototype
은 객체이므로 [[Prototype]]
속성이 있습니다. Function.prototype
할당하지 않으면 .prototype
의 [[Prototype]]
은 프로토타입 객체( Object.prototype
)를 가리킵니다. 이것은 새 기능을 만들 때마다 자동으로 수행됩니다.
new Bar;
를 할 때마다; 프로토타입 체인이 설정되면 Bar.prototype
Object.prototype
정의된 모든 것을 얻을 수 있습니다.
var b = new Bar; // Get all Bar.prototype properties console.log(b.__proto__ === Bar.prototype) // Get all Object.prototype properties console.log(b.__proto__.__proto__ === Object.prototype)
당신이 만드는 할당을 할 때 Function.prototype
다른 객체를 포함하는 프로토 타입 체인을 확장하고 모든 일을. 단일 연결 목록에 삽입하는 것과 같습니다.
이것은 기본적으로 [[Prototype]]
Function.prototype
에 할당된 객체에 정의된 속성을 함수에 의해 생성된 모든 객체에서 볼 수 있도록 합니다.
[1: 아무도 혼동하지 않을 것입니다. 많은 구현에서 __proto__
속성 을 통해 사용할 수 있습니다.
[2]: null
제외한 모든 것.
Dimitris Fasarakis Hilliard프로토타입에 대한 제 이해를 말씀드리겠습니다. 여기서는 상속을 다른 언어와 비교하지 않을 것입니다. 사람들이 언어 비교를 멈추고 언어 자체를 이해하기를 바랍니다. 프로토타입과 프로토타입 상속을 이해하는 것은 매우 간단합니다. 아래에서 보여드리겠습니다.
프로토타입은 제품을 만드는 데 기반을 둔 모델과 같습니다. 이해해야 할 중요한 점은 다른 개체를 프로토타입으로 사용하여 개체를 만들 때 프로토타입과 제품 간의 연결이 영원히 지속된다는 것입니다. 예를 들어:
var model = {x:2}; var product = Object.create(model); model.y = 5; product.y =>5
Object.getPrototypeOf()
함수로 액세스할 수 있는 [[prototype]]이라는 내부 속성이 있습니다. Object.create(model)
은 새 객체를 만들고 [[prototype]] 속성을 객체 모델로 설정 합니다. Object.getPrototypeOf(product)
를 수행 하면 객체 모델 을 얻게 됩니다.
제품의 속성은 다음과 같은 방식으로 처리됩니다.
- 값을 읽기 위해 속성에 액세스하면 범위 체인에서 조회됩니다. 변수 검색은 제품 에서 시작하여 프로토타입까지 시작됩니다. 검색에서 이러한 변수가 발견되면 바로 검색이 중지되고 값이 반환됩니다. 범위 체인에서 이러한 변수를 찾을 수 없으면 undefined가 반환됩니다.
- 속성이 기록(변경)되면 속성은 항상 제품 개체에 기록됩니다. 제품에 이미 그러한 속성이 없으면 암시적으로 생성되고 작성됩니다.
이러한 프로토타입 속성을 사용하여 객체를 연결하는 것을 프로토타입 상속이라고 합니다. 너무 간단합니다. 동의하십니까?
Aravindrus1keyValueStore
객체를 고려하십시오.
var keyValueStore = (function() { var count = 0; var kvs = function() { count++; this.data = {}; this.get = function(key) { return this.data[key]; }; this.set = function(key, value) { this.data[key] = value; }; this.delete = function(key) { delete this.data[key]; }; this.getLength = function() { var l = 0; for (p in this.data) l++; return l; } }; return { // Singleton public properties 'create' : function() { return new kvs(); }, 'count' : function() { return count; } }; })();
다음을 수행하여 이 개체의 새 인스턴스를 만들 수 있습니다.
kvs = keyValueStore.create();
이 개체의 각 인스턴스에는 다음과 같은 공용 속성이 있습니다.
-
data
-
get
-
set
-
delete
-
getLength
keyValueStore
개체의 100개 인스턴스를 생성한다고 가정합니다. get
, set
, delete
, getLength
가 이 100개의 인스턴스 각각에 대해 정확히 동일한 작업을 수행하지만 모든 인스턴스에는 이 함수의 자체 복사본이 있습니다.
get
, set
, delete
및 getLength
복사본이 하나만 있고 각 인스턴스가 동일한 기능을 참조한다고 상상해보십시오. 이것은 성능에 더 좋고 더 적은 메모리를 필요로 합니다.
그것이 프로토타입이 필요한 곳입니다. 프로토타입은 상속되지만 인스턴스에 의해 복사되지 않는 속성의 "청사진"입니다. 따라서 이는 개체의 모든 인스턴스에 대해 메모리에 한 번만 존재하고 해당 인스턴스 모두에서 공유됨을 의미합니다.
이제 keyValueStore
객체를 다시 고려하십시오. 다음과 같이 다시 작성할 수 있습니다.
var keyValueStore = (function() { var count = 0; var kvs = function() { count++; this.data = {}; }; kvs.prototype = { 'get' : function(key) { return this.data[key]; }, 'set' : function(key, value) { this.data[key] = value; }, 'delete' : function(key) { delete this.data[key]; }, 'getLength' : function() { var l = 0; for (p in this.data) l++; return l; } }; return { 'create' : function() { return new kvs(); }, 'count' : function() { return count; } }; })();
이것은 모든 메서드가 이제 프로토타입에 배치된다는 점을 제외하고 keyValueStore
객체의 이전 버전과 정확히 동일합니다. 이것이 의미하는 바는 100개의 모든 인스턴스가 이제 각각 고유한 복사본을 갖는 대신 이 네 가지 메서드를 공유한다는 것입니다.
John Slegers요약:
- 함수는 자바스크립트의 객체이므로 속성을 가질 수 있습니다.
- (생성자) 함수에는 항상 프로토타입 속성이 있습니다.
-
new
키워드와 함께 생성자로 사용될 때 객체는 프로토타입을 얻습니다. 이 프로토타입에 대한 참조는 새로 생성된 객체 __proto__
- 이
__proto__
속성은 생성자 함수 prototype
예시:
function Person (name) { this.name = name; } let me = new Person('willem'); console.log(Person.prototype) // Person has a prototype property console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.
이것이 유용한 이유:
Javascript에는 '프로토타입 상속' 이라고 하는 객체의 속성을 조회할 때 기본적으로 수행되는 작업이 있습니다.
- 먼저 속성이 개체 자체에 있는지 확인합니다. 그렇다면 이 속성이 반환됩니다.
- 속성이 개체 자체에 없으면 '프로토체인 위로 올라갑니다'. 기본적으로 proto 속성이 참조하는 객체를 살펴봅니다. 거기에서 proto가 참조하는 객체에서 속성을 사용할 수 있는지 확인합니다.
- 속성이 proto 개체에 없으면 개체 개체까지 프로토 체인을 올라갑니다.
- 객체와 프로토타입 체인에서 속성을 찾을 수 없으면 정의되지 않은 값을 반환합니다.
예를 들어:
function Person(name) { this.name = name; } let mySelf = new Person('Willem'); console.log(mySelf.__proto__ === Person.prototype); console.log(mySelf.__proto__.__proto__ === Object.prototype);
업데이트:
__proto__
속성은 더 이상 사용되지 않지만 대부분의 최신 브라우저에서 구현되지만 프로토타입 개체 참조를 얻는 더 좋은 방법은 다음과 같습니다.
Object.getPrototypeOf()
Willem van der Veen나는 항상 이런 종류의 것들을 이해할 때 비유를 좋아합니다. 프로토타입이 훨씬 단순한 패러다임임에도 불구하고 '프로토타입 상속'은 클래스 베이스 상속에 비해 상당히 혼란스럽습니다. 실제로 프로토타입에는 상속이 없으므로 이름 자체가 오해의 소지가 있으므로 일종의 '위임'에 가깝습니다.
이것을 상상해보십시오 ....
당신은 고등학생이고 수업 중이고 오늘 마감인 퀴즈가 있지만 답을 채울 펜이 없습니다. 도!
당신은 펜을 가지고 있을지도 모르는 친구 Finnius 옆에 앉아 있습니다. 당신이 물었고 그는 성공하지 못하고 책상을 둘러봅니다. 그러나 그는 "나는 펜이 없어요"라고 말하는 대신에 다른 친구인 Derp에게 펜이 있는지 확인하는 좋은 친구입니다. Derp는 실제로 여분의 펜을 가지고 있으며 Finnius에게 다시 전달하면 Finnius는 퀴즈를 완료하기 위해 그것을 전달합니다. Derp는 펜을 사용하도록 위임한 Finnius에게 펜을 위임했습니다.
여기서 중요한 것은 Derp와 직접적인 관계 가 없기 때문에 Derp가 펜을 주지 않는다는 것입니다.
이것은 데이터 트리에서 찾고 있는 것을 검색하는 프로토타입 작동 방식의 간단한 예입니다.
Louis Moore__proto__ , 프로토타입 및 생성자 관계를 보여주는 또 다른 체계:
IvanMObject.new
가 포함된 객체가 이미 있지만 생성자 구문을 사용할 때 객체가 없다는 것입니다.
shiva kumarObject.getPrototypeOf(obj)
또는 더 이상 사용되지 않는 __proto__
속성을 통해 사용 가능)과 생성자 함수 prototype
속성 사이에는 차이가 있음을 이해하는 것이 중요합니다. 전자는 각 인스턴스의 속성이고 후자는 생성자의 속성입니다. 즉, Object.getPrototypeOf(new Foobar())
Foobar.prototype
과 동일한 객체를 참조합니다.
참조: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
Baraa Al-TabbaaPrototype 은 기존 객체 를 복제하여 새로운 객체를 생성합니다 . 그래서 실제로 프로토타입에 대해 생각할 때 무언가를 만드는 대신 복제하거나 복사하는 것을 생각할 수 있습니다.
Arif프로토타입 및 프로토타입 기반 상속의 개념을 기본부터 이해하고 싶다면 공식 MDN 문서를 확인하십시오. 잘 설명되어 있습니다.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
상속과 관련하여 JavaScript에는 객체라는 하나의 구조만 있습니다. 각 객체에는 프로토타입이라는 다른 객체에 대한 링크를 보유하는 개인 속성이 있습니다. 그 프로토타입 객체에는 자체 프로토타입이 있으며, 프로토타입이 null인 객체에 도달할 때까지 계속됩니다. 정의에 따라 null에는 프로토타입이 없으며 이 프로토타입 체인의 최종 링크 역할을 합니다.
또한 간단한 예제를 사용하여 설명하는 또 다른 좋은 리소스가 있습니다. https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
kabirbaidhya출처 : http:www.stackoverflow.com/questions/572897/how-does-javascript-prototype-work