最近,为了更好地理解JS ES6,我一直在从事一个使用JS ES6的实践项目,因此我阅读了很多关于JS设计模式和JS编码策略的文章。我的问题是如何分割项目的功能,所以我必须简单地解释一下我在这个项目中要做什么。
我有一个输入,它得到一个带有页面URL的命令。命令是summarize和crawl。summarize实际上总结了给定URL的内容,并抓取URL中的单词。
class App {
constructor(options) {
this.email = options.email;
this.inputElement = options.inputElement;
this.progressElement = options.progressElement;
this.infoElement = options.infoElement;
this.outputElement = options.outputElement;
this.init();
}
init() {
this.socket = io();
this.socket.emit('join', {email: this.email});
this.progress = {
action: document.querySelector('.progress-action'),
percentage: document.querySelector('.progress-percentage'),
bar: document.querySelector('.progress-bar')
};
this.bindEvents();
}
bindEvents() {
let that = this;
this.inputElement.addEventListener('keyup', function (e) {
if (e.keyCode === 13) {
let compiledInput = that.tools().compileInput(this.value);
if (!compiledInput.target) {
that.tools().showInfo(that.resources().messages.noURL);
}
else if (!compiledInput.command) {
that.tools().showInfo(that.resources().messages.noCommand);
}
else {
that.tools().showInfo(that.resources().messages.syntax);
that.progressElement.classList.add('show');
that.action()[compiledInput.command](compiledInput);
}
}
else if (this.value.trim() !== '') {
that.tools().showInfo(that.resources().messages.pressEnter);
}
else {
that.tools().showInfo(that.resources().messages.syntax);
}
});
that.socket.on('crawlProcess', function (resp) {
that.progress.action.innerHTML = resp.action;
that.progress.percentage.innerHTML = resp.index + ' Files Crawled - ' + resp.percentage + '%';
that.progress.bar.style.width = resp.percentage + '%';
that.outputElement.innerHTML = '';
for (let i = 0; i < resp.response.length; i++) {
let fieldKey = Object.keys(resp.response[i])[0];
let fields = '<span class="word">' + resp.response[i][fieldKey] + '</span>';
that.outputElement.insertAdjacentHTML('beforeend', fields);
}
if (parseInt(resp.percentage) === 100) {
setTimeout(()=> {
that.progressElement.classList.remove('show');
if (that.outputElement.innerHTML.trim() === '') {
that.tools().showInfo(that.resources().messages.alreadyCrawled);
}
else {
that.outputElement.classList.add('show');
}
}, 500);
}
});
that.socket.on('summarize', function (resp) {
that.progress.action.innerHTML = resp.action;
that.progress.percentage.innerHTML = resp.percentage + '%';
that.progress.bar.style.width = resp.percentage + '%';
if (parseInt(resp.percentage) === 100) {
setTimeout(()=> {
if (!resp.error) {
that.outputElement.innerHTML = resp.response;
that.outputElement.classList.add('show');
}
else {
that.outputElement.innerHTML = '';
that.outputElement.classList.remove('show');
that.tools().showInfo(resp.response.message);
}
that.progressElement.classList.remove('show');
}, 500);
}
});
}
action() {
let that = this;
return {
crawl(options){
that.socket.emit(options.command, {
url: options.target,
maxCrawlCount: options.option || 10,
includeAbsolute: true
});
},
summarize(options){
that.socket.emit(options.command, {
url: options.target,
paragraphs: options.option || 1
});
}
}
}
resources() {
return {
messages: {
pressEnter: 'Press enter to go!',
noURL: 'Please provide a valid target URL to act on!',
noCommand: 'Command not found!',
syntax: 'What can I do for you?',
alreadyCrawled: 'This page is already crawled!'
},
commands: ['summarize', 'crawl']
}
}
tools() {
let that = this;
return {
levenshteinDistance(a, b) {
if (a.length == 0) return b.length;
if (b.length == 0) return a.length;
let matrix = [];
// increment along the first column of each row
let i;
for (i = 0; i <= b.length; i++) {
matrix[i] = [i];
}
// increment each column in the first row
let j;
for (j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}
// Fill in the rest of the matrix
for (i = 1; i <= b.length; i++) {
for (j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) == a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
Math.min(matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j] + 1)); // deletion
}
}
}
return matrix[b.length][a.length];
},
levenshteinPercentage(a, b) {
return 1 - (1 / (Math.max(a.length, b.length)) * that.tools().levenshteinDistance(a, b));
},
compileInput (input) {
let url = that.tools().extractURL(input),
command = that.tools().extractCommand(input.replace(url || '', '')),
option = input.match(/ \d+/);
option = (option) ? parseInt(option[0]) : null;
return {
target: url,
command: command,
option: option
};
},
extractURL (input) {
let matchedURLs = input.match(/(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/ig);
return (matchedURLs) ? matchedURLs[0] : null;
},
extractCommand (input) {
let matchedCommands = [];
input = input.split(' ');
for (let j = 0; j < that.resources().commands.length; j++) {
for (let i = 0; i < input.length; i++) {
if (input[i].trim() !== '') {
let distance = that.tools().levenshteinPercentage(input[i].toLowerCase(), that.resources().commands[j].toLowerCase());
if (distance > .5) {
matchedCommands.push({
command: that.resources().commands[j],
distance: distance
});
}
}
}
}
return that.tools().sortByKeyVal(matchedCommands, 'distance')[0].command;
},
sortByKeyVal (arr, key) {
return arr.sort(function (a, b) {
if (a[key] < b[key])
return 1;
if (a[key] > b[key])
return -1;
return 0;
});
},
showInfo(message){
that.infoElement.innerText = message;
}
}
}
}
new App({
email: 'a.jafari.90@gmail.com',
inputElement: document.querySelector('.input'),
progressElement: document.querySelector('.progress'),
infoElement: document.querySelector('.info'),
outputElement: document.querySelector('.output')
});这是一个有效的编码策略,只有一个类,并将函数包装并分组为方法吗?这会使更大的项目变得更复杂吗?如果是这样的话,对于像我当前项目这样的项目,建议的或最佳实践编码策略是什么?
发布于 2016-12-01 14:55:32
tools(), resources() and actions()都应该静态地实现为Objects,而不是返回对象的函数。否则,每次使用它们时,都会在内存中重新创建它们。
示例:
class App { ... }
App.Tools = { tools code... };
App.Resources = { resources code... };
App.Actions = { actions code };更进一步说,tools通常称为Utilities,可以在单独的实用程序文件/模块中定义,该文件/模块可以在应用程序中进行引用和重用。特别是如果实用程序包含常用的函数。
https://codereview.stackexchange.com/questions/148367
复制相似问题