面试题-Array最后一位加法运算

最近去公司面试遇到一个关于Array操作的问题如下:

实现 [5,6,9] + 1 = [5,7,0];

当时回答的时候提出的一种方案是采用Array的reduceRight操作

1
2
3
4
5
6
7
8
9
10
11
var arr = [5,6,9];
arr.reduceRight(function(prev, next,index,self){
if(next + prev >= 10){
self[index] = prev + next - 10;
return 1;
}else{
self[index] = prev + next;
return 0;
}
},1);
console.log(arr); // [5,7,0]

Jade模板迁移到Pug模板修改.md

Jade模板迁移到Pug模板修改

部分引用:https://pugjs.org/language/attributes.html

  • 修改模板引擎,修改所有文件后缀

    app.set(‘view engine’, ‘pug’);

属性修改

以前的Pug/Jade支持如下的表达式来获取数据

1
a(href="/#{url}") Link

新版本将不再支持上面表达式来获取数据,而是采用以下形式.

1
2
- var url = 'pug-test.html';
a(href='/' + url) Link

如果你的版本支持ES2015(包括 Node.js/io.js 1.0.0 或者更高版本),还可以采取下面的形式

1
2
3
4
5
- var btnType = 'info'
- var btnSize = 'lg'
button(type='button' class='btn btn-' + btnType + ' btn-' + btnSize)
= '\n'
button(type='button' class=`btn btn-${btnType} btn-${btnSize}`)

&attributes

1
2
3
4
- var attributes = {};
- attributes.class = 'baz';
div#foo(data-bar="foo")&attributes(attributes)
/*out: <div class="baz" id="foo" data-bar="foo"></div>*/

注意 : Attributes applied using &attributes are not automatically escaped. You must be sure to sanitize any user inputs to avoid cross-site scripting (XSS). This is done for you if you are passing in attributes from a mixin call.

Express+Jade引入bootstrap无法应用样式.md

在使用jade模板引擎开发时,引入bootstrap发现样式,无法正常显示

1
link(href="/bootstrap/dist/css/bootstrap.css")

修改为

1
link(href="/bootstrap/dist/css/bootstrap.css",rel="stylesheet" type="text/css")

就可以正常显示了.具体原因可能跟jade版本或者express版本有关

windows上安装启动Mongodb.md

安装MongoDB数据库

MongoDB官网

下载MongoDB

简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

下载安装完成后,需要新建数据存储目录

我的目录为 C:\DATA\DB

调用cmd命令,设置db目录

mongod.exe –dbpath C:\DATA\DB

如果执行成功,会出现一长串这么多东西,不用管它.

2016-11-09T11:23:47.798+0800 I CONTROL [initandlisten] MongoDB starting : pid=1384 port=27017 dbpat
h=C:\DATA\DB 64-bit host=cuining-PC
2016-11-09T11:23:47.798+0800 I CONTROL [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R
2
2016-11-09T11:23:47.798+0800 I CONTROL [initandlisten] db version v3.4.0-rc2-85-g4b42373
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] git version: 4b423738f24c1ccd628e1fcc2b9ee5f
d84bbfe4c
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] OpenSSL version: OpenSSL 1.0.1t-fips 3 May
2016
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] allocator: tcmalloc
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] modules: none
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] build environment:
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] distmod: 2008plus-ssl
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] distarch: x86_64
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] target_arch: x86_64
2016-11-09T11:23:47.799+0800 I CONTROL [initandlisten] options: { storage: { dbPath: “C:\DATA\DB” }
}
2016-11-09T11:23:47.802+0800 I STORAGE [initandlisten] wiredtiger_open

下面将MongoDB服务器作为Windows服务运行

C:\Program Files\MongoDB\Server\3.4\bin>mongod.exe –logpath “C:\DATA\dbConf\mongodb.log” –logappen
d –dbpath “C:\DATA\DB” –port 27017 –serviceName “MongoDBService” –serviceDisplayName “芒果数据服
务” –install

参数 描述
–bind_ip 绑定服务IP,若绑定127.0.0.1,则只能本机访问,不指定默认本地所有IP
–logpath 定MongoDB日志文件,注意是指定文件不是目录
–logappend 使用追加的方式写日志
–port 指定服务端口号,默认端口27017
–serviceName 指定服务名称
–serviceDisplayName 指定服务名称,有多个mongodb服务时执行。
–install 指定作为一个Windows服务安装。

如果直接运行mongo,则会报以下错误

Mongo运行错误:Failed to connect 127.0.0.1:27017,reason:errno:10061
Mongo运行错误:Failed to connect 127.0.0.1:27017,reason:errno:10061由于目标计算机积极拒绝,无法连接

这是因为服务器没有开启,

net start MongoDBService 启动mongodb服务

net stop MongoDBService 关闭mongodb服务

一步步实现Amd-loader(三)

通过前面几步,我们基本实现了一个模块化编程,现在要为程序实现AMD的接口(define方法)
AMD的规范只定义了一个函数 “define”,它是全局变量。函数的描述为:

define(id?, dependencies?, factory);

具体请参考 –> Amd规范

实现AMD的类库两个比较著名的分别是RequireJSCurlJS
说实话如果直接看这两个类库的源码,可能多少有点难,甚至懵逼,建议初学者可以参考别的实现:foio.github.io

我们把每一个模块改为一个js文件,然后实现我们的AMD模块加载器

add.js

1
2
3
4
5
define([],function () {
return function () {
console.log("define an add module ....");
}
});

minus.js

1
2
3
4
5
define([],function () {
return function () {
console.log("define minus module ....");
}
});

calc.js

1
2
3
4
5
6
define(['./add','./minus'],function (add,minus) {
return {
add: add,
minus: minus
}
});

main.js

1
2
3
4
5
6
7
8
9
10
require(['./calc'],function (calc) {
var btnAddEl = document.getElementById('btnAdd');
var btnMinusEl = document.getElementById('btnMinus');
btnAddEl.addEventListener("click",function () {
calc.add();
});
btnMinusEl.addEventListener("click",function () {
calc.minus();
});
});

通过分析,可以整个过程看做是一个”栈”操作.

  • 1.define() 操作定义一个Module,立即压入”栈”(这里push到数组中);
  • 2.加载该模块的deps(依赖数组)
  • 3.出”栈”执行模块的工厂函数,获取返回值

define 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function define(id,deps,length){
var len = arguments.length;
if (len == 2) {
factory = deps;
deps = id;
id = undefined;
}
var mod = new Module(id,deps,factory);
context.newModules.push(mod);
context.waitingModules.push(mod);
mod.loadDeps();
exec();
}

exec函数(执行context.waitingModules中的模块,如果已经准备好,则从数组中剔除)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 执行所有等待模块,如果模块加载完成,则从等待数组剔除
* @return {[type]} [description]
*/
function exec() {
var i;
var j = 0;
var depID;
var len = context.waitingModules.length;
var val;
var mod;
var args;
var callback;
for(i = len;i--;){
mod = context.waitingModules[i];
if ((!mod.returnVal) && mod.checkDeps()) {//如果一个没有执行输出结果,并且依赖已经准备好
//从等待数组中删除
context.waitingModules.splice(i,1);
args = [];
callback = mod.factory;
for(j = mod.deps.length;j--;){
depID = mod.deps[j];
args.unshift(mod.getDepsValue(depID));
}
val = callback.apply(global,args);
mod.returnVal = val;
}
}
}

require函数其实也是一个define函数的过程,为了便于理解,暂时不处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 定义require函数
* @param {[type]} deps [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
function require(deps, callback) {
var mod = new Module(context.topModule,deps,callback);
context.loads[context.topModule] = true;
context.modulesMap[context.topModule] = mod; //top main module already loaded
context.newModules.push(mod);
context.waitingModules.push(mod);
mod.loadDeps();
exec();
}

具体实现可以参考我的github或者foio.github.io实现.

一步步实现Amd-loader(二)

通过上面的代码,我们对模块化有了一定的了解,下面从面向对象思想出发,对模块进行分析.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 这是定义模块add
*/
var addModule = (function () {
return function () {
console.log("i'm add module ....");
}
})();
/**
* 这是定义模块minus
*/
var minusModule = (function () {
return function () {
console.log("I'm minu module....");
}
})();
/**
* 这是计算模块,依赖模块add 和模块minus
* @type {[type]}
*/
var calcModule = (function (add,minus) {
return {
add: add,
minus: minus
}
})(addModule,minusModule);

我们通过上面的代码可以分析抽象建立我们的Module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Module = {
id:"",//模块唯一标识
deps: [],//模块依赖数组
factory: function, //回调函数
returnVal: {} //模块暴露返回值
}
/**
* 模块缓存对象
* @type {Object}
*/
moduleMap: {
"scripts/main": {//-->Module
id:"scripts/main",
deps: ['./calc'],
factory: function,
returnVal: {} //返回值
}
}

代码修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 创建增加计算模块
* @type {Module}
*/
var addModule = new Module('add',[],function () {
return function () {
console.log("i'm new add module ....");
}
});
moduleMap['add'] = addModule;
/**
* 创建减少计算模块
* @type {Module}
*/
var addModule = new Module('minus',[],function () {
return function () {
console.log("I'm new minu module....");
}
});
moduleMap['minus'] = addModule;
var calcModule = new Module("calc",['add','minus'],function (add,minus) {
return {
add: add,
minus: minus
}
});
moduleMap['calc'] = calcModule;

需要为我们的Module对象添加两个方法: fireFactory(执行factory函数,赋值给returnVal)和getDepsValues(获取依赖模块的返回值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Module.prototype.fireFactory = function () {
var mod = this;
// 获取依赖模块的exports列表
var args = mod.getDepsValues();
var ret = mod.factory.apply(null, args);
mod.returnVal = ret;
return mod.returnVal;
}
Module.prototype.getDepsValues = function () {
var mod = this;
var args = [];
var deps = mod.deps;
var dep;
var argsLen = deps.length;
for (var i = 0; i < argsLen; i++) {
dep = getMod(deps[i]);//从缓存中获取模块
args.push(dep.exec());//执行递归函数
}
return args;
}

一步步实现Amd-loader(一)

javascript 模块

通常,在js中模块应该是IIFE-立即执行调用函数表达式(Immediately-Invoked-Function-Expressions)运行私有域–即防止变量和方法污染全局变量和方法.格式如下

1
2
3
4
5
6
7
8
9
(function() {
// 声明私有变量和方法
return {
// 声明公共方法和变量
}
})();

下面我们利用模块化设计一个小的测试程序,流程如下:

主要模块( mainModule ) –> 计算模块( calcModule ) –> [增加模块( addModule ),减少模块(minusModule)]

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>一步步理解Requirejs 异步模块化编程</title>
</head>
<body>
<button id="btnAdd" type="button" name="button">增加</button>
<button id="btnMinus" type="button" name="button">减少</button>
<script src="scripts/main.js" charset="utf-8"></script>
</body>
</html>

main.js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
(function (global) {
/**
* 封装事件处理
* @param {[type]} el [description]
* @param {[type]} type [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
var $emit = function (el,type,callback) {
if (el.addEventListener) {
el.addEventListener(type,callback);
} else if(el.attachEvent){
el.attachEvent("on"+type,callback);
}else {
el[type] = callback;
}
};
global.$emit = $emit;
/**
* 这是定义模块add
*/
var addModule = (function () {
return function () {
console.log("i'm add module ....");
}
})();
/**
* 这是定义模块minus
*/
var minusModule = (function () {
return function () {
console.log("I'm minu module....");
}
})();
/**
* 这是计算模块,依赖模块add 和模块minus
* @type {[type]}
*/
var calcModule = (function (add,minus) {
return {
add: add,
minus: minus
}
})(addModule,minusModule);
/***
*这里是主模块
*/
$emit(document.getElementById('btnAdd'),"click",function () {
calcModule.add();
});
$emit(document.getElementById('btnMinus'),"click",function () {
calcModule.minus();
});
})(this);