"새"키워드가없는 세계.
그리고 Object.create ()를 사용하여 더 간단한 "동일한"구문.
*이 예제는 ES6 클래스 용으로 업데이트되었습니다.
우선, 자바 스크립트는 프로토 타입 언어 입니다. 클래스 기반이 아닙니다. 따라서 프로토 타입 형태로 글을 쓰면 그 본질이 드러나고 매우 단순하고 산문적이며 강력 할 수 있습니다.
TLDR;
const Person = { name: 'Anonymous' } // person has a name
const jack = Object.create(Person) // jack is a person
jack.name = 'Jack' // and has a name 'Jack'
아니요, 생성자가 필요하지 않으며 new
인스턴스화 가 필요하지 않습니다 ( 사용하지 않아야하는 이유를 읽으십시오new
). 아니요 . super
재미가 없습니다 __construct
. 단순히 객체를 만든 다음 확장하거나 모핑합니다.
( 당신이 getter 및 setter에 대해 알고있는 경우, 섹션이 패턴은 자바 스크립트가했던 방법으로 당신에게 무료 getter 및 setter를 제공하는 방법을보고 "추가 읽기"를 참조 원래 의도, 그리고 얼마나 강력한 그들이 .)
산문과 같은 구문 : Base protoype
const Person = {
//attributes
firstName : 'Anonymous',
lastName: 'Anonymous',
birthYear : 0,
type : 'human',
//methods
name() { return this.firstName + ' ' + this.lastName },
greet() {
console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' )
},
age() {
// age is a function of birth time.
}
}
const person = Object.create(Person). // that's it!
한눈에, 매우 읽기 쉽게 보입니다.
확장,의 자손 만들기 Person
* 올바른 용어는 prototypes
, 그 descendants
. 아무 없습니다 classes
, 그리고 필요 instances
.
const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'
const anakin = Object.create(Skywalker)
anakin.firstName = 'Anakin'
anakin.birthYear = '442 BBY'
anakin.gender = 'male' // you can attach new properties.
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'
Person.isPrototypeOf(Skywalker) // outputs true
Person.isPrototypeOf(anakin) // outputs true
Skywalker.isPrototypeOf(anakin) // outputs true
를 만드는 "기본"방법을 제공하는 한 가지 방법 descendant
은 #create
메소드 를 첨부하는 것입니다.
Skywalker.create = function(firstName, gender, birthYear) {
let skywalker = Object.create(Skywalker)
Object.assign(skywalker, {
firstName,
birthYear,
gender,
lastName: 'Skywalker',
type: 'human'
})
return skywalker
}
const anakin = Skywalker.create('Anakin', 'male', '442 BBY')
아래 방법은 가독성이 떨어집니다.
"클래식"동등 항목과 비교하십시오.
function Person (firstName, lastName, birthYear, type) {
this.firstName = firstName
this.lastName = lastName
this.birthYear = birthYear
this.type = type
}
// attaching methods
Person.prototype.name = function() { return firstName + ' ' + lastName }
Person.prototype.greet = function() { ... }
Person.prototype.age = function() { ... }
function Skywalker(firstName, birthYear) {
Person.apply(this, [firstName, 'Skywalker', birthYear, 'human'])
}
// confusing re-pointing...
Skywalker.prototype = Person.prototype
Skywalker.prototype.constructor = Skywalker
const anakin = new Skywalker('Anakin', '442 BBY')
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns false!
"클래식"스타일을 사용한 코드 가독성은 그리 좋지 않습니다.
ES6 수업
분명히, 이러한 문제 중 일부는 ES6 클래스에 의해 제거되지만 여전히 :
class Person {
constructor(firstName, lastName, birthYear, type) {
this.firstName = firstName
this.lastName = lastName
this.birthYear = birthYear
this.type = type
}
name() { return this.firstName + ' ' + this.lastName }
greet() { console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' ) }
}
class Skywalker extends Person {
constructor(firstName, birthYear) {
super(firstName, 'Skywalker', birthYear, 'human')
}
}
const anakin = new Skywalker('Anakin', '442 BBY')
// prototype chain inheritance checking is partially fixed.
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns true
기본 프로토 타입 분기
// create a `Robot` prototype by extending the `Person` prototype:
const Robot = Object.create(Person)
Robot.type = 'robot'
Robot.variant = '' // add properties for Robot prototype
고유 한 메소드 첨부 Robot
// Robots speak in binaries, so we need a different greet function:
Robot.machineGreet = function() { /*some function to convert strings to binary */ }
// morphing the `Robot` object doesn't affect `Person` prototypes
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'
anakin.machineGreet() // error
상속 확인
Person.isPrototypeOf(Robot) // outputs true
Robot.isPrototypeOf(Skywalker) // outputs false
당신은 당신이 이미 필요한 모든 것을 가지고 있습니다! 생성자도없고 인스턴스도 없습니다. 깨끗하고 명확한 산문.
추가 자료
쓰기 가능성, 구성 가능성 및 무료 Getter 및 Setter!
무료 게터 및 세터 또는 추가 구성의 경우 Object.create ()의 두 번째 인수 인 propertiesObject를 사용할 수 있습니다. # Object.defineProperty 및 # Object.defineProperties 에서도 사용할 수 있습니다 .
이것이 얼마나 강력한지를 설명하기 위해 모두 Robot
가 엄격하게 금속으로 만들어지고 (비아를 통해 writable: false
) powerConsumption
값을 표준화 하기를 원한다고 가정하십시오 (게터 및 세터를 통해).
const Robot = Object.create(Person, {
// define your property attributes
madeOf: {
value: "metal",
writable: false,
configurable: false,
enumerable: true
},
// getters and setters, how javascript had (naturally) intended.
powerConsumption: {
get() { return this._powerConsumption },
set(value) {
if (value.indexOf('MWh')) return this._powerConsumption = value.replace('M', ',000k')
this._powerConsumption = value
throw new Error('Power consumption format not recognised.')
}
}
})
const newRobot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh
그리고의 모든 프로토 타입은 다른 Robot
것이 될 수 없습니다 .madeOf
writable: false
const polymerRobot = Object.create(Robot)
polymerRobot.madeOf = 'polymer'
console.log(polymerRobot.madeOf) // outputs 'metal'
믹스 인 (# Object.assign 사용)-Anakin Skywalker
어디로 가는지 알 수 있습니까?
const darthVader = Object.create(anakin)
// for brevity, property assignments are skipped because you get the point by now.
Object.assign(darthVader, Robot)
다스 베이더는 다음의 방법을 얻습니다 Robot
.
darthVader.greet() // inherited from `Person`, outputs "Hi, my name is Darth Vader..."
darthVader.machineGreet() // inherited from `Robot`, outputs 001010011010...
다른 이상한 것들과 함께 :
console.log(darthVader.type) // outputs robot.
Robot.isPrototypeOf(darthVader) // returns false.
Person.isPrototypeOf(darthVader) // returns true.
다스 베이더가 사람인지 기계인지는 실제로 주관적입니다.
"그는 지금 사람보다 기계가 많고 뒤틀리고 사악합니다." -오비완 케노비
"당신에게 좋은 것이 있다는 것을 알고 있습니다." - 루크 스카이 워커
추가-# Object.assign을 사용하여 약간 더 짧은 구문
이 패턴은 구문을 단축시킵니다. 그러나 ES6 # Object.assign은 더 짧아 질 수 있습니다 (오래된 브라우저에서 폴리 필을 사용하려면 ES6의 MDN 참조 ).
//instead of this
const Robot = Object.create(Person)
Robot.name = "Robot"
Robot.madeOf = "metal"
//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
name: "Robot",
madeOf: "metal"
// for brevity, you can imagine a long list will save more code.
})