2014-12-02 66 views
21

最近我看了道格拉斯克羅克福德的一次談話(他的談話令我着迷,但總是讓我感到困惑)。他給了一個構造函數的例子,但我不太明白我怎麼會用它在實踐中:道格拉斯克羅克福德的構造模式

function constructor(spec) { 
    var that = other_constructor(spec), 
    member, 
    method = function() { 
     //spec , member, method 
    }; 

    that.method = method; 
    return that;  
} 

也許有人可以給我基於此模式的簡單工作的例子嗎?

回答

14

這是在工廠函數內使用另一個構造函數返回對象的一個​​例子。在這種情況下,other_constructor是構造函數,它正在創建other_constructor類型的對象(理想情況下實際上這將會大寫)。該對象存儲在that中。在這個工廠功能中,method是一個定義的功能,它被添加到that以某種方式擴展對象的功能。

構造函數和工廠函數之間的差別在於一個工廠函數僅僅是一個返回對象的正常功能,而一個構造函數有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 

一個典型的工廠函數:

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 

他們和每一個不同的用例之間的差別的一個很好的解釋是at Eric Elliot's blog

+0

謝謝,這個對我有意義。類似於面嚮對象語言的類構造函數 – 2016-03-15 23:30:00

14

這是道格拉斯Crockford的原始來源,因爲它出現在他的幻燈片:

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(); 
})(); 

據道格拉斯Crockford的談話,他避免了使用:

  • Object.create
  • this !!!

觀看原始克羅克福德視頻: https://www.youtube.com/watch?v=PSGEjv3Tqo0

的克羅克福德道格拉斯對象創建模式2014年很好的解釋是這樣的博客:https://weblogs.asp.net/bleroy/crockford%E2%80%99s-2014-object-creation-pattern

+0

,因爲構造函數應該總是在JS中大寫。 – 2015-06-29 22:19:39

+5

穩定。這是爲了符合克羅克福德的說法,它不需要一個新的前綴。 – jiku 2015-10-31 22:12:00

+1

@Rob Raisch如果我沒有記錯,他確實提到過,爲了不與構造函數混淆,他選擇不使用大寫字母。 – LiweiZ 2016-07-29 13:53:49

1

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())

瞭解更多構造函數模式http://www.sga.su/constructor-pattern-javascript/

2

與解釋道格拉斯Crockford的新的構造格局的香草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's 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);