Конструкторский рисунок Дугласа Крокфорда
Недавно я смотрел один из переговоров Дугласа Крокфорда (его разговоры очаровывают меня, но всегда оставляют меня в замешательстве). Он привел пример конструктора, но я не совсем понимаю, как использовать его на практике:
function constructor(spec) {
var that = other_constructor(spec),
member,
method = function () {
//spec , member, method
};
that.method = method;
return that;
}
Может кто-нибудь может дать мне простой рабочий пример, основанный на этом шаблоне?
Ответы
Ответ 1
Это пример использования другого конструктора внутри функции factory для возврата объекта. В этом случае other_constructor
- это функция конструктора, которая создает объект типа other_constructor
(в идеале на практике это будет заглавное). Этот объект хранится в that
. В этой функции factory method
- это определенная функция, которая добавляется к that
, чтобы каким-то образом расширить функциональность объекта.
Разница между конструкторами и функциями factory заключается в том, что функция factory - это просто нормальная функция, которая возвращает объект, тогда как функция-конструктор имеет this
, указывающую на новый объект и обычно должна вызываться с ключевое слово new
, предшествующее ему.
Типичная конструкторская функция:
function Dog(breed, height, name){
this.breed = breed;
this.animalType = "dog";
this.height = height;
this.name = name;
// calling `return` isn't necessary here
}
И это использование:
var lab = new Dog("labrador", 100, "Sugar"); // `new` is necessary (usually)
console.log(lab.animalType); // prints out "dog"
console.log(lab.height); // prints out 100
Типичная функция factory:
function createDog(breed, height, name){
var dog = {
breed: breed,
height: height,
animalType: "dog",
name: name
};
return dog;
// `return` is necessary here, because `this` refers to the
// outer scope `this`, not the new object
}
И его использование:
var lab = createDog("labrador", 100, "Sugar"); // notice no need for `new`
console.log(lab.animalType); // prints out "dog"
console.log(lab.height); // prints out 100
Хорошее объяснение различий между ними и различными вариантами использования каждого из них - в блоге Эрика Эллиота
Ответ 2
Это оригинальный источник Дугласа Крокфорда, который появляется в его слайдах:
function constructor(spec) {
let {member} = spec,
{other} = other_constructor(spec),
method = function () {
// member, other, method, spec
};
return Object.freeze({
method,
other
});
}
Следующий пример - более конкретная версия шаблона создания объектов Дугласа Крокфорда 2014.
Дуглас Крокфорд активно использует ECMAScript 6, такие как деструктурирование и т.д.
Запустите код в node.js со следующими параметрами (включите ES6):
node --harmony --harmony_destructuring demo.js
demo.js
// Douglas Crockford 2014 Object Creation
(function() {
'use strict';
function adress(spec) {
let {
street, city
} = spec,
logAdress = function() {
console.log('Adress:', street, city);
};
return Object.freeze({
logAdress
});
};
function person(spec) {
let {
preName,
name
} = spec, {
logAdress
} = adress(spec),
logPerson = function() {
// member, other, method, spec
console.log('Name: ', preName, name);
logAdress();
};
return Object.freeze({
logPerson,
logAdress
});
};
let myPerson = person({
preName: 'Mike',
name: 'Douglas',
street: 'Newstreet',
city: 'London'
});
myPerson.logPerson();
})();
По словам Дугласа Крокфорда, он избегает использования:
- новый
- Object.create
- это!!!
Посмотрите оригинальное видео Crockford:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
Хорошим объяснением для проекта Crockford Douglas Object Creation Pattern 2014 является этот блог: https://weblogs.asp.net/bleroy/crockford%E2%80%99s-2014-object-creation-pattern
Ответ 3
Ванильные JavaScript-примеры нового шаблона конструктора Дугласа Крокфорда с пояснениями:
console.clear();
var fauna = (function (){
privitizeNewVariables=function (specs) {
if (!specs.is_private) {
var members = Object.assign({}, specs);
members.is_private = true;
return members;
}
return specs;
},
newAnimal=function (specs) {
var members = privitizeNewVariables(specs);
members.inheritance_type_list = ['Animal'];
whenInDanger = function () {
try{
console.log('When in danger ', members.common_name);
members.movesBy();
}catch (e){
console.log('Error - whenInDanger() has no movesBy()');
}
};
var isA = function(object_type){
if (members.inheritance_type_list.indexOf(object_type)>-1) {
console.log(members.common_name, 'is a', object_type);
}else{
console.log(members.common_name, 'is not a', object_type);
}
}
return Object.freeze({
whenInDanger: whenInDanger,
isA: isA
});
},
newSnake=function (specs){
var members = privitizeNewVariables(specs);
members.movesBy = function () {
console.log('Moves By: slithering');
};
colorScheme = function () {
console.log('Color scheme :', members.color_scheme);
};
aPrivateFunction = function (){
console.log('I only exist inside a Snake object');
};
var an_animal = newAnimal(members);
members.inheritance_type_list.unshift('Snake');
return Object.freeze({
whenInDanger: an_animal.whenInDanger,
isA: an_animal.isA,
movesBy: members.movesBy,
colorScheme: colorScheme
});
};
return {
newAnimal:newAnimal,
newSnake: newSnake
}
})();
var animal_specs = {common_name: 'Alf the animal'};
var an_animal = fauna.newAnimal(animal_specs);
animal_specs.common_name = "does not change Alf common_name";
an_animal.whenInDanger();
console.log(an_animal);
console.log('-');
var snake_specs = {common_name: 'Snorky the snake',
color_scheme:'yellow'};
var a_snake = fauna.newSnake(snake_specs);
a_snake.whenInDanger();
console.log('-');
a_snake.colorScheme();
a_snake.isA('Animal');
a_snake.isA('Snake');
a_snake.isA('Bear');
console.log('-');
console.log(fauna);
Ответ 4
function Car(model, year, miles, price) {
this.model = model;
this.year = year;
this.miles = miles;
this.price = price;
this.toString = function() {
return this.model + " has done " + this.miles + " miles and cost $" + this.price;
};
}
// We can create new instances of the car
var civic = new Car("Toyota Prius", 2015, 1500, 12000);
var mondeo = new Car("Ford Focus", 2010, 5000, 3000);
// these objects
console.log(civic.toString());
console.log(mondeo.toString())