โลกที่ไม่มีคำหลัก "ใหม่"
และไวยากรณ์ "prose-like" ที่ง่ายขึ้นด้วย Object.create ()
* ตัวอย่างนี้ถูกอัพเดตสำหรับคลาส ES6
ปิดครั้งแรกจำได้ว่า JavaScript เป็นภาษา prototypal มันไม่ได้เป็นคลาส ดังนั้นการเขียนในรูปแบบต้นแบบแสดงให้เห็นถึงลักษณะที่แท้จริงของมันและสามารถง่ายมากร้อยแก้วเหมือนและมีประสิทธิภาพ
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
instantiation ( อ่านเหตุผลที่คุณไม่ควรใช้new
) ไม่มีไม่มีตลกตลกsuper
__construct
คุณเพียงแค่สร้างออบเจ็กต์จากนั้นขยายหรือปรับเปลี่ยน
( ถ้าคุณทราบเกี่ยว getters และ setters ดู "อ่านเพิ่มเติม" เพื่อดูว่ารูปแบบนี้จะช่วยให้คุณฟรีและ getters setters ในทางจาวาสคริเพิ่งเดิมไว้สำหรับการและวิธีการที่มีประสิทธิภาพที่พวกเขามี .)
ไวยากรณ์แบบร้อยแก้วที่เหมือนกัน: ฐาน 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
คุณมีทุกสิ่งที่คุณต้องการแล้ว! ไม่มีสิ่งก่อสร้างไม่มีการสร้างอินสแตนซ์ ทำความสะอาดร้อยแก้วที่ชัดเจน
อ่านเพิ่มเติม
Writability, Configurability และ Getters และ Setters ฟรี!
สำหรับ getters และ setters ฟรีหรือการกำหนดค่าเพิ่มเติมคุณสามารถใช้อาร์กิวเมนต์ที่สองของ Object.create () 'aka aka 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'
Mixins (ใช้ # 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)
Darth Vader ได้รับวิธีการ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.
เอาละไม่ว่า Darth Vader จะเป็นคนหรือเครื่องจักรจริง ๆ
“ ตอนนี้เขามีกลไกมากกว่ามนุษย์บิดและชั่ว” - โอบีวันเคโนบี
"ฉันรู้ว่าคุณเก่ง" - Luke Skywalker
พิเศษ - ไวยากรณ์ที่สั้นกว่าเล็กน้อยด้วย # Object.assign
รูปแบบนี้จะทำให้ไวยากรณ์ของคุณสั้นลง แต่ ES6 # Object.assign สามารถตัดให้สั้นลงได้อีก (สำหรับ polyfill เพื่อใช้กับเบราว์เซอร์รุ่นเก่าดูMDN บน ES6 )
//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.
})