CS-Playground-React接口
Medium网友Peter Weinberg的自述:我是一名自学成才的程序员。我觉得自己做得不够好,并且在掌握复杂的计算机科学概念方面处于劣势。
我对数学不是十分擅长。我总是把强大的数学技巧和天生擅长编程的能力联系在了一起。我觉得我必须比其他人(他们有天生的数学能力)更努力地学习相同的概念。这个想法深深扎根在我的大脑中,我很确定我永远无法学习像“二叉搜索树”这样的东西,以及如何在精神上分析像“归并排序”这样的递归噩梦。
进入CS-Playground-React,它是一个浏览器内的JavaScript沙盒(sandbox),用于学习和练习算法和数据结构。这款无需注册的应用程序可以自动保存你的进度,当你困住的时候为你提供解决方案,还会提供一些有用的文章、教程和其他资源的链接,让你的学习过程变得更加轻松!
我承认,这款应用并不是什么开创性的东西。市面上有大量的应用程序,它们教授类似的技能,让你能够在浏览器中编写和运行代码。
为什么我做了这个
我开发这款应用的动机很简单:我想让学习变得更简单、更有趣。更重要的是,我为什么要学习这些特殊技能。在过去的18个月左右,我可以自信地说我已经学会了如何编码。尽管我仍然不愿自称为程序员。通过学习CS的基本原理,我希望不仅能对自己作为一名程序员更有信心,而且还能帮助其他人。自学成才的程序员是科技行业近年来更容易接受的一种人才。特别是在像硅谷这样的地方,在每个街角都有编程训练营。然而,对于希望进入这个行业而没有接受正规计算机科学教育的大多数程序员来说,仍然有很多障碍需要克服。
对我来说,学习某些东西的最好方法(尤其是枯燥的东西),就是把它和你喜欢的东西联系起来。所以当我在开发这款应用的时候,我也在为它开发内容。现在,学习算法和数据结构是我的最新项目的一个必要部分。每隔几天,我就在学习一种新的算法或数据结构。一旦我把它写下来,我就会编译学习资源并把它添加到应用程序中。现在,我可以在一个我自己构建的超级简单的工作空间中反复练习。这不是很酷吗! ?
我发现了一个非常棒的网站,它能让我们看到如何对算法和数据结构进行排序。这是快速排序在100个项目数组中执行的操作。你可以在下面的地址中找到完整的可视化列表。
技术堆栈和黑客
如果你感兴趣的话,我用React & React-Redux(尽管第一个版本是vanilla JS,CSS和HTML)构建了这个应用程序。它还使用了CodeMirror和React-Codemirror2来将一个编辑器嵌入到浏览器中(注意:原始版本的React-CodeMirror已经不再被维护,而且在新版本的反应中也没有很好地发挥作用)。
模拟控制台
每次用户在它们的代码中调用console.log时,一次小的hack就可以触发一次redux操作。通过这种方式,我可以捕获已登录的消息,然后在浏览器中模拟一个控制台以显示代码的输出。你可以在任何需要清除模拟控制台消息的时候运行clearConsole()。
import { store } from './index';
export const hijackConsole = () => {
const OG_LOG = console.log;
console.log = function(...args) {
// map over arguments and convert
// objects in to readable strings
const messages = [...args].map(msg => {
return typeof msg !== 'string'
? JSON.stringify(msg)
: msg;
}).join(' ');
store.dispatch({
type: CONSOLE_LOG,
messages
});
// retain original functionality
OG_LOG.apply(console, [...args]);
};
};
重新定义console.log捕捉和存储已记录的代码
我想让这个应用程序超级容易使用。因此,我选择了一种更简单的方法来保存进度,而不是实现数据库并请求用户登录。Redux在每个会话期间管理应用程序的状态,我使用localStorage来在会话中持久化代码。该应用程序将在下一次访问时检索这个保存的状态,并将Redux存储与它解除冻结。这样你就可以在你离开的地方找到你的位置。
如果出于某种原因你想要删除所有的进程,你可以在编辑器中的任何时候运行runresetState()。如果你不想将代码提交给本地存储,那么在操作之前,不要保存注释。这将防止保存任何代码,而不仅仅是为该文件保存。
import { store } from './fileWhereStoreLives';
// add this code in your app's entry point file to
// set localStorage when navigating away from app
window.onbeforeunload = function(e) {
const state = store.getState();
localStorage.setItem(
'local-storage-key',
JSON.stringify(state.stateYouWantToPersist)
);
};
import { importedState } from './fileWhereStateLives';
// define your reducer's initial state:
const initialState = {
...importedState;
};
// define default state for each subsequent visit.
// if localStorage with this key exists, assign it
// to this variable, otherwise, use initialState.
const defaultState = JSON.parse(
localStorage.getItem('local-storage-key')
) || initialState;
// set defaultState of reducer to result of above operation
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'DO_SOMETHING_COOL':
return {
...state,
...action.newState
};
default:
return state;
}
}
export default reducer;