2017-01-27 18 views
0

我理解OOP的主要原理,並且我有點知道如何將它實現爲JS。面向對象的Javascript如何用於DOM操作

function Person(name) { 
    this.name = name; 
    this.speak = function(msg) { 
     console.log('Person says:' + msg); 
    } 
} 

var dad = new Person('David'); 
dad.speak('I am your dad!'); 

上面的腳本只是在控制檯中輸出消息。我不明白我們如何用這種技術來處理DOM。也許這樣?:

function Person(target, name) { 
    this.target = target; 
    this.name = name; 
    this.speak = function(msg) { 
     this.target.find('.speech-bubble').html(msg); 
    } 
} 

var dad = new Person($('#dad'), 'David'); 
dad.speak('I am your dad!'); 

雖然這似乎不是一個好方法。

我們如何通過OO Javascript使用對象,方法,構造函數等操作DOM?

+0

嘗試MDN的解釋考慮看看:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain –

+0

你有Person對象的兩個參數,因此它會是'var dad = new Person($('#dad'),'David');'then'dad.speak('我是你的爸爸!');' –

+0

@ oliv37哎呀,糾正它;) –

回答

1

您需要了解的是Prototype的概念。

當您使用new創建實例時,您正在構建基於原型的對象。

考慮以下幾點:

function Person(name) { 
 
    this.name = name; 
 
    this.speak = function (msg) { 
 
     console.log('Person says:' + msg); 
 
    }; 
 
} 
 
var dad = new Person('David'); 
 
dad.speak('I am your dad!'); 
 
console.log('Is dad.speak equal to dad.speak?', dad.speak === dad.speak); 
 
var mom = new Person('David'); 
 
console.log('Is mom.speak equal to dad.speak?', mom.speak === dad.speak);

每次構建的Person一個新實例,新speak原型現在周圍漂浮在某處你的邏輯。這是非常低效的。

爲了解決這個問題,我們需要修改我們的函數的prototype

function Person(name) { 
 
    this.name = name; 
 
} 
 
Person.prototype.speak = function (msg) { 
 
    console.log('Person says:' + msg); 
 
}; 
 
var dad = new Person('David'); 
 
dad.speak('I am your dad!'); 
 
console.log('Is dad.speak equal to dad.speak?', dad.speak === dad.speak); 
 
var mom = new Person('David'); 
 
console.log('Is mom.speak equal to dad.speak?', dad.speak === dad.speak);

這樣,我們只需要創建一次函數,其上繼承到所有prototype實例。這更容易維護,效率更高。

現在我們可以通過他們prototype擴展DOM對象,但不建議這樣做,因爲你開始與web標準的混亂,使故障排除變得更加困難。

Array.prototype.isLengthGreaterThanFive = function(thisArg) { 
 
    return this.length > 5; 
 
}; 
 
console.log([1, 2, 3, 4].isLengthGreaterThanFive(), [1, 2, 3, 4, 5, 6].isLengthGreaterThanFive());

處理這更好的方法是創建一個擴展的對象,或者簡單地使用功能:

//Using functions 
 
function isLengthGreaterThanFive(array) { 
 
    return array.length > 5; 
 
} 
 
console.log(isLengthGreaterThanFive([1, 2, 3, 4]), isLengthGreaterThanFive([1, 2, 3, 4, 5, 6]));

//Using a wrapper class 
 
var MyArray = (function() { 
 
    function MyArray(array) { 
 
    if (array === void 0) { 
 
     array = []; 
 
    } 
 
    this.array = array; 
 
    } 
 
    MyArray.prototype.isLengthGreaterThanFive = function() { 
 
    return this.array.length > 5; 
 
    }; 
 
    return MyArray; 
 
}()); 
 
console.log(new MyArray([1, 2, 3, 4]).isLengthGreaterThanFive(), new MyArray([1, 2, 3, 4, 5, 6]).isLengthGreaterThanFive());

使用類的好處是,我們可以在我們的對象的理念延伸:

//Base class 
 
function Person(firstname, lastname, says) { 
 
    if (firstname === void 0) { 
 
     firstname = "Leonado"; 
 
    } 
 
    this.firstname = firstname; 
 
    if (lastname === void 0) { 
 
     lastname = "Da Vinci"; 
 
    } 
 
    this.lastname = lastname; 
 
    if (says === void 0) { 
 
     says = "hello"; 
 
    } 
 
    this.says = says; 
 
} 
 
//Base methods 
 
Person.prototype.iAm = function() { 
 
    return this.firstname + " " + this.lastname; 
 
}; 
 
Person.prototype.Speak = function() { 
 
    return this.says + " my name is " + this.iAm(); 
 
}; 
 
//Extended class 
 
function Warrior(firstname, lastname, says) { 
 
    //Call in constructor 
 
    Person.call(this, firstname, lastname, says); 
 
} 
 
//Inheriting 
 
Warrior.prototype = Object.create(Person.prototype); 
 
Warrior.prototype.constructor = Warrior; 
 
//Overruling "Speak" 
 
Warrior.prototype.Speak = function() { 
 
    return "My name is " + this.iAm() + ", " + this.says; 
 
}; 
 
console.log([new Warrior("Peter", "Allan", "Ahoyhoy").Speak(), new Person("Peter", "Allan", "Ahoyhoy").Speak()]);

在上面的例子中,我們爲Warrior因此延長Person原型我們保留Person的功能,然後簡單地修改Warrior的不同之處。這樣我們可以重新使用原型方法iAm,我們可以專注於僅改變Speak方法中需要更改的內容。

編輯1

我發現爲時已晚,該問題已經改變了一點。

你可以把DOM元素,如JavaScript中的任何其他類。以下安裝有所有Persons共享單個DIVspeakUp

var Person = (function() { 
 
    function Person(age, firstname, lastname) { 
 
     if (age === void 0) { age = 50; } 
 
     if (firstname === void 0) { firstname = "Peter"; } 
 
     if (lastname === void 0) { lastname = "Venkman"; } 
 
     this.age = age; 
 
     this.firstname = firstname; 
 
     this.lastname = lastname; 
 
    } 
 
    Person.prototype.speakUp = function() { 
 
     Person.bubble.innerHTML = this.firstname + " " + this.lastname + " is " + this.age + " years old"; 
 
    }; 
 
    return Person; 
 
}()); 
 
Person.bubble = document.createElement("div"); 
 
document.body.appendChild(Person.bubble); 
 
setInterval(function() { 
 
    var p = new Person(Math.floor(Math.random() * 100)); 
 
    p.speakUp(); 
 
}, 3000);

這很容易成爲DIVPerson,或所有Person選自S共享一個refereced DOM對象(的document.getElementById) 。

EDIT 2

在回答您的評論:

在JavaScript中的一切在本質上和object。你創建一個函數,它用函數名稱object註冊並返回objectinstance。像Arrays,Strings,DOM等元素和自定義功能都有一些object隱藏在幕後。每創建一個新的ArrayDOM元素或其他東西,它都會引用其主對象(稱爲原型)。這被稱爲原型鏈。

如果你看看我的第二個例子,當dad.speak被稱爲JavaScript的第一個搜索實例爲speak屬性,但它不會找到一個,因爲我們還沒有分配它,我們做的方式例如在一個是它是特定於實例的。

然後JavaScript會嘗試一個級別上的prototype鏈,在這裏它會找到一個匹配的屬性,並用它來代替。通過這種方式,我們可以改變JavaScript中現有元素的自定義的默認行爲。

這個想法是,如果你有一些屬性,原型的所有實例應該有,那麼我們只需修改一次原型,他們將全部inherit這個屬性。

想想這樣。如果你用JavaScript描述地球上的所有生物,你會想要某種形式的分組。例如,第一個級別就像是一個Exists對象,它攜帶一個名稱和一個id的屬性。從這裏你可以創建PlantAnimal並讓它們都繼承Exists的原型。現在我們可以創建一個繼承PlantFlower類和繼承Flower等的Rose類。

這個想法是以一種對人類有意義的方式通過繼承來應用你的屬性(一隻貓頭鷹可以飛,因爲它是一隻鳥/一隻鯊魚可以游泳,因爲它是一條魚)。將它們綁定在有意義的級別上,以邏輯模式繼承並有效利用您的時間。

如果您仍然感到困惑,請嘗試查找prototype教程。

這裏是一個很好的Youtube視頻來解釋它:

https://www.youtube.com/watch?v=PMfcsYzj-9M

+0

原型對我來說一直很難。對不起,如果我聽起來很愚蠢,但在你的解釋之後,我仍然無法理解原型的使用(我以荷蘭語爲主要原因)。對我來說,看起來好像原型被用於在課堂之外爲課程分配方法。你是否在說原型的目標是響應(自動適應各種子類/對象)? –

2

關於OO,如果你要請採用DOM面臨的代碼,你是不是太遠的。

我想說一個類應該代表DOM上的一個組件/元素。它的方法是國家管理部分。但說實話,這裏沒有正確的答案。這只是面向DOM部分設計面向對象的一種方式。

例子:

const basicClassName = 'component'; 
 
const basicTemplate = '<h1>This is my basic component</h1>'; 
 

 
class MyComponent { 
 
    constructor(template = basicTemplate, className = basicClassName) { 
 
    this.template = template; 
 
    this.className = className; 
 
    
 
    this.element = document.createElement('div'); 
 
    this.element.className = className; 
 
    this.element.innerHTML = template; 
 
    this.element.onclick = this.onClick.bind(this); 
 
    this.element.style.cursor = 'pointer'; 
 
    } 
 
    
 
    onClick() { 
 
    this.element.classList.toggle('clicked'); 
 
    } 
 
} 
 

 
const component = new MyComponent(); 
 

 
const container = document.querySelector('.container'); 
 

 
container.appendChild(component.element);
body { 
 
    font-size: 14px; 
 
} 
 

 
.component { 
 
    display: block; 
 
    padding: 1.3em; 
 
    box-shadow: 1px 1px 4px lightgray; 
 
} 
 

 

 
.clicked { 
 
    background-color: papayawhip; 
 
}
<div class="container"></div>