转载自这儿
快捷键

Ctrl+P 通过文件名或者标签名导航
Ctrl+Tab 在前一个文件和当前文件间切换
F1 打开全局命令
Ctrl+Shift+O will let you navigate to a specific symbol in a file // 不会
Ctrl+G 根据行号跳转行
Ctrl+\ 快速分割当前窗口

Ctrl+[ 缩进行
Ctrl+] 扩张行
Ctrl+F4 关闭当前标签页

Ctrl+Shift+w 关闭 vs code
Ctrl+T 搜索symbol
Ctrl+Shift+P 打开命令行并带一个 > 符号
Ctrl+P 打开命令行
Ctrl+Shift+] 在两个闭合的符号之间切换
Ctrl+F2 选中页面当中所有的当前指定的游标所在的单词
Ctrl+Shift+L 本来是选中当前游标下的所有相同的单词,但是在windows上不好用
Alt+左键 增加游标(其实这个游标Cursor是复制出来的)
Alt+windows+上/下 在多个游标中上下移动来上下选定多个游标
ESC 取消所有游标
Ctrl+Space 打开智能感知功能
Ctrl+F12 查看单个函数的定义
Shift+F12 查看所有函数的定义
format code 格式化代码不能使用,这个还比较重要,但是windows中的不好用
Ctrl+Shift+M 打开错误提示框
Ctrl+Shift+O 打开Symbol提示框
F8 游标停在错误的代码上,按F8显示代码错误信息
Ctrl + 上/下 游标定住 视窗上下移动
Alt + 上/下 游标拉住所在的行,随着视窗往下移动
Shift + Alt +上/下 游标复制所在的行,随着视窗上下移动
Ctrl + Shift + D 打开调试选项栏
Ctrl + Shift + v 打开调试的view模式

命令提示框提示符表示:

代表展示和运行命令
!展示错误和警告

通过名字打开标签

git 就是运行git命令
task 运行task
...打开文件和标签名通过名字
跳转行
@ 跳转symbol
@:跳转symbol通过category

使用CSS中用到的快捷键
m:20px 用一下tab就成了margin:20px;
bdw:用一下就成了border-width:
fz 用一下就成了font-size
bd 扩展一下就成了border
bd+ 扩展一下就成了border:1px solid #000
lg 扩展成background-img

调试快捷键
F5 Run / Pause / Run to Cursor
Shift+F5 : Stop
F10 : Stop Over
F11 : Step into
Shift + F11 : Step out
F9 : Toggle Breakpoint
重要的debug特性
1. Launching
2. Attaching
3. Stop on entry
4. Inspecting
5. Sourcemaps

在浏览器中, window是用来"兜底"的对象, 所有默认定义的对象都是window的子对象.

var a = {}
window.a //{}
parseInt === window.parseInt //true

而在node.js中没有window, 对等关系的是global

var a = {}
global.a //{}
parseInt === global.parseInt //true

那么在cocos creator中, 究竟是哪一个呢? 测试了一下, 是window. global是不存在的.
那么electron呢? electron中,两者都存在, 并且两者其实是同一个.

//electron中
window === global //true

typeof得出的是数据类型, 如:

typeof(1) //'number'
typeof("abc") //'string'
typeof(true) //'boolean'
var a = {}
typeof(a) //'object'
var b = []
typeof(b) // 'object'

注意最后两句, 一个array的type是object,是不是有些奇怪? 因为, array其实不是基本类型. 那怎么知道array是array呢? 那就要用object的判断方式, instanceof

var b = []
b instanceof Array //true
b instanceof Object //true
1 instanceof Number //false
"abc" instanceof String //false

注意最后两句, 1和"abc"是基本类型, 如果是要Number和String类型的,需要用 new Number和new String来获取

var n = new Number(1)
n instanceof Number //true

然而对于函数function又有点不一样了

var f = function(){}
typeof(f) //function
f instanceof Function //true
f instanceof Object //true

您可以看到, f虽然是一个Object,然而用typeof却可以得到他的类型.
再看看RegExp, 和Array是类似的

typeof(/a/) //object
/a/ instanceof RegExp //true
/a/ instanceof Object //true

js单元测试有好多个方式, 按照诞生时间依次是Qunit, jasmine, mocha, ava. 其中, ava是15年的项目, 还很新. Qunit和ava的star人数还没有超过1万, jasmine和mocha平分秋色,基本差不多. 考虑到jasmine是比mocha老的项目,而且jasmine最早是针对浏览器端的,而mocha似乎开始时就是针对node.js的, 这儿就选择mocha了.

安装使用

全局安装mocha

npm install -g mocha

项目本地安装chai(assert库)

npm install chai

chai库提供多种assert方式, 后面将举例用expect

示例被测项目, 叫add.js

function add(a, b){
    return a + b
}

function minus(a,b){
    return a - b
}
module.exports = add

测试代码, 叫test.js

var expect = require("chai").expect
var add = require("add")
describe("add", function(){

    it("1+2=3", function(){
        expect(add(1,2)).to.be.equal(3)
    })

})

运行代码

mocha test.js

js经常需要对比object,一般用意是对比内容key和value是否一致,就不能用expect().to.be.equal()了,需要用

expect().to.deep.equal()

其他方面

测试private function,以及mock.

例如, 上面的minus()函数没有通过module.exports导出, 是个私有函数, 如何进行测试? 这儿需要用到rewire. 将rewire安装到项目中.

npm install rewire

测试minus的文件test2.js

var expect = require("chai").expect
var rewire = require('rewire')  // 使用rewire加载被测文件.
var add = rewire("add")
describe("add", function(){
    var minus = add.__get__("minus")  // 使用__get__获取私有函数
    it("1-2=-3", function(){
        expect(minus(1,2)).to.be.equal(-1)
    })

})

rewire还可以使用set来mock函数, 看这儿
关于更多chai的用法, 看这儿

最佳实践

  • 装所有测试文件的目录命名为test,然后在目录上一级运行mocha可以测试所有test中的文件.
  • 文件名为 xx.test.js或者xx_spec.js ,spec是inspect(核查)的简称.
  • 使用npm test运行测试, 需要在package.json中加入:
    "scripts": {
    "test": "mocha"
    }

网上流传的许多并不能用的答案, 常见的是这样的:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<button onclick="down()">down</button>
<script type="text/javascript">
function down(){
    location = "/downloadpic/icon.png"
    var    pic   =   window.open(location,"a1")   
    pic.document.execCommand("SaveAs") 
}  
</script>
</body>
</html>

这儿的问题是, window.open只会打开新窗口, 并且在新窗口中打开文件. 如果文件是图片, 浏览器只会显示而不是下载.
并且, pic.document.execCommand("SaveAs") 这一句似乎并没有什么用.

下面是正确答案. 使用标签, 加download属性, 就这么简单.

<body>
<a href="icon.png" download>download icon</a>
</body>

还可以为download属性指定下载文件名称:

<body>
<a href="icon.png" download="new_icon.png">download icon</a>
</body>

有jslint, javascriptlint(jsl), 还有eslint. 貌似eslint是最受欢迎的.
安装eslint

npm i -g eslint

运行:

eslint *.js

在js目录下放一个.eslintrc.json文件, 可以对需要lint的规则做设置.下面是我复制cocos creator的配置,并做了一点修改, 忽略了末尾分号检测.

{
  "extends": "eslint:recommended",
  "rules": {
    "comma-dangle": 0,
    "no-console": 0,
    "no-constant-condition": 0,
    "semi": 0,
    "no-unused-vars": 1
  },
  "env": {
    "browser": true,
    "node": true,
    "es6": true,
    "mocha": true
  },
  "plugins": [
  ],
  "globals": {
    "cc": false,
    "CC_EDITOR": false,
    "CC_DEV": false,
    "CC_JSB": false,
    "_ccsg": false
  }
}

在REPL中比较容易调试和发现问题, 所以这儿介绍REPL的玩法.

node.js服务端需要安装模块.

    npm install ws

进入node, 开启服务,等待客户端连接. 为了便于以后向客户端发送消息, 把连接后的ws对象赋值给全局变量thisws

node
>
var thisws
var Wss = require('./ws').Server

var wss = new Wss({port: 3888})
wss.on('connection', function(ws){
    thisws = ws
    console.log('connected.')
    ws.on('message', function(message){
        console.log("msg: ",message)
    })
})

chrome 打开console,进行连接和监听服务器消息

s = new WebSocket('ws://localhost:3888')
s.onmessage = function(e){console.log(e.data)}

好啦!, 在chrome中send消息可以在node那边收到, 在node中send消息也可以在chrome中收到了
先从chrome中send

s.send('我是chrome') // 在node中将看到这条消息.

再从node中send

thisws.send('我是node服务器') //在chrome中将看到这条消息.

当然,除了chrome自带的WebSocket客户端, 在node中ws也提供客户端, 另外,socket.io也是另一种websocket客户端和服务器的提供者.

  • 总结
    浏览器客户端监听和发送
onclose = function(e){}
onmessage = function(e){}
onopen = function(){}
onerror = function(){}

send(string)
close()

node ws服务端监听和发送

wss.on('connection',function(ws){})
wss.on('error', function(err){})
wss.on('header',function(array){})
wss.on('listening',function(){})

ws.on('message',function(message_string,flags){})
ws.on('close',function(code, reason){})
ws.on('error',function(err){})
ws.on('open',function(){})

ws.onclose = function(e){}
ws.onerror = function(e){}
ws.onmessage = function(e){}
ws.onopen = function(e){}
ws.readyState

ws.send(message_string, function(error){})
ws.close(code, reason)

// 所有客户端列表
wss.clients
wss.close(function(){})

参考文章: WebSocket and Socket.IO
node ws API

开始以前,准备好visual studio 2015, 现在社区版是免费的.这玩意儿很大, 需要装个半天的.

先安装由微软推出的Electron打包为uwp工具 (真的是微软推出啊! 微软现在竟然这么拥抱开源...)

npm install -g electron-windows-store

然后进入管理员权限的powershell运行:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

OK, 接下来就打包了, 举我自己的app的例子:

electron-windows-store --input-directory C:\r\vueproj\nhproj\nhpe --output-directory C:\r\vueproj\nhproj\nhpe_uwp --flatten true --package-version 1.0.0.0 --package-name nhpe

哦, 真的好长, 幸好里面的参数还可以简写:

electron-windows-store -i C:\r\vueproj\nhproj\nhpe -o C:\r\vueproj\nhproj\nhpe_uwp -f true -p 1.0.0.0 -n nhpe

需要注意的是, --package-name一项, 名称必须是app运行文件的名称. 比如, 我已经把electron.exe修改为nhpe.exe了,这儿就一定要填写nphe
然后回车后要提示:

? Did you download and install the Desktop App Converter? It is *not* required to run this tool. No

这一步不是必须的, 回答no即可. 如果yes的话, 你需要去这儿安装Desktop App Converter,不过还是懒得麻烦了.
回车后提示:

? You need to install a development certificate in order to run your app. Would you like us to create one?  Yes

这一步必须yes, 否则虽然可以打包成功,然而打好的包由于没有签名而不能运行. 继续回车:

? Please enter your publisher identity:  CN=idarc
? Please enter the location of your Windows Kit's bin folder:  C:\Program Files (x86)\Windows Kits\10\bin\x64

publisher identity这一步必须填写为 CN=xxxx 的格式,否则后面会报错的...
Windows Kit这一步, 如果visual studio 装的OK的话, 直接回车就可以了.
接下来会弹窗让你输入密码. 不用输入密码, 点击"none"即可.
等待一会儿, 如果没有错误的话, 就会在指定的目录下看到nhpe.appx, 双击运行安装即可.
安装完了再运行, 哦, 这货和直接运行electron.exe改名的nhpe.exe为毛没有任何外观上的区别? 微软说区别是可以获取在在其他xbox等上运行的能力,然而我并没有xbox...

参考原文
假如有两个空对象, 判断他们是否相等, 结果一定是false:

var a = {}
var b = {}
a == b // false

因为跟c语言类似, 这儿判断的是地址而不是内容.
那么怎么知道a是空呢?
有三个方法. 这儿先假设有一个对象obj

var obj = {}

方法1

Object.keys(obj).length === 0

方法2

Object.getOwnPropertyNames(obj).length === 0

方法3, 自己判断

// Speed up calls to hasOwnProperty
var hasOwnProperty = Object.prototype.hasOwnProperty;

function isEmpty(obj) {

    // null and undefined are "empty"
    if (obj == null) return true;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;

    // If it isn't an object at this point
    // it is empty, but it can't be anything *but* empty
    // Is it empty?  Depends on your application.
    if (typeof obj !== "object") return true;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) return false;
    }

    return true;
}
// test it
isEmpty(""), // true
isEmpty(33), // true (arguably could be a TypeError)
isEmpty([]), // true
isEmpty({}), // true
isEmpty({length: 0, custom_property: []}), // true

isEmpty("Hello"), // false
isEmpty([1,2,3]), // false
isEmpty({test: 1}), // false
isEmpty({length: 3, custom_property: [1,2,3]}) // false

在chrome中你只能这么做了:

(function()
{
    'use strict';
    var foo = 123;//works fine
    bar = 345;//ReferenceError: bar is not defined
}());

上面这种模式被称之为IIFE(Immediately Invoked Function Expression)即刻执行的函数表达式.
在node中, 你当然也可以用上这种方式, 不过还有一种方式, 在启动node的时候使用--use-strict参数

node --use_strict

试听win10上的网易云音乐的轻音乐, 发现即便是自动推荐的, 也有很多蛮好听的曲子. 去看了一下作曲者, 竟然很多是国内的原创音乐人. 比如这个: 饭碗的彼岸, 就有好几首好听的曲子《小河》《小樱》。
感觉真是高手在民间啊。