Ste*_*gen 5 javascript oop dom
我了解 OOP 的主要原理,并且我有点知道如何将其实现到 JS 中。
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!');
Run Code Online (Sandbox Code Playgroud)
上面的脚本只是在控制台中打印出一条消息。我不明白我们如何用这种技术处理 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!');
Run Code Online (Sandbox Code Playgroud)
虽然这似乎不是一个好方法。
我们如何通过 OO Javascript 使用对象、方法、构造函数等操作 DOM?
小智 5
关于 OO,如果您打算采用面向 DOM 的代码,那您就离得不远了。
我会说一个类应该代表 DOM 上的一个组件/元素。它的方法是状态管理的一部分。但老实说,这里没有正确的答案。这只是设计面向 DOM 部分的 OO 的一种方式。
例子:
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);Run Code Online (Sandbox Code Playgroud)
body {
font-size: 14px;
}
.component {
display: block;
padding: 1.3em;
box-shadow: 1px 1px 4px lightgray;
}
.clicked {
background-color: papayawhip;
}Run Code Online (Sandbox Code Playgroud)
<div class="container"></div>Run Code Online (Sandbox Code Playgroud)
您需要了解的是 的概念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);Run Code Online (Sandbox Code Playgroud)
每次构造 的新实例时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);Run Code Online (Sandbox Code Playgroud)
这样,我们只创建一次函数,然后将prototype其继承到所有实例。这更容易维护并且效率更高。
现在我们可以通过它们扩展 DOM 对象prototype,但不建议这样做,因为你会开始搞乱 Web 标准,从而使故障排除变得更加困难。
Array.prototype.isLengthGreaterThanFive = function(thisArg) {
return this.length > 5;
};
console.log([1, 2, 3, 4].isLengthGreaterThanFive(), [1, 2, 3, 4, 5, 6].isLengthGreaterThanFive());Run Code Online (Sandbox Code Playgroud)
处理此问题的更好方法是创建扩展对象或简单地使用函数:
//Using functions
function isLengthGreaterThanFive(array) {
return array.length > 5;
}
console.log(isLengthGreaterThanFive([1, 2, 3, 4]), isLengthGreaterThanFive([1, 2, 3, 4, 5, 6]));Run Code Online (Sandbox Code Playgroud)
//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());Run Code Online (Sandbox Code Playgroud)
使用类的好处是我们可以扩展我们对对象的想法:
//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()]);Run Code Online (Sandbox Code Playgroud)
Person在上面的示例中,我们扩展了for的原型,Warrior以便保留 的功能Person,然后简单地修改 a 的不同之处Warrior。这样我们就可以重用原型方法iAm,并且我们可以只专注于更改方法中需要更改的内容Speak。
编辑1
我发现问题发生了一些变化,为时已晚。
您可以像 JavaScript 中的任何其他类一样对待 DOM 元素。以下设置全部Persons共享一个DIVto speakUp:
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);Run Code Online (Sandbox Code Playgroud)
这很容易成为一个DIVperPerson或一个在所有Persons 之间共享的引用 DOM 对象 (document.getElementById)。
编辑2
回复您的评论:
在 JavaScript 中,一切本质上都是object. 您创建一个函数,它object使用函数名称注册 an 并返回instance该函数的和object。诸如Arrays、Strings、DOM元素和自定义函数之类的一切都object隐藏在幕后。每次创建新的Array或DOM元素或其他任何内容时,它都会引用其主对象(称为原型)。这称为原型链。
如果你看一下上面的第二个例子,当dad.speak调用 JavaScript 时,它首先会在实例中搜索属性speak,但它找不到属性,因为我们没有像示例一中那样分配它,因为它是特定于实例的。
然后 JavaScript 将尝试链上一级prototype,在这里它将找到一个匹配的属性并使用它。这样我们就可以改变JavaScript 中自定义或现有元素的默认行为。
这个想法是,如果你有一个原型的所有实例都应该有的一些属性,那么我们只需修改原型一次,它们就会拥有所有inherit这些属性。
这样想吧。如果你要用 JavaScript 描述地球上的所有生物,你会需要某种形式的分组。例如,第一层类似于一个Exists带有名称和 ID 属性的对象。从这里您可以创建Plant并Animal让它们继承 的原型Exists。现在我们可以创建一个Flower继承的类Plant和一个Rose继承的类Flower等等。
这个想法是通过继承以对人类有意义的方式应用你的属性(猫头鹰可以飞,因为它是鸟/鲨鱼可以游泳,因为它是鱼)。将它们绑定在有意义的级别上,以逻辑模式继承并有效地利用你的时间。
如果您仍然感到困惑,请尝试查找prototype教程。
这是一个很好的 Youtube 视频来解释它:
https://www.youtube.com/watch?v=PMfcsYzj-9M
| 归档时间: |
|
| 查看次数: |
3851 次 |
| 最近记录: |