关于nodejs的调试

最近使用了nodejs写程序,但是之前调试都是在程序源码中打印console.log来查看变量或者代替断点,这样在每次修改完之后要重启服务,并且相对来说比较繁琐耗时,因此上网探索了一下nodejs的调试相关内容,把学到的东西整理一下。

因为项目是用express搭的,因此直接说怎么调试express(其实调试单个文件也同理)。

在搭建好node开发环境的前提下,首先要在全局安装node-inspector,

npm install -g node-inspector

然后再安装supervisor(这是一个修改代码保存后自动刷新的插件,免去了每次修改代码后都要重新启动服务的烦恼,如果想了解详情,请自行百度(谷歌)supervisor^_^)

sudo install supervisor
//mac上加sudo,否则有时会出错(因为权限问题)

接下来就要正是进行nodejs的调试了

supervisor --debug ./bin/www
//在终端中的项目目录下输入这句话回车,监听程序启动,express也跑起来了

打开http://localhost:3000,就可以看到启动的express了。

再打开一个新的终端,cd到文件目录下,执行

node-inspector &

这时出现一个地址,复制地址到chrome中打开,就可以看到类似chrome开发者工具的东西了,在这里,可以进行设置断点,查看变量等操作,完美调试nodejs程序。

over (^_^)

js正则表达式学习笔记

正则表达式中的特殊字符

\ 转义
^ 匹配一个或一行的开头
$ 匹配一个或一行的结尾
* 匹配前面元字符0次或多次
+ 匹配前面元字符1次或多次
? 匹配前面元字符0次或1次
x|y 匹配x或y
. 表示匹配字符串中出现的第一个非换行符字符
{n} 精确匹配元字符n次
{n,} 匹配元字符n次或以上
{n,m} 匹配n-m次
[xyz] 字符集,匹配这个字符集中的任意一个字符
[^xyz] 不匹配这个字符集中的任意一个字符
[\b] 匹配一个退格符
\b 匹配一个单词的边界
\B 匹配一个单词的非边界
\cX 这儿,X是一个控制符,/\cM/匹配Ctrl-M
\d 匹配一个字数字符,/\d/ = /[0-9]/
\D 匹配一个非字数字符,/\D/ = /[^0-9]/
\n 匹配一个换行符
\r 匹配一个回车符
\s 匹配一个空白字符,包括\n,\r,\f,\t,\v等
\S 匹配一个非空白字符,等于/[^\n\f\r\t\v]/
\t 匹配一个制表符
\v 匹配一个重直制表符
\w 匹配一个可以组成单词的字符,包括字母大小写、数字、下划线,如[\w]匹配”$5.98”中的5,等于[a-zA-Z0-9]
\W 匹配一个不可以组成单词的字符,如[\W]匹配”$5.98”中的$,等于[^a-zA-Z0-9]

注:(1) javascript默认是贪婪匹配,也就是说匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。而进行非贪婪匹配,只需要在待匹配的字符后面跟随一个问号即可:“??”、“+?”、“*?”、“{1,5}?”。比如:/a+/可以匹配一个或多个连续的字母a。当使用“aaa”作为匹配字符串时,/a+/会匹配它的三个字母。但是/a+?/会尽可能少的匹配,只能匹配第一个哦~

(2)当要匹配连字符-时,在[]中请把它放在第一位,以防解释为范围。

正则表达式中/i,/g,/ig,/gi,/m的区别和含义

/i (忽略大小写)
/g (全文查找出现的所有匹配字符)
/m (多行查找)
/gi(全文查找、忽略大小写)
/ig(全文查找、忽略大小写)

js中的call和apply

call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。

fn.call(thisObj, arg1, arg2, ...);
fn.apply(thisObj, [arg1, arg2, ...]);

两者作用一致,都是把fn(即fn中的this)绑定到thisObj,这时候thisObj具备了obj的属性和方法。或者说thisObj『继承』了obj的属性和方法。

唯一区别是apply接受的是数组参数,call接受的是连续参数。所以当参数固定时可以使用call,当参数不固定时使用apply。

举个栗子:
// 改变this
var obj = {
name: ‘linxin’
}

function func() {
    console.log(this.name);
}

func.call(obj);       // linxin

call 方法的第一个参数是作为函数上下文的对象,这里把 obj 作为参数传给了 func,此时函数里的 this 便指向了 obj 对象。此处 func 函数里其实相当于

function func() {
    console.log(obj.name);
}

调用原生对象的方法

var a = {0:1, 1:"zjz", length: 2}; 
a.slice(); //TypeError: a.slice is not a function
Array.prototype.slice.call(a);//[1, "zjz"]

实现继承

var Parent = function(){
    this.name = "zjz";
    this.age = 22;
}
var child = {};
console.log(child);//Object {} ,空对象
Parent.call(child);
console.log(child); //Object {name: "zjz", age: 24}

bind的使用

obj.bind(thisObj, arg1, arg2, ...);

把obj绑定到thisObj,这时候thisObj具备了obj的属性和方法。与call和apply不同的是,bind绑定后不会立即执行。

同样是add()和sub():

add.bind(sub, 5, 3); //不再返回8
add.bind(sub, 5, 3)(); //8

如果bind的第一个参数是null或者undefined,等于将this绑定到全局对象。

js回调函数

什么是js的回调函数,简而言之,就是把一个函数当做参数传入另一个函数中。

funtion a(a,callback) {
    callback()
}
funtion b() {
    alert(a)
}
a(b)

其中,函数b就是函数a的回调函数。

那么回调函数如何传参?

function a(callback){
    var m = 1;
    var n = 2;
    alert(callback(m,n));
}
function b(m,n){
    return m+n;
}
a(b);
//alert得出3

node中n的使用——版本控制

在node开发中,有时候会遇到这样一些情况:

一些工程要求低版本的node,而一些工程要求高版本的node,因此出来这样一个需求,那就是node的版本控制,要求在想要的时候可以切换到相应的node版本,且各个版本之间互不干扰。

基于这一需求,网上给出两种答案,一是用nvm进行node的版本控制管理,二是用n进行node的版本控制管理,在权衡完nvm与n的利弊之后,笔者选择了n作为node的版本控制工具。原因如下:

相比nvm,n更轻量,且n的操作更简单。但n也有弊端,那就是n是依赖于npm下的包,在想装n之前,要先装一个node环境。

安装n

npm install -g n

安装指定的node版本

n install <version>

选择指定的node版本

n //这时出现了安装过的node的版本号,按上下键选择相应的版本,回车
node -v //查看当前node版本号

删除指定的node版本

n rm <version>

在n安装过程中遇到的一些问题:

安装n后选择node版本号失效。呃。。。对于这个问题。。笔者的解决方法是删除所有node环境重新安装,然后成功。初步估计是路径问题。

碰到 dyld:bad external relocation length Trace/BPT trap: 5

这个问题也困扰了我比较长的时间,最后看到overstackflow上有个兄弟给出了一个解决的方案,在终端中输入

n latest 

将版本更新到最新,然后node -v就是最新的版本,然后把出问题的版本删除,成功解决。

MVC、MVP与MVVM模型理解

早就听说过MVC,MCP,MVVM模型,但一直只知其一,不知其二。这几天终于找机会实力查了一波资料,好好的了解了一下,下面就聊一聊这三种模型,如有不对,欢迎大家指正。

首先来说一下MVC框架,就是经典的Model,view,controller,最早提出于上世纪80年代。一般来说,Model提供数据,view是向用户展示的界面,而controller,以及用Model中的数据是Model和View之间联系的桥梁。一个简单的例子就是一般建设一个网站,数据库扮演的就是Model的角色,而后台扮演的就是controller的角色,前端扮演的是View角色。但是在前端中,MVC又该如何理解呢?

下面来举一个例子:

/**本实例来源于维基百科 */    
/** 模型 Model, View, Controller */
var M = {}, V = {}, C = {};

/** Model 负责存放资料 */
M.data = "hello world";

/** View 负责将资料打印到屏幕上 */
V.render = function (M) { alert(M.data); }

/** Controller 作为一个M和V的桥梁 */
C.handleOnload = function () { V.render(M); }

/** 在网页读取的时候呼叫 Controller */
window.onload = C.handleOnload;

这就是一个前端的MVC实例

那么MVP呢?即 Model View Presenter

  1. Model 定义使用者界面所需要被显示的资料模型,一个模型包含着相关的业务逻辑。
  2. View 视图为呈现使用者界面的终端,用以表现来自 Model 的资料,和使用者命令路由再经过 Presenter 对事件处理后的资料。
  3. Presenter 包含着元件的事件处理,负责检索 Model 取得资料,和将取得的资料经过格式转换与 View 进行沟通。

    那MVC与MVP之前又有什么不同呢?

在经典MVC中,一对controller-view捆绑起来表示一个ui组件,controller直接接受用户输入,并将输入转为相应命令来调用model的接口,对model的状态进行修改,最后通过观察者模式对view进行重新渲染。而MVP是修改controller-view的捆绑关系,为了解决controller-view的捆绑关系,将进行改造,使view不仅拥有UI组件的结构,还拥有处理用户事件的能力,这样就能将controller独立出来。为了对用户事件进行统一管理,view只负责将用户产生的事件传递给controller,由controller来统一处理,这样的好处是多个view可共用同一个controller。总结而言,即提升了controller的作用,把他从ui组件中提取出来,进而成为一个可以通用的逻辑处理程序。

MVVM —— Model-View-ViewModel

这个让我们来看一下下图:

view和model是不知道彼此存在的,同MVP一样,将view和model清晰地分离开来。 其次,view是对viewmodel的外在显示,与viewmodel保持同步,viewmodel对象可以看作是view的上下文。view绑定到viewmodel的属性上,如果viewmodel中的属性值变化了,这些新值通过数据绑定会自动传递给view。反过来viewmodel会暴露model中的数据和特定状态给view。 所以,view不知道model的存在,viewmodel和model也觉察不到view。事实上,model也完全忽略viewmodel和view的存在。这是一个非常松散耦合的设计。

hexo常用命令

由于很长时间没有写博客,因此竟忘了一些hexo的基本操作【==| 尴尬。。】,在此复习一下,顺便做下笔记。
hexo new “blog title” //在终端中cd到hexo所在的文件夹下,输入这条命令,自动生成blog的titie、date、tages等模板;
hexo s //这条命令是在本地开启服务,在指定的url下可以在本地预览blog最终展现的模样;
hexo g //根据md生成静态页面存到public目录下
hexo d //将.deploy目录部署到GitHub
当hexo s后到0.0.0.0:4000 显示未发送任何数据时,请检测是否开启了vpn,如果开启了请关闭。