From 5ea058a033f17111b6e89e6c081a6a57a583833f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 23 Jul 2024 13:15:11 +0800 Subject: [PATCH] feat: update links --- .../index.html | 2 +- 2015/generating-ssh-key/index.html | 2 +- 2015/hexo-your-blog/index.html | 2 +- .../index.html | 2 +- 2016/MarkDown-incomplete-Guide/index.html | 4 +- 2016/commonly-used-media-queries/index.html | 2 +- .../index.html | 2 +- .../index.html | 2 +- 2016/judgment-variable-type/index.html | 2 +- 2017/add-a-lock-to-your-website/index.html | 2 +- .../index.html | 2 +- 2017/country-city-and-language/index.html | 2 +- 2017/git-command-backup/index.html | 2 +- 2017/mysql-tutorial/index.html | 2 +- 2024/upgrade-debian-kernel-version/index.html | 2 +- 404.html | 2 +- about/index.html | 2 +- archives/2015/05/index.html | 2 +- archives/2015/12/index.html | 2 +- archives/2015/index.html | 2 +- archives/2016/05/index.html | 2 +- archives/2016/09/index.html | 2 +- archives/2016/index.html | 2 +- archives/2017/03/index.html | 2 +- archives/2017/06/index.html | 2 +- archives/2017/08/index.html | 2 +- archives/2017/11/index.html | 2 +- archives/2017/index.html | 2 +- archives/2024/03/index.html | 2 +- archives/2024/index.html | 2 +- archives/index.html | 2 +- archives/page/2/index.html | 2 +- atom.xml | 42 +++---- baidusitemap.xml | 30 ++--- books/index.html | 2 +- categories/index.html | 2 +- .../\345\205\266\344\273\226/index.html" | 2 +- .../index.html" | 2 +- content.json | 2 +- css/style.css | 2 +- index.html | 2 +- links/index.html | 2 +- page/2/index.html | 2 +- repository/index.html | 2 +- sitemap.xml | 118 +++++++++--------- tags/CSS/index.html | 2 +- tags/Command/index.html | 2 +- tags/Comment-System/index.html | 2 +- tags/Git/index.html | 2 +- tags/GitHub/index.html | 2 +- tags/Guide/index.html | 2 +- tags/Hexo/index.html | 2 +- tags/JavaScript/index.html | 2 +- .../index.html" | 2 +- tags/MarkDown/index.html | 2 +- tags/Media-Query/index.html | 2 +- tags/MySql/index.html | 2 +- tags/SSH-Key/index.html | 2 +- tags/Valine/index.html | 2 +- tags/bbr/index.html | 2 +- tags/cerbot/index.html | 2 +- tags/index.html | 2 +- tags/linux/index.html | 2 +- tags/ssl/index.html | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- "tags/\345\211\215\347\253\257/index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- "tags/\346\212\200\345\267\247/index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- "tags/\350\247\204\350\214\203/index.html" | 2 +- .../index.html" | 2 +- "tags/\350\257\221\346\226\207/index.html" | 2 +- .../index.html" | 2 +- 79 files changed, 172 insertions(+), 172 deletions(-) diff --git a/2015/about-javascript-spcial-technique/index.html b/2015/about-javascript-spcial-technique/index.html index 895935ff..8eddeedd 100644 --- a/2015/about-javascript-spcial-technique/index.html +++ b/2015/about-javascript-spcial-technique/index.html @@ -1 +1 @@ -你可能不知道的一些JavaScript 奇技淫巧 | 云淡风轻

你可能不知道的一些JavaScript 奇技淫巧

这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们。
## 遍历一个obj的属性到数组
1
2
3
4
5
6
7
function getAttr(obj){
var a=[];
for(a[a.length] in obj);
return a;
}
console.log(getAttr({'name':'zhangsan','age':'20'}));//输出:['name','age']

乍一看可能比较蒙,不过仔细分析还是不难理解的。常见用法是`for(var key in obj)`,这里`key`初始也是`undefined`的,`a[a.length]`整体也是`undefined`,所以二者其实是等价的。 在`for`循环中,`obj`的属性会依次赋值给`key`,同样,也依次赋值给`a[a.length]`,这里`length`一直在变,就巧妙地挨个赋值给数组的每一个元素了。

重复字符串(如abc=>abcabc)

1
2
3
function repeat(target,n){
return (new Array(n+1).join(target));
}

改进版本:

1
2
3
4
function repeat(target,n){
return Array.prototype.join.call({length:n+1},target);
//之所以要创建带length属性的对象,是因为调用数组原型方法时,必须是一个类数组对象,而类数组对象的条件就是length为非负整数
}

不新建数组,而是用拥有length属性的对象替代,然后调用数组的join方法,性能提升很大.
再改进:

1
2
3
4
5
6
7
var repeat=(function(){
var join=Array.prototype.join,obj={};
return function(target,n){
obj.length=n+1;
return join.call(obj,target);
}
})();

利用闭包将对象join方法缓存起来,不用每次都新建对象和寻找方法

for循环

for循环中,当第二项为false时会终止循环,这里并不一定存在比较,可以直接赋值,如果赋值为undefined之类的值时,转成bool值也为假,因此也会终止,比如遍历数组可以写成:

1
for(var i=arr.length,element;element=arr[—-i];){…}

这里,第二项一定是arr[--i]而非arr[i--],如果是后者的话,上来就是undefined,就不会执行循环体,或者for(var i=0,element;element=arr[i++];){…}

NaN

NaN是JS中唯一不等于自己的值,因此可以用来判断一个变量是否真的为NaN:a!==a

/+等算术运算符

</+等运算符会强制符号两边的表达式执行valueOf然后比较,所以如果两边是函数或者对象,而又重写了该对象的valueOf方法,就会自动执行两边的方法。如:

1
2
var a={valueOf:function(){console.log("aaa");}},b={valueOf:function(){console.log("bbb");}};
a < b;//会输出:aaa;bbb;false

闭包

理解闭包需学会三个基本事实:

  1. JS允许你引用在当前函数意外定义的变量
  2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这是因为JS的函数值包含里比调用它们时执行所需要的代码更多的信息
  3. 闭包可以更新外部变量的值。这是因为闭包存储的是外部变量的引用而非值副本。如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function box(){
    var val=undefined;
    return {
    set:function(x){val=x;},
    get:function(){return val;}
    };
    }
    var b=box();
    b.get();//“undefined”
    b.set(5);
    b.get();//5
    这一点很重要,比如在函数的for循环体内返回闭包或者有闭包取for循环的计数器值,那么这个闭包取到的永远是for循环结束时i的最终值,因为闭包存储的是它的引用而非当时的值副本。

块级作用域

JS没有块级作用域,因此通常情况下函数内部的所有变量都是绑定到函数作用域的,也就是说相当于都在函数一开始就声明了的,一个例外就是try/catch中的变量是块级的,只属于try/catch块。

嵌套函数

众所周知,在函数内部声明函数是可以的,但是在在函数内的局部块里声明,可能会出现问题:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
function f(){return “local”}
var result=[];
if(x){
result.push(f());
}
result.push(f());
return result;
}
test(true);//[“local”,”local”]
test(false);//[“local”]

将函数声明到if块中:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
var result=[];
if(x){
function f(){return “local”}
result.push(f());
}
result.push(f());
return result;
}
test(true);//?
test(false);//?

结果会如何呢?理论上讲,JS没有块级作用域,因此f()的作用域是整个test函数,因此合理猜测应该是与上一次输出相同,全部为”local”,可是并不是所有的JS执行环境都如此行事,有的会根据是否执行包含f的代码块来有条件地绑定函数f(绑定即意味着将该变量绑定到其最近的作用域,而赋值是发生在代码实际执行到赋值那一步的时候进行的)。
因此最好的办法是如果要声明嵌套函数,都在其富函数的最外层声明,要么就不要声明函数,而是使用var声明和函数表达式来实现:

1
2
3
4
5
6
7
8
9
10
function f(){return “global”;}
function test(x){
var result=[];
if(x){
var g=function(){return “local”}
result.push(g());
}
result.push(f());
return result;
}

hasOwnProperty

用js创建字典的时候,如果是利用对象的方式(因为JS对象的核心是一个字符串属性名称和属性值的映射表),会遇到一个问题就是原型污染,因为获取字典属性值的时候用hasOwnProperty还好,如果用for in遍历的话,不仅会遍历对象本身,包括它的原型,因此如果在其他地方污染了Object的原型,那么for in就会产生非预期的结果,这时可能会用hasOwnProperty来先检测该对象本身是否含有属性来避免原型污染,然而更极端的情况是连hasOwnProperty这个原型方法都有可能被污染。
避免原型污染的方法是在创建字典对象的时候用Object.create(null)来创建一个完全空对象,这个对象没有原型,这个方法是ES5的,在没有这个方法可用的时候,最好是创建字典类,然后在字典类里用数组来存储有序集合,自己维护这个集合。

类数组对象

JS中的类数组对象可以享用数组的大部分原型方法如map
类数组对象是指满足两个条件的对象:
一是具备合理范围值内的length属性
二是length属性大于该对象的最大索引,索引是一个合理范围的证书,它的字符串表示的是对象的一个key;
但是数组的一个原型方法contact是不能被类数组对象调用的,因此需要先用[].slice.call把类数组对象转换为真正的数组比如[].slice.call(arguments)

结构类型

并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类的实例,而是直接返回对象,对象具备预期的方法和属性,比如:

1
2
3
4
5
6
7
SomeObj.someWidget=function(opts){
return {
a:blabla,
b:function(){...},
c:blabla
}
}

JavaScript 自动插入分号

JavaScript 具备自动插入分号的能力,但是自动插入分号并不是万能的,其有三条规则:

  1. 只在}标记之前、一个或多个换行之后以及程序输入的结尾被插入

  2. 分号只在随后的输入标记不能被解析时插入

    !!这一点很重要,比如:
    a = b
    (fn());
    是不会在a=b之后自动插入分号的,因为a=b(f())是可以被解析的,因此像(,[,+,-,/开头的时候,需要特别注意上一行可能不会自动插入。
    还有一些情况,尽管不会出现解析错误,JS仍然会强制插入分号,这就是所谓的JS语法限制产生式。它不允许在两个字符间出现换行,最危险的就是return语句,如
    return
    {};
    会被强制插入而成为
    return;
    {};
    类似的还有:throw语句、带有显示标签的break或着continue语句、后置自增或自减运算符

  3. 分号不会作为分隔符在for循环空语句的头部被自动插入

因此,最好的办法是在自己的js文件的最开始防御性地插入;,这样在合并js文件的时候就不会出问题了。

本文转载自博客园,原文略有删减,侵权即删.
原文链接:你可能不知道的一些JavaScript 奇技淫巧
原文作者:FirstLovt

\ No newline at end of file +你可能不知道的一些JavaScript 奇技淫巧 | 云淡风轻

你可能不知道的一些JavaScript 奇技淫巧

这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们。
## 遍历一个obj的属性到数组
1
2
3
4
5
6
7
function getAttr(obj){
var a=[];
for(a[a.length] in obj);
return a;
}
console.log(getAttr({'name':'zhangsan','age':'20'}));//输出:['name','age']

乍一看可能比较蒙,不过仔细分析还是不难理解的。常见用法是`for(var key in obj)`,这里`key`初始也是`undefined`的,`a[a.length]`整体也是`undefined`,所以二者其实是等价的。 在`for`循环中,`obj`的属性会依次赋值给`key`,同样,也依次赋值给`a[a.length]`,这里`length`一直在变,就巧妙地挨个赋值给数组的每一个元素了。

重复字符串(如abc=>abcabc)

1
2
3
function repeat(target,n){
return (new Array(n+1).join(target));
}

改进版本:

1
2
3
4
function repeat(target,n){
return Array.prototype.join.call({length:n+1},target);
//之所以要创建带length属性的对象,是因为调用数组原型方法时,必须是一个类数组对象,而类数组对象的条件就是length为非负整数
}

不新建数组,而是用拥有length属性的对象替代,然后调用数组的join方法,性能提升很大.
再改进:

1
2
3
4
5
6
7
var repeat=(function(){
var join=Array.prototype.join,obj={};
return function(target,n){
obj.length=n+1;
return join.call(obj,target);
}
})();

利用闭包将对象join方法缓存起来,不用每次都新建对象和寻找方法

for循环

for循环中,当第二项为false时会终止循环,这里并不一定存在比较,可以直接赋值,如果赋值为undefined之类的值时,转成bool值也为假,因此也会终止,比如遍历数组可以写成:

1
for(var i=arr.length,element;element=arr[—-i];){…}

这里,第二项一定是arr[--i]而非arr[i--],如果是后者的话,上来就是undefined,就不会执行循环体,或者for(var i=0,element;element=arr[i++];){…}

NaN

NaN是JS中唯一不等于自己的值,因此可以用来判断一个变量是否真的为NaN:a!==a

/+等算术运算符

</+等运算符会强制符号两边的表达式执行valueOf然后比较,所以如果两边是函数或者对象,而又重写了该对象的valueOf方法,就会自动执行两边的方法。如:

1
2
var a={valueOf:function(){console.log("aaa");}},b={valueOf:function(){console.log("bbb");}};
a < b;//会输出:aaa;bbb;false

闭包

理解闭包需学会三个基本事实:

  1. JS允许你引用在当前函数意外定义的变量
  2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这是因为JS的函数值包含里比调用它们时执行所需要的代码更多的信息
  3. 闭包可以更新外部变量的值。这是因为闭包存储的是外部变量的引用而非值副本。如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function box(){
    var val=undefined;
    return {
    set:function(x){val=x;},
    get:function(){return val;}
    };
    }
    var b=box();
    b.get();//“undefined”
    b.set(5);
    b.get();//5
    这一点很重要,比如在函数的for循环体内返回闭包或者有闭包取for循环的计数器值,那么这个闭包取到的永远是for循环结束时i的最终值,因为闭包存储的是它的引用而非当时的值副本。

块级作用域

JS没有块级作用域,因此通常情况下函数内部的所有变量都是绑定到函数作用域的,也就是说相当于都在函数一开始就声明了的,一个例外就是try/catch中的变量是块级的,只属于try/catch块。

嵌套函数

众所周知,在函数内部声明函数是可以的,但是在在函数内的局部块里声明,可能会出现问题:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
function f(){return “local”}
var result=[];
if(x){
result.push(f());
}
result.push(f());
return result;
}
test(true);//[“local”,”local”]
test(false);//[“local”]

将函数声明到if块中:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
var result=[];
if(x){
function f(){return “local”}
result.push(f());
}
result.push(f());
return result;
}
test(true);//?
test(false);//?

结果会如何呢?理论上讲,JS没有块级作用域,因此f()的作用域是整个test函数,因此合理猜测应该是与上一次输出相同,全部为”local”,可是并不是所有的JS执行环境都如此行事,有的会根据是否执行包含f的代码块来有条件地绑定函数f(绑定即意味着将该变量绑定到其最近的作用域,而赋值是发生在代码实际执行到赋值那一步的时候进行的)。
因此最好的办法是如果要声明嵌套函数,都在其富函数的最外层声明,要么就不要声明函数,而是使用var声明和函数表达式来实现:

1
2
3
4
5
6
7
8
9
10
function f(){return “global”;}
function test(x){
var result=[];
if(x){
var g=function(){return “local”}
result.push(g());
}
result.push(f());
return result;
}

hasOwnProperty

用js创建字典的时候,如果是利用对象的方式(因为JS对象的核心是一个字符串属性名称和属性值的映射表),会遇到一个问题就是原型污染,因为获取字典属性值的时候用hasOwnProperty还好,如果用for in遍历的话,不仅会遍历对象本身,包括它的原型,因此如果在其他地方污染了Object的原型,那么for in就会产生非预期的结果,这时可能会用hasOwnProperty来先检测该对象本身是否含有属性来避免原型污染,然而更极端的情况是连hasOwnProperty这个原型方法都有可能被污染。
避免原型污染的方法是在创建字典对象的时候用Object.create(null)来创建一个完全空对象,这个对象没有原型,这个方法是ES5的,在没有这个方法可用的时候,最好是创建字典类,然后在字典类里用数组来存储有序集合,自己维护这个集合。

类数组对象

JS中的类数组对象可以享用数组的大部分原型方法如map
类数组对象是指满足两个条件的对象:
一是具备合理范围值内的length属性
二是length属性大于该对象的最大索引,索引是一个合理范围的证书,它的字符串表示的是对象的一个key;
但是数组的一个原型方法contact是不能被类数组对象调用的,因此需要先用[].slice.call把类数组对象转换为真正的数组比如[].slice.call(arguments)

结构类型

并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类的实例,而是直接返回对象,对象具备预期的方法和属性,比如:

1
2
3
4
5
6
7
SomeObj.someWidget=function(opts){
return {
a:blabla,
b:function(){...},
c:blabla
}
}

JavaScript 自动插入分号

JavaScript 具备自动插入分号的能力,但是自动插入分号并不是万能的,其有三条规则:

  1. 只在}标记之前、一个或多个换行之后以及程序输入的结尾被插入

  2. 分号只在随后的输入标记不能被解析时插入

    !!这一点很重要,比如:
    a = b
    (fn());
    是不会在a=b之后自动插入分号的,因为a=b(f())是可以被解析的,因此像(,[,+,-,/开头的时候,需要特别注意上一行可能不会自动插入。
    还有一些情况,尽管不会出现解析错误,JS仍然会强制插入分号,这就是所谓的JS语法限制产生式。它不允许在两个字符间出现换行,最危险的就是return语句,如
    return
    {};
    会被强制插入而成为
    return;
    {};
    类似的还有:throw语句、带有显示标签的break或着continue语句、后置自增或自减运算符

  3. 分号不会作为分隔符在for循环空语句的头部被自动插入

因此,最好的办法是在自己的js文件的最开始防御性地插入;,这样在合并js文件的时候就不会出问题了。

本文转载自博客园,原文略有删减,侵权即删.
原文链接:你可能不知道的一些JavaScript 奇技淫巧
原文作者:FirstLovt

\ No newline at end of file diff --git a/2015/generating-ssh-key/index.html b/2015/generating-ssh-key/index.html index 17dcefde..d36ee41b 100644 --- a/2015/generating-ssh-key/index.html +++ b/2015/generating-ssh-key/index.html @@ -1 +1 @@ -生成 SSH Key 免密码提交 GitHub | 云淡风轻

生成 SSH Key 免密码提交 GitHub


之前上传文件到 GitHub 的时候,一直都是用的账号密码登录,每次提交都弹个窗体出来,感觉烦死了。。。今天有空,就来捣鼓下 SSH Key

Step1. 检查是否已经存在 SSH Key

运行 Git Bush 客户端,执行以下代码:

1
2
$ ls -al ~/.ssh 
# 如果存在,将会列出.ssh 目录下的所有文件
1
2
# 如果不存在则会给出如下提示
ls: cannot open directory /Users/you/.ssh: Permission denied

检查列出来的目录,看看是否已经有了一个 SSH Key。默认情况下,key 的文件名是下列之一:
> id_dsa.pub
> id_ecdsa.pub
> id_ed25519.pub
> id_rsa.pub

如果已经存在(如 id_rsaid_rsa.pub)而且你想使用已经存在的密钥对直接连接 GitHub ,那么可以跳过 Step2,直接进入 Step3

Step2. 生成 SSH Key

复制下面的代码(记得请将email修改成自己的email地址):

1
2
$ ssh-keygen -t rsa -b 4096 -C "your_name@example.com" 
Generating public/private rsa key pair.

这里 GitHub 的建议是保持默认,所以只需要按 Enter 继续:

1
Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press Enter]

如果存在,将会提示是否覆盖:

1
2
/Users/you/.ssh/id_rsa already exists.
Overwrite (y/n)?

继续后会提示输入密码:

1
2
Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]

然后你就会得到你的 SSH Key 的指纹,看起来像下面的代码:

1
2
3
4
Your identification has been saved in /Users/you/.ssh/id_rsa.
Your public key has been saved in /Users/you/.ssh/id_rsa.pub.
The key fingerprint is:
01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com

Step3. 添加 SSH Key 到 GitHub

先拷贝 id_rsa.pub 文件的内容,可以用编辑器打开然后复制,也可以用 git 命令复制:

1
$ clip < ~/.ssh/id_rsa.pub

进入 GitHub 账户设置,点击左边 SSH Key ,点击 Add SSH key ,粘贴刚刚复制的内容,然后保存。
输入 GitHub 账户的密码就能看到刚刚添加的 SSH Key 了。

Step4. 测试是否添加成功

Git Bush 中输入下面的代码,然后回车

1
2
$ ssh -T git@GitHub.com
# Attempts to ssh to GitHub

会得到如下的指纹提示:键入yes

1
2
3
The authenticity of host 'GitHub.com (207.97.227.239)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)?

如果出现下面的提示,恭喜你,验证成功。

1
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

如果你看到的是 access denied(拒绝访问) ,可以点击这里 ,查看解决办法。

然后将https替换成ssh重新下载下代码,就OK了~~~

Good Luck

** 参考文档 **

  1. Generating SSH keys

\ No newline at end of file +生成 SSH Key 免密码提交 GitHub | 云淡风轻

生成 SSH Key 免密码提交 GitHub


之前上传文件到 GitHub 的时候,一直都是用的账号密码登录,每次提交都弹个窗体出来,感觉烦死了。。。今天有空,就来捣鼓下 SSH Key

Step1. 检查是否已经存在 SSH Key

运行 Git Bush 客户端,执行以下代码:

1
2
$ ls -al ~/.ssh 
# 如果存在,将会列出.ssh 目录下的所有文件
1
2
# 如果不存在则会给出如下提示
ls: cannot open directory /Users/you/.ssh: Permission denied

检查列出来的目录,看看是否已经有了一个 SSH Key。默认情况下,key 的文件名是下列之一:
> id_dsa.pub
> id_ecdsa.pub
> id_ed25519.pub
> id_rsa.pub

如果已经存在(如 id_rsaid_rsa.pub)而且你想使用已经存在的密钥对直接连接 GitHub ,那么可以跳过 Step2,直接进入 Step3

Step2. 生成 SSH Key

复制下面的代码(记得请将email修改成自己的email地址):

1
2
$ ssh-keygen -t rsa -b 4096 -C "your_name@example.com" 
Generating public/private rsa key pair.

这里 GitHub 的建议是保持默认,所以只需要按 Enter 继续:

1
Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press Enter]

如果存在,将会提示是否覆盖:

1
2
/Users/you/.ssh/id_rsa already exists.
Overwrite (y/n)?

继续后会提示输入密码:

1
2
Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]

然后你就会得到你的 SSH Key 的指纹,看起来像下面的代码:

1
2
3
4
Your identification has been saved in /Users/you/.ssh/id_rsa.
Your public key has been saved in /Users/you/.ssh/id_rsa.pub.
The key fingerprint is:
01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com

Step3. 添加 SSH Key 到 GitHub

先拷贝 id_rsa.pub 文件的内容,可以用编辑器打开然后复制,也可以用 git 命令复制:

1
$ clip < ~/.ssh/id_rsa.pub

进入 GitHub 账户设置,点击左边 SSH Key ,点击 Add SSH key ,粘贴刚刚复制的内容,然后保存。
输入 GitHub 账户的密码就能看到刚刚添加的 SSH Key 了。

Step4. 测试是否添加成功

Git Bush 中输入下面的代码,然后回车

1
2
$ ssh -T git@GitHub.com
# Attempts to ssh to GitHub

会得到如下的指纹提示:键入yes

1
2
3
The authenticity of host 'GitHub.com (207.97.227.239)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)?

如果出现下面的提示,恭喜你,验证成功。

1
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

如果你看到的是 access denied(拒绝访问) ,可以点击这里 ,查看解决办法。

然后将https替换成ssh重新下载下代码,就OK了~~~

Good Luck

** 参考文档 **

  1. Generating SSH keys

\ No newline at end of file diff --git a/2015/hexo-your-blog/index.html b/2015/hexo-your-blog/index.html index cff8b421..c912e977 100644 --- a/2015/hexo-your-blog/index.html +++ b/2015/hexo-your-blog/index.html @@ -1 +1 @@ -Hello World for Hexo | 云淡风轻

Hello World for Hexo

今天把博客移到了Hexo,感觉蛮不错的 ^_^ .

简介

hexo 是一款基于Node.js的静态博客框架。目前在GitHub上已有4k+ star 和 700+ fork (官网)。
是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

特性

  • 风一般的速度:
    Hexo基于Node.js,支持多进程,几百篇文章也可以秒生成。
  • 流畅的撰写:
    支持GitHub Flavored Markdown和所有Octopress插件
  • 扩展性:
    Hexo支持EJSSwigStylus。通过插件支持HamlJadeLess.

快速入门

安装

安装 Hexo 相当简单。然而在安装前,您必须检查电脑中是否已安装下列应用程序:

如果您的电脑中已经安装上述必备程序,那么恭喜您!接下来只需要使用 npm 即可完成 Hexo 的安装。

1
npm install -g hexo-cli 

仅需一步就把 Hexo 本体和所有相依套件安装完毕,很简单吧?

升级

更新hexo到最新版

1
npm update hexo -g  

初始化

1
2
3
hexo init <folder>
cd <floder>
npm install

如果指定 <folder>,便会在目前的资料夹建立一个名为 <folder> 的新文件夹;否则会在目前文件夹初始化。

新建

1
hexo new [layout] <title>

新建一篇文章。如果没有设置 layout 的话,默认使用 _config.yml 中的 default_layout 参数代替。如果标题包含空格的话,请使用引号括起来。

生成静态文件

1
2
hexo g
//或者 hexo generate

启动服务

1
2
hexo s
//或者 hexo server

启动服务后,打开浏览器输入 http://localhost:4000 回车,即可看到效果.

部署

1
2
hexo d
//可以通过hexo d -g 命令完成生成和部署

如果出现错误,可能是没有安装部署插件,请执行下面的命令安装插件:

1
npm install hexo-deploy-git --save-dev

Hexo官网:[http://Hexo.io]
部署Hexo

\ No newline at end of file +Hello World for Hexo | 云淡风轻

Hello World for Hexo

今天把博客移到了Hexo,感觉蛮不错的 ^_^ .

简介

hexo 是一款基于Node.js的静态博客框架。目前在GitHub上已有4k+ star 和 700+ fork (官网)。
是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

特性

  • 风一般的速度:
    Hexo基于Node.js,支持多进程,几百篇文章也可以秒生成。
  • 流畅的撰写:
    支持GitHub Flavored Markdown和所有Octopress插件
  • 扩展性:
    Hexo支持EJSSwigStylus。通过插件支持HamlJadeLess.

快速入门

安装

安装 Hexo 相当简单。然而在安装前,您必须检查电脑中是否已安装下列应用程序:

如果您的电脑中已经安装上述必备程序,那么恭喜您!接下来只需要使用 npm 即可完成 Hexo 的安装。

1
npm install -g hexo-cli 

仅需一步就把 Hexo 本体和所有相依套件安装完毕,很简单吧?

升级

更新hexo到最新版

1
npm update hexo -g  

初始化

1
2
3
hexo init <folder>
cd <floder>
npm install

如果指定 <folder>,便会在目前的资料夹建立一个名为 <folder> 的新文件夹;否则会在目前文件夹初始化。

新建

1
hexo new [layout] <title>

新建一篇文章。如果没有设置 layout 的话,默认使用 _config.yml 中的 default_layout 参数代替。如果标题包含空格的话,请使用引号括起来。

生成静态文件

1
2
hexo g
//或者 hexo generate

启动服务

1
2
hexo s
//或者 hexo server

启动服务后,打开浏览器输入 http://localhost:4000 回车,即可看到效果.

部署

1
2
hexo d
//可以通过hexo d -g 命令完成生成和部署

如果出现错误,可能是没有安装部署插件,请执行下面的命令安装插件:

1
npm install hexo-deploy-git --save-dev

Hexo官网:[http://Hexo.io]
部署Hexo

\ No newline at end of file diff --git a/2015/the-front-end-javascript-specification/index.html b/2015/the-front-end-javascript-specification/index.html index 525cde50..5c5a6025 100644 --- a/2015/the-front-end-javascript-specification/index.html +++ b/2015/the-front-end-javascript-specification/index.html @@ -1 +1 @@ -前端 JavaScript 规范 | 云淡风轻

前端 JavaScript 规范

类型

原始值:相当于传值(JavaScript对象都提供了字面量),使用字面量创建对象。

  • string
  • number
  • boolean
  • null
  • undefined
1
2
3
4
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9

复杂类型:相当于传引用

  • object
  • array
  • function
1
2
3
4
var foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9

对象

  1. 使用字面值创建对象
    1
    2
    3
    4
    5
    // bad
    var item = new Object();

    // good
    var item = {};
  2. 不要使用保留字 reserved words 作为键
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    var superman = {
    class: 'superhero',
    default: { clark: 'kent' },
    private: true
    };

    // good
    var superman = {
    klass: 'superhero',
    defaults: { clark: 'kent' },
    hidden: true
    };

数组

  1. 使用字面值创建数组
    1
    2
    3
    4
    5
    // bad
    var items = new Array();

    // good
    var items = [];
  2. 如果你不知道数组的长度,使用push
    1
    2
    3
    4
    5
    6
    7
    var someStack = [];

    // bad
    someStack[someStack.length] = 'abracadabra';

    // good
    someStack.push('abracadabra');
  3. 当你需要拷贝数组时使用slice . jsPerf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var len = items.length,
    itemsCopy = [],
    i;

    // bad
    for (i = 0; i < len; i++) {
    itemsCopy[i] = items[i];
    }

    // good
    itemsCopy = items.slice();
  4. 使用slice类数组的对象转成数组.
    1
    2
    3
    4
    function trigger() {
    var args = [].slice.apply(arguments);
    ...
    }

字符串

  1. 对字符串使用单引号 ''(因为大多时候我们的字符串。特别html会出现")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    var name = "Bob Parr";

    // good
    var name = 'Bob Parr';

    // bad
    var fullName = "Bob " + this.lastName;

    // good
    var fullName = 'Bob ' + this.lastName;
  2. 超过80(也有规定140的,项目具体可制定)个字符的字符串应该使用字符串连接换行
    !!!: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

    // bad
    var errorMessage = 'This is a super long error that \
    was thrown because of Batman. \
    When you stop to think about \
    how Batman had anything to do \
    with this, you would get nowhere \
    fast.';

    // good
    var errorMessage = 'This is a super long error that ' +
    'was thrown because of Batman.' +
    'When you stop to think about ' +
    'how Batman had anything to do ' +
    'with this, you would get nowhere ' +
    'fast.';
  3. 编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.
    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
    var items,
    messages,
    length, i;

    messages = [{
    state: 'success',
    message: 'This one worked.'
    },{
    state: 'success',
    message: 'This one worked as well.'
    },{
    state: 'error',
    message: 'This one did not work.'
    }];

    length = messages.length;

    // bad
    function inbox(messages) {
    items = '<ul>';
    for (i = 0; i < length; i++) {
    items += '<li>' + messages[i].message + '</li>';
    }
    return items + '</ul>';
    }

    // good
    function inbox(messages) {
    items = [];
    for (i = 0; i < length; i++) {
    items[i] = messages[i].message;
    }
    return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
    }

函数

  1. 函数表达式:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 匿名函数表达式
    var anonymous = function() {
    return true;
    };

    // 有名函数表达式
    var named = function named() {
    return true;
    };

    // 立即调用函数表达式
    (function() {
    console.log('Welcome to the Internet. Please follow me.');
    })();
  2. 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
  3. : ECMA-262定义把定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    if (currentUser) {
    function test() {
    console.log('Nope.');
    }
    }

    // good
    if (currentUser) {
    var test = function test() {
    console.log('Yup.');
    };
    }
  4. 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function nope(name, options, arguments) {
    // ...stuff...
    }

    // good
    function yup(name, options, args) {
    // ...stuff...
    }

属性

  1. 当使用变量和特殊非法变量名时,访问属性时可以使用中括号(. 优先).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var luke = {
    jedi: true,
    age: 28
    };

    function getProp(prop) {
    return luke[prop];
    }

    var isJedi = getProp('jedi');

变量

  1. 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。
    1
    2
    3
    4
    5
    // bad
    superPower = new SuperPower();

    // good
    var superPower = new SuperPower();
  2. 使用一个 var 以及新行声明多个变量,缩进4个空格。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    var items = getItems();
    var goSportsTeam = true;
    var dragonball = 'z';

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  3. 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

    // bad
    var i, items = getItems(),
    dragonball,
    goSportsTeam = true,
    len;

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball,
    length,
    i;
  4. 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
    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
    // bad
    function() {
    test();
    console.log('doing stuff..');

    //..other stuff..

    var name = getName();

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // good
    function() {
    var name = getName();

    test();
    console.log('doing stuff..');

    //..other stuff..

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // bad
    function() {
    var name = getName();

    if (!arguments.length) {
    return false;
    }

    return true;
    }

    // good
    function() {
    if (!arguments.length) {
    return false;
    }

    var name = getName();

    return true;
    }

条件表达式和等号

  1. 合理使用 ===!== 以及 ==!=.
  2. 合理使用表达式逻辑操作运算.
  3. 条件表达式的强制类型转换遵循以下规则:
  • 对象 被计算为 true
  • Undefined 被计算为 false
  • Null 被计算为 false
  • 布尔值 被计算为 布尔的值
  • 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
  • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true
    1
    2
    3
    4
    if ([0]) {
    // true
    // An array is an object, objects evaluate to true
    }
  1. 使用快捷方式.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (name !== '') {
    // ...stuff...
    }

    // good
    if (name) {
    // ...stuff...
    }

    // bad
    if (collection.length > 0) {
    // ...stuff...
    }

    // good
    if (collection.length) {
    // ...stuff...
    }
  2. 阅读 Truth Equality and JavaScript 了解更多

  1. 给所有多行的块使用大括号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (test)
    return false;

    // good
    if (test) return false;

    // good
    if (test) {
    return false;
    }

    // bad
    function() { return false; }

    // good
    function() {
    return false;
    }

注释

  1. 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值
    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
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {

    // ...stuff...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    *
    * @param <String> tag
    * @return <Element> element
    */
    function make(tag) {

    // ...stuff...

    return element;
    }
  2. 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.
    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
    // bad
    var active = true; // is current tab

    // good
    // is current tab
    var active = true;

    // bad
    function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }

    // good
    function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }
  3. 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXMETODO 帮助其他人迅速理解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function Calculator() {

    // FIXME: shouldn't use a global here
    total = 0;

    return this;
    }


    function Calculator() {

    // TODO: total should be configurable by an options param
    this.total = 0;

    return this;
    }
  4. 满足规范的文档,在需要文档的时候,可以尝试jsdoc.

空白

  1. 缩进、格式化能帮助团队更快得定位修复代码BUG.
  2. 将tab设为4个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    function() {
    ∙∙var name;
    }

    // bad
    function() {
    var name;
    }

    // good
    function() {
    ∙∙∙∙var name;
    }
  3. 大括号前放一个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    function test(){
    console.log('test');
    }

    // good
    function test() {
    console.log('test');
    }

    // bad
    dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });

    // good
    dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });
  4. 在做长方法链时使用缩进.
    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
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // good
    $('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

    // bad
    var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

    // good
    var leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .class('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

逗号

  1. 不要将逗号放前面
    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
    // bad
    var once
    , upon
    , aTime;

    // good
    var once,
    upon,
    aTime;

    // bad
    var hero = {
    firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
    };

    // good
    var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
    };
  2. 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
    };

    var heroes = [
    'Batman',
    'Superman',
    ];

    // good
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
    };

    var heroes = [
    'Batman',
    'Superman'
    ];

分号

  1. 语句结束一定要加分号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    (function() {
    var name = 'Skywalker'
    return name
    })()

    // good
    (function() {
    var name = 'Skywalker';
    return name;
    })();

    // good
    ;(function() {
    var name = 'Skywalker';
    return name;
    })();

类型转换

  1. 在语句的开始执行类型转换.
  2. 字符串:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  => this.reviewScore = 9;

    // bad
    var totalScore = this.reviewScore + '';

    // good
    var totalScore = '' + this.reviewScore;

    // bad
    var totalScore = '' + this.reviewScore + ' total score';

    // good
    var totalScore = this.reviewScore + ' total score';
  3. 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)
    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
    var inputValue = '4';

    // bad
    var val = new Number(inputValue);

    // bad
    var val = +inputValue;

    // bad
    var val = inputValue >> 0;

    // bad
    var val = parseInt(inputValue);

    // good
    var val = Number(inputValue);

    // good
    var val = parseInt(inputValue, 10);

    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var val = inputValue >> 0;
  4. 布尔值:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var age = 0;

    // bad
    var hasAge = new Boolean(age);

    // good
    var hasAge = Boolean(age);

    // good
    var hasAge = !!age;

命名约定

  1. 避免单个字符名,让你的变量名有描述意义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function q() {
    // ...stuff...
    }

    // good
    function query() {
    // ..stuff..
    }
  2. 当命名对象、函数和实例时使用驼峰命名规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // bad
    var OBJEcttsssss = {};
    var this_is_my_object = {};
    var this-is-my-object = {};
    function c() {};
    var u = new user({
    name: 'Bob Parr'
    });

    // good
    var thisIsMyObject = {};
    function thisIsMyFunction() {};
    var user = new User({
    name: 'Bob Parr'
    });
  3. 当命名构造函数或类时使用驼峰式大写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    function user(options) {
    this.name = options.name;
    }

    var bad = new user({
    name: 'nope'
    });

    // good
    function User(options) {
    this.name = options.name;
    }

    var good = new User({
    name: 'yup'
    });
  4. 命名私有属性时前面加个下划线 _
    1
    2
    3
    4
    5
    6
    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';

    // good
    this._firstName = 'Panda';
  5. 当保存对 this 的引用时使用 self(python 风格),避免this issue . Angular建议使用vm(MVVM模式中view-model)
    1
    2
    3
    4
    5
    6
    7
    // good
    function() {
    var self = this;
    return function() {
    console.log(self);
    };
    }

存取器

  1. 属性的存取器函数不是必需的
  2. 如果你确实有存取器函数的话使用getVal()setVal(‘hello’),java getter、setter风格或者jQuery风格
  3. 如果属性是布尔值,使用isVal()hasVal()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    if (!dragon.age()) {
    return false;
    }

    // good
    if (!dragon.hasAge()) {
    return false;
    }
  4. 可以创建get()set()函数,但是要保持一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Jedi(options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    Jedi.prototype.set = function(key, val) {
    this[key] = val;
    };

    Jedi.prototype.get = function(key) {
    return this[key];
    };

构造器

  1. 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function Jedi() {
    console.log('new jedi');
    }

    // bad
    Jedi.prototype = {
    fight: function fight() {
    console.log('fighting');
    },

    block: function block() {
    console.log('blocking');
    }
    };

    // good
    Jedi.prototype.fight = function fight() {
    console.log('fighting');
    };

    Jedi.prototype.block = function block() {
    console.log('blocking');
    };
  2. 方法可以返回 this 帮助方法可链。
    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
    // bad
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return true;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    };

    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined

    // good
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return this;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    return this;
    };

    var luke = new Jedi();

    luke.jump()
    .setHeight(20);
  3. 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Jedi(options) {
    options || (options = {});
    this.name = options.name || 'no name';
    }

    Jedi.prototype.getName = function getName() {
    return this.name;
    };

    Jedi.prototype.toString = function toString() {
    return 'Jedi - ' + this.getName();
    };

事件

  1. 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    $(this).trigger('listingUpdated', listing.id);

    ...

    $(this).on('listingUpdated', function(e, listingId) {
    // do something with listingId
    });


    // good
    $(this).trigger('listingUpdated', { listingId : listing.id });

    ...

    $(this).on('listingUpdated', function(e, data) {
    // do something with data.listingId
    });

模块

  1. 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
  2. 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
  3. 总是在模块顶部声明 'use strict';,引入JSHint规范
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // fancyInput/fancyInput.js

    function(global) {
    'use strict';

    var previousFancyInput = global.FancyInput;

    function FancyInput(options) {
    this.options = options || {};
    }

    FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
    };

    global.FancyInput = FancyInput;
    })(this);

jQuery

  1. 对于jQuery对象以$开头,以和原生DOM节点区分。
    1
    2
    3
    4
    5
    // bad
    var menu = $(".menu");

    // good
    var $menu = $(".menu");
  2. 缓存jQuery查询
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // bad
    function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
    'background-color': 'pink'
    });
    }

    // good
    function setSidebar() {
    var $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
    'background-color': 'pink'
    });
    }
  3. 对DOM查询使用级联的 $('.sidebar ul')$('.sidebar ul')jsPerf
  4. 对有作用域的jQuery对象查询使用 find
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $('.sidebar', 'ul').hide();

    // bad
    $('.sidebar').find('ul').hide();

    // good
    $('.sidebar ul').hide();

    // good
    $('.sidebar > ul').hide();

    // good (slower)
    $sidebar.find('ul');

    // good (faster)
    $($sidebar[0]).find('ul');
  5. 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。
    1
    2
    3
    $(function(){
    //do your page init.
    });
  6. 事件利用jQuery.on从页面分离到JavaScript文件。
    1
    2
    3
    4
    5
    6
    7
    // bad
    <a id="myLink" href="#" onclick="myEventHandler();"></a>

    // good
    <a id="myLink" href="#"></a>

    $("#myLink").on("click", myEventHandler);
  7. 对于Ajax使用promise方式。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $.ajax({
    ...
    success : function(){
    },
    error : function(){
    }
    })

    // good
    $.ajax({.
    ..
    }).then( function( ){
    // success
    }, function( ){
    // error
    })
  8. 利用promisedeferred对象解决延迟注册问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var dtd = $.Deferred(); // 新建一个deferred对象
    var wait = function(dtd){
    var tasks = function(){
    alert("执行完毕!");
    dtd.resolve(); // 改变deferred对象的执行状态
    };
    setTimeout(tasks,5000);
      return dtd;
    };
  9. HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。

ECMAScript 5兼容性

尽量采用ES5方法,特别数组mapfilterforEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscorelodash 常用辅助库.

HTML、CSS、JavaScript分离

  1. 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中
    分离在不同类型文件,文件link。
  2. HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。
  3. CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。
  4. 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。
  5. 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + flux架构、Knockout等。
  6. 对于兼容性可用Modernizr规范库辅助。

使用jsHint

  1. 前端项目中推荐引入 jshint插件来规范项目编码规范。以及一套完善的IDE配置。
  2. 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。

前端工具

  1. 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。
  2. 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。
  3. 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。

本文转载自破狼,原文略有修改,侵权即删.
原文链接:前端javascript规范
原文作者:破狼

\ No newline at end of file +前端 JavaScript 规范 | 云淡风轻

前端 JavaScript 规范

类型

原始值:相当于传值(JavaScript对象都提供了字面量),使用字面量创建对象。

  • string
  • number
  • boolean
  • null
  • undefined
1
2
3
4
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9

复杂类型:相当于传引用

  • object
  • array
  • function
1
2
3
4
var foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9

对象

  1. 使用字面值创建对象
    1
    2
    3
    4
    5
    // bad
    var item = new Object();

    // good
    var item = {};
  2. 不要使用保留字 reserved words 作为键
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    var superman = {
    class: 'superhero',
    default: { clark: 'kent' },
    private: true
    };

    // good
    var superman = {
    klass: 'superhero',
    defaults: { clark: 'kent' },
    hidden: true
    };

数组

  1. 使用字面值创建数组
    1
    2
    3
    4
    5
    // bad
    var items = new Array();

    // good
    var items = [];
  2. 如果你不知道数组的长度,使用push
    1
    2
    3
    4
    5
    6
    7
    var someStack = [];

    // bad
    someStack[someStack.length] = 'abracadabra';

    // good
    someStack.push('abracadabra');
  3. 当你需要拷贝数组时使用slice . jsPerf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var len = items.length,
    itemsCopy = [],
    i;

    // bad
    for (i = 0; i < len; i++) {
    itemsCopy[i] = items[i];
    }

    // good
    itemsCopy = items.slice();
  4. 使用slice类数组的对象转成数组.
    1
    2
    3
    4
    function trigger() {
    var args = [].slice.apply(arguments);
    ...
    }

字符串

  1. 对字符串使用单引号 ''(因为大多时候我们的字符串。特别html会出现")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    var name = "Bob Parr";

    // good
    var name = 'Bob Parr';

    // bad
    var fullName = "Bob " + this.lastName;

    // good
    var fullName = 'Bob ' + this.lastName;
  2. 超过80(也有规定140的,项目具体可制定)个字符的字符串应该使用字符串连接换行
    !!!: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

    // bad
    var errorMessage = 'This is a super long error that \
    was thrown because of Batman. \
    When you stop to think about \
    how Batman had anything to do \
    with this, you would get nowhere \
    fast.';

    // good
    var errorMessage = 'This is a super long error that ' +
    'was thrown because of Batman.' +
    'When you stop to think about ' +
    'how Batman had anything to do ' +
    'with this, you would get nowhere ' +
    'fast.';
  3. 编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.
    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
    var items,
    messages,
    length, i;

    messages = [{
    state: 'success',
    message: 'This one worked.'
    },{
    state: 'success',
    message: 'This one worked as well.'
    },{
    state: 'error',
    message: 'This one did not work.'
    }];

    length = messages.length;

    // bad
    function inbox(messages) {
    items = '<ul>';
    for (i = 0; i < length; i++) {
    items += '<li>' + messages[i].message + '</li>';
    }
    return items + '</ul>';
    }

    // good
    function inbox(messages) {
    items = [];
    for (i = 0; i < length; i++) {
    items[i] = messages[i].message;
    }
    return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
    }

函数

  1. 函数表达式:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 匿名函数表达式
    var anonymous = function() {
    return true;
    };

    // 有名函数表达式
    var named = function named() {
    return true;
    };

    // 立即调用函数表达式
    (function() {
    console.log('Welcome to the Internet. Please follow me.');
    })();
  2. 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
  3. : ECMA-262定义把定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    if (currentUser) {
    function test() {
    console.log('Nope.');
    }
    }

    // good
    if (currentUser) {
    var test = function test() {
    console.log('Yup.');
    };
    }
  4. 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function nope(name, options, arguments) {
    // ...stuff...
    }

    // good
    function yup(name, options, args) {
    // ...stuff...
    }

属性

  1. 当使用变量和特殊非法变量名时,访问属性时可以使用中括号(. 优先).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var luke = {
    jedi: true,
    age: 28
    };

    function getProp(prop) {
    return luke[prop];
    }

    var isJedi = getProp('jedi');

变量

  1. 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。
    1
    2
    3
    4
    5
    // bad
    superPower = new SuperPower();

    // good
    var superPower = new SuperPower();
  2. 使用一个 var 以及新行声明多个变量,缩进4个空格。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    var items = getItems();
    var goSportsTeam = true;
    var dragonball = 'z';

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  3. 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

    // bad
    var i, items = getItems(),
    dragonball,
    goSportsTeam = true,
    len;

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball,
    length,
    i;
  4. 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
    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
    // bad
    function() {
    test();
    console.log('doing stuff..');

    //..other stuff..

    var name = getName();

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // good
    function() {
    var name = getName();

    test();
    console.log('doing stuff..');

    //..other stuff..

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // bad
    function() {
    var name = getName();

    if (!arguments.length) {
    return false;
    }

    return true;
    }

    // good
    function() {
    if (!arguments.length) {
    return false;
    }

    var name = getName();

    return true;
    }

条件表达式和等号

  1. 合理使用 ===!== 以及 ==!=.
  2. 合理使用表达式逻辑操作运算.
  3. 条件表达式的强制类型转换遵循以下规则:
  • 对象 被计算为 true
  • Undefined 被计算为 false
  • Null 被计算为 false
  • 布尔值 被计算为 布尔的值
  • 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
  • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true
    1
    2
    3
    4
    if ([0]) {
    // true
    // An array is an object, objects evaluate to true
    }
  1. 使用快捷方式.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (name !== '') {
    // ...stuff...
    }

    // good
    if (name) {
    // ...stuff...
    }

    // bad
    if (collection.length > 0) {
    // ...stuff...
    }

    // good
    if (collection.length) {
    // ...stuff...
    }
  2. 阅读 Truth Equality and JavaScript 了解更多

  1. 给所有多行的块使用大括号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (test)
    return false;

    // good
    if (test) return false;

    // good
    if (test) {
    return false;
    }

    // bad
    function() { return false; }

    // good
    function() {
    return false;
    }

注释

  1. 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值
    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
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {

    // ...stuff...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    *
    * @param <String> tag
    * @return <Element> element
    */
    function make(tag) {

    // ...stuff...

    return element;
    }
  2. 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.
    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
    // bad
    var active = true; // is current tab

    // good
    // is current tab
    var active = true;

    // bad
    function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }

    // good
    function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }
  3. 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXMETODO 帮助其他人迅速理解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function Calculator() {

    // FIXME: shouldn't use a global here
    total = 0;

    return this;
    }


    function Calculator() {

    // TODO: total should be configurable by an options param
    this.total = 0;

    return this;
    }
  4. 满足规范的文档,在需要文档的时候,可以尝试jsdoc.

空白

  1. 缩进、格式化能帮助团队更快得定位修复代码BUG.
  2. 将tab设为4个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    function() {
    ∙∙var name;
    }

    // bad
    function() {
    var name;
    }

    // good
    function() {
    ∙∙∙∙var name;
    }
  3. 大括号前放一个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    function test(){
    console.log('test');
    }

    // good
    function test() {
    console.log('test');
    }

    // bad
    dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });

    // good
    dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });
  4. 在做长方法链时使用缩进.
    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
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // good
    $('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

    // bad
    var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

    // good
    var leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .class('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

逗号

  1. 不要将逗号放前面
    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
    // bad
    var once
    , upon
    , aTime;

    // good
    var once,
    upon,
    aTime;

    // bad
    var hero = {
    firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
    };

    // good
    var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
    };
  2. 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
    };

    var heroes = [
    'Batman',
    'Superman',
    ];

    // good
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
    };

    var heroes = [
    'Batman',
    'Superman'
    ];

分号

  1. 语句结束一定要加分号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    (function() {
    var name = 'Skywalker'
    return name
    })()

    // good
    (function() {
    var name = 'Skywalker';
    return name;
    })();

    // good
    ;(function() {
    var name = 'Skywalker';
    return name;
    })();

类型转换

  1. 在语句的开始执行类型转换.
  2. 字符串:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  => this.reviewScore = 9;

    // bad
    var totalScore = this.reviewScore + '';

    // good
    var totalScore = '' + this.reviewScore;

    // bad
    var totalScore = '' + this.reviewScore + ' total score';

    // good
    var totalScore = this.reviewScore + ' total score';
  3. 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)
    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
    var inputValue = '4';

    // bad
    var val = new Number(inputValue);

    // bad
    var val = +inputValue;

    // bad
    var val = inputValue >> 0;

    // bad
    var val = parseInt(inputValue);

    // good
    var val = Number(inputValue);

    // good
    var val = parseInt(inputValue, 10);

    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var val = inputValue >> 0;
  4. 布尔值:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var age = 0;

    // bad
    var hasAge = new Boolean(age);

    // good
    var hasAge = Boolean(age);

    // good
    var hasAge = !!age;

命名约定

  1. 避免单个字符名,让你的变量名有描述意义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function q() {
    // ...stuff...
    }

    // good
    function query() {
    // ..stuff..
    }
  2. 当命名对象、函数和实例时使用驼峰命名规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // bad
    var OBJEcttsssss = {};
    var this_is_my_object = {};
    var this-is-my-object = {};
    function c() {};
    var u = new user({
    name: 'Bob Parr'
    });

    // good
    var thisIsMyObject = {};
    function thisIsMyFunction() {};
    var user = new User({
    name: 'Bob Parr'
    });
  3. 当命名构造函数或类时使用驼峰式大写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    function user(options) {
    this.name = options.name;
    }

    var bad = new user({
    name: 'nope'
    });

    // good
    function User(options) {
    this.name = options.name;
    }

    var good = new User({
    name: 'yup'
    });
  4. 命名私有属性时前面加个下划线 _
    1
    2
    3
    4
    5
    6
    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';

    // good
    this._firstName = 'Panda';
  5. 当保存对 this 的引用时使用 self(python 风格),避免this issue . Angular建议使用vm(MVVM模式中view-model)
    1
    2
    3
    4
    5
    6
    7
    // good
    function() {
    var self = this;
    return function() {
    console.log(self);
    };
    }

存取器

  1. 属性的存取器函数不是必需的
  2. 如果你确实有存取器函数的话使用getVal()setVal(‘hello’),java getter、setter风格或者jQuery风格
  3. 如果属性是布尔值,使用isVal()hasVal()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    if (!dragon.age()) {
    return false;
    }

    // good
    if (!dragon.hasAge()) {
    return false;
    }
  4. 可以创建get()set()函数,但是要保持一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Jedi(options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    Jedi.prototype.set = function(key, val) {
    this[key] = val;
    };

    Jedi.prototype.get = function(key) {
    return this[key];
    };

构造器

  1. 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function Jedi() {
    console.log('new jedi');
    }

    // bad
    Jedi.prototype = {
    fight: function fight() {
    console.log('fighting');
    },

    block: function block() {
    console.log('blocking');
    }
    };

    // good
    Jedi.prototype.fight = function fight() {
    console.log('fighting');
    };

    Jedi.prototype.block = function block() {
    console.log('blocking');
    };
  2. 方法可以返回 this 帮助方法可链。
    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
    // bad
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return true;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    };

    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined

    // good
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return this;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    return this;
    };

    var luke = new Jedi();

    luke.jump()
    .setHeight(20);
  3. 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Jedi(options) {
    options || (options = {});
    this.name = options.name || 'no name';
    }

    Jedi.prototype.getName = function getName() {
    return this.name;
    };

    Jedi.prototype.toString = function toString() {
    return 'Jedi - ' + this.getName();
    };

事件

  1. 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    $(this).trigger('listingUpdated', listing.id);

    ...

    $(this).on('listingUpdated', function(e, listingId) {
    // do something with listingId
    });


    // good
    $(this).trigger('listingUpdated', { listingId : listing.id });

    ...

    $(this).on('listingUpdated', function(e, data) {
    // do something with data.listingId
    });

模块

  1. 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
  2. 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
  3. 总是在模块顶部声明 'use strict';,引入JSHint规范
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // fancyInput/fancyInput.js

    function(global) {
    'use strict';

    var previousFancyInput = global.FancyInput;

    function FancyInput(options) {
    this.options = options || {};
    }

    FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
    };

    global.FancyInput = FancyInput;
    })(this);

jQuery

  1. 对于jQuery对象以$开头,以和原生DOM节点区分。
    1
    2
    3
    4
    5
    // bad
    var menu = $(".menu");

    // good
    var $menu = $(".menu");
  2. 缓存jQuery查询
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // bad
    function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
    'background-color': 'pink'
    });
    }

    // good
    function setSidebar() {
    var $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
    'background-color': 'pink'
    });
    }
  3. 对DOM查询使用级联的 $('.sidebar ul')$('.sidebar ul')jsPerf
  4. 对有作用域的jQuery对象查询使用 find
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $('.sidebar', 'ul').hide();

    // bad
    $('.sidebar').find('ul').hide();

    // good
    $('.sidebar ul').hide();

    // good
    $('.sidebar > ul').hide();

    // good (slower)
    $sidebar.find('ul');

    // good (faster)
    $($sidebar[0]).find('ul');
  5. 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。
    1
    2
    3
    $(function(){
    //do your page init.
    });
  6. 事件利用jQuery.on从页面分离到JavaScript文件。
    1
    2
    3
    4
    5
    6
    7
    // bad
    <a id="myLink" href="#" onclick="myEventHandler();"></a>

    // good
    <a id="myLink" href="#"></a>

    $("#myLink").on("click", myEventHandler);
  7. 对于Ajax使用promise方式。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $.ajax({
    ...
    success : function(){
    },
    error : function(){
    }
    })

    // good
    $.ajax({.
    ..
    }).then( function( ){
    // success
    }, function( ){
    // error
    })
  8. 利用promisedeferred对象解决延迟注册问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var dtd = $.Deferred(); // 新建一个deferred对象
    var wait = function(dtd){
    var tasks = function(){
    alert("执行完毕!");
    dtd.resolve(); // 改变deferred对象的执行状态
    };
    setTimeout(tasks,5000);
      return dtd;
    };
  9. HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。

ECMAScript 5兼容性

尽量采用ES5方法,特别数组mapfilterforEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscorelodash 常用辅助库.

HTML、CSS、JavaScript分离

  1. 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中
    分离在不同类型文件,文件link。
  2. HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。
  3. CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。
  4. 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。
  5. 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + flux架构、Knockout等。
  6. 对于兼容性可用Modernizr规范库辅助。

使用jsHint

  1. 前端项目中推荐引入 jshint插件来规范项目编码规范。以及一套完善的IDE配置。
  2. 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。

前端工具

  1. 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。
  2. 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。
  3. 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。

本文转载自破狼,原文略有修改,侵权即删.
原文链接:前端javascript规范
原文作者:破狼

\ No newline at end of file diff --git a/2016/MarkDown-incomplete-Guide/index.html b/2016/MarkDown-incomplete-Guide/index.html index 1e6d1327..36129f91 100644 --- a/2016/MarkDown-incomplete-Guide/index.html +++ b/2016/MarkDown-incomplete-Guide/index.html @@ -1,4 +1,4 @@ -MarkDown 不完全指南 | 云淡风轻

MarkDown 不完全指南

Markdown

A markdown example shows how to write a markdown file. This document integrates core syntax and extensions (GMF).

Block Elements

Paragraphs and Line Breaks

Paragraphs

HTML Tag: <p>

One or more blank lines. (A blank line is a line containing nothing but spaces or tabs is considered blank.)

Code:

1
2
3
4
This will be 
inline.

This is second paragraph.

Preview:


This will be
inline.

This is second paragraph.


Line Breaks

HTML Tag: <br />

End a line with two or more spaces.

Code:

1
2
This will be not  
inline.

Preview:


This will be not
inline.


Headers

Markdown supports two styles of headers, Setext and atx.

Setext

HTML Tags: <h1>, <h2>

“Underlined” using equal signs (=) as <h1> and dashes (-) as <h2> in any number.

Code:
1
2
3
4
This is an H1
=============
This is an H2
-------------

Preview:
***
This is an H1

This is an H2


atx

HTML Tags: <h1>, <h2>, <h3>, <h4>, <h5>, <h6>

Uses 1-6 hash characters (#) at the start of the line, corresponding to <h1> - <h6>.

Code:

1
2
3
# This is an H1
## This is an H2
###### This is an H6

Preview:


This is an H1

This is an H2

This is an H6

Optionally, you may “close” atx-style headers. The closing hashes don’t need to match the number of hashes used to open the header.

Code:

1
2
3
# This is an H1 #
## This is an H2 ##
### This is an H3 ######

Preview:


This is an H1

This is an H2

This is an H3


Blockquotes

HTML Tag: <blockquote>

Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and put a > before every line.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
>
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
> id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >.

Code:

1
2
3
4
5
> This is the first level of quoting.
>
> > This is nested blockquote.
>
> Back to the first level.

Preview:


This is the first level of quoting.

This is nested blockquote.

Back to the first level.


Blockquotes can contain other Markdown elements, including headers, lists, and code blocks.

Code:

1
2
3
4
5
6
7
8
> ## This is a header.
>
> 1. This is the first list item.
> 2. This is the second list item.
>
> Here's some example code:
>
> return shell_exec("echo $input | $markdown_script");

Preview:


This is a header.

  1. This is the first list item.
  2. This is the second list item.

Here’s some example code:

return shell_exec("echo $input | $markdown_script");
+MarkDown 不完全指南 | 云淡风轻

MarkDown 不完全指南

Markdown

A markdown example shows how to write a markdown file. This document integrates core syntax and extensions (GMF).

Block Elements

Paragraphs and Line Breaks

Paragraphs

HTML Tag: <p>

One or more blank lines. (A blank line is a line containing nothing but spaces or tabs is considered blank.)

Code:

1
2
3
4
This will be 
inline.

This is second paragraph.

Preview:


This will be
inline.

This is second paragraph.


Line Breaks

HTML Tag: <br />

End a line with two or more spaces.

Code:

1
2
This will be not  
inline.

Preview:


This will be not
inline.


Headers

Markdown supports two styles of headers, Setext and atx.

Setext

HTML Tags: <h1>, <h2>

“Underlined” using equal signs (=) as <h1> and dashes (-) as <h2> in any number.

Code:
1
2
3
4
This is an H1
=============
This is an H2
-------------

Preview:
***
This is an H1

This is an H2


atx

HTML Tags: <h1>, <h2>, <h3>, <h4>, <h5>, <h6>

Uses 1-6 hash characters (#) at the start of the line, corresponding to <h1> - <h6>.

Code:

1
2
3
# This is an H1
## This is an H2
###### This is an H6

Preview:


This is an H1

This is an H2

This is an H6

Optionally, you may “close” atx-style headers. The closing hashes don’t need to match the number of hashes used to open the header.

Code:

1
2
3
# This is an H1 #
## This is an H2 ##
### This is an H3 ######

Preview:


This is an H1

This is an H2

This is an H3


Blockquotes

HTML Tag: <blockquote>

Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and put a > before every line.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
>
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
> id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >.

Code:

1
2
3
4
5
> This is the first level of quoting.
>
> > This is nested blockquote.
>
> Back to the first level.

Preview:


This is the first level of quoting.

This is nested blockquote.

Back to the first level.


Blockquotes can contain other Markdown elements, including headers, lists, and code blocks.

Code:

1
2
3
4
5
6
7
8
> ## This is a header.
>
> 1. This is the first list item.
> 2. This is the second list item.
>
> Here's some example code:
>
> return shell_exec("echo $input | $markdown_script");

Preview:


This is a header.

  1. This is the first list item.
  2. This is the second list item.

Here’s some example code:

return shell_exec("echo $input | $markdown_script");
 

Lists

Markdown supports ordered (numbered) and unordered (bulleted) lists.

Unordered

HTML Tag: <ul>

Unordered lists use asterisks (*), pluses (+), and hyphens (-).

Code:

1
2
3
*   Red
* Green
* Blue

Preview:


  • Red
  • Green
  • Blue

is equivalent to:

Code:

1
2
3
+   Red
+ Green
+ Blue

and:

Code:

1
2
3
-   Red
- Green
- Blue

Ordered

HTML Tag: <ol>

Ordered lists use numbers followed by periods:

Code:

1
2
3
1.  Bird
2. McHale
3. Parish

Preview:


  1. Bird
  2. McHale
  3. Parish

It’s possible to trigger an ordered list by accident, by writing something like this:

Code:

1
1986. What a great season.

Preview:


  1. What a great season.

You can backslash-escape (\) the period:

Code:

1
1986\. What a great season.

Preview:


1986. What a great season.


Indented

Blockquote

To put a blockquote within a list item, the blockquote’s > delimiters need to be indented:

Code:

1
2
3
4
*   A list item with a blockquote:

> This is a blockquote
> inside a list item.

Preview:


  • A list item with a blockquote:

    This is a blockquote
    inside a list item.


Code Block

To put a code block within a list item, the code block needs to be indented twice — 8 spaces or two tabs:

Code:

1
2
3
*   A list item with a code block:

<code goes here>

Preview:


  • A list item with a code block:

    <code goes here>
     

Nested List

Code:

1
2
3
4
5
* A
* A1
* A2
* B
* C

Preview:


  • A
    • A1
    • A2
  • B
  • C

Code Blocks

HTML Tag: <pre>

Indent every line of the block by at least 4 spaces or 1 tab.

Code:

1
2
3
This is a normal paragraph:

This is a code block.

Preview:


This is a normal paragraph:

This is a code block.
-

A code block continues until it reaches a line that is not indented (or the end of the article).

Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities.

Code:

1
2
3
<div class="thanclass">
&copy; 2004 Foo Corporation
</div>

Preview:


© 2004 Foo Corporation
*** Following sections Fenced Code Blocks and Syntax Highlighting are extensions, you can use the other way to write the code block. #### Fenced Code Blocks Just wrap your code in \`\`\` \`\`\` (as shown below) and you won't need to indent it by four spaces.

Code:

Here’s an example:
```
function test() {
console.log(“notice the blank line before this function?”);
}
```

Preview:


Here’s an example:

1
2
3
function test() {
console.log("notice the blank line before this function?");
}

Syntax Highlighting

In your fenced block, add an optional language identifier and we’ll run it through syntax highlighting (Support Languages).

Code:

```ruby
require ‘redcarpet’
markdown = Redcarpet.new(“Hello World!”)
puts markdown.to_html
```

Preview:


1
2
3
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html

Horizontal Rules

HTML Tag: <hr />
Places three or more hyphens (-), asterisks (*), or underscores (_) on a line by themselves. You may use spaces between the hyphens or asterisks.

Code:

1
2
3
4
5
6
* * *
***
*****
- - -
---------------------------------------
___

Table

HTML Tag: <table>

It’s an extension.

Separates column by pipe (|) and header by dashes (-), and uses colon (:) for alignment.

The outer pipes (|) and alignment are optional. There are 3 delimiters each cell at least for separating header.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
| Left | Center | Right |
|:-----|:------:|------:|
|aaa |bbb |ccc |
|ddd |eee |fff |

A | B
---|---
123|456


A |B
--|--
12|45

Preview:


LeftCenterRight
aaabbbccc
dddeeefff
AB
123456
AB
1245

Span Elements

HTML Tag: <a>

Markdown supports two style of links: inline and reference.

Inline

Inline link format like this: [Link Text](URL "Title")

Title is optional.

Code:

1
2
3
This is [an example](http://example.com/ "Title") inline link.

[This link](http://example.net/) has no title attribute.

Preview:


This is an example inline link.

This link has no title attribute.


If you’re referring to a local resource on the same server, you can use relative paths:

Code:

1
See my [Tags](/tags/) page for details. 

Preview:


See my Tags page for details.


Reference

You could predefine link references. Format like this: [id]: URL "Title"

Title is also optional. And the you refer the link, format like this: [Link Text][id]

Code:

1
2
[id]: http://example.com/  "Optional Title Here"
This is [an example][id] reference-style link.

Preview:


This is 点我跳转到百度 reference-style link.


That is:

  • Square brackets containing the link identifier (not case sensitive, optionally indented from the left margin using up to three spaces);
  • followed by a colon;
  • followed by one or more spaces (or tabs);
  • followed by the URL for the link;
  • The link URL may, optionally, be surrounded by angle brackets.
  • optionally followed by a title attribute for the link, enclosed in double or single quotes, or enclosed in parentheses.

The following three link definitions are equivalent:

Code:

1
2
3
4
[foo]: http://example.com/  "Optional Title Here"
[foo]: http://example.com/ 'Optional Title Here'
[foo]: http://example.com/ (Optional Title Here)
[foo]: <http://example.com/> "Optional Title Here"

Uses an empty set of square brackets, the link text itself is used as the name.

Code:

1
2
[Google]: http://google.com/
[Google][]

Preview:


Google


Emphasis

HTML Tags: <em>, <strong>

Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. One delimiter will be <em>; *double delimiters will be <strong>.

Code:

1
2
3
4
5
6
7
*single asterisks*

_single underscores_

**double asterisks**

__double underscores__

Preview:


single asterisks

single underscores

double asterisks

double underscores


But if you surround an * or _ with spaces, it’ll be treated as a literal asterisk or underscore.

You can backslash escape it:

Code:

1
*this text is surrounded by literal asterisks*

Preview:


*this text is surrounded by literal asterisks*


Code

HTML Tag: <code>

Wraps it with backtick quotes (`).

Code:

1
Use the `printf()` function.

Preview:


Use the printf() function.


To include a literal backtick character within a code span, you can use multiple backticks as the opening and closing delimiters:

Code:

1
``There is a literal backtick (`) here.``

Preview:


There is a literal backtick (`) here.


The backtick delimiters surrounding a code span may include spaces — one after the opening, one before the closing. This allows you to place literal backtick characters at the beginning or end of a code span:

Code:

1
2
3
A single backtick in a code span: `` ` ``

A backtick-delimited string in a code span: `` `foo` ``

Preview:


A single backtick in a code span: `

A backtick-delimited string in a code span: `foo`


Images

HTML Tag: <img />

Markdown uses an image syntax that is intended to resemble the syntax for links, allowing for two styles: inline and reference.

Inline

Inline image syntax looks like this: ![Alt text](URL "Title")

Title is optional.

Code:

1
2
3
![Alt text](/path/to/img.jpg)

![Alt text](/path/to/img.jpg "Optional title")

Preview:


Alt text

Alt text


That is:

  • An exclamation mark: !;
  • followed by a set of square brackets, containing the alt attribute text for the image;
  • followed by a set of parentheses, containing the URL or path to the image, and an optional title attribute enclosed in double or single quotes.

Reference

Reference-style image syntax looks like this: ![Alt text][id]

Code:

1
2
[img id]: url/to/image  "Optional title attribute"
![Alt text][img id]

Preview:


Alt text


Strikethrough

HTML Tag: <del>

It’s an extension.

GFM adds syntax to strikethrough text.

Code:

1
~~Mistaken text.~~

Preview:


Mistaken text.


Miscellaneous

Markdown supports a shortcut style for creating “automatic” links for URLs and email addresses: simply surround the URL or email address with angle brackets.

Code:

1
2
3
<http://example.com/>

<address@example.com>

Preview:


http://example.com/

address@example.com


GFM will autolink standard URLs.

Code:

1
https://github.com/xcss

Preview:


https://github.com/xcss


Backslash Escapes

Markdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax.

Code:

1
\*literal asterisks\*

Preview:


*literal asterisks*


Markdown provides backslash escapes for the following characters:

Code:

1
2
3
4
5
6
7
8
9
10
11
12
\   backslash
` backtick
* asterisk
_ underscore
{} curly braces
[] square brackets
() parentheses
# hash mark
+ plus sign
- minus sign (hyphen)
. dot
! exclamation mark

Inline HTML

For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.

Code:

1
2
3
4
5
6
7
8
9
This is a regular paragraph.

<table>
<tr>
<td>Foo</td>
</tr>
</table>

This is another regular paragraph.

Preview:


This is a regular paragraph.

Foo
This is another regular paragraph. *** Note that Markdown formatting syntax is **not processed within block-level HTML tags**.

Unlike block-level HTML tags, Markdown syntax is processed within span-level tags.

Code:

1
2
3
4
5
<span>**Work**</span>

<div>
**No Work**
</div>

Preview:


Work

**No Work**
***

参考文档: http://www.markdown.cn/

\ No newline at end of file +

A code block continues until it reaches a line that is not indented (or the end of the article).

Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities.

Code:

1
2
3
<div class="thanclass">
&copy; 2004 Foo Corporation
</div>

Preview:


© 2004 Foo Corporation
*** Following sections Fenced Code Blocks and Syntax Highlighting are extensions, you can use the other way to write the code block. #### Fenced Code Blocks Just wrap your code in \`\`\` \`\`\` (as shown below) and you won't need to indent it by four spaces.

Code:

Here’s an example:
```
function test() {
console.log(“notice the blank line before this function?”);
}
```

Preview:


Here’s an example:

1
2
3
function test() {
console.log("notice the blank line before this function?");
}

Syntax Highlighting

In your fenced block, add an optional language identifier and we’ll run it through syntax highlighting (Support Languages).

Code:

```ruby
require ‘redcarpet’
markdown = Redcarpet.new(“Hello World!”)
puts markdown.to_html
```

Preview:


1
2
3
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html

Horizontal Rules

HTML Tag: <hr />
Places three or more hyphens (-), asterisks (*), or underscores (_) on a line by themselves. You may use spaces between the hyphens or asterisks.

Code:

1
2
3
4
5
6
* * *
***
*****
- - -
---------------------------------------
___

Table

HTML Tag: <table>

It’s an extension.

Separates column by pipe (|) and header by dashes (-), and uses colon (:) for alignment.

The outer pipes (|) and alignment are optional. There are 3 delimiters each cell at least for separating header.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
| Left | Center | Right |
|:-----|:------:|------:|
|aaa |bbb |ccc |
|ddd |eee |fff |

A | B
---|---
123|456


A |B
--|--
12|45

Preview:


LeftCenterRight
aaabbbccc
dddeeefff
AB
123456
AB
1245

Span Elements

HTML Tag: <a>

Markdown supports two style of links: inline and reference.

Inline

Inline link format like this: [Link Text](URL "Title")

Title is optional.

Code:

1
2
3
This is [an example](http://example.com/ "Title") inline link.

[This link](http://example.net/) has no title attribute.

Preview:


This is an example inline link.

This link has no title attribute.


If you’re referring to a local resource on the same server, you can use relative paths:

Code:

1
See my [Tags](/tags/) page for details. 

Preview:


See my Tags page for details.


Reference

You could predefine link references. Format like this: [id]: URL "Title"

Title is also optional. And the you refer the link, format like this: [Link Text][id]

Code:

1
2
[id]: http://example.com/  "Optional Title Here"
This is [an example][id] reference-style link.

Preview:


This is 点我跳转到百度 reference-style link.


That is:

  • Square brackets containing the link identifier (not case sensitive, optionally indented from the left margin using up to three spaces);
  • followed by a colon;
  • followed by one or more spaces (or tabs);
  • followed by the URL for the link;
  • The link URL may, optionally, be surrounded by angle brackets.
  • optionally followed by a title attribute for the link, enclosed in double or single quotes, or enclosed in parentheses.

The following three link definitions are equivalent:

Code:

1
2
3
4
[foo]: http://example.com/  "Optional Title Here"
[foo]: http://example.com/ 'Optional Title Here'
[foo]: http://example.com/ (Optional Title Here)
[foo]: <http://example.com/> "Optional Title Here"

Uses an empty set of square brackets, the link text itself is used as the name.

Code:

1
2
[Google]: http://google.com/
[Google][]

Preview:


Google


Emphasis

HTML Tags: <em>, <strong>

Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. One delimiter will be <em>; *double delimiters will be <strong>.

Code:

1
2
3
4
5
6
7
*single asterisks*

_single underscores_

**double asterisks**

__double underscores__

Preview:


single asterisks

single underscores

double asterisks

double underscores


But if you surround an * or _ with spaces, it’ll be treated as a literal asterisk or underscore.

You can backslash escape it:

Code:

1
*this text is surrounded by literal asterisks*

Preview:


*this text is surrounded by literal asterisks*


Code

HTML Tag: <code>

Wraps it with backtick quotes (`).

Code:

1
Use the `printf()` function.

Preview:


Use the printf() function.


To include a literal backtick character within a code span, you can use multiple backticks as the opening and closing delimiters:

Code:

1
``There is a literal backtick (`) here.``

Preview:


There is a literal backtick (`) here.


The backtick delimiters surrounding a code span may include spaces — one after the opening, one before the closing. This allows you to place literal backtick characters at the beginning or end of a code span:

Code:

1
2
3
A single backtick in a code span: `` ` ``

A backtick-delimited string in a code span: `` `foo` ``

Preview:


A single backtick in a code span: `

A backtick-delimited string in a code span: `foo`


Images

HTML Tag: <img />

Markdown uses an image syntax that is intended to resemble the syntax for links, allowing for two styles: inline and reference.

Inline

Inline image syntax looks like this: ![Alt text](URL "Title")

Title is optional.

Code:

1
2
3
![Alt text](/path/to/img.jpg)

![Alt text](/path/to/img.jpg "Optional title")

Preview:


Alt text

Alt text


That is:

  • An exclamation mark: !;
  • followed by a set of square brackets, containing the alt attribute text for the image;
  • followed by a set of parentheses, containing the URL or path to the image, and an optional title attribute enclosed in double or single quotes.

Reference

Reference-style image syntax looks like this: ![Alt text][id]

Code:

1
2
[img id]: url/to/image  "Optional title attribute"
![Alt text][img id]

Preview:


Alt text


Strikethrough

HTML Tag: <del>

It’s an extension.

GFM adds syntax to strikethrough text.

Code:

1
~~Mistaken text.~~

Preview:


Mistaken text.


Miscellaneous

Markdown supports a shortcut style for creating “automatic” links for URLs and email addresses: simply surround the URL or email address with angle brackets.

Code:

1
2
3
<http://example.com/>

<address@example.com>

Preview:


http://example.com/

address@example.com


GFM will autolink standard URLs.

Code:

1
https://github.com/xcss

Preview:


https://github.com/xcss


Backslash Escapes

Markdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax.

Code:

1
\*literal asterisks\*

Preview:


*literal asterisks*


Markdown provides backslash escapes for the following characters:

Code:

1
2
3
4
5
6
7
8
9
10
11
12
\   backslash
` backtick
* asterisk
_ underscore
{} curly braces
[] square brackets
() parentheses
# hash mark
+ plus sign
- minus sign (hyphen)
. dot
! exclamation mark

Inline HTML

For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.

Code:

1
2
3
4
5
6
7
8
9
This is a regular paragraph.

<table>
<tr>
<td>Foo</td>
</tr>
</table>

This is another regular paragraph.

Preview:


This is a regular paragraph.

Foo
This is another regular paragraph. *** Note that Markdown formatting syntax is **not processed within block-level HTML tags**.

Unlike block-level HTML tags, Markdown syntax is processed within span-level tags.

Code:

1
2
3
4
5
<span>**Work**</span>

<div>
**No Work**
</div>

Preview:


Work

**No Work**
***

参考文档: http://www.markdown.cn/

\ No newline at end of file diff --git a/2016/commonly-used-media-queries/index.html b/2016/commonly-used-media-queries/index.html index dd29788f..33fba898 100644 --- a/2016/commonly-used-media-queries/index.html +++ b/2016/commonly-used-media-queries/index.html @@ -1 +1 @@ -响应式设计 (Responsive Design) 中常用的媒体查询 | 云淡风轻

响应式设计 (Responsive Design) 中常用的媒体查询

现在Web朝着响应式的趋势发展,媒体查询在创建响应式网站中起到了主要作用。

没有媒体查询几乎不能实现响应式设计,利用媒体查询,我们可以针对特定的设备,如显示器、智能手机和平板,写CSS。

媒体查询是响应式设计的核心

在这篇文章中我将分享一些到目前为止我收集到的常用媒体查询。在一些示例中,我可能是错误的,但是不用担心,因为我针对这个开通了评论功能。我把它们分为显示器媒体查询智能手机媒体查询平板媒体查询

显示器媒体查询

显示器媒体查询是以屏幕大小为基础划分的

640px

1
2
3
@media screen and (max-width: 640px){
/*some rules*/
}

800px

1
2
3
@media screen and (max-width: 800px){
/*some rules*/
}

1024px

1
2
3
@media screen and (max-width: 1024px){
/*some rules*/
}

智能手机媒体查询

适用于大部分主流智能手机

iPhone(2G-4S)

1
2
3
4
5
6
7
8
/*Landscape Mode*/
@media screen and (max-device-width: 480px) and (orientation:landscape){
/*some rules*/
}
/* Portrait Mode */
@media screen and (max-device-width: 320px) and (orientation:portrait){
/*some rules*/
}

iPhone 4

1
2
3
4
@media only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5){
/*some rules*/
}

iPhone 5

1
2
3
4
5
@media only screen
and (min-device-width : 320px)
and (max-device-width : 568px){
/*some rules*/
}

iPhone 6

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
@media only screen and (min-device-width: 375px) and (max-device-width: 667px)
and (orientation : portrait) {
/*iPhone 6 Portrait*/
}
@media only screen and (min-device-width: 375px) and (max-device-width: 667px)
and (orientation : landscape) {
/*iPhone 6 landscape*/
}
@media only screen and (min-device-width: 414px) and (max-device-width: 736px)
and (orientation : portrait) {
/*iPhone 6+ Portrait*/
}
@media only screen and (min-device-width: 414px) and (max-device-width: 736px)
and (orientation : landscape) {
/*iPhone 6+ landscape*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px){
/*iPhone 6 and iPhone 6+ portrait and landscape*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px) and (orientation : portrait){
/*iPhone 6 and iPhone 6+ portrait*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px) and (orientation : landscape){
/*iPhone 6 and iPhone 6+ landscape*/
}

HTC Evo,BlackBerry Torch,HTC Thunderbolt,HD2

1
2
3
@media screen and (max-device-width: 480px){
/*some rules*/
}

平板媒体查询

iPad / iPad 2 / iPad 3

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

iPad Mini

1
2
3
4
5
6
@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (-webkit-min-device-pixel-ratio: 1){
/*some rules*/
}

Samsung Galaxy Tab 10.1 / Motorola Xoom / Lenovo Thinkpad Tablet / Sony Tablet S

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1280px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 800px) and (orientation: portrait){
/*some rules*/
}

HTC Flyer / BlackBerry PlayBook

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 600px) and (orientation: portrait){
/*some rules*/
}

HP TouchPad

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

T-Mobile G-Slate

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1280px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

ViewSonic ViewPad 10

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 600px) and (orientation: portrait){
/*some rules*/
}

Dell Streak 7

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 800px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 400px) and (orientation: portrait){
/*some rules*/
}

ASUS Eee Pad Transformer

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1080px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 800px) and (orientation: portrait){
/*some rules*/
}

其他参考文档

  1. 七个高度有效的媒体查询技巧
  2. iPads和iPhones的Media Queries
  3. media-queries-for-standard-devices

本文转载自淡忘~浅思,略有删改,侵权即删.
原文链接: Some Media Queries for Responsive Design
译文链接: 【译】Responsive Design常用的媒体查询

\ No newline at end of file +响应式设计 (Responsive Design) 中常用的媒体查询 | 云淡风轻

响应式设计 (Responsive Design) 中常用的媒体查询

现在Web朝着响应式的趋势发展,媒体查询在创建响应式网站中起到了主要作用。

没有媒体查询几乎不能实现响应式设计,利用媒体查询,我们可以针对特定的设备,如显示器、智能手机和平板,写CSS。

媒体查询是响应式设计的核心

在这篇文章中我将分享一些到目前为止我收集到的常用媒体查询。在一些示例中,我可能是错误的,但是不用担心,因为我针对这个开通了评论功能。我把它们分为显示器媒体查询智能手机媒体查询平板媒体查询

显示器媒体查询

显示器媒体查询是以屏幕大小为基础划分的

640px

1
2
3
@media screen and (max-width: 640px){
/*some rules*/
}

800px

1
2
3
@media screen and (max-width: 800px){
/*some rules*/
}

1024px

1
2
3
@media screen and (max-width: 1024px){
/*some rules*/
}

智能手机媒体查询

适用于大部分主流智能手机

iPhone(2G-4S)

1
2
3
4
5
6
7
8
/*Landscape Mode*/
@media screen and (max-device-width: 480px) and (orientation:landscape){
/*some rules*/
}
/* Portrait Mode */
@media screen and (max-device-width: 320px) and (orientation:portrait){
/*some rules*/
}

iPhone 4

1
2
3
4
@media only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5){
/*some rules*/
}

iPhone 5

1
2
3
4
5
@media only screen
and (min-device-width : 320px)
and (max-device-width : 568px){
/*some rules*/
}

iPhone 6

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
@media only screen and (min-device-width: 375px) and (max-device-width: 667px)
and (orientation : portrait) {
/*iPhone 6 Portrait*/
}
@media only screen and (min-device-width: 375px) and (max-device-width: 667px)
and (orientation : landscape) {
/*iPhone 6 landscape*/
}
@media only screen and (min-device-width: 414px) and (max-device-width: 736px)
and (orientation : portrait) {
/*iPhone 6+ Portrait*/
}
@media only screen and (min-device-width: 414px) and (max-device-width: 736px)
and (orientation : landscape) {
/*iPhone 6+ landscape*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px){
/*iPhone 6 and iPhone 6+ portrait and landscape*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px) and (orientation : portrait){
/*iPhone 6 and iPhone 6+ portrait*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px) and (orientation : landscape){
/*iPhone 6 and iPhone 6+ landscape*/
}

HTC Evo,BlackBerry Torch,HTC Thunderbolt,HD2

1
2
3
@media screen and (max-device-width: 480px){
/*some rules*/
}

平板媒体查询

iPad / iPad 2 / iPad 3

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

iPad Mini

1
2
3
4
5
6
@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (-webkit-min-device-pixel-ratio: 1){
/*some rules*/
}

Samsung Galaxy Tab 10.1 / Motorola Xoom / Lenovo Thinkpad Tablet / Sony Tablet S

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1280px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 800px) and (orientation: portrait){
/*some rules*/
}

HTC Flyer / BlackBerry PlayBook

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 600px) and (orientation: portrait){
/*some rules*/
}

HP TouchPad

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

T-Mobile G-Slate

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1280px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

ViewSonic ViewPad 10

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 600px) and (orientation: portrait){
/*some rules*/
}

Dell Streak 7

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 800px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 400px) and (orientation: portrait){
/*some rules*/
}

ASUS Eee Pad Transformer

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1080px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 800px) and (orientation: portrait){
/*some rules*/
}

其他参考文档

  1. 七个高度有效的媒体查询技巧
  2. iPads和iPhones的Media Queries
  3. media-queries-for-standard-devices

本文转载自淡忘~浅思,略有删改,侵权即删.
原文链接: Some Media Queries for Responsive Design
译文链接: 【译】Responsive Design常用的媒体查询

\ No newline at end of file diff --git a/2016/css-content-and-special-characters/index.html b/2016/css-content-and-special-characters/index.html index 5135ab2e..eb3ade77 100644 --- a/2016/css-content-and-special-characters/index.html +++ b/2016/css-content-and-special-characters/index.html @@ -1 +1 @@ -CSS 内容和特殊字符 | 云淡风轻

CSS 内容和特殊字符

当我写这个主题theme的时候,我想在我的列表元素(list elements)上用CSS内容(CSS content)属性添加一些**向右双角引号(right-pointing double-angle quotation marks)(<<)**。

所以,我在里面添加了&raquo;,然而,它并不工作!

我花了一点时间去了解到,你不能使用常规的 HTML 实体内容。相反,你必须使用 Unicode 十六进制格式,它看起来像这样:\bb

这是一些你可以轻而易举找到的东西,只因为它出现在了众多课程和参考书里。

将HTML实体转换成Unicode十六进制代码

这里有很多的HTML实体对应表,但是没有更多的 Unicode十六进制表,所以很方便的知道二者之间的转换。你需要知道所有的HTML十进制单位(它们看起来像这样&#123;,而不是像这样&quot;)。
那数字,你猜到了吧,就是十进制格式。我们需要将其转换成Unicode十六进制(我知道,你震惊了!)。

如果你不是一个程序员或者数学天才,可能你不熟悉到底该怎么做(具体请Google)。OK,其实这并不难,但有一个更快捷的方式:

打开类似于经典的Windows计算器,切换到“程序员”视图(View > Programmer)。点击Dec(十进制)单选按钮,输入你的数字然后点击Hex(十六进制)按钮,你就会得到你的十六进制数字。

然后把刚刚得到的数字放到\之后,你就得到了你自己的Unicode十六进制字符。

更容易的方法 - HTML实体(HTML Entity)和 Unicode 十六进制 对应表

这个方法不需要你手动的将十进制转成十六进制,这个图表能够给你一些常见的(或者不是那么常见的)符号的参考:

\ No newline at end of file +CSS 内容和特殊字符 | 云淡风轻

CSS 内容和特殊字符

当我写这个主题theme的时候,我想在我的列表元素(list elements)上用CSS内容(CSS content)属性添加一些**向右双角引号(right-pointing double-angle quotation marks)(<<)**。

所以,我在里面添加了&raquo;,然而,它并不工作!

我花了一点时间去了解到,你不能使用常规的 HTML 实体内容。相反,你必须使用 Unicode 十六进制格式,它看起来像这样:\bb

这是一些你可以轻而易举找到的东西,只因为它出现在了众多课程和参考书里。

将HTML实体转换成Unicode十六进制代码

这里有很多的HTML实体对应表,但是没有更多的 Unicode十六进制表,所以很方便的知道二者之间的转换。你需要知道所有的HTML十进制单位(它们看起来像这样&#123;,而不是像这样&quot;)。
那数字,你猜到了吧,就是十进制格式。我们需要将其转换成Unicode十六进制(我知道,你震惊了!)。

如果你不是一个程序员或者数学天才,可能你不熟悉到底该怎么做(具体请Google)。OK,其实这并不难,但有一个更快捷的方式:

打开类似于经典的Windows计算器,切换到“程序员”视图(View > Programmer)。点击Dec(十进制)单选按钮,输入你的数字然后点击Hex(十六进制)按钮,你就会得到你的十六进制数字。

然后把刚刚得到的数字放到\之后,你就得到了你自己的Unicode十六进制字符。

更容易的方法 - HTML实体(HTML Entity)和 Unicode 十六进制 对应表

这个方法不需要你手动的将十进制转成十六进制,这个图表能够给你一些常见的(或者不是那么常见的)符号的参考:

\ No newline at end of file diff --git a/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/index.html b/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/index.html index 20a6e88f..81b10f70 100644 --- a/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/index.html +++ b/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/index.html @@ -1,2 +1,2 @@ -JavaScript 最佳实践: 提升你代码质量的一些提示&技巧 | 云淡风轻

JavaScript 最佳实践: 提升你代码质量的一些提示&技巧

每天学习新事物是成为一个伟大的人的一部分。而对开发者而言,持续不断学习新的东西是我们工作中的一部分,无论这些东西是否是你主动想学的。

在本教程中,我会指出一些重要的 JavaScript 最佳实践,因此你不必觉得学习它是条艰难的路。准备提升你的代码吧!

避免全局污染(Avoid polluting the global scope)

声明变量(Declaring variables)是很有趣的。有时候,你可能声明了全局变量,即使你不想声明它。在如今的浏览器中,全局变量存储在window对象中。因此,有很多有趣的东西发生在那里,你可能会重写默认值。
让我们假设你有一个HTML文件,其中包含一个<script>标签(或者在加载的 JavaScript 文件中包含):

1
2
var foo = 42;
console.log(foo);

这很显然会在控制台输出42。但是,因为这段代码没有在函数中执行,上下文将是一个全局的。因此,变量是附加到window对象的。这意味着window.foo的值也是42

这是危险的,因为你可以重写已经存在的全局变量:

1
2
3
4
5
function print(){
//do something...
}

print();

因为我们重写了原生的打印弹窗(native print popup),所以当我们执行window.print() (或者只执行print())的时候不会打开打印弹窗(print popup)。

这个问题很好解决,我们需要一个立即调用(called immediately) 的包装函数(wrapping function) (译者注:作者这里可能是要表达一个闭包函数closure function或者是匿名函数anonymous function),像下面的代码:

1
2
3
4
5
6
7
8
9
10
// Declare an anonymous function
// 声明一个匿名函数
(function () {
var foo = 42;
console.log(window.foo);
// → undefined
console.log(foo);
// → 42
})();
//^ and call it immediately

另外,你应该选择发送window和其他的全局变量(如:document)作为函数的参数(这可能会提高性能):

1
2
3
4
5
(function (global, doc) {
global.setTimeout(function () {
doc.body.innerHTML = "Hello!";
}, 1000);
})(window, document);

因此,使用包装函数来防止创建不必要的全局变量。注意,这不是说我在接下来的代码片段使用包装函数,我们应该把关注点放在代码本身。

💡小提示: browserify是另外一种防止创建不必要的全局变量的方式。它和 Node.js 采用的是同样的方式,使用的require function


JavaScript 最佳实践: 提升你代码质量的一些提示&技巧 | 云淡风轻

JavaScript 最佳实践: 提升你代码质量的一些提示&技巧

每天学习新事物是成为一个伟大的人的一部分。而对开发者而言,持续不断学习新的东西是我们工作中的一部分,无论这些东西是否是你主动想学的。

在本教程中,我会指出一些重要的 JavaScript 最佳实践,因此你不必觉得学习它是条艰难的路。准备提升你的代码吧!

避免全局污染(Avoid polluting the global scope)

声明变量(Declaring variables)是很有趣的。有时候,你可能声明了全局变量,即使你不想声明它。在如今的浏览器中,全局变量存储在window对象中。因此,有很多有趣的东西发生在那里,你可能会重写默认值。
让我们假设你有一个HTML文件,其中包含一个<script>标签(或者在加载的 JavaScript 文件中包含):

1
2
var foo = 42;
console.log(foo);

这很显然会在控制台输出42。但是,因为这段代码没有在函数中执行,上下文将是一个全局的。因此,变量是附加到window对象的。这意味着window.foo的值也是42

这是危险的,因为你可以重写已经存在的全局变量:

1
2
3
4
5
function print(){
//do something...
}

print();

因为我们重写了原生的打印弹窗(native print popup),所以当我们执行window.print() (或者只执行print())的时候不会打开打印弹窗(print popup)。

这个问题很好解决,我们需要一个立即调用(called immediately) 的包装函数(wrapping function) (译者注:作者这里可能是要表达一个闭包函数closure function或者是匿名函数anonymous function),像下面的代码:

1
2
3
4
5
6
7
8
9
10
// Declare an anonymous function
// 声明一个匿名函数
(function () {
var foo = 42;
console.log(window.foo);
// → undefined
console.log(foo);
// → 42
})();
//^ and call it immediately

另外,你应该选择发送window和其他的全局变量(如:document)作为函数的参数(这可能会提高性能):

1
2
3
4
5
(function (global, doc) {
global.setTimeout(function () {
doc.body.innerHTML = "Hello!";
}, 1000);
})(window, document);

因此,使用包装函数来防止创建不必要的全局变量。注意,这不是说我在接下来的代码片段使用包装函数,我们应该把关注点放在代码本身。

💡小提示: browserify是另外一种防止创建不必要的全局变量的方式。它和 Node.js 采用的是同样的方式,使用的require function


学习更多关于浏览器开发者工具请点击 Web 开发指南

顺便说一句,Node.js 会在函数里自动打包你的文件,它们看起来像这样:

1
2
(function (exports, require, module, __filename, __dirname) {
// ...

因此,如果这让你认为require函数是全局的那就错了。它只不过是一个函数的参数罢了。

你知道吗?
由于window对象本身就是一个包含全局变量的全局变量,因此它的引用是自身:

1
2
window.window.window
// => Window {...}

那是因为window对象是一个环路对象(circular object),下面演示怎么创建一个这样的对象:

1
2
3
4
5
6
7
8
9
10
// Create an Object
var foo = {};

// Point a key value to the object itself
// 设置一个key,值为它本身
foo.bar = foo;

// The `foo` object just became a circular one:
foo.bar.bar.bar
// → foo

或者,去展现你对JavaScript 的爱,你可以做得更好:

Yes,你可以无限的扩展这个对象(大概直到你的浏览器崩溃).

使用严格模式(use strict)

严格的使用use strict!这只不过是(译者注:这里原作者可能是想表达不仅仅是)在你的代码脚本中添加字符串而已。
举个栗子:

1
2
3
4
5
6
7
8
// This is bad, since you do create a global without having anyone to tell you
(function () {
a = 42;
console.log(a);
// → 42
})();
console.log(a);
// → 42

使用use strict,你可以得到更多的确切的错误:

1
2
3
4
5
(function () {
"use strict";
a = 42;
// Error: Uncaught ReferenceError: a is not defined
})();

你可能会奇怪,为什么不能将use strict 写在函数体外。当然,这是可以的,但它将会应用为全局的范围。这仍然是不错的,但如果你的代码中含有来自其他库的代码,这也会受其影响,或者你把所有的东西都绑定在一个文件里。

严格相等(Strict equal)

这是短的。如果你使用==对比ab(像在其他编程语言),在 JavaScript 中,你可能这种非常奇怪的运行方式:如果你有一个字符串和一个数字,他们是相等的(==):

1
2
"42" == 42
// → true

由于显而易见的原因(如 验证(validations)),最好使用严格相等(===):

1
2
"42" === 42
// → false

使用断言(&&/||)

根据你的需要,你可以使用逻辑运算符是你的代码更简短。
默认值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"" || "foo"
// → "foo"

undefined || 42
// → 42

// Note that if you want to handle 0 there, you need
// to check if a number was provided:
var a = 0;
a || 42
// → 42

// This is a ternary operator—works like an inline if-else statement
var b = typeof a === "number" ? a : 42;
// → 0

检查是否是一个真正的if表达式,你可以简单的这么做:

1
2
3
4
5
6
expr && doSomething();

// Instead of:
if (expr) {
doSomething();
}

你可能会不赞同我这里的写法,但是这是比较理想的。如果你不想用这种方式丑化你的代码,但那些 JavaScript 压缩工具实际上会这么做。

如果你问我,尽管这些代码比较短,但它仍然是人类可读的。

类型转换

有几种方式来转换这些东西,这取决于你想怎么做。最常见的方式是:

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
// From anything to a number

var foo = "42";
var myNumber = +foo; // shortcut for Number(foo)
// → 42

// Tip: you can convert it directly into a negative number
var negativeFoo = -foo; // or -Number(foo)
// → -42

// From object to array
// Tip: `arguments` is an object and in general you want to use it as array
var args = { 0: "foo", 1: "bar", length: 2 };
Array.prototype.slice.call(args)
// → [ 'foo', 'bar' ]

// Anything to boolean
/// Non non p is a boolean p
var t = 1;
var f = 0;
!!t
// → true
!!f
// → false

/// And non-p is a boolean non-p
!t
// → false
!f
// → true

// Anything to string
var foo = 42;
"" + foo // shortcut for String(foo)
// → "42"

foo = { hello: "world" };
JSON.stringify(foo);
// → '{ "hello":"world" }'

JSON.stringify(foo, null, 4); // beautify the things
// →
// '{
// "hello": "world"
// }'

// Note you cannot JSON.stringify circular structures
JSON.stringify(window);
// ⚠ TypeError: JSON.stringify cannot serialize cyclic structures.

代码样式/样式指南

在新项目中,遵循整个文件相同的代码风格。对于现有的,采用已经存在的代码风格,除非你只是决定改变它(提示:同你的合作者商讨)。即使你创建并记录你的代码风格,请始终遵循它。

这里是不同的现有的代码样式:

附加提示

其他重要的 JavaScript 最佳实践,你应该记住的是使用工具帮助你格式化你的代码。这是其中的一些:

  • js-beautify: Beautifies your code
  • UglifyJS(2): Uglifies/minimifies your code
  • jshint: Detects errors/potential problems in your JavaScript code
  • jscs: A configurable style guide checker

最后一件事:Debug your Code

Happy programming!


致谢:@屠夫@QistChan@nApolin@Ant


\ No newline at end of file diff --git a/2016/judgment-variable-type/index.html b/2016/judgment-variable-type/index.html index 6020912e..dafc69e1 100644 --- a/2016/judgment-variable-type/index.html +++ b/2016/judgment-variable-type/index.html @@ -1 +1 @@ -判断变量类型的一些方法 | 云淡风轻

判断变量类型的一些方法

久了不用,就会发现,以前会的东西都会忘记掉(或者是完全想不起来了),不知道你们有没有遇到过这个情况 - -!

这里只是对判断变量类型方法的一些记录,方便以后能够随时查看。

typeof

要判断变量类型,首先想到的就是typeof,但用了才知道,其结果完全不是理想中的:

1
2
3
4
5
6
typeof {};  //"object"
typeof []; //"object"
typeof ""; //"string"
typeof 0; //"number"
typeof function(){};//"function"
typeof true;//"boolean"

由上面代码可以看出,数组也是对象,所以typeof不是我们理想中的解决方案。

当然,有的童鞋可能会说,由于lengthArray特有的属性(非绝对),那是不是可以用length+typeof来判断。

当然,这是可以的:

1
2
3
4
5
var arr = [1,2];
if(typeof arr === 'object'){
console.log(typeof arr.length === "number" ? "array" : "object");//这里输出 "array"
}
//...其他的就不一一罗列了

不过这个方法不通用,如果{key:value}对象中有 length 字段呢,如:

1
2
3
4
5
6
//这种情况对于上面的代码就不适用了
var obj = {
name:"square",
length:50,
width:50
};

instanceof

第二种解决方案就是使用instanceof,不过使用instanceof会出现[] instanceof Object === true的情况。这样就需要优先判断Array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = [1,2,3];
var b = {name:'zhangsan',sex:123};
var fn = function(){};
var detectType = function(o){
if(o instanceof Array){
return 'Array'
}else if( o instanceof Object ){
return 'Object';
}else{
return 'param is no object type';
}
}
console.log( detectType(a) ); // Array
console.log( detectType(b) ); // Object
console.log( detectType(1) ); // param is no object type
console.log( detectType(true) ); // param is no object type
console.log( detectType('a') ); // param is no object type

Object.prototype.toString.call

还有一种最靠谱的办法就是Object.prototype.toString.call:

1
2
3
4
5
6
7
8
9
10
Object.prototype.toString.call([])              //"[object Array]"
Object.prototype.toString.call(Object) //"[object Function]"
Object.prototype.toString.call(function x(){}) //"[object Function]"
Object.prototype.toString.call("") //"[object String]"
Object.prototype.toString.call({}) //"[object Object]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/test/) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"

参考文档

  1. Object.prototype.toString()
\ No newline at end of file +判断变量类型的一些方法 | 云淡风轻

判断变量类型的一些方法

久了不用,就会发现,以前会的东西都会忘记掉(或者是完全想不起来了),不知道你们有没有遇到过这个情况 - -!

这里只是对判断变量类型方法的一些记录,方便以后能够随时查看。

typeof

要判断变量类型,首先想到的就是typeof,但用了才知道,其结果完全不是理想中的:

1
2
3
4
5
6
typeof {};  //"object"
typeof []; //"object"
typeof ""; //"string"
typeof 0; //"number"
typeof function(){};//"function"
typeof true;//"boolean"

由上面代码可以看出,数组也是对象,所以typeof不是我们理想中的解决方案。

当然,有的童鞋可能会说,由于lengthArray特有的属性(非绝对),那是不是可以用length+typeof来判断。

当然,这是可以的:

1
2
3
4
5
var arr = [1,2];
if(typeof arr === 'object'){
console.log(typeof arr.length === "number" ? "array" : "object");//这里输出 "array"
}
//...其他的就不一一罗列了

不过这个方法不通用,如果{key:value}对象中有 length 字段呢,如:

1
2
3
4
5
6
//这种情况对于上面的代码就不适用了
var obj = {
name:"square",
length:50,
width:50
};

instanceof

第二种解决方案就是使用instanceof,不过使用instanceof会出现[] instanceof Object === true的情况。这样就需要优先判断Array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = [1,2,3];
var b = {name:'zhangsan',sex:123};
var fn = function(){};
var detectType = function(o){
if(o instanceof Array){
return 'Array'
}else if( o instanceof Object ){
return 'Object';
}else{
return 'param is no object type';
}
}
console.log( detectType(a) ); // Array
console.log( detectType(b) ); // Object
console.log( detectType(1) ); // param is no object type
console.log( detectType(true) ); // param is no object type
console.log( detectType('a') ); // param is no object type

Object.prototype.toString.call

还有一种最靠谱的办法就是Object.prototype.toString.call:

1
2
3
4
5
6
7
8
9
10
Object.prototype.toString.call([])              //"[object Array]"
Object.prototype.toString.call(Object) //"[object Function]"
Object.prototype.toString.call(function x(){}) //"[object Function]"
Object.prototype.toString.call("") //"[object String]"
Object.prototype.toString.call({}) //"[object Object]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/test/) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"

参考文档

  1. Object.prototype.toString()
\ No newline at end of file diff --git a/2017/add-a-lock-to-your-website/index.html b/2017/add-a-lock-to-your-website/index.html index 3abf1262..9fb93ae7 100644 --- a/2017/add-a-lock-to-your-website/index.html +++ b/2017/add-a-lock-to-your-website/index.html @@ -1 +1 @@ -给你的网站加把锁 -- Let's Encrypt 完全体验 | 云淡风轻

给你的网站加把锁 -- Let's Encrypt 完全体验

今天抽时间将所有的网站SSL证书都更新了成 Let’s Encrypt 了。采用了certbot 这样的自动化工具,配置管理起来非常容易(一本正经的胡说八道),这里将对整个体验过程做个详细记录。

了解 Let’s Encrypt

The project aims to make encrypted connections in the World Wide Web the default case. By getting rid of payment, web server configuration, validation emails and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.On a Linux web server, execution of only two commands is sufficient to set up HTTPS encryption, acquire and install certificates within 20 to 30 seconds.

Let’s Encrypt 是一个2015年末推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。

获取 Let’s Encrypt


Let’s Encrypt 证书生成不需要手动进行,官方推荐 Certbot 这套自动化工具来实现。4步轻松搞定:

  • 下载安装 certbot (Let’s Encrypt项目的自动化工具)
  • 获得SSL证书
  • 修改Nginx配置文件
  • 续订

1. 安装 Certbot

根据 Certbot 官网指南,Debian 8上执行如下命令,安装certbot:

1
2
$ sudo apt-get update
$ sudo apt-get install certbot -t jessie-backports

等安装完成,certbot就可以使用了。

2. 获取SSL证书

Let’s Encrypt提供了通过各种插件获取SSL证书的各种方法。不同的是Apache的插件,大多数的插件只会帮助你得到,你必须手动配置你的Web服务器使用证书。仅获取证书而不安装证书的插件称为“验证器”,因为它们用于验证服务器是否应颁发证书。
下面将使用Webroot的插件来获取SSL证书。

如何使用 Webroot 插件:

Webroot 的工作插件放置在一个特殊的文件/.well-known目录文档根目录下,它可以打开(通过Web服务器)内由让我们的加密服务进行验证。 根据配置的不同,你可能需要明确允许访问/.well-known目录。

为了确保该目录可供Let’s Encrypt进行验证,让我们快速更改我们的Nginx配置。编辑/etc/nginx/conf.d/example.com.conf文件,并将下面代码添加进去:

1
2
3
location ~ /.well-known {
allow all;
}

使用nginx -t测试配置文件是否正确,在正确的情况下,重新让Nginx重新加载配置文件:

1
$ sudo systemctl reload nginx

使用certbot命令获取证书:

1
$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is
  • -w:指定网站所在目录
  • -d:指定要生成证书的域名,如果你想多个域名保存在一个证书里(最多四个)(如example.comwww.example.comthing.ism.thing.is),请确保使用适当的webroot路径和域名替换命令中的相对应部分。

接下来,同意加密订阅协议:

如果一切顺利,你应该看到一个类似下面的输出消息:

IMPORTANT NOTES:

  • Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expire
    on 2017-06-19. To obtain a new or tweaked version of this
    certificate in the future, simply run certbot again. To
    non-interactively renew all of your certificates, run “certbot
    renew”
  • If you like Certbot, please consider supporting our work by:
    Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
    Donating to EFF: https://eff.org/donate-le

证书文件

如果运行顺利,所有服务器所需要的证书就已经生成好了。他们被放在了 /etc/letsencrypt/live/example.com/ 下:

1
2
3
4
5
$ ls /etc/letsencrypt/live/example.com/
cert.pem #server cert only
privkey.pem #private key
chain.pem #intermediates
fullchain.pem #server cert + intermediates

3.修改Nginx配置文件

到这里已经成功一大半了,只需要配置 Nginx 支持刚刚生成的证书。最佳实践可以参考Mozilla SSL Configuration Generator

注意去掉HSTS的勾(勾上会强制https,并且很难消除后续影响)。

请根据自己的服务配置修改和添加内容,重点只需要关注6行

1
2
3
4
5
6
7
8
9
10
11
12
server {  
listen 443 ssl http2;
....
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_trusted_certificate /etc/letsencrypt/live/example.com/root_ca_cert_plus_intermediates;

resolver <IP DNS resolver>;
....
}

dhparam.pem可以通过以下命令生成:

1
2
$ sudo mkdir /etc/nginx/ssl
$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

Nginx 配置完成后重启,用浏览器测试是否一切正常。

4.续订

Let's Encrypt证书有效期只有3个月,所以,需要定时renew。我将使用corntab来执行renew命令:

1
$ sudo crontab -e

添加以下行:

1
30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log && /bin/systemctl reload nginx

保存,并退出。这个定时任务将在每个星期一的凌晨两点半执行certbot renew命令,并重启Nginx。最后将日志输出到/var/log/le-renewal.log

测试你的网站 SSL 安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。

这意味着你网站的HTTPS已经启用成功啦,为自己鼓个掌。 (๑•̀ㅂ•́)و✧。


附:

还有一种方法,不需要访问你的网站目录,但需要临时停止Nginx服务器(需要用到80端口):

  1. 停止Nginx
  2. 域名解析到你的服务器IP
  3. 执行命令:certbot certonly --standalone -d example.com -d www.example.com

然后的步骤就和上面一样啦~~~

以上。

\ No newline at end of file +给你的网站加把锁 -- Let's Encrypt 完全体验 | 云淡风轻

给你的网站加把锁 -- Let's Encrypt 完全体验

今天抽时间将所有的网站SSL证书都更新了成 Let’s Encrypt 了。采用了certbot 这样的自动化工具,配置管理起来非常容易(一本正经的胡说八道),这里将对整个体验过程做个详细记录。

了解 Let’s Encrypt

The project aims to make encrypted connections in the World Wide Web the default case. By getting rid of payment, web server configuration, validation emails and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.On a Linux web server, execution of only two commands is sufficient to set up HTTPS encryption, acquire and install certificates within 20 to 30 seconds.

Let’s Encrypt 是一个2015年末推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。

获取 Let’s Encrypt


Let’s Encrypt 证书生成不需要手动进行,官方推荐 Certbot 这套自动化工具来实现。4步轻松搞定:

  • 下载安装 certbot (Let’s Encrypt项目的自动化工具)
  • 获得SSL证书
  • 修改Nginx配置文件
  • 续订

1. 安装 Certbot

根据 Certbot 官网指南,Debian 8上执行如下命令,安装certbot:

1
2
$ sudo apt-get update
$ sudo apt-get install certbot -t jessie-backports

等安装完成,certbot就可以使用了。

2. 获取SSL证书

Let’s Encrypt提供了通过各种插件获取SSL证书的各种方法。不同的是Apache的插件,大多数的插件只会帮助你得到,你必须手动配置你的Web服务器使用证书。仅获取证书而不安装证书的插件称为“验证器”,因为它们用于验证服务器是否应颁发证书。
下面将使用Webroot的插件来获取SSL证书。

如何使用 Webroot 插件:

Webroot 的工作插件放置在一个特殊的文件/.well-known目录文档根目录下,它可以打开(通过Web服务器)内由让我们的加密服务进行验证。 根据配置的不同,你可能需要明确允许访问/.well-known目录。

为了确保该目录可供Let’s Encrypt进行验证,让我们快速更改我们的Nginx配置。编辑/etc/nginx/conf.d/example.com.conf文件,并将下面代码添加进去:

1
2
3
location ~ /.well-known {
allow all;
}

使用nginx -t测试配置文件是否正确,在正确的情况下,重新让Nginx重新加载配置文件:

1
$ sudo systemctl reload nginx

使用certbot命令获取证书:

1
$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is
  • -w:指定网站所在目录
  • -d:指定要生成证书的域名,如果你想多个域名保存在一个证书里(最多四个)(如example.comwww.example.comthing.ism.thing.is),请确保使用适当的webroot路径和域名替换命令中的相对应部分。

接下来,同意加密订阅协议:

如果一切顺利,你应该看到一个类似下面的输出消息:

IMPORTANT NOTES:

  • Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expire
    on 2017-06-19. To obtain a new or tweaked version of this
    certificate in the future, simply run certbot again. To
    non-interactively renew all of your certificates, run “certbot
    renew”
  • If you like Certbot, please consider supporting our work by:
    Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
    Donating to EFF: https://eff.org/donate-le

证书文件

如果运行顺利,所有服务器所需要的证书就已经生成好了。他们被放在了 /etc/letsencrypt/live/example.com/ 下:

1
2
3
4
5
$ ls /etc/letsencrypt/live/example.com/
cert.pem #server cert only
privkey.pem #private key
chain.pem #intermediates
fullchain.pem #server cert + intermediates

3.修改Nginx配置文件

到这里已经成功一大半了,只需要配置 Nginx 支持刚刚生成的证书。最佳实践可以参考Mozilla SSL Configuration Generator

注意去掉HSTS的勾(勾上会强制https,并且很难消除后续影响)。

请根据自己的服务配置修改和添加内容,重点只需要关注6行

1
2
3
4
5
6
7
8
9
10
11
12
server {  
listen 443 ssl http2;
....
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_trusted_certificate /etc/letsencrypt/live/example.com/root_ca_cert_plus_intermediates;

resolver <IP DNS resolver>;
....
}

dhparam.pem可以通过以下命令生成:

1
2
$ sudo mkdir /etc/nginx/ssl
$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

Nginx 配置完成后重启,用浏览器测试是否一切正常。

4.续订

Let's Encrypt证书有效期只有3个月,所以,需要定时renew。我将使用corntab来执行renew命令:

1
$ sudo crontab -e

添加以下行:

1
30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log && /bin/systemctl reload nginx

保存,并退出。这个定时任务将在每个星期一的凌晨两点半执行certbot renew命令,并重启Nginx。最后将日志输出到/var/log/le-renewal.log

测试你的网站 SSL 安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。

这意味着你网站的HTTPS已经启用成功啦,为自己鼓个掌。 (๑•̀ㅂ•́)و✧。


附:

还有一种方法,不需要访问你的网站目录,但需要临时停止Nginx服务器(需要用到80端口):

  1. 停止Nginx
  2. 域名解析到你的服务器IP
  3. 执行命令:certbot certonly --standalone -d example.com -d www.example.com

然后的步骤就和上面一样啦~~~

以上。

\ No newline at end of file diff --git a/2017/add-valine-comments-to-your-blog/index.html b/2017/add-valine-comments-to-your-blog/index.html index 539624ec..b2e19c85 100644 --- a/2017/add-valine-comments-to-your-blog/index.html +++ b/2017/add-valine-comments-to-your-blog/index.html @@ -1 +1 @@ -Valine -- 一款极简的评论系统 | 云淡风轻

Valine -- 一款极简的评论系统

Valine

Valine - 一款极简的无后端评论系统.

2017年6月1日,在你等超龄儿童欢度节日的时候,多说躺下了。
2017年8月1日,不甘寂寞的网易云跟帖也跟多说随风而去了。

2017年8月7日,一款基于Leancloud的极简风评论系统诞生:Valine

食用方法

获取 APP IDAPP KEY

  1. 点击这里登录或注册Leancloud
  2. 点这里创建应用,应用名看个人喜好。
  3. 选择刚刚创建的应用>设置>选择应用 Key,然后你就能看到你的APP IDAPP KEY了,参考下图:
  4. 为了您的数据安全,请填写应用>设置>安全设置中的Web 安全域名,如下图:

页面中的设置

页面中的食用方法炒鸡简单,来来来,我们用代码说话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Valine - A simple comment system based on Leancloud.</title>
<!--Leancloud 操作库:-->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<!--Valine 的核心代码库:-->
<script src="./dist/Valine.min.js"></script>
</head>
<body>
<div class="comment"></div>
<script>
new Valine({
// AV 对象来自上面引入av-min.js(老司机们不要开车➳♡゛扎心了老铁)
av: AV,
el: '.comment', //
app_id: 'Your APP ID', // 这里填写上面得到的APP ID
app_key: 'Your APP KEY', // 这里填写上面得到的APP KEY
placeholder: 'ヾノ≧∀≦)o来啊,快活啊!' // [v1.0.7 new]留言框占位提示文字
});
</script>
</body>
</html>

看吧,我是不是没说大话(_(:з」∠)_一本正经的胡说八道)。

评论数据管理

插播一下,关于评论数据管理,请自行登录Leancloud应用管理。
具体步骤:登录>选择你创建的应用>存储>选择ClassComment,然后就可以尽情的发挥你的权利啦(~ ̄▽ ̄)~


更多配置信息请移步:https://valine.js.org


–EOF–

\ No newline at end of file +Valine -- 一款极简的评论系统 | 云淡风轻

Valine -- 一款极简的评论系统

Valine

Valine - 一款极简的无后端评论系统.

2017年6月1日,在你等超龄儿童欢度节日的时候,多说躺下了。
2017年8月1日,不甘寂寞的网易云跟帖也跟多说随风而去了。

2017年8月7日,一款基于Leancloud的极简风评论系统诞生:Valine

食用方法

获取 APP IDAPP KEY

  1. 点击这里登录或注册Leancloud
  2. 点这里创建应用,应用名看个人喜好。
  3. 选择刚刚创建的应用>设置>选择应用 Key,然后你就能看到你的APP IDAPP KEY了,参考下图:
  4. 为了您的数据安全,请填写应用>设置>安全设置中的Web 安全域名,如下图:

页面中的设置

页面中的食用方法炒鸡简单,来来来,我们用代码说话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Valine - A simple comment system based on Leancloud.</title>
<!--Leancloud 操作库:-->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<!--Valine 的核心代码库:-->
<script src="./dist/Valine.min.js"></script>
</head>
<body>
<div class="comment"></div>
<script>
new Valine({
// AV 对象来自上面引入av-min.js(老司机们不要开车➳♡゛扎心了老铁)
av: AV,
el: '.comment', //
app_id: 'Your APP ID', // 这里填写上面得到的APP ID
app_key: 'Your APP KEY', // 这里填写上面得到的APP KEY
placeholder: 'ヾノ≧∀≦)o来啊,快活啊!' // [v1.0.7 new]留言框占位提示文字
});
</script>
</body>
</html>

看吧,我是不是没说大话(_(:з」∠)_一本正经的胡说八道)。

评论数据管理

插播一下,关于评论数据管理,请自行登录Leancloud应用管理。
具体步骤:登录>选择你创建的应用>存储>选择ClassComment,然后就可以尽情的发挥你的权利啦(~ ̄▽ ̄)~


更多配置信息请移步:https://valine.js.org


–EOF–

\ No newline at end of file diff --git a/2017/country-city-and-language/index.html b/2017/country-city-and-language/index.html index c4d5c0d0..09bb52a6 100644 --- a/2017/country-city-and-language/index.html +++ b/2017/country-city-and-language/index.html @@ -1 +1 @@ -不同的国家/地区与语言缩写代码 | 云淡风轻

不同的国家/地区与语言缩写代码

国家/地区语言代码国家地区语言代码
简体中文(中国)zh-cn简体中文(台湾地区)zh-tw
繁体中文(香港)zh-hk英语(香港)en-hk
英语(美国)en-us英语(英国)en-gb
英语(全球)en-ww英语(加拿大)en-ca
英语(澳大利亚)en-au英语(爱尔兰)en-ie
英语(芬兰)en-fi芬兰语(芬兰)fi-fi
英语(丹麦)en-dk丹麦语(丹麦)da-dk
英语(以色列)en-il希伯来语(以色列)he-il
英语(南非)en-za英语(印度)en-in
英语(挪威)en-no英语(新加坡)en-sg
英语(新西兰)en-nz英语(印度尼西亚)en-id
英语(菲律宾)en-ph英语(泰国)en-th
英语(马来西亚)en-my英语(阿拉伯)en-xa
韩文(韩国)ko-kr日语(日本)ja-jp
荷兰语(荷兰)nl-nl荷兰语(比利时)nl-be
葡萄牙语(葡萄牙)pt-pt葡萄牙语(巴西)pt-br
法语(法国)fr-fr法语(卢森堡)fr-lu
法语(瑞士)fr-ch法语(比利时)fr-be
法语(加拿大)fr-ca西班牙语(拉丁美洲)es-la
西班牙语(西班牙)es-es西班牙语(阿根廷)es-ar
西班牙语(美国)es-us西班牙语(墨西哥)es-mx
西班牙语(哥伦比亚)es-co西班牙语(波多黎各)es-pr
德语(德国)de-de德语(奥地利)de-at
德语(瑞士)de-ch俄语(俄罗斯)ru-ru
意大利语(意大利)it-it希腊语(希腊)el-gr
挪威语(挪威)no-no匈牙利语(匈牙利)hu-hu
土耳其语(土耳其)tr-tr捷克语(捷克共和国)cs-cz
斯洛文尼亚语sl-sl波兰语(波兰)pl-pl
瑞典语(瑞典)sv-se西班牙语 (智利)es-cl
\ No newline at end of file +不同的国家/地区与语言缩写代码 | 云淡风轻

不同的国家/地区与语言缩写代码

国家/地区语言代码国家地区语言代码
简体中文(中国)zh-cn简体中文(台湾地区)zh-tw
繁体中文(香港)zh-hk英语(香港)en-hk
英语(美国)en-us英语(英国)en-gb
英语(全球)en-ww英语(加拿大)en-ca
英语(澳大利亚)en-au英语(爱尔兰)en-ie
英语(芬兰)en-fi芬兰语(芬兰)fi-fi
英语(丹麦)en-dk丹麦语(丹麦)da-dk
英语(以色列)en-il希伯来语(以色列)he-il
英语(南非)en-za英语(印度)en-in
英语(挪威)en-no英语(新加坡)en-sg
英语(新西兰)en-nz英语(印度尼西亚)en-id
英语(菲律宾)en-ph英语(泰国)en-th
英语(马来西亚)en-my英语(阿拉伯)en-xa
韩文(韩国)ko-kr日语(日本)ja-jp
荷兰语(荷兰)nl-nl荷兰语(比利时)nl-be
葡萄牙语(葡萄牙)pt-pt葡萄牙语(巴西)pt-br
法语(法国)fr-fr法语(卢森堡)fr-lu
法语(瑞士)fr-ch法语(比利时)fr-be
法语(加拿大)fr-ca西班牙语(拉丁美洲)es-la
西班牙语(西班牙)es-es西班牙语(阿根廷)es-ar
西班牙语(美国)es-us西班牙语(墨西哥)es-mx
西班牙语(哥伦比亚)es-co西班牙语(波多黎各)es-pr
德语(德国)de-de德语(奥地利)de-at
德语(瑞士)de-ch俄语(俄罗斯)ru-ru
意大利语(意大利)it-it希腊语(希腊)el-gr
挪威语(挪威)no-no匈牙利语(匈牙利)hu-hu
土耳其语(土耳其)tr-tr捷克语(捷克共和国)cs-cz
斯洛文尼亚语sl-sl波兰语(波兰)pl-pl
瑞典语(瑞典)sv-se西班牙语 (智利)es-cl
\ No newline at end of file diff --git a/2017/git-command-backup/index.html b/2017/git-command-backup/index.html index 9b0c209d..967f4d8c 100644 --- a/2017/git-command-backup/index.html +++ b/2017/git-command-backup/index.html @@ -1 +1 @@ -Git中的一些骚操作 | 云淡风轻

Git中的一些骚操作

最近因为Valine,所以经常用到Git。当然,工作中也有用到,但基本上是用的图形化

这里最Git的相关操作命令做个备份,以备不时之需。

可能不定时更新。

配置自动换行

1
git config --global core.autocrlf input # 提交时自动将换行符转成lf

多账号配置SSH

修改~/.ssh/config文件(Windows平台)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置 Github.com
Host github.com
HostName github.com
IdentityFile C:\\path\\to\\.ssh\\id_rsa_github
PreferredAuthentications publickey
User YourName

# 配置 Coding.net
Host git.coding.net
HostName git.coding.net
IdentityFile C:\\path\\to\\.ssh\\id_rsa_coding
PreferredAuthentications publickey
User YourName

# 配置 Gitee.com
Host gitee.com
HostName gitee.com
IdentityFile C:\\path\\to\\.ssh\\id_rsa_gitee
PreferredAuthentications publickey
User YourName

pull 强制覆盖本地文件

1
2
git fetch --all  
git reset --hard origin/master

push 强制覆盖远程文件

1
git push -f origin master 

保持fork之后的项目和上游同步

团队协作,为了规范,一般都是fork组织的仓库到自己帐号下,再提交pr,组织的仓库一直保持更新,下面介绍如何保持自己fork之后的仓库与上游仓库同步。

下面以我 fork 团队的博客仓库为例

点击 fork 组织仓库到自己帐号下,然后就可以在自己的帐号下 clone 相应的仓库

使用 git remote -v 查看当前的远程仓库地址,输出如下:

1
2
origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin git@github.com:ibrother/staticblog.github.io.git (push)

可以看到从自己帐号 clone 下来的仓库,远程仓库地址是与自己的远程仓库绑定的(这不是废话吗)

接下来运行:

1
git remote add upstream https://github.com/staticblog/staticblog.github.io.git

这条命令就算添加一个别名为 upstream(上游)的地址,指向之前 fork 的原仓库地址。git remote -v 输出如下:

1
2
3
4
origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin git@github.com:ibrother/staticblog.github.io.git (push)
upstream https://github.com/staticblog/staticblog.github.io.git (fetch)
upstream https://github.com/staticblog/staticblog.github.io.git (push)

之后运行下面几条命令,就可以保持本地仓库和上游仓库同步了

1
2
3
git fetch upstream
git checkout master
git merge upstream/master

接着就是熟悉的推送本地仓库到远程仓库

1
git push origin master

From staticblog .

\ No newline at end of file +Git中的一些骚操作 | 云淡风轻

Git中的一些骚操作

最近因为Valine,所以经常用到Git。当然,工作中也有用到,但基本上是用的图形化

这里最Git的相关操作命令做个备份,以备不时之需。

可能不定时更新。

配置自动换行

1
git config --global core.autocrlf input # 提交时自动将换行符转成lf

多账号配置SSH

修改~/.ssh/config文件(Windows平台)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置 Github.com
Host github.com
HostName github.com
IdentityFile C:\\path\\to\\.ssh\\id_rsa_github
PreferredAuthentications publickey
User YourName

# 配置 Coding.net
Host git.coding.net
HostName git.coding.net
IdentityFile C:\\path\\to\\.ssh\\id_rsa_coding
PreferredAuthentications publickey
User YourName

# 配置 Gitee.com
Host gitee.com
HostName gitee.com
IdentityFile C:\\path\\to\\.ssh\\id_rsa_gitee
PreferredAuthentications publickey
User YourName

pull 强制覆盖本地文件

1
2
git fetch --all  
git reset --hard origin/master

push 强制覆盖远程文件

1
git push -f origin master 

保持fork之后的项目和上游同步

团队协作,为了规范,一般都是fork组织的仓库到自己帐号下,再提交pr,组织的仓库一直保持更新,下面介绍如何保持自己fork之后的仓库与上游仓库同步。

下面以我 fork 团队的博客仓库为例

点击 fork 组织仓库到自己帐号下,然后就可以在自己的帐号下 clone 相应的仓库

使用 git remote -v 查看当前的远程仓库地址,输出如下:

1
2
origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin git@github.com:ibrother/staticblog.github.io.git (push)

可以看到从自己帐号 clone 下来的仓库,远程仓库地址是与自己的远程仓库绑定的(这不是废话吗)

接下来运行:

1
git remote add upstream https://github.com/staticblog/staticblog.github.io.git

这条命令就算添加一个别名为 upstream(上游)的地址,指向之前 fork 的原仓库地址。git remote -v 输出如下:

1
2
3
4
origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin git@github.com:ibrother/staticblog.github.io.git (push)
upstream https://github.com/staticblog/staticblog.github.io.git (fetch)
upstream https://github.com/staticblog/staticblog.github.io.git (push)

之后运行下面几条命令,就可以保持本地仓库和上游仓库同步了

1
2
3
git fetch upstream
git checkout master
git merge upstream/master

接着就是熟悉的推送本地仓库到远程仓库

1
git push origin master

From staticblog .

\ No newline at end of file diff --git a/2017/mysql-tutorial/index.html b/2017/mysql-tutorial/index.html index 677af6ed..b26779bc 100644 --- a/2017/mysql-tutorial/index.html +++ b/2017/mysql-tutorial/index.html @@ -1 +1 @@ -从删库到跑路 -- MySql 不算初体验的初体验 | 云淡风轻

从删库到跑路 -- MySql 不算初体验的初体验

最近准备找时间把bing壁纸项目重构,但由于虚拟主机快要过期了,所以目前的首要任务是将数据库从阿里云的虚拟主机转移到我自己的服务器上。

因为多年前学过SQLServer、Oracle、MySql等数据库,但许久未用,技艺生疏,所以这里是不算初体验的初体验。

本文将执行三步走计划:

  • 安装
  • 登录
  • 使用

安装

在Debian上安装MySql很简单,运行如下命令就基本OK:

1
$ apt-get install mysql-server mysql-client

其中mysql-server是服务器程序,mysql-client是客户端程序。安装过程中会有如下提示,需要设置mysql数据库密码;输入要设置的密码后,回车即可继续安装。

如果出现Unable to locate package mysql-server等错误,请先执行apt-get update后重试。

登录

安装成功后,mysql会自动启动,可以通过ps -ef | grep mysql查看mysql是否运行。
登陆mysql:

1
2
3
# login
$ mysql -u root -p
Enter password: # 输入密码

其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。

查看数据库show databases;

1
2
3
4
5
6
7
8
9
10
$ mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)

使用

创建数据库

1
2
$ mysql> create database DB_name;
Query OK, 1 row affected (0.05 sec)

查看刚刚创建的数据库

1
2
3
4
5
6
7
8
9
10
11
$ mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| DB_name |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)

使用刚刚创建的数据库

1
2
$ mysql> use DB_name;
Database changed

创建表

1
2
3
4
5
$ mysql> CREATE TABLE IF NOT EXISTS person (
number INT(11),
name VARCHAR(255),
birthday DATE
);

查看表

1
2
3
4
5
6
7
$ mysql> SHOW CREATE table person;

CREATE TABLE `person` (
`number` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

查看表的所有列

1
2
3
4
5
6
7
8
$ mysql> SHOW FULL COLUMNS from person;
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| number | int(11) | NULL | YES | | NULL | | select,insert,update,references | |
| name | varchar(255) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| birthday | date | NULL | YES | | NULL | | select,insert,update,references | |
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+

创建临时表

1
2
3
4
5
$ mysql> CREATE TEMPORARY TABLE temp_person (
number INT(11),
name VARCHAR(255),
birthday DATE
);

删除表

1
2
3
$ mysql> DROP TABLE temp_person;
# or
$ mysql> DROP TABLE IF EXISTS temp_person;

创建用户

命令:

1
$mysql> CREATE USER 'username'@'host' IDENTIFIED BY 'password';

说明:

  • username:你将创建的用户名
  • host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符%
  • password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器

例子:

1
2
3
4
5
$mysql> CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';
$mysql> CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';
$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '123456';
$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '';
$mysql> CREATE USER 'pig'@'%';

授权

命令:

1
$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host'

说明:

  • privileges:用户的操作权限,如SELECTINSERTUPDATE等,如果要授予所的权限则使用ALL
  • databasename:数据库名
  • tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*
    例子:
    1
    2
    $mysql> GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
    $mysql> GRANT ALL ON *.* TO 'pig'@'%';

    注意
    用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:

    1
    $mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;

设置与更改用户密码

命令:

1
$mysql> SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');

如果是当前登陆用户用:

1
>$mysql> SET PASSWORD = PASSWORD("newpassword");

例子:

1
$mysql> SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456");

撤销用户权限

命令:

1
$mysql> REVOKE privilege ON databasename.tablename FROM 'username'@'host';

说明:
privilege, databasename, tablename同授权部分
例子:

1
$mysql> REVOKE SELECT ON *.* FROM 'pig'@'%';

注意:
假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):GRANT SELECT ON test.user TO 'pig'@'%',则在使用REVOKE SELECT ON *.* FROM 'pig'@'%';
命令并不能撤销该用户对test数据库中user表的SELECT 操作。
相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%', 则REVOKE SELECT ON test.user FROM 'pig'@'%';
命令也不能撤销该用户对test数据库中user表的SELECT权限。
具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看。

删除用户

1
$mysql> DROP USER 'username'@'host';

最后

能看到这里,那就先要恭喜你了,你已经成功达成建库、建表、建用户到删表、删库、删用户等成就。那还等什么?赶紧跑路吧ε=ε=ε=┏(゜ロ゜;)┛


附:

\ No newline at end of file +从删库到跑路 -- MySql 不算初体验的初体验 | 云淡风轻

从删库到跑路 -- MySql 不算初体验的初体验

最近准备找时间把bing壁纸项目重构,但由于虚拟主机快要过期了,所以目前的首要任务是将数据库从阿里云的虚拟主机转移到我自己的服务器上。

因为多年前学过SQLServer、Oracle、MySql等数据库,但许久未用,技艺生疏,所以这里是不算初体验的初体验。

本文将执行三步走计划:

  • 安装
  • 登录
  • 使用

安装

在Debian上安装MySql很简单,运行如下命令就基本OK:

1
$ apt-get install mysql-server mysql-client

其中mysql-server是服务器程序,mysql-client是客户端程序。安装过程中会有如下提示,需要设置mysql数据库密码;输入要设置的密码后,回车即可继续安装。

如果出现Unable to locate package mysql-server等错误,请先执行apt-get update后重试。

登录

安装成功后,mysql会自动启动,可以通过ps -ef | grep mysql查看mysql是否运行。
登陆mysql:

1
2
3
# login
$ mysql -u root -p
Enter password: # 输入密码

其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。

查看数据库show databases;

1
2
3
4
5
6
7
8
9
10
$ mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)

使用

创建数据库

1
2
$ mysql> create database DB_name;
Query OK, 1 row affected (0.05 sec)

查看刚刚创建的数据库

1
2
3
4
5
6
7
8
9
10
11
$ mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| DB_name |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)

使用刚刚创建的数据库

1
2
$ mysql> use DB_name;
Database changed

创建表

1
2
3
4
5
$ mysql> CREATE TABLE IF NOT EXISTS person (
number INT(11),
name VARCHAR(255),
birthday DATE
);

查看表

1
2
3
4
5
6
7
$ mysql> SHOW CREATE table person;

CREATE TABLE `person` (
`number` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

查看表的所有列

1
2
3
4
5
6
7
8
$ mysql> SHOW FULL COLUMNS from person;
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| number | int(11) | NULL | YES | | NULL | | select,insert,update,references | |
| name | varchar(255) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| birthday | date | NULL | YES | | NULL | | select,insert,update,references | |
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+

创建临时表

1
2
3
4
5
$ mysql> CREATE TEMPORARY TABLE temp_person (
number INT(11),
name VARCHAR(255),
birthday DATE
);

删除表

1
2
3
$ mysql> DROP TABLE temp_person;
# or
$ mysql> DROP TABLE IF EXISTS temp_person;

创建用户

命令:

1
$mysql> CREATE USER 'username'@'host' IDENTIFIED BY 'password';

说明:

  • username:你将创建的用户名
  • host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符%
  • password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器

例子:

1
2
3
4
5
$mysql> CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';
$mysql> CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';
$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '123456';
$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '';
$mysql> CREATE USER 'pig'@'%';

授权

命令:

1
$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host'

说明:

  • privileges:用户的操作权限,如SELECTINSERTUPDATE等,如果要授予所的权限则使用ALL
  • databasename:数据库名
  • tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*
    例子:
    1
    2
    $mysql> GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
    $mysql> GRANT ALL ON *.* TO 'pig'@'%';

    注意
    用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:

    1
    $mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;

设置与更改用户密码

命令:

1
$mysql> SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');

如果是当前登陆用户用:

1
>$mysql> SET PASSWORD = PASSWORD("newpassword");

例子:

1
$mysql> SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456");

撤销用户权限

命令:

1
$mysql> REVOKE privilege ON databasename.tablename FROM 'username'@'host';

说明:
privilege, databasename, tablename同授权部分
例子:

1
$mysql> REVOKE SELECT ON *.* FROM 'pig'@'%';

注意:
假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):GRANT SELECT ON test.user TO 'pig'@'%',则在使用REVOKE SELECT ON *.* FROM 'pig'@'%';
命令并不能撤销该用户对test数据库中user表的SELECT 操作。
相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%', 则REVOKE SELECT ON test.user FROM 'pig'@'%';
命令也不能撤销该用户对test数据库中user表的SELECT权限。
具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看。

删除用户

1
$mysql> DROP USER 'username'@'host';

最后

能看到这里,那就先要恭喜你了,你已经成功达成建库、建表、建用户到删表、删库、删用户等成就。那还等什么?赶紧跑路吧ε=ε=ε=┏(゜ロ゜;)┛


附:

\ No newline at end of file diff --git a/2024/upgrade-debian-kernel-version/index.html b/2024/upgrade-debian-kernel-version/index.html index 698c0cb4..784fdeb7 100644 --- a/2024/upgrade-debian-kernel-version/index.html +++ b/2024/upgrade-debian-kernel-version/index.html @@ -1 +1 @@ -在Debian 11上升级内核并启用BBR加速 | 云淡风轻

在Debian 11上升级内核并启用BBR加速

如果你正在使用Debian 11并且希望提升你的系统性能,升级到最新的内核版本并启用BBR加速可能是一个不错的选择。以下是一篇指南,将带你了解如何安全地升级内核以及如何启用BBR来优化你的网络连接。

升级到新版内核

第一步:备份你的系统

在进行任何重大系统更改之前,备份是非常重要的。你可以使用如Timeshift等工具来备份你的系统。

第二步:修改软件源

为了安装最新的内核,我们可能需要添加Debian的Backports源。以下是添加Backports源的步骤:

  1. 打开/etc/apt/sources.list文件:

    1
    sudo nano /etc/apt/sources.list
  2. 在文件末尾添加以下行:

    1
    2
    deb http://deb.debian.org/debian bullseye-backports main contrib non-free
    deb-src http://deb.debian.org/debian bullseye-backports main contrib non-free
  3. 保存并退出编辑器。

  4. 更新软件包列表:

    1
    sudo apt update

第三步:安装新内核

使用Backports源安装新内核:

1
2
sudo apt-get -t bullseye-backports install linux-image-6.x.x-x-amd64
sudo apt-get -t bullseye-backports install linux-headers-6.x.x-x-amd64

请确保替换命令中的版本号为你想要安装的实际版本。

第四步:更新GRUB并重启

安装完新内核后,更新GRUB:

1
sudo update-grub

然后重启你的系统:

1
sudo reboot

清除旧内核

第一步:列出当前内核

使用以下命令查看当前安装的内核:

1
2
dpkg --list | grep linux-image
dpkg --list | grep linux-headers

第二步:删除旧内核

选择你不再需要的内核版本,并使用apt-get purge命令进行删除:

1
2
sudo apt-get purge linux-image-5.x.x-x-amd64
sudo apt-get purge linux-headers-5.x.x-x-amd64

第三步:更新GRUB

再次更新GRUB配置:

1
sudo update-grub

启用BBR加速

第一步:加载TCP BBR模块

编辑/etc/sysctl.conf文件,在文件末尾添加以下两行:

1
2
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

第二步:应用新的系统配置

应用新的配置:

1
sudo sysctl -p

第三步:验证BBR是否启用

运行以下命令:

1
sysctl net.ipv4.tcp_congestion_control

如果输出显示bbr,则BBR已启用。

结语

现在,你的Debian 11系统应该运行在最新的内核上,并且已经启用了BBR加速。这将帮助你提高系统的整体性能和网络连接的速度。请确保在执行以上操作时仔细检查,并始终保持系统的备份。

参考

\ No newline at end of file +在Debian 11上升级内核并启用BBR加速 | 云淡风轻

在Debian 11上升级内核并启用BBR加速

如果你正在使用Debian 11并且希望提升你的系统性能,升级到最新的内核版本并启用BBR加速可能是一个不错的选择。以下是一篇指南,将带你了解如何安全地升级内核以及如何启用BBR来优化你的网络连接。

升级到新版内核

第一步:备份你的系统

在进行任何重大系统更改之前,备份是非常重要的。你可以使用如Timeshift等工具来备份你的系统。

第二步:修改软件源

为了安装最新的内核,我们可能需要添加Debian的Backports源。以下是添加Backports源的步骤:

  1. 打开/etc/apt/sources.list文件:

    1
    sudo nano /etc/apt/sources.list
  2. 在文件末尾添加以下行:

    1
    2
    deb http://deb.debian.org/debian bullseye-backports main contrib non-free
    deb-src http://deb.debian.org/debian bullseye-backports main contrib non-free
  3. 保存并退出编辑器。

  4. 更新软件包列表:

    1
    sudo apt update

第三步:安装新内核

使用Backports源安装新内核:

1
2
sudo apt-get -t bullseye-backports install linux-image-6.x.x-x-amd64
sudo apt-get -t bullseye-backports install linux-headers-6.x.x-x-amd64

请确保替换命令中的版本号为你想要安装的实际版本。

第四步:更新GRUB并重启

安装完新内核后,更新GRUB:

1
sudo update-grub

然后重启你的系统:

1
sudo reboot

清除旧内核

第一步:列出当前内核

使用以下命令查看当前安装的内核:

1
2
dpkg --list | grep linux-image
dpkg --list | grep linux-headers

第二步:删除旧内核

选择你不再需要的内核版本,并使用apt-get purge命令进行删除:

1
2
sudo apt-get purge linux-image-5.x.x-x-amd64
sudo apt-get purge linux-headers-5.x.x-x-amd64

第三步:更新GRUB

再次更新GRUB配置:

1
sudo update-grub

启用BBR加速

第一步:加载TCP BBR模块

编辑/etc/sysctl.conf文件,在文件末尾添加以下两行:

1
2
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

第二步:应用新的系统配置

应用新的配置:

1
sudo sysctl -p

第三步:验证BBR是否启用

运行以下命令:

1
sysctl net.ipv4.tcp_congestion_control

如果输出显示bbr,则BBR已启用。

结语

现在,你的Debian 11系统应该运行在最新的内核上,并且已经启用了BBR加速。这将帮助你提高系统的整体性能和网络连接的速度。请确保在执行以上操作时仔细检查,并始终保持系统的备份。

参考

\ No newline at end of file diff --git a/404.html b/404.html index de93281d..27428f26 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ -404 Not Found:该页无法显示 | 云淡风轻
\ No newline at end of file +404 Not Found:该页无法显示 | 云淡风轻
\ No newline at end of file diff --git a/about/index.html b/about/index.html index 3b8c1a2f..fac31f33 100644 --- a/about/index.html +++ b/about/index.html @@ -1 +1 @@ -关于 | 云淡风轻

关于

个人简介

这个人很懒,什么都没有留下!

\ No newline at end of file +关于 | 云淡风轻

关于

个人简介

这个人很懒,什么都没有留下!

\ No newline at end of file diff --git a/archives/2015/05/index.html b/archives/2015/05/index.html index 08869239..5e2e736a 100644 --- a/archives/2015/05/index.html +++ b/archives/2015/05/index.html @@ -1 +1 @@ -归档: 2015/5 | 云淡风轻
\ No newline at end of file +归档: 2015/5 | 云淡风轻
\ No newline at end of file diff --git a/archives/2015/12/index.html b/archives/2015/12/index.html index ce5467ff..be11693e 100644 --- a/archives/2015/12/index.html +++ b/archives/2015/12/index.html @@ -1 +1 @@ -归档: 2015/12 | 云淡风轻
\ No newline at end of file +归档: 2015/12 | 云淡风轻
\ No newline at end of file diff --git a/archives/2015/index.html b/archives/2015/index.html index 9be16a1d..8f43ded9 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -1 +1 @@ -归档: 2015 | 云淡风轻
\ No newline at end of file +归档: 2015 | 云淡风轻
\ No newline at end of file diff --git a/archives/2016/05/index.html b/archives/2016/05/index.html index 7ea452b8..6b7d5be6 100644 --- a/archives/2016/05/index.html +++ b/archives/2016/05/index.html @@ -1 +1 @@ -归档: 2016/5 | 云淡风轻
\ No newline at end of file +归档: 2016/5 | 云淡风轻
\ No newline at end of file diff --git a/archives/2016/09/index.html b/archives/2016/09/index.html index 35a92711..f9f4232b 100644 --- a/archives/2016/09/index.html +++ b/archives/2016/09/index.html @@ -1 +1 @@ -归档: 2016/9 | 云淡风轻
\ No newline at end of file +归档: 2016/9 | 云淡风轻
\ No newline at end of file diff --git a/archives/2016/index.html b/archives/2016/index.html index c3fbba55..84feabc1 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -1 +1 @@ -归档: 2016 | 云淡风轻
\ No newline at end of file +归档: 2016 | 云淡风轻
\ No newline at end of file diff --git a/archives/2017/03/index.html b/archives/2017/03/index.html index f850c36b..1af36d22 100644 --- a/archives/2017/03/index.html +++ b/archives/2017/03/index.html @@ -1 +1 @@ -归档: 2017/3 | 云淡风轻
\ No newline at end of file +归档: 2017/3 | 云淡风轻
\ No newline at end of file diff --git a/archives/2017/06/index.html b/archives/2017/06/index.html index d071c176..b1b46520 100644 --- a/archives/2017/06/index.html +++ b/archives/2017/06/index.html @@ -1 +1 @@ -归档: 2017/6 | 云淡风轻
\ No newline at end of file +归档: 2017/6 | 云淡风轻
\ No newline at end of file diff --git a/archives/2017/08/index.html b/archives/2017/08/index.html index f574ac4f..7d0ef6a4 100644 --- a/archives/2017/08/index.html +++ b/archives/2017/08/index.html @@ -1 +1 @@ -归档: 2017/8 | 云淡风轻
\ No newline at end of file +归档: 2017/8 | 云淡风轻
\ No newline at end of file diff --git a/archives/2017/11/index.html b/archives/2017/11/index.html index f1cdbdd1..319689e7 100644 --- a/archives/2017/11/index.html +++ b/archives/2017/11/index.html @@ -1 +1 @@ -归档: 2017/11 | 云淡风轻
\ No newline at end of file +归档: 2017/11 | 云淡风轻
\ No newline at end of file diff --git a/archives/2017/index.html b/archives/2017/index.html index 3eca87fa..bad0cd81 100644 --- a/archives/2017/index.html +++ b/archives/2017/index.html @@ -1 +1 @@ -归档: 2017 | 云淡风轻
\ No newline at end of file +归档: 2017 | 云淡风轻
\ No newline at end of file diff --git a/archives/2024/03/index.html b/archives/2024/03/index.html index 050c5c5c..b3cf2828 100644 --- a/archives/2024/03/index.html +++ b/archives/2024/03/index.html @@ -1 +1 @@ -归档: 2024/3 | 云淡风轻
\ No newline at end of file +归档: 2024/3 | 云淡风轻
\ No newline at end of file diff --git a/archives/2024/index.html b/archives/2024/index.html index d4e3519a..e80580d9 100644 --- a/archives/2024/index.html +++ b/archives/2024/index.html @@ -1 +1 @@ -归档: 2024 | 云淡风轻
\ No newline at end of file +归档: 2024 | 云淡风轻
\ No newline at end of file diff --git a/archives/index.html b/archives/index.html index ef81c323..cbfa3ca6 100644 --- a/archives/index.html +++ b/archives/index.html @@ -1 +1 @@ -归档 | 云淡风轻

归档

共 10 篇文章

\ No newline at end of file +归档 | 云淡风轻

归档

共 10 篇文章

\ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 78d3edde..370529b4 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -1 +1 @@ -归档 | 云淡风轻
\ No newline at end of file +归档 | 云淡风轻
\ No newline at end of file diff --git a/atom.xml b/atom.xml index 29866ba6..e0863fd7 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z https://ioliu.cn/ @@ -21,9 +21,9 @@ https://ioliu.cn/2024/upgrade-debian-kernel-version/ 2024-03-23T14:53:34.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z - 如果你正在使用Debian 11并且希望提升你的系统性能,升级到最新的内核版本并启用BBR加速可能是一个不错的选择。以下是一篇指南,将带你了解如何安全地升级内核以及如何启用BBR来优化你的网络连接。

升级到新版内核

第一步:备份你的系统

在进行任何重大系统更改之前,备份是非常重要的。你可以使用如Timeshift等工具来备份你的系统。

第二步:修改软件源

为了安装最新的内核,我们可能需要添加Debian的Backports源。以下是添加Backports源的步骤:

  1. 打开/etc/apt/sources.list文件:

    1
    sudo nano /etc/apt/sources.list
  2. 在文件末尾添加以下行:

    1
    2
    deb http://deb.debian.org/debian bullseye-backports main contrib non-free
    deb-src http://deb.debian.org/debian bullseye-backports main contrib non-free
  3. 保存并退出编辑器。

  4. 更新软件包列表:

    1
    sudo apt update

第三步:安装新内核

使用Backports源安装新内核:

1
2
sudo apt-get -t bullseye-backports install linux-image-6.x.x-x-amd64
sudo apt-get -t bullseye-backports install linux-headers-6.x.x-x-amd64

请确保替换命令中的版本号为你想要安装的实际版本。

第四步:更新GRUB并重启

安装完新内核后,更新GRUB:

1
sudo update-grub

然后重启你的系统:

1
sudo reboot

清除旧内核

第一步:列出当前内核

使用以下命令查看当前安装的内核:

1
2
dpkg --list | grep linux-image
dpkg --list | grep linux-headers

第二步:删除旧内核

选择你不再需要的内核版本,并使用apt-get purge命令进行删除:

1
2
sudo apt-get purge linux-image-5.x.x-x-amd64
sudo apt-get purge linux-headers-5.x.x-x-amd64

第三步:更新GRUB

再次更新GRUB配置:

1
sudo update-grub

启用BBR加速

第一步:加载TCP BBR模块

编辑/etc/sysctl.conf文件,在文件末尾添加以下两行:

1
2
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

第二步:应用新的系统配置

应用新的配置:

1
sudo sysctl -p

第三步:验证BBR是否启用

运行以下命令:

1
sysctl net.ipv4.tcp_congestion_control

如果输出显示bbr,则BBR已启用。

结语

现在,你的Debian 11系统应该运行在最新的内核上,并且已经启用了BBR加速。这将帮助你提高系统的整体性能和网络连接的速度。请确保在执行以上操作时仔细检查,并始终保持系统的备份。

参考

]]>
+ 如果你正在使用Debian 11并且希望提升你的系统性能,升级到最新的内核版本并启用BBR加速可能是一个不错的选择。以下是一篇指南,将带你了解如何安全地升级内核以及如何启用BBR来优化你的网络连接。

升级到新版内核

第一步:备份你的系统

在进行任何重大系统更改之前,备份是非常重要的。你可以使用如Timeshift等工具来备份你的系统。

第二步:修改软件源

为了安装最新的内核,我们可能需要添加Debian的Backports源。以下是添加Backports源的步骤:

  1. 打开/etc/apt/sources.list文件:

    1
    sudo nano /etc/apt/sources.list
  2. 在文件末尾添加以下行:

    1
    2
    deb http://deb.debian.org/debian bullseye-backports main contrib non-free
    deb-src http://deb.debian.org/debian bullseye-backports main contrib non-free
  3. 保存并退出编辑器。

  4. 更新软件包列表:

    1
    sudo apt update

第三步:安装新内核

使用Backports源安装新内核:

1
2
sudo apt-get -t bullseye-backports install linux-image-6.x.x-x-amd64
sudo apt-get -t bullseye-backports install linux-headers-6.x.x-x-amd64

请确保替换命令中的版本号为你想要安装的实际版本。

第四步:更新GRUB并重启

安装完新内核后,更新GRUB:

1
sudo update-grub

然后重启你的系统:

1
sudo reboot

清除旧内核

第一步:列出当前内核

使用以下命令查看当前安装的内核:

1
2
dpkg --list | grep linux-image
dpkg --list | grep linux-headers

第二步:删除旧内核

选择你不再需要的内核版本,并使用apt-get purge命令进行删除:

1
2
sudo apt-get purge linux-image-5.x.x-x-amd64
sudo apt-get purge linux-headers-5.x.x-x-amd64

第三步:更新GRUB

再次更新GRUB配置:

1
sudo update-grub

启用BBR加速

第一步:加载TCP BBR模块

编辑/etc/sysctl.conf文件,在文件末尾添加以下两行:

1
2
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

第二步:应用新的系统配置

应用新的配置:

1
sudo sysctl -p

第三步:验证BBR是否启用

运行以下命令:

1
sysctl net.ipv4.tcp_congestion_control

如果输出显示bbr,则BBR已启用。

结语

现在,你的Debian 11系统应该运行在最新的内核上,并且已经启用了BBR加速。这将帮助你提高系统的整体性能和网络连接的速度。请确保在执行以上操作时仔细检查,并始终保持系统的备份。

参考

]]>
@@ -50,7 +50,7 @@ https://ioliu.cn/2017/git-command-backup/ 2017-11-10T06:30:25.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z 最近因为Valine,所以经常用到Git。当然,工作中也有用到,但基本上是用的图形化

这里最Git的相关操作命令做个备份,以备不时之需。

可能不定时更新。

配置自动换行

1
git config --global core.autocrlf input # 提交时自动将换行符转成lf

多账号配置SSH

修改~/.ssh/config文件(Windows平台)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置 Github.com
Host github.com
HostName github.com
IdentityFile C:\\path\\to\\.ssh\\id_rsa_github
PreferredAuthentications publickey
User YourName

# 配置 Coding.net
Host git.coding.net
HostName git.coding.net
IdentityFile C:\\path\\to\\.ssh\\id_rsa_coding
PreferredAuthentications publickey
User YourName

# 配置 Gitee.com
Host gitee.com
HostName gitee.com
IdentityFile C:\\path\\to\\.ssh\\id_rsa_gitee
PreferredAuthentications publickey
User YourName

pull 强制覆盖本地文件

1
2
git fetch --all  
git reset --hard origin/master

push 强制覆盖远程文件

1
git push -f origin master 

保持fork之后的项目和上游同步

团队协作,为了规范,一般都是fork组织的仓库到自己帐号下,再提交pr,组织的仓库一直保持更新,下面介绍如何保持自己fork之后的仓库与上游仓库同步。

下面以我 fork 团队的博客仓库为例

点击 fork 组织仓库到自己帐号下,然后就可以在自己的帐号下 clone 相应的仓库

使用 git remote -v 查看当前的远程仓库地址,输出如下:

1
2
origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin git@github.com:ibrother/staticblog.github.io.git (push)

可以看到从自己帐号 clone 下来的仓库,远程仓库地址是与自己的远程仓库绑定的(这不是废话吗)

接下来运行:

1
git remote add upstream https://github.com/staticblog/staticblog.github.io.git

这条命令就算添加一个别名为 upstream(上游)的地址,指向之前 fork 的原仓库地址。git remote -v 输出如下:

1
2
3
4
origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin git@github.com:ibrother/staticblog.github.io.git (push)
upstream https://github.com/staticblog/staticblog.github.io.git (fetch)
upstream https://github.com/staticblog/staticblog.github.io.git (push)

之后运行下面几条命令,就可以保持本地仓库和上游仓库同步了

1
2
3
git fetch upstream
git checkout master
git merge upstream/master

接着就是熟悉的推送本地仓库到远程仓库

1
git push origin master

From staticblog .

]]>
@@ -79,7 +79,7 @@ https://ioliu.cn/2017/add-valine-comments-to-your-blog/ 2017-08-07T06:30:25.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z Valine

Valine - 一款极简的无后端评论系统.

2017年6月1日,在你等超龄儿童欢度节日的时候,多说躺下了。
2017年8月1日,不甘寂寞的网易云跟帖也跟多说随风而去了。

2017年8月7日,一款基于Leancloud的极简风评论系统诞生:Valine

食用方法

获取 APP IDAPP KEY

  1. 点击这里登录或注册Leancloud
  2. 点这里创建应用,应用名看个人喜好。
  3. 选择刚刚创建的应用>设置>选择应用 Key,然后你就能看到你的APP IDAPP KEY了,参考下图:
  4. 为了您的数据安全,请填写应用>设置>安全设置中的Web 安全域名,如下图:

页面中的设置

页面中的食用方法炒鸡简单,来来来,我们用代码说话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Valine - A simple comment system based on Leancloud.</title>
<!--Leancloud 操作库:-->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<!--Valine 的核心代码库:-->
<script src="./dist/Valine.min.js"></script>
</head>
<body>
<div class="comment"></div>
<script>
new Valine({
// AV 对象来自上面引入av-min.js(老司机们不要开车➳♡゛扎心了老铁)
av: AV,
el: '.comment', //
app_id: 'Your APP ID', // 这里填写上面得到的APP ID
app_key: 'Your APP KEY', // 这里填写上面得到的APP KEY
placeholder: 'ヾノ≧∀≦)o来啊,快活啊!' // [v1.0.7 new]留言框占位提示文字
});
</script>
</body>
</html>

看吧,我是不是没说大话(_(:з」∠)_一本正经的胡说八道)。

评论数据管理

插播一下,关于评论数据管理,请自行登录Leancloud应用管理。
具体步骤:登录>选择你创建的应用>存储>选择ClassComment,然后就可以尽情的发挥你的权利啦(~ ̄▽ ̄)~


更多配置信息请移步:https://valine.js.org


–EOF–

]]>
@@ -111,7 +111,7 @@ https://ioliu.cn/2017/country-city-and-language/ 2017-06-29T07:30:08.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z 国家/地区语言代码国家地区语言代码简体中文(中国)zh-cn简体中文(台湾地区)zh-tw繁体中文(香港)zh-hk英语(香港)en-hk英语(美国)en-us英语(英国)en-gb英语(全球)en-ww英语(加拿大)en-ca英语(澳大利亚)en-au英语(爱尔兰)en-ie英语(芬兰)en-fi芬兰语(芬兰)fi-fi英语(丹麦)en-dk丹麦语(丹麦)da-dk英语(以色列)en-il希伯来语(以色列)he-il英语(南非)en-za英语(印度)en-in英语(挪威)en-no英语(新加坡)en-sg英语(新西兰)en-nz英语(印度尼西亚)en-id英语(菲律宾)en-ph英语(泰国)en-th英语(马来西亚)en-my英语(阿拉伯)en-xa韩文(韩国)ko-kr日语(日本)ja-jp荷兰语(荷兰)nl-nl荷兰语(比利时)nl-be葡萄牙语(葡萄牙)pt-pt葡萄牙语(巴西)pt-br法语(法国)fr-fr法语(卢森堡)fr-lu法语(瑞士)fr-ch法语(比利时)fr-be法语(加拿大)fr-ca西班牙语(拉丁美洲)es-la西班牙语(西班牙)es-es西班牙语(阿根廷)es-ar西班牙语(美国)es-us西班牙语(墨西哥)es-mx西班牙语(哥伦比亚)es-co西班牙语(波多黎各)es-pr德语(德国)de-de德语(奥地利)de-at德语(瑞士)de-ch俄语(俄罗斯)ru-ru意大利语(意大利)it-it希腊语(希腊)el-gr挪威语(挪威)no-no匈牙利语(匈牙利)hu-hu土耳其语(土耳其)tr-tr捷克语(捷克共和国)cs-cz斯洛文尼亚语sl-sl波兰语(波兰)pl-pl瑞典语(瑞典)sv-se西班牙语 (智利)es-cl]]> @@ -149,7 +149,7 @@ https://ioliu.cn/2017/mysql-tutorial/ 2017-03-24T03:00:25.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z

最近准备找时间把bing壁纸项目重构,但由于虚拟主机快要过期了,所以目前的首要任务是将数据库从阿里云的虚拟主机转移到我自己的服务器上。

因为多年前学过SQLServer、Oracle、MySql等数据库,但许久未用,技艺生疏,所以这里是不算初体验的初体验。

本文将执行三步走计划:

  • 安装
  • 登录
  • 使用

安装

在Debian上安装MySql很简单,运行如下命令就基本OK:

1
$ apt-get install mysql-server mysql-client

其中mysql-server是服务器程序,mysql-client是客户端程序。安装过程中会有如下提示,需要设置mysql数据库密码;输入要设置的密码后,回车即可继续安装。

如果出现Unable to locate package mysql-server等错误,请先执行apt-get update后重试。

登录

安装成功后,mysql会自动启动,可以通过ps -ef | grep mysql查看mysql是否运行。
登陆mysql:

1
2
3
# login
$ mysql -u root -p
Enter password: # 输入密码

其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。

查看数据库show databases;

1
2
3
4
5
6
7
8
9
10
$ mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)

使用

创建数据库

1
2
$ mysql> create database DB_name;
Query OK, 1 row affected (0.05 sec)

查看刚刚创建的数据库

1
2
3
4
5
6
7
8
9
10
11
$ mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| DB_name |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)

使用刚刚创建的数据库

1
2
$ mysql> use DB_name;
Database changed

创建表

1
2
3
4
5
$ mysql> CREATE TABLE IF NOT EXISTS person (
number INT(11),
name VARCHAR(255),
birthday DATE
);

查看表

1
2
3
4
5
6
7
$ mysql> SHOW CREATE table person;

CREATE TABLE `person` (
`number` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

查看表的所有列

1
2
3
4
5
6
7
8
$ mysql> SHOW FULL COLUMNS from person;
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| number | int(11) | NULL | YES | | NULL | | select,insert,update,references | |
| name | varchar(255) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| birthday | date | NULL | YES | | NULL | | select,insert,update,references | |
+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+

创建临时表

1
2
3
4
5
$ mysql> CREATE TEMPORARY TABLE temp_person (
number INT(11),
name VARCHAR(255),
birthday DATE
);

删除表

1
2
3
$ mysql> DROP TABLE temp_person;
# or
$ mysql> DROP TABLE IF EXISTS temp_person;

创建用户

命令:

1
$mysql> CREATE USER 'username'@'host' IDENTIFIED BY 'password';

说明:

  • username:你将创建的用户名
  • host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符%
  • password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器

例子:

1
2
3
4
5
$mysql> CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';
$mysql> CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';
$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '123456';
$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '';
$mysql> CREATE USER 'pig'@'%';

授权

命令:

1
$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host'

说明:

  • privileges:用户的操作权限,如SELECTINSERTUPDATE等,如果要授予所的权限则使用ALL
  • databasename:数据库名
  • tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*
    例子:
    1
    2
    $mysql> GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
    $mysql> GRANT ALL ON *.* TO 'pig'@'%';

    注意
    用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:

    1
    $mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;

设置与更改用户密码

命令:

1
$mysql> SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');

如果是当前登陆用户用:

1
>$mysql> SET PASSWORD = PASSWORD("newpassword");

例子:

1
$mysql> SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456");

撤销用户权限

命令:

1
$mysql> REVOKE privilege ON databasename.tablename FROM 'username'@'host';

说明:
privilege, databasename, tablename同授权部分
例子:

1
$mysql> REVOKE SELECT ON *.* FROM 'pig'@'%';

注意:
假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):GRANT SELECT ON test.user TO 'pig'@'%',则在使用REVOKE SELECT ON *.* FROM 'pig'@'%';
命令并不能撤销该用户对test数据库中user表的SELECT 操作。
相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%', 则REVOKE SELECT ON test.user FROM 'pig'@'%';
命令也不能撤销该用户对test数据库中user表的SELECT权限。
具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看。

删除用户

1
$mysql> DROP USER 'username'@'host';

最后

能看到这里,那就先要恭喜你了,你已经成功达成建库、建表、建用户到删表、删库、删用户等成就。那还等什么?赶紧跑路吧ε=ε=ε=┏(゜ロ゜;)┛


附:

]]>
@@ -178,9 +178,9 @@ https://ioliu.cn/2017/add-a-lock-to-your-website/ 2017-03-21T10:30:25.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z -

今天抽时间将所有的网站SSL证书都更新了成 Let’s Encrypt 了。采用了certbot 这样的自动化工具,配置管理起来非常容易(一本正经的胡说八道),这里将对整个体验过程做个详细记录。

了解 Let’s Encrypt

The project aims to make encrypted connections in the World Wide Web the default case. By getting rid of payment, web server configuration, validation emails and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.On a Linux web server, execution of only two commands is sufficient to set up HTTPS encryption, acquire and install certificates within 20 to 30 seconds.

Let’s Encrypt 是一个2015年末推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。

获取 Let’s Encrypt


Let’s Encrypt 证书生成不需要手动进行,官方推荐 Certbot 这套自动化工具来实现。4步轻松搞定:

  • 下载安装 certbot (Let’s Encrypt项目的自动化工具)
  • 获得SSL证书
  • 修改Nginx配置文件
  • 续订

1. 安装 Certbot

根据 Certbot 官网指南,Debian 8上执行如下命令,安装certbot:

1
2
$ sudo apt-get update
$ sudo apt-get install certbot -t jessie-backports

等安装完成,certbot就可以使用了。

2. 获取SSL证书

Let’s Encrypt提供了通过各种插件获取SSL证书的各种方法。不同的是Apache的插件,大多数的插件只会帮助你得到,你必须手动配置你的Web服务器使用证书。仅获取证书而不安装证书的插件称为“验证器”,因为它们用于验证服务器是否应颁发证书。
下面将使用Webroot的插件来获取SSL证书。

如何使用 Webroot 插件:

Webroot 的工作插件放置在一个特殊的文件/.well-known目录文档根目录下,它可以打开(通过Web服务器)内由让我们的加密服务进行验证。 根据配置的不同,你可能需要明确允许访问/.well-known目录。

为了确保该目录可供Let’s Encrypt进行验证,让我们快速更改我们的Nginx配置。编辑/etc/nginx/conf.d/example.com.conf文件,并将下面代码添加进去:

1
2
3
location ~ /.well-known {
allow all;
}

使用nginx -t测试配置文件是否正确,在正确的情况下,重新让Nginx重新加载配置文件:

1
$ sudo systemctl reload nginx

使用certbot命令获取证书:

1
$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is
  • -w:指定网站所在目录
  • -d:指定要生成证书的域名,如果你想多个域名保存在一个证书里(最多四个)(如example.comwww.example.comthing.ism.thing.is),请确保使用适当的webroot路径和域名替换命令中的相对应部分。

接下来,同意加密订阅协议:

如果一切顺利,你应该看到一个类似下面的输出消息:

IMPORTANT NOTES:

  • Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expire
    on 2017-06-19. To obtain a new or tweaked version of this
    certificate in the future, simply run certbot again. To
    non-interactively renew all of your certificates, run “certbot
    renew”
  • If you like Certbot, please consider supporting our work by:
    Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
    Donating to EFF: https://eff.org/donate-le

证书文件

如果运行顺利,所有服务器所需要的证书就已经生成好了。他们被放在了 /etc/letsencrypt/live/example.com/ 下:

1
2
3
4
5
$ ls /etc/letsencrypt/live/example.com/
cert.pem #server cert only
privkey.pem #private key
chain.pem #intermediates
fullchain.pem #server cert + intermediates

3.修改Nginx配置文件

到这里已经成功一大半了,只需要配置 Nginx 支持刚刚生成的证书。最佳实践可以参考Mozilla SSL Configuration Generator

注意去掉HSTS的勾(勾上会强制https,并且很难消除后续影响)。

请根据自己的服务配置修改和添加内容,重点只需要关注6行

1
2
3
4
5
6
7
8
9
10
11
12
server {  
listen 443 ssl http2;
....
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_trusted_certificate /etc/letsencrypt/live/example.com/root_ca_cert_plus_intermediates;

resolver <IP DNS resolver>;
....
}

dhparam.pem可以通过以下命令生成:

1
2
$ sudo mkdir /etc/nginx/ssl
$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

Nginx 配置完成后重启,用浏览器测试是否一切正常。

4.续订

Let's Encrypt证书有效期只有3个月,所以,需要定时renew。我将使用corntab来执行renew命令:

1
$ sudo crontab -e

添加以下行:

1
30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log && /bin/systemctl reload nginx

保存,并退出。这个定时任务将在每个星期一的凌晨两点半执行certbot renew命令,并重启Nginx。最后将日志输出到/var/log/le-renewal.log

测试你的网站 SSL 安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。

这意味着你网站的HTTPS已经启用成功啦,为自己鼓个掌。 (๑•̀ㅂ•́)و✧。


附:

还有一种方法,不需要访问你的网站目录,但需要临时停止Nginx服务器(需要用到80端口):

  1. 停止Nginx
  2. 域名解析到你的服务器IP
  3. 执行命令:certbot certonly --standalone -d example.com -d www.example.com

然后的步骤就和上面一样啦~~~

以上。

]]>
+

今天抽时间将所有的网站SSL证书都更新了成 Let’s Encrypt 了。采用了certbot 这样的自动化工具,配置管理起来非常容易(一本正经的胡说八道),这里将对整个体验过程做个详细记录。

了解 Let’s Encrypt

The project aims to make encrypted connections in the World Wide Web the default case. By getting rid of payment, web server configuration, validation emails and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.On a Linux web server, execution of only two commands is sufficient to set up HTTPS encryption, acquire and install certificates within 20 to 30 seconds.

Let’s Encrypt 是一个2015年末推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。

获取 Let’s Encrypt


Let’s Encrypt 证书生成不需要手动进行,官方推荐 Certbot 这套自动化工具来实现。4步轻松搞定:

  • 下载安装 certbot (Let’s Encrypt项目的自动化工具)
  • 获得SSL证书
  • 修改Nginx配置文件
  • 续订

1. 安装 Certbot

根据 Certbot 官网指南,Debian 8上执行如下命令,安装certbot:

1
2
$ sudo apt-get update
$ sudo apt-get install certbot -t jessie-backports

等安装完成,certbot就可以使用了。

2. 获取SSL证书

Let’s Encrypt提供了通过各种插件获取SSL证书的各种方法。不同的是Apache的插件,大多数的插件只会帮助你得到,你必须手动配置你的Web服务器使用证书。仅获取证书而不安装证书的插件称为“验证器”,因为它们用于验证服务器是否应颁发证书。
下面将使用Webroot的插件来获取SSL证书。

如何使用 Webroot 插件:

Webroot 的工作插件放置在一个特殊的文件/.well-known目录文档根目录下,它可以打开(通过Web服务器)内由让我们的加密服务进行验证。 根据配置的不同,你可能需要明确允许访问/.well-known目录。

为了确保该目录可供Let’s Encrypt进行验证,让我们快速更改我们的Nginx配置。编辑/etc/nginx/conf.d/example.com.conf文件,并将下面代码添加进去:

1
2
3
location ~ /.well-known {
allow all;
}

使用nginx -t测试配置文件是否正确,在正确的情况下,重新让Nginx重新加载配置文件:

1
$ sudo systemctl reload nginx

使用certbot命令获取证书:

1
$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is
  • -w:指定网站所在目录
  • -d:指定要生成证书的域名,如果你想多个域名保存在一个证书里(最多四个)(如example.comwww.example.comthing.ism.thing.is),请确保使用适当的webroot路径和域名替换命令中的相对应部分。

接下来,同意加密订阅协议:

如果一切顺利,你应该看到一个类似下面的输出消息:

IMPORTANT NOTES:

  • Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expire
    on 2017-06-19. To obtain a new or tweaked version of this
    certificate in the future, simply run certbot again. To
    non-interactively renew all of your certificates, run “certbot
    renew”
  • If you like Certbot, please consider supporting our work by:
    Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
    Donating to EFF: https://eff.org/donate-le

证书文件

如果运行顺利,所有服务器所需要的证书就已经生成好了。他们被放在了 /etc/letsencrypt/live/example.com/ 下:

1
2
3
4
5
$ ls /etc/letsencrypt/live/example.com/
cert.pem #server cert only
privkey.pem #private key
chain.pem #intermediates
fullchain.pem #server cert + intermediates

3.修改Nginx配置文件

到这里已经成功一大半了,只需要配置 Nginx 支持刚刚生成的证书。最佳实践可以参考Mozilla SSL Configuration Generator

注意去掉HSTS的勾(勾上会强制https,并且很难消除后续影响)。

请根据自己的服务配置修改和添加内容,重点只需要关注6行

1
2
3
4
5
6
7
8
9
10
11
12
server {  
listen 443 ssl http2;
....
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_trusted_certificate /etc/letsencrypt/live/example.com/root_ca_cert_plus_intermediates;

resolver <IP DNS resolver>;
....
}

dhparam.pem可以通过以下命令生成:

1
2
$ sudo mkdir /etc/nginx/ssl
$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

Nginx 配置完成后重启,用浏览器测试是否一切正常。

4.续订

Let's Encrypt证书有效期只有3个月,所以,需要定时renew。我将使用corntab来执行renew命令:

1
$ sudo crontab -e

添加以下行:

1
30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log && /bin/systemctl reload nginx

保存,并退出。这个定时任务将在每个星期一的凌晨两点半执行certbot renew命令,并重启Nginx。最后将日志输出到/var/log/le-renewal.log

测试你的网站 SSL 安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。

这意味着你网站的HTTPS已经启用成功啦,为自己鼓个掌。 (๑•̀ㅂ•́)و✧。


附:

还有一种方法,不需要访问你的网站目录,但需要临时停止Nginx服务器(需要用到80端口):

  1. 停止Nginx
  2. 域名解析到你的服务器IP
  3. 执行命令:certbot certonly --standalone -d example.com -d www.example.com

然后的步骤就和上面一样啦~~~

以上。

]]>
@@ -207,7 +207,7 @@ https://ioliu.cn/2016/judgment-variable-type/ 2016-09-13T14:10:01.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z 久了不用,就会发现,以前会的东西都会忘记掉(或者是完全想不起来了),不知道你们有没有遇到过这个情况 - -!

这里只是对判断变量类型方法的一些记录,方便以后能够随时查看。

typeof

要判断变量类型,首先想到的就是typeof,但用了才知道,其结果完全不是理想中的:

1
2
3
4
5
6
typeof {};  //"object"
typeof []; //"object"
typeof ""; //"string"
typeof 0; //"number"
typeof function(){};//"function"
typeof true;//"boolean"

由上面代码可以看出,数组也是对象,所以typeof不是我们理想中的解决方案。

当然,有的童鞋可能会说,由于lengthArray特有的属性(非绝对),那是不是可以用length+typeof来判断。

当然,这是可以的:

1
2
3
4
5
var arr = [1,2];
if(typeof arr === 'object'){
console.log(typeof arr.length === "number" ? "array" : "object");//这里输出 "array"
}
//...其他的就不一一罗列了

不过这个方法不通用,如果{key:value}对象中有 length 字段呢,如:

1
2
3
4
5
6
//这种情况对于上面的代码就不适用了
var obj = {
name:"square",
length:50,
width:50
};

instanceof

第二种解决方案就是使用instanceof,不过使用instanceof会出现[] instanceof Object === true的情况。这样就需要优先判断Array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = [1,2,3];
var b = {name:'zhangsan',sex:123};
var fn = function(){};
var detectType = function(o){
if(o instanceof Array){
return 'Array'
}else if( o instanceof Object ){
return 'Object';
}else{
return 'param is no object type';
}
}
console.log( detectType(a) ); // Array
console.log( detectType(b) ); // Object
console.log( detectType(1) ); // param is no object type
console.log( detectType(true) ); // param is no object type
console.log( detectType('a') ); // param is no object type

Object.prototype.toString.call

还有一种最靠谱的办法就是Object.prototype.toString.call:

1
2
3
4
5
6
7
8
9
10
Object.prototype.toString.call([])              //"[object Array]"
Object.prototype.toString.call(Object) //"[object Function]"
Object.prototype.toString.call(function x(){}) //"[object Function]"
Object.prototype.toString.call("") //"[object String]"
Object.prototype.toString.call({}) //"[object Object]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/test/) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"

参考文档

  1. Object.prototype.toString()
]]>
@@ -239,7 +239,7 @@ https://ioliu.cn/2016/css-content-and-special-characters/ 2016-09-06T06:10:01.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z 当我写这个主题theme的时候,我想在我的列表元素(list elements)上用CSS内容(CSS content)属性添加一些**向右双角引号(right-pointing double-angle quotation marks)(<<)**。

所以,我在里面添加了&raquo;,然而,它并不工作!

我花了一点时间去了解到,你不能使用常规的 HTML 实体内容。相反,你必须使用 Unicode 十六进制格式,它看起来像这样:\bb

这是一些你可以轻而易举找到的东西,只因为它出现在了众多课程和参考书里。

将HTML实体转换成Unicode十六进制代码

这里有很多的HTML实体对应表,但是没有更多的 Unicode十六进制表,所以很方便的知道二者之间的转换。你需要知道所有的HTML十进制单位(它们看起来像这样&#123;,而不是像这样&quot;)。
那数字,你猜到了吧,就是十进制格式。我们需要将其转换成Unicode十六进制(我知道,你震惊了!)。

如果你不是一个程序员或者数学天才,可能你不熟悉到底该怎么做(具体请Google)。OK,其实这并不难,但有一个更快捷的方式:

打开类似于经典的Windows计算器,切换到“程序员”视图(View > Programmer)。点击Dec(十进制)单选按钮,输入你的数字然后点击Hex(十六进制)按钮,你就会得到你的十六进制数字。

然后把刚刚得到的数字放到\之后,你就得到了你自己的Unicode十六进制字符。

更容易的方法 - HTML实体(HTML Entity)和 Unicode 十六进制 对应表

这个方法不需要你手动的将十进制转成十六进制,这个图表能够给你一些常见的(或者不是那么常见的)符号的参考:

]]>
@@ -267,7 +267,7 @@ https://ioliu.cn/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/ 2016-09-02T06:10:01.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z

每天学习新事物是成为一个伟大的人的一部分。而对开发者而言,持续不断学习新的东西是我们工作中的一部分,无论这些东西是否是你主动想学的。

在本教程中,我会指出一些重要的 JavaScript 最佳实践,因此你不必觉得学习它是条艰难的路。准备提升你的代码吧!

避免全局污染(Avoid polluting the global scope)

声明变量(Declaring variables)是很有趣的。有时候,你可能声明了全局变量,即使你不想声明它。在如今的浏览器中,全局变量存储在window对象中。因此,有很多有趣的东西发生在那里,你可能会重写默认值。
让我们假设你有一个HTML文件,其中包含一个<script>标签(或者在加载的 JavaScript 文件中包含):

1
2
var foo = 42;
console.log(foo);

这很显然会在控制台输出42。但是,因为这段代码没有在函数中执行,上下文将是一个全局的。因此,变量是附加到window对象的。这意味着window.foo的值也是42

这是危险的,因为你可以重写已经存在的全局变量:

1
2
3
4
5
function print(){
//do something...
}

print();

因为我们重写了原生的打印弹窗(native print popup),所以当我们执行window.print() (或者只执行print())的时候不会打开打印弹窗(print popup)。

这个问题很好解决,我们需要一个立即调用(called immediately) 的包装函数(wrapping function) (译者注:作者这里可能是要表达一个闭包函数closure function或者是匿名函数anonymous function),像下面的代码:

1
2
3
4
5
6
7
8
9
10
// Declare an anonymous function
// 声明一个匿名函数
(function () {
var foo = 42;
console.log(window.foo);
// → undefined
console.log(foo);
// → 42
})();
//^ and call it immediately

另外,你应该选择发送window和其他的全局变量(如:document)作为函数的参数(这可能会提高性能):

1
2
3
4
5
(function (global, doc) {
global.setTimeout(function () {
doc.body.innerHTML = "Hello!";
}, 1000);
})(window, document);

因此,使用包装函数来防止创建不必要的全局变量。注意,这不是说我在接下来的代码片段使用包装函数,我们应该把关注点放在代码本身。

💡小提示: browserify是另外一种防止创建不必要的全局变量的方式。它和 Node.js 采用的是同样的方式,使用的require function


学习更多关于浏览器开发者工具请点击 Web 开发指南

顺便说一句,Node.js 会在函数里自动打包你的文件,它们看起来像这样:

1
2
(function (exports, require, module, __filename, __dirname) {
// ...

因此,如果这让你认为require函数是全局的那就错了。它只不过是一个函数的参数罢了。

你知道吗?
由于window对象本身就是一个包含全局变量的全局变量,因此它的引用是自身:

1
2
window.window.window
// => Window {...}

那是因为window对象是一个环路对象(circular object),下面演示怎么创建一个这样的对象:

1
2
3
4
5
6
7
8
9
10
// Create an Object
var foo = {};

// Point a key value to the object itself
// 设置一个key,值为它本身
foo.bar = foo;

// The `foo` object just became a circular one:
foo.bar.bar.bar
// → foo

或者,去展现你对JavaScript 的爱,你可以做得更好:

Yes,你可以无限的扩展这个对象(大概直到你的浏览器崩溃).

使用严格模式(use strict)

严格的使用use strict!这只不过是(译者注:这里原作者可能是想表达不仅仅是)在你的代码脚本中添加字符串而已。
举个栗子:

1
2
3
4
5
6
7
8
// This is bad, since you do create a global without having anyone to tell you
(function () {
a = 42;
console.log(a);
// → 42
})();
console.log(a);
// → 42

使用use strict,你可以得到更多的确切的错误:

1
2
3
4
5
(function () {
"use strict";
a = 42;
// Error: Uncaught ReferenceError: a is not defined
})();

你可能会奇怪,为什么不能将use strict 写在函数体外。当然,这是可以的,但它将会应用为全局的范围。这仍然是不错的,但如果你的代码中含有来自其他库的代码,这也会受其影响,或者你把所有的东西都绑定在一个文件里。

严格相等(Strict equal)

这是短的。如果你使用==对比ab(像在其他编程语言),在 JavaScript 中,你可能这种非常奇怪的运行方式:如果你有一个字符串和一个数字,他们是相等的(==):

1
2
"42" == 42
// → true

由于显而易见的原因(如 验证(validations)),最好使用严格相等(===):

1
2
"42" === 42
// → false

使用断言(&&/||)

根据你的需要,你可以使用逻辑运算符是你的代码更简短。
默认值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"" || "foo"
// → "foo"

undefined || 42
// → 42

// Note that if you want to handle 0 there, you need
// to check if a number was provided:
var a = 0;
a || 42
// → 42

// This is a ternary operator—works like an inline if-else statement
var b = typeof a === "number" ? a : 42;
// → 0

检查是否是一个真正的if表达式,你可以简单的这么做:

1
2
3
4
5
6
expr && doSomething();

// Instead of:
if (expr) {
doSomething();
}

你可能会不赞同我这里的写法,但是这是比较理想的。如果你不想用这种方式丑化你的代码,但那些 JavaScript 压缩工具实际上会这么做。

如果你问我,尽管这些代码比较短,但它仍然是人类可读的。

类型转换

有几种方式来转换这些东西,这取决于你想怎么做。最常见的方式是:

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
// From anything to a number

var foo = "42";
var myNumber = +foo; // shortcut for Number(foo)
// → 42

// Tip: you can convert it directly into a negative number
var negativeFoo = -foo; // or -Number(foo)
// → -42

// From object to array
// Tip: `arguments` is an object and in general you want to use it as array
var args = { 0: "foo", 1: "bar", length: 2 };
Array.prototype.slice.call(args)
// → [ 'foo', 'bar' ]

// Anything to boolean
/// Non non p is a boolean p
var t = 1;
var f = 0;
!!t
// → true
!!f
// → false

/// And non-p is a boolean non-p
!t
// → false
!f
// → true

// Anything to string
var foo = 42;
"" + foo // shortcut for String(foo)
// → "42"

foo = { hello: "world" };
JSON.stringify(foo);
// → '{ "hello":"world" }'

JSON.stringify(foo, null, 4); // beautify the things
// →
// '{
// "hello": "world"
// }'

// Note you cannot JSON.stringify circular structures
JSON.stringify(window);
// ⚠ TypeError: JSON.stringify cannot serialize cyclic structures.

代码样式/样式指南

在新项目中,遵循整个文件相同的代码风格。对于现有的,采用已经存在的代码风格,除非你只是决定改变它(提示:同你的合作者商讨)。即使你创建并记录你的代码风格,请始终遵循它。

这里是不同的现有的代码样式:

附加提示

其他重要的 JavaScript 最佳实践,你应该记住的是使用工具帮助你格式化你的代码。这是其中的一些:

  • js-beautify: Beautifies your code
  • UglifyJS(2): Uglifies/minimifies your code
  • jshint: Detects errors/potential problems in your JavaScript code
  • jscs: A configurable style guide checker

最后一件事:Debug your Code

Happy programming!


致谢:@屠夫@QistChan@nApolin@Ant


]]>
@@ -299,9 +299,9 @@ https://ioliu.cn/2016/MarkDown-incomplete-Guide/ 2016-05-18T06:21:08.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z -

Markdown

A markdown example shows how to write a markdown file. This document integrates core syntax and extensions (GMF).

Block Elements

Paragraphs and Line Breaks

Paragraphs

HTML Tag: <p>

One or more blank lines. (A blank line is a line containing nothing but spaces or tabs is considered blank.)

Code:

1
2
3
4
This will be 
inline.

This is second paragraph.

Preview:


This will be
inline.

This is second paragraph.


Line Breaks

HTML Tag: <br />

End a line with two or more spaces.

Code:

1
2
This will be not  
inline.

Preview:


This will be not
inline.


Headers

Markdown supports two styles of headers, Setext and atx.

Setext

HTML Tags: <h1>, <h2>

“Underlined” using equal signs (=) as <h1> and dashes (-) as <h2> in any number.

Code:
1
2
3
4
This is an H1
=============
This is an H2
-------------

Preview:
***
This is an H1

This is an H2


atx

HTML Tags: <h1>, <h2>, <h3>, <h4>, <h5>, <h6>

Uses 1-6 hash characters (#) at the start of the line, corresponding to <h1> - <h6>.

Code:

1
2
3
# This is an H1
## This is an H2
###### This is an H6

Preview:


This is an H1

This is an H2

This is an H6

Optionally, you may “close” atx-style headers. The closing hashes don’t need to match the number of hashes used to open the header.

Code:

1
2
3
# This is an H1 #
## This is an H2 ##
### This is an H3 ######

Preview:


This is an H1

This is an H2

This is an H3


Blockquotes

HTML Tag: <blockquote>

Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and put a > before every line.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
>
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
> id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >.

Code:

1
2
3
4
5
> This is the first level of quoting.
>
> > This is nested blockquote.
>
> Back to the first level.

Preview:


This is the first level of quoting.

This is nested blockquote.

Back to the first level.


Blockquotes can contain other Markdown elements, including headers, lists, and code blocks.

Code:

1
2
3
4
5
6
7
8
> ## This is a header.
>
> 1. This is the first list item.
> 2. This is the second list item.
>
> Here's some example code:
>
> return shell_exec("echo $input | $markdown_script");

Preview:


This is a header.

  1. This is the first list item.
  2. This is the second list item.

Here’s some example code:

return shell_exec("echo $input | $markdown_script");

Lists

Markdown supports ordered (numbered) and unordered (bulleted) lists.

Unordered

HTML Tag: <ul>

Unordered lists use asterisks (*), pluses (+), and hyphens (-).

Code:

1
2
3
*   Red
* Green
* Blue

Preview:


  • Red
  • Green
  • Blue

is equivalent to:

Code:

1
2
3
+   Red
+ Green
+ Blue

and:

Code:

1
2
3
-   Red
- Green
- Blue

Ordered

HTML Tag: <ol>

Ordered lists use numbers followed by periods:

Code:

1
2
3
1.  Bird
2. McHale
3. Parish

Preview:


  1. Bird
  2. McHale
  3. Parish

It’s possible to trigger an ordered list by accident, by writing something like this:

Code:

1
1986. What a great season.

Preview:


  1. What a great season.

You can backslash-escape (\) the period:

Code:

1
1986\. What a great season.

Preview:


1986. What a great season.


Indented

Blockquote

To put a blockquote within a list item, the blockquote’s > delimiters need to be indented:

Code:

1
2
3
4
*   A list item with a blockquote:

> This is a blockquote
> inside a list item.

Preview:


  • A list item with a blockquote:

    This is a blockquote
    inside a list item.


Code Block

To put a code block within a list item, the code block needs to be indented twice — 8 spaces or two tabs:

Code:

1
2
3
*   A list item with a code block:

<code goes here>

Preview:


  • A list item with a code block:

    <code goes here>

Nested List

Code:

1
2
3
4
5
* A
* A1
* A2
* B
* C

Preview:


  • A
    • A1
    • A2
  • B
  • C

Code Blocks

HTML Tag: <pre>

Indent every line of the block by at least 4 spaces or 1 tab.

Code:

1
2
3
This is a normal paragraph:

This is a code block.

Preview:


This is a normal paragraph:

This is a code block.

A code block continues until it reaches a line that is not indented (or the end of the article).

Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities.

Code:

1
2
3
<div class="thanclass">
&copy; 2004 Foo Corporation
</div>

Preview:


© 2004 Foo Corporation
***Following sections Fenced Code Blocks and Syntax Highlighting are extensions, you can use the other way to write the code block.#### Fenced Code BlocksJust wrap your code in \`\`\` \`\`\` (as shown below) and you won't need to indent it by four spaces.

Code:

Here’s an example:
```
function test() {
console.log(“notice the blank line before this function?”);
}
```

Preview:


Here’s an example:

1
2
3
function test() {
console.log("notice the blank line before this function?");
}

Syntax Highlighting

In your fenced block, add an optional language identifier and we’ll run it through syntax highlighting (Support Languages).

Code:

```ruby
require ‘redcarpet’
markdown = Redcarpet.new(“Hello World!”)
puts markdown.to_html
```

Preview:


1
2
3
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html

Horizontal Rules

HTML Tag: <hr />
Places three or more hyphens (-), asterisks (*), or underscores (_) on a line by themselves. You may use spaces between the hyphens or asterisks.

Code:

1
2
3
4
5
6
* * *
***
*****
- - -
---------------------------------------
___

Table

HTML Tag: <table>

It’s an extension.

Separates column by pipe (|) and header by dashes (-), and uses colon (:) for alignment.

The outer pipes (|) and alignment are optional. There are 3 delimiters each cell at least for separating header.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
| Left | Center | Right |
|:-----|:------:|------:|
|aaa |bbb |ccc |
|ddd |eee |fff |

A | B
---|---
123|456


A |B
--|--
12|45

Preview:


LeftCenterRight
aaabbbccc
dddeeefff
AB
123456
AB
1245

Span Elements

HTML Tag: <a>

Markdown supports two style of links: inline and reference.

Inline

Inline link format like this: [Link Text](URL "Title")

Title is optional.

Code:

1
2
3
This is [an example](http://example.com/ "Title") inline link.

[This link](http://example.net/) has no title attribute.

Preview:


This is an example inline link.

This link has no title attribute.


If you’re referring to a local resource on the same server, you can use relative paths:

Code:

1
See my [Tags](/tags/) page for details. 

Preview:


See my Tags page for details.


Reference

You could predefine link references. Format like this: [id]: URL "Title"

Title is also optional. And the you refer the link, format like this: [Link Text][id]

Code:

1
2
[id]: http://example.com/  "Optional Title Here"
This is [an example][id] reference-style link.

Preview:


This is 点我跳转到百度 reference-style link.


That is:

  • Square brackets containing the link identifier (not case sensitive, optionally indented from the left margin using up to three spaces);
  • followed by a colon;
  • followed by one or more spaces (or tabs);
  • followed by the URL for the link;
  • The link URL may, optionally, be surrounded by angle brackets.
  • optionally followed by a title attribute for the link, enclosed in double or single quotes, or enclosed in parentheses.

The following three link definitions are equivalent:

Code:

1
2
3
4
[foo]: http://example.com/  "Optional Title Here"
[foo]: http://example.com/ 'Optional Title Here'
[foo]: http://example.com/ (Optional Title Here)
[foo]: <http://example.com/> "Optional Title Here"

Uses an empty set of square brackets, the link text itself is used as the name.

Code:

1
2
[Google]: http://google.com/
[Google][]

Preview:


Google


Emphasis

HTML Tags: <em>, <strong>

Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. One delimiter will be <em>; *double delimiters will be <strong>.

Code:

1
2
3
4
5
6
7
*single asterisks*

_single underscores_

**double asterisks**

__double underscores__

Preview:


single asterisks

single underscores

double asterisks

double underscores


But if you surround an * or _ with spaces, it’ll be treated as a literal asterisk or underscore.

You can backslash escape it:

Code:

1
*this text is surrounded by literal asterisks*

Preview:


*this text is surrounded by literal asterisks*


Code

HTML Tag: <code>

Wraps it with backtick quotes (`).

Code:

1
Use the `printf()` function.

Preview:


Use the printf() function.


To include a literal backtick character within a code span, you can use multiple backticks as the opening and closing delimiters:

Code:

1
``There is a literal backtick (`) here.``

Preview:


There is a literal backtick (`) here.


The backtick delimiters surrounding a code span may include spaces — one after the opening, one before the closing. This allows you to place literal backtick characters at the beginning or end of a code span:

Code:

1
2
3
A single backtick in a code span: `` ` ``

A backtick-delimited string in a code span: `` `foo` ``

Preview:


A single backtick in a code span: `

A backtick-delimited string in a code span: `foo`


Images

HTML Tag: <img />

Markdown uses an image syntax that is intended to resemble the syntax for links, allowing for two styles: inline and reference.

Inline

Inline image syntax looks like this: ![Alt text](URL "Title")

Title is optional.

Code:

1
2
3
![Alt text](/path/to/img.jpg)

![Alt text](/path/to/img.jpg "Optional title")

Preview:


Alt text

Alt text


That is:

  • An exclamation mark: !;
  • followed by a set of square brackets, containing the alt attribute text for the image;
  • followed by a set of parentheses, containing the URL or path to the image, and an optional title attribute enclosed in double or single quotes.

Reference

Reference-style image syntax looks like this: ![Alt text][id]

Code:

1
2
[img id]: url/to/image  "Optional title attribute"
![Alt text][img id]

Preview:


Alt text


Strikethrough

HTML Tag: <del>

It’s an extension.

GFM adds syntax to strikethrough text.

Code:

1
~~Mistaken text.~~

Preview:


Mistaken text.


Miscellaneous

Markdown supports a shortcut style for creating “automatic” links for URLs and email addresses: simply surround the URL or email address with angle brackets.

Code:

1
2
3
<http://example.com/>

<address@example.com>

Preview:


http://example.com/

address@example.com


GFM will autolink standard URLs.

Code:

1
https://github.com/xcss

Preview:


https://github.com/xcss


Backslash Escapes

Markdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax.

Code:

1
\*literal asterisks\*

Preview:


*literal asterisks*


Markdown provides backslash escapes for the following characters:

Code:

1
2
3
4
5
6
7
8
9
10
11
12
\   backslash
` backtick
* asterisk
_ underscore
{} curly braces
[] square brackets
() parentheses
# hash mark
+ plus sign
- minus sign (hyphen)
. dot
! exclamation mark

Inline HTML

For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.

Code:

1
2
3
4
5
6
7
8
9
This is a regular paragraph.

<table>
<tr>
<td>Foo</td>
</tr>
</table>

This is another regular paragraph.

Preview:


This is a regular paragraph.

Foo
This is another regular paragraph.***Note that Markdown formatting syntax is **not processed within block-level HTML tags**.

Unlike block-level HTML tags, Markdown syntax is processed within span-level tags.

Code:

1
2
3
4
5
<span>**Work**</span>

<div>
**No Work**
</div>

Preview:


Work

**No Work**
***

参考文档: http://www.markdown.cn/

]]>
+

Markdown

A markdown example shows how to write a markdown file. This document integrates core syntax and extensions (GMF).

Block Elements

Paragraphs and Line Breaks

Paragraphs

HTML Tag: <p>

One or more blank lines. (A blank line is a line containing nothing but spaces or tabs is considered blank.)

Code:

1
2
3
4
This will be 
inline.

This is second paragraph.

Preview:


This will be
inline.

This is second paragraph.


Line Breaks

HTML Tag: <br />

End a line with two or more spaces.

Code:

1
2
This will be not  
inline.

Preview:


This will be not
inline.


Headers

Markdown supports two styles of headers, Setext and atx.

Setext

HTML Tags: <h1>, <h2>

“Underlined” using equal signs (=) as <h1> and dashes (-) as <h2> in any number.

Code:
1
2
3
4
This is an H1
=============
This is an H2
-------------

Preview:
***
This is an H1

This is an H2


atx

HTML Tags: <h1>, <h2>, <h3>, <h4>, <h5>, <h6>

Uses 1-6 hash characters (#) at the start of the line, corresponding to <h1> - <h6>.

Code:

1
2
3
# This is an H1
## This is an H2
###### This is an H6

Preview:


This is an H1

This is an H2

This is an H6

Optionally, you may “close” atx-style headers. The closing hashes don’t need to match the number of hashes used to open the header.

Code:

1
2
3
# This is an H1 #
## This is an H2 ##
### This is an H3 ######

Preview:


This is an H1

This is an H2

This is an H3


Blockquotes

HTML Tag: <blockquote>

Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and put a > before every line.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
>
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
> id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph.

Code:

1
2
3
4
5
6
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.

Preview:


This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.


Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >.

Code:

1
2
3
4
5
> This is the first level of quoting.
>
> > This is nested blockquote.
>
> Back to the first level.

Preview:


This is the first level of quoting.

This is nested blockquote.

Back to the first level.


Blockquotes can contain other Markdown elements, including headers, lists, and code blocks.

Code:

1
2
3
4
5
6
7
8
> ## This is a header.
>
> 1. This is the first list item.
> 2. This is the second list item.
>
> Here's some example code:
>
> return shell_exec("echo $input | $markdown_script");

Preview:


This is a header.

  1. This is the first list item.
  2. This is the second list item.

Here’s some example code:

return shell_exec("echo $input | $markdown_script");

Lists

Markdown supports ordered (numbered) and unordered (bulleted) lists.

Unordered

HTML Tag: <ul>

Unordered lists use asterisks (*), pluses (+), and hyphens (-).

Code:

1
2
3
*   Red
* Green
* Blue

Preview:


  • Red
  • Green
  • Blue

is equivalent to:

Code:

1
2
3
+   Red
+ Green
+ Blue

and:

Code:

1
2
3
-   Red
- Green
- Blue

Ordered

HTML Tag: <ol>

Ordered lists use numbers followed by periods:

Code:

1
2
3
1.  Bird
2. McHale
3. Parish

Preview:


  1. Bird
  2. McHale
  3. Parish

It’s possible to trigger an ordered list by accident, by writing something like this:

Code:

1
1986. What a great season.

Preview:


  1. What a great season.

You can backslash-escape (\) the period:

Code:

1
1986\. What a great season.

Preview:


1986. What a great season.


Indented

Blockquote

To put a blockquote within a list item, the blockquote’s > delimiters need to be indented:

Code:

1
2
3
4
*   A list item with a blockquote:

> This is a blockquote
> inside a list item.

Preview:


  • A list item with a blockquote:

    This is a blockquote
    inside a list item.


Code Block

To put a code block within a list item, the code block needs to be indented twice — 8 spaces or two tabs:

Code:

1
2
3
*   A list item with a code block:

<code goes here>

Preview:


  • A list item with a code block:

    <code goes here>

Nested List

Code:

1
2
3
4
5
* A
* A1
* A2
* B
* C

Preview:


  • A
    • A1
    • A2
  • B
  • C

Code Blocks

HTML Tag: <pre>

Indent every line of the block by at least 4 spaces or 1 tab.

Code:

1
2
3
This is a normal paragraph:

This is a code block.

Preview:


This is a normal paragraph:

This is a code block.

A code block continues until it reaches a line that is not indented (or the end of the article).

Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities.

Code:

1
2
3
<div class="thanclass">
&copy; 2004 Foo Corporation
</div>

Preview:


© 2004 Foo Corporation
***Following sections Fenced Code Blocks and Syntax Highlighting are extensions, you can use the other way to write the code block.#### Fenced Code BlocksJust wrap your code in \`\`\` \`\`\` (as shown below) and you won't need to indent it by four spaces.

Code:

Here’s an example:
```
function test() {
console.log(“notice the blank line before this function?”);
}
```

Preview:


Here’s an example:

1
2
3
function test() {
console.log("notice the blank line before this function?");
}

Syntax Highlighting

In your fenced block, add an optional language identifier and we’ll run it through syntax highlighting (Support Languages).

Code:

```ruby
require ‘redcarpet’
markdown = Redcarpet.new(“Hello World!”)
puts markdown.to_html
```

Preview:


1
2
3
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html

Horizontal Rules

HTML Tag: <hr />
Places three or more hyphens (-), asterisks (*), or underscores (_) on a line by themselves. You may use spaces between the hyphens or asterisks.

Code:

1
2
3
4
5
6
* * *
***
*****
- - -
---------------------------------------
___

Table

HTML Tag: <table>

It’s an extension.

Separates column by pipe (|) and header by dashes (-), and uses colon (:) for alignment.

The outer pipes (|) and alignment are optional. There are 3 delimiters each cell at least for separating header.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
| Left | Center | Right |
|:-----|:------:|------:|
|aaa |bbb |ccc |
|ddd |eee |fff |

A | B
---|---
123|456


A |B
--|--
12|45

Preview:


LeftCenterRight
aaabbbccc
dddeeefff
AB
123456
AB
1245

Span Elements

HTML Tag: <a>

Markdown supports two style of links: inline and reference.

Inline

Inline link format like this: [Link Text](URL "Title")

Title is optional.

Code:

1
2
3
This is [an example](http://example.com/ "Title") inline link.

[This link](http://example.net/) has no title attribute.

Preview:


This is an example inline link.

This link has no title attribute.


If you’re referring to a local resource on the same server, you can use relative paths:

Code:

1
See my [Tags](/tags/) page for details. 

Preview:


See my Tags page for details.


Reference

You could predefine link references. Format like this: [id]: URL "Title"

Title is also optional. And the you refer the link, format like this: [Link Text][id]

Code:

1
2
[id]: http://example.com/  "Optional Title Here"
This is [an example][id] reference-style link.

Preview:


This is 点我跳转到百度 reference-style link.


That is:

  • Square brackets containing the link identifier (not case sensitive, optionally indented from the left margin using up to three spaces);
  • followed by a colon;
  • followed by one or more spaces (or tabs);
  • followed by the URL for the link;
  • The link URL may, optionally, be surrounded by angle brackets.
  • optionally followed by a title attribute for the link, enclosed in double or single quotes, or enclosed in parentheses.

The following three link definitions are equivalent:

Code:

1
2
3
4
[foo]: http://example.com/  "Optional Title Here"
[foo]: http://example.com/ 'Optional Title Here'
[foo]: http://example.com/ (Optional Title Here)
[foo]: <http://example.com/> "Optional Title Here"

Uses an empty set of square brackets, the link text itself is used as the name.

Code:

1
2
[Google]: http://google.com/
[Google][]

Preview:


Google


Emphasis

HTML Tags: <em>, <strong>

Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. One delimiter will be <em>; *double delimiters will be <strong>.

Code:

1
2
3
4
5
6
7
*single asterisks*

_single underscores_

**double asterisks**

__double underscores__

Preview:


single asterisks

single underscores

double asterisks

double underscores


But if you surround an * or _ with spaces, it’ll be treated as a literal asterisk or underscore.

You can backslash escape it:

Code:

1
*this text is surrounded by literal asterisks*

Preview:


*this text is surrounded by literal asterisks*


Code

HTML Tag: <code>

Wraps it with backtick quotes (`).

Code:

1
Use the `printf()` function.

Preview:


Use the printf() function.


To include a literal backtick character within a code span, you can use multiple backticks as the opening and closing delimiters:

Code:

1
``There is a literal backtick (`) here.``

Preview:


There is a literal backtick (`) here.


The backtick delimiters surrounding a code span may include spaces — one after the opening, one before the closing. This allows you to place literal backtick characters at the beginning or end of a code span:

Code:

1
2
3
A single backtick in a code span: `` ` ``

A backtick-delimited string in a code span: `` `foo` ``

Preview:


A single backtick in a code span: `

A backtick-delimited string in a code span: `foo`


Images

HTML Tag: <img />

Markdown uses an image syntax that is intended to resemble the syntax for links, allowing for two styles: inline and reference.

Inline

Inline image syntax looks like this: ![Alt text](URL "Title")

Title is optional.

Code:

1
2
3
![Alt text](/path/to/img.jpg)

![Alt text](/path/to/img.jpg "Optional title")

Preview:


Alt text

Alt text


That is:

  • An exclamation mark: !;
  • followed by a set of square brackets, containing the alt attribute text for the image;
  • followed by a set of parentheses, containing the URL or path to the image, and an optional title attribute enclosed in double or single quotes.

Reference

Reference-style image syntax looks like this: ![Alt text][id]

Code:

1
2
[img id]: url/to/image  "Optional title attribute"
![Alt text][img id]

Preview:


Alt text


Strikethrough

HTML Tag: <del>

It’s an extension.

GFM adds syntax to strikethrough text.

Code:

1
~~Mistaken text.~~

Preview:


Mistaken text.


Miscellaneous

Markdown supports a shortcut style for creating “automatic” links for URLs and email addresses: simply surround the URL or email address with angle brackets.

Code:

1
2
3
<http://example.com/>

<address@example.com>

Preview:


http://example.com/

address@example.com


GFM will autolink standard URLs.

Code:

1
https://github.com/xcss

Preview:


https://github.com/xcss


Backslash Escapes

Markdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax.

Code:

1
\*literal asterisks\*

Preview:


*literal asterisks*


Markdown provides backslash escapes for the following characters:

Code:

1
2
3
4
5
6
7
8
9
10
11
12
\   backslash
` backtick
* asterisk
_ underscore
{} curly braces
[] square brackets
() parentheses
# hash mark
+ plus sign
- minus sign (hyphen)
. dot
! exclamation mark

Inline HTML

For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.

Code:

1
2
3
4
5
6
7
8
9
This is a regular paragraph.

<table>
<tr>
<td>Foo</td>
</tr>
</table>

This is another regular paragraph.

Preview:


This is a regular paragraph.

Foo
This is another regular paragraph.***Note that Markdown formatting syntax is **not processed within block-level HTML tags**.

Unlike block-level HTML tags, Markdown syntax is processed within span-level tags.

Code:

1
2
3
4
5
<span>**Work**</span>

<div>
**No Work**
</div>

Preview:


Work

**No Work**
***

参考文档: http://www.markdown.cn/

]]>
@@ -328,7 +328,7 @@ https://ioliu.cn/2016/commonly-used-media-queries/ 2016-05-11T11:21:08.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z

现在Web朝着响应式的趋势发展,媒体查询在创建响应式网站中起到了主要作用。

没有媒体查询几乎不能实现响应式设计,利用媒体查询,我们可以针对特定的设备,如显示器、智能手机和平板,写CSS。

媒体查询是响应式设计的核心

在这篇文章中我将分享一些到目前为止我收集到的常用媒体查询。在一些示例中,我可能是错误的,但是不用担心,因为我针对这个开通了评论功能。我把它们分为显示器媒体查询智能手机媒体查询平板媒体查询

显示器媒体查询

显示器媒体查询是以屏幕大小为基础划分的

640px

1
2
3
@media screen and (max-width: 640px){
/*some rules*/
}

800px

1
2
3
@media screen and (max-width: 800px){
/*some rules*/
}

1024px

1
2
3
@media screen and (max-width: 1024px){
/*some rules*/
}

智能手机媒体查询

适用于大部分主流智能手机

iPhone(2G-4S)

1
2
3
4
5
6
7
8
/*Landscape Mode*/
@media screen and (max-device-width: 480px) and (orientation:landscape){
/*some rules*/
}
/* Portrait Mode */
@media screen and (max-device-width: 320px) and (orientation:portrait){
/*some rules*/
}

iPhone 4

1
2
3
4
@media only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5){
/*some rules*/
}

iPhone 5

1
2
3
4
5
@media only screen
and (min-device-width : 320px)
and (max-device-width : 568px){
/*some rules*/
}

iPhone 6

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
@media only screen and (min-device-width: 375px) and (max-device-width: 667px)
and (orientation : portrait) {
/*iPhone 6 Portrait*/
}
@media only screen and (min-device-width: 375px) and (max-device-width: 667px)
and (orientation : landscape) {
/*iPhone 6 landscape*/
}
@media only screen and (min-device-width: 414px) and (max-device-width: 736px)
and (orientation : portrait) {
/*iPhone 6+ Portrait*/
}
@media only screen and (min-device-width: 414px) and (max-device-width: 736px)
and (orientation : landscape) {
/*iPhone 6+ landscape*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px){
/*iPhone 6 and iPhone 6+ portrait and landscape*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px) and (orientation : portrait){
/*iPhone 6 and iPhone 6+ portrait*/
}
@media only screen and (max-device-width: 640px),
only screen and (max-device-width: 667px),
only screen and (max-width: 480px) and (orientation : landscape){
/*iPhone 6 and iPhone 6+ landscape*/
}

HTC Evo,BlackBerry Torch,HTC Thunderbolt,HD2

1
2
3
@media screen and (max-device-width: 480px){
/*some rules*/
}

平板媒体查询

iPad / iPad 2 / iPad 3

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

iPad Mini

1
2
3
4
5
6
@media only screen
and (min-device-width : 768px)
and (max-device-width : 1024px)
and (-webkit-min-device-pixel-ratio: 1){
/*some rules*/
}

Samsung Galaxy Tab 10.1 / Motorola Xoom / Lenovo Thinkpad Tablet / Sony Tablet S

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1280px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 800px) and (orientation: portrait){
/*some rules*/
}

HTC Flyer / BlackBerry PlayBook

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 600px) and (orientation: portrait){
/*some rules*/
}

HP TouchPad

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

T-Mobile G-Slate

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1280px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 768px) and (orientation: portrait){
/*some rules*/
}

ViewSonic ViewPad 10

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1024px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 600px) and (orientation: portrait){
/*some rules*/
}

Dell Streak 7

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 800px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 400px) and (orientation: portrait){
/*some rules*/
}

ASUS Eee Pad Transformer

1
2
3
4
5
6
7
8
/* Landscape Mode */
@media (max-device-width: 1080px) and (orientation: landscape){
/*some rules*/
}
/* Portrait Mode */
@media (max-device-width: 800px) and (orientation: portrait){
/*some rules*/
}

其他参考文档

  1. 七个高度有效的媒体查询技巧
  2. iPads和iPhones的Media Queries
  3. media-queries-for-standard-devices

本文转载自淡忘~浅思,略有删改,侵权即删.
原文链接: Some Media Queries for Responsive Design
译文链接: 【译】Responsive Design常用的媒体查询

]]>
@@ -360,7 +360,7 @@ https://ioliu.cn/2015/generating-ssh-key/ 2015-12-13T02:19:18.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z
之前上传文件到 GitHub 的时候,一直都是用的账号密码登录,每次提交都弹个窗体出来,感觉烦死了。。。今天有空,就来捣鼓下 SSH Key

Step1. 检查是否已经存在 SSH Key

运行 Git Bush 客户端,执行以下代码:

1
2
$ ls -al ~/.ssh 
# 如果存在,将会列出.ssh 目录下的所有文件
1
2
# 如果不存在则会给出如下提示
ls: cannot open directory /Users/you/.ssh: Permission denied

检查列出来的目录,看看是否已经有了一个 SSH Key。默认情况下,key 的文件名是下列之一:
> id_dsa.pub
> id_ecdsa.pub
> id_ed25519.pub
> id_rsa.pub

如果已经存在(如 id_rsaid_rsa.pub)而且你想使用已经存在的密钥对直接连接 GitHub ,那么可以跳过 Step2,直接进入 Step3

Step2. 生成 SSH Key

复制下面的代码(记得请将email修改成自己的email地址):

1
2
$ ssh-keygen -t rsa -b 4096 -C "your_name@example.com" 
Generating public/private rsa key pair.

这里 GitHub 的建议是保持默认,所以只需要按 Enter 继续:

1
Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press Enter]

如果存在,将会提示是否覆盖:

1
2
/Users/you/.ssh/id_rsa already exists.
Overwrite (y/n)?

继续后会提示输入密码:

1
2
Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]

然后你就会得到你的 SSH Key 的指纹,看起来像下面的代码:

1
2
3
4
Your identification has been saved in /Users/you/.ssh/id_rsa.
Your public key has been saved in /Users/you/.ssh/id_rsa.pub.
The key fingerprint is:
01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com

Step3. 添加 SSH Key 到 GitHub

先拷贝 id_rsa.pub 文件的内容,可以用编辑器打开然后复制,也可以用 git 命令复制:

1
$ clip < ~/.ssh/id_rsa.pub

进入 GitHub 账户设置,点击左边 SSH Key ,点击 Add SSH key ,粘贴刚刚复制的内容,然后保存。
输入 GitHub 账户的密码就能看到刚刚添加的 SSH Key 了。

Step4. 测试是否添加成功

Git Bush 中输入下面的代码,然后回车

1
2
$ ssh -T git@GitHub.com
# Attempts to ssh to GitHub

会得到如下的指纹提示:键入yes

1
2
3
The authenticity of host 'GitHub.com (207.97.227.239)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)?

如果出现下面的提示,恭喜你,验证成功。

1
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

如果你看到的是 access denied(拒绝访问) ,可以点击这里 ,查看解决办法。

然后将https替换成ssh重新下载下代码,就OK了~~~

Good Luck

** 参考文档 **

  1. Generating SSH keys

]]>
@@ -390,9 +390,9 @@ https://ioliu.cn/2015/the-front-end-javascript-specification/ 2015-05-12T04:53:34.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z -

类型

原始值:相当于传值(JavaScript对象都提供了字面量),使用字面量创建对象。

  • string
  • number
  • boolean
  • null
  • undefined
1
2
3
4
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9

复杂类型:相当于传引用

  • object
  • array
  • function
1
2
3
4
var foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9

对象

  1. 使用字面值创建对象
    1
    2
    3
    4
    5
    // bad
    var item = new Object();

    // good
    var item = {};
  2. 不要使用保留字 reserved words 作为键
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    var superman = {
    class: 'superhero',
    default: { clark: 'kent' },
    private: true
    };

    // good
    var superman = {
    klass: 'superhero',
    defaults: { clark: 'kent' },
    hidden: true
    };

数组

  1. 使用字面值创建数组
    1
    2
    3
    4
    5
    // bad
    var items = new Array();

    // good
    var items = [];
  2. 如果你不知道数组的长度,使用push
    1
    2
    3
    4
    5
    6
    7
    var someStack = [];

    // bad
    someStack[someStack.length] = 'abracadabra';

    // good
    someStack.push('abracadabra');
  3. 当你需要拷贝数组时使用slice . jsPerf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var len = items.length,
    itemsCopy = [],
    i;

    // bad
    for (i = 0; i < len; i++) {
    itemsCopy[i] = items[i];
    }

    // good
    itemsCopy = items.slice();
  4. 使用slice类数组的对象转成数组.
    1
    2
    3
    4
    function trigger() {
    var args = [].slice.apply(arguments);
    ...
    }

字符串

  1. 对字符串使用单引号 ''(因为大多时候我们的字符串。特别html会出现")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    var name = "Bob Parr";

    // good
    var name = 'Bob Parr';

    // bad
    var fullName = "Bob " + this.lastName;

    // good
    var fullName = 'Bob ' + this.lastName;
  2. 超过80(也有规定140的,项目具体可制定)个字符的字符串应该使用字符串连接换行
    !!!: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

    // bad
    var errorMessage = 'This is a super long error that \
    was thrown because of Batman. \
    When you stop to think about \
    how Batman had anything to do \
    with this, you would get nowhere \
    fast.';

    // good
    var errorMessage = 'This is a super long error that ' +
    'was thrown because of Batman.' +
    'When you stop to think about ' +
    'how Batman had anything to do ' +
    'with this, you would get nowhere ' +
    'fast.';
  3. 编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.
    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
    var items,
    messages,
    length, i;

    messages = [{
    state: 'success',
    message: 'This one worked.'
    },{
    state: 'success',
    message: 'This one worked as well.'
    },{
    state: 'error',
    message: 'This one did not work.'
    }];

    length = messages.length;

    // bad
    function inbox(messages) {
    items = '<ul>';
    for (i = 0; i < length; i++) {
    items += '<li>' + messages[i].message + '</li>';
    }
    return items + '</ul>';
    }

    // good
    function inbox(messages) {
    items = [];
    for (i = 0; i < length; i++) {
    items[i] = messages[i].message;
    }
    return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
    }

函数

  1. 函数表达式:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 匿名函数表达式
    var anonymous = function() {
    return true;
    };

    // 有名函数表达式
    var named = function named() {
    return true;
    };

    // 立即调用函数表达式
    (function() {
    console.log('Welcome to the Internet. Please follow me.');
    })();
  2. 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
  3. : ECMA-262定义把定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    if (currentUser) {
    function test() {
    console.log('Nope.');
    }
    }

    // good
    if (currentUser) {
    var test = function test() {
    console.log('Yup.');
    };
    }
  4. 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function nope(name, options, arguments) {
    // ...stuff...
    }

    // good
    function yup(name, options, args) {
    // ...stuff...
    }

属性

  1. 当使用变量和特殊非法变量名时,访问属性时可以使用中括号(. 优先).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var luke = {
    jedi: true,
    age: 28
    };

    function getProp(prop) {
    return luke[prop];
    }

    var isJedi = getProp('jedi');

变量

  1. 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。
    1
    2
    3
    4
    5
    // bad
    superPower = new SuperPower();

    // good
    var superPower = new SuperPower();
  2. 使用一个 var 以及新行声明多个变量,缩进4个空格。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    var items = getItems();
    var goSportsTeam = true;
    var dragonball = 'z';

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  3. 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

    // bad
    var i, items = getItems(),
    dragonball,
    goSportsTeam = true,
    len;

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball,
    length,
    i;
  4. 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
    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
    // bad
    function() {
    test();
    console.log('doing stuff..');

    //..other stuff..

    var name = getName();

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // good
    function() {
    var name = getName();

    test();
    console.log('doing stuff..');

    //..other stuff..

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // bad
    function() {
    var name = getName();

    if (!arguments.length) {
    return false;
    }

    return true;
    }

    // good
    function() {
    if (!arguments.length) {
    return false;
    }

    var name = getName();

    return true;
    }

条件表达式和等号

  1. 合理使用 ===!== 以及 ==!=.
  2. 合理使用表达式逻辑操作运算.
  3. 条件表达式的强制类型转换遵循以下规则:
  • 对象 被计算为 true
  • Undefined 被计算为 false
  • Null 被计算为 false
  • 布尔值 被计算为 布尔的值
  • 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
  • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true
    1
    2
    3
    4
    if ([0]) {
    // true
    // An array is an object, objects evaluate to true
    }
  1. 使用快捷方式.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (name !== '') {
    // ...stuff...
    }

    // good
    if (name) {
    // ...stuff...
    }

    // bad
    if (collection.length > 0) {
    // ...stuff...
    }

    // good
    if (collection.length) {
    // ...stuff...
    }
  2. 阅读 Truth Equality and JavaScript 了解更多

  1. 给所有多行的块使用大括号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (test)
    return false;

    // good
    if (test) return false;

    // good
    if (test) {
    return false;
    }

    // bad
    function() { return false; }

    // good
    function() {
    return false;
    }

注释

  1. 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值
    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
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {

    // ...stuff...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    *
    * @param <String> tag
    * @return <Element> element
    */
    function make(tag) {

    // ...stuff...

    return element;
    }
  2. 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.
    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
    // bad
    var active = true; // is current tab

    // good
    // is current tab
    var active = true;

    // bad
    function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }

    // good
    function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }
  3. 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXMETODO 帮助其他人迅速理解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function Calculator() {

    // FIXME: shouldn't use a global here
    total = 0;

    return this;
    }


    function Calculator() {

    // TODO: total should be configurable by an options param
    this.total = 0;

    return this;
    }
  4. 满足规范的文档,在需要文档的时候,可以尝试jsdoc.

空白

  1. 缩进、格式化能帮助团队更快得定位修复代码BUG.
  2. 将tab设为4个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    function() {
    ∙∙var name;
    }

    // bad
    function() {
    var name;
    }

    // good
    function() {
    ∙∙∙∙var name;
    }
  3. 大括号前放一个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    function test(){
    console.log('test');
    }

    // good
    function test() {
    console.log('test');
    }

    // bad
    dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });

    // good
    dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });
  4. 在做长方法链时使用缩进.
    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
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // good
    $('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

    // bad
    var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

    // good
    var leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .class('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

逗号

  1. 不要将逗号放前面
    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
    // bad
    var once
    , upon
    , aTime;

    // good
    var once,
    upon,
    aTime;

    // bad
    var hero = {
    firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
    };

    // good
    var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
    };
  2. 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
    };

    var heroes = [
    'Batman',
    'Superman',
    ];

    // good
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
    };

    var heroes = [
    'Batman',
    'Superman'
    ];

分号

  1. 语句结束一定要加分号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    (function() {
    var name = 'Skywalker'
    return name
    })()

    // good
    (function() {
    var name = 'Skywalker';
    return name;
    })();

    // good
    ;(function() {
    var name = 'Skywalker';
    return name;
    })();

类型转换

  1. 在语句的开始执行类型转换.
  2. 字符串:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  => this.reviewScore = 9;

    // bad
    var totalScore = this.reviewScore + '';

    // good
    var totalScore = '' + this.reviewScore;

    // bad
    var totalScore = '' + this.reviewScore + ' total score';

    // good
    var totalScore = this.reviewScore + ' total score';
  3. 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)
    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
    var inputValue = '4';

    // bad
    var val = new Number(inputValue);

    // bad
    var val = +inputValue;

    // bad
    var val = inputValue >> 0;

    // bad
    var val = parseInt(inputValue);

    // good
    var val = Number(inputValue);

    // good
    var val = parseInt(inputValue, 10);

    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var val = inputValue >> 0;
  4. 布尔值:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var age = 0;

    // bad
    var hasAge = new Boolean(age);

    // good
    var hasAge = Boolean(age);

    // good
    var hasAge = !!age;

命名约定

  1. 避免单个字符名,让你的变量名有描述意义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function q() {
    // ...stuff...
    }

    // good
    function query() {
    // ..stuff..
    }
  2. 当命名对象、函数和实例时使用驼峰命名规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // bad
    var OBJEcttsssss = {};
    var this_is_my_object = {};
    var this-is-my-object = {};
    function c() {};
    var u = new user({
    name: 'Bob Parr'
    });

    // good
    var thisIsMyObject = {};
    function thisIsMyFunction() {};
    var user = new User({
    name: 'Bob Parr'
    });
  3. 当命名构造函数或类时使用驼峰式大写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    function user(options) {
    this.name = options.name;
    }

    var bad = new user({
    name: 'nope'
    });

    // good
    function User(options) {
    this.name = options.name;
    }

    var good = new User({
    name: 'yup'
    });
  4. 命名私有属性时前面加个下划线 _
    1
    2
    3
    4
    5
    6
    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';

    // good
    this._firstName = 'Panda';
  5. 当保存对 this 的引用时使用 self(python 风格),避免this issue . Angular建议使用vm(MVVM模式中view-model)
    1
    2
    3
    4
    5
    6
    7
    // good
    function() {
    var self = this;
    return function() {
    console.log(self);
    };
    }

存取器

  1. 属性的存取器函数不是必需的
  2. 如果你确实有存取器函数的话使用getVal()setVal(‘hello’),java getter、setter风格或者jQuery风格
  3. 如果属性是布尔值,使用isVal()hasVal()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    if (!dragon.age()) {
    return false;
    }

    // good
    if (!dragon.hasAge()) {
    return false;
    }
  4. 可以创建get()set()函数,但是要保持一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Jedi(options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    Jedi.prototype.set = function(key, val) {
    this[key] = val;
    };

    Jedi.prototype.get = function(key) {
    return this[key];
    };

构造器

  1. 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function Jedi() {
    console.log('new jedi');
    }

    // bad
    Jedi.prototype = {
    fight: function fight() {
    console.log('fighting');
    },

    block: function block() {
    console.log('blocking');
    }
    };

    // good
    Jedi.prototype.fight = function fight() {
    console.log('fighting');
    };

    Jedi.prototype.block = function block() {
    console.log('blocking');
    };
  2. 方法可以返回 this 帮助方法可链。
    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
    // bad
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return true;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    };

    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined

    // good
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return this;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    return this;
    };

    var luke = new Jedi();

    luke.jump()
    .setHeight(20);
  3. 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Jedi(options) {
    options || (options = {});
    this.name = options.name || 'no name';
    }

    Jedi.prototype.getName = function getName() {
    return this.name;
    };

    Jedi.prototype.toString = function toString() {
    return 'Jedi - ' + this.getName();
    };

事件

  1. 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    $(this).trigger('listingUpdated', listing.id);

    ...

    $(this).on('listingUpdated', function(e, listingId) {
    // do something with listingId
    });


    // good
    $(this).trigger('listingUpdated', { listingId : listing.id });

    ...

    $(this).on('listingUpdated', function(e, data) {
    // do something with data.listingId
    });

模块

  1. 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
  2. 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
  3. 总是在模块顶部声明 'use strict';,引入JSHint规范
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // fancyInput/fancyInput.js

    function(global) {
    'use strict';

    var previousFancyInput = global.FancyInput;

    function FancyInput(options) {
    this.options = options || {};
    }

    FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
    };

    global.FancyInput = FancyInput;
    })(this);

jQuery

  1. 对于jQuery对象以$开头,以和原生DOM节点区分。
    1
    2
    3
    4
    5
    // bad
    var menu = $(".menu");

    // good
    var $menu = $(".menu");
  2. 缓存jQuery查询
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // bad
    function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
    'background-color': 'pink'
    });
    }

    // good
    function setSidebar() {
    var $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
    'background-color': 'pink'
    });
    }
  3. 对DOM查询使用级联的 $('.sidebar ul')$('.sidebar ul')jsPerf
  4. 对有作用域的jQuery对象查询使用 find
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $('.sidebar', 'ul').hide();

    // bad
    $('.sidebar').find('ul').hide();

    // good
    $('.sidebar ul').hide();

    // good
    $('.sidebar > ul').hide();

    // good (slower)
    $sidebar.find('ul');

    // good (faster)
    $($sidebar[0]).find('ul');
  5. 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。
    1
    2
    3
    $(function(){
    //do your page init.
    });
  6. 事件利用jQuery.on从页面分离到JavaScript文件。
    1
    2
    3
    4
    5
    6
    7
    // bad
    <a id="myLink" href="#" onclick="myEventHandler();"></a>

    // good
    <a id="myLink" href="#"></a>

    $("#myLink").on("click", myEventHandler);
  7. 对于Ajax使用promise方式。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $.ajax({
    ...
    success : function(){
    },
    error : function(){
    }
    })

    // good
    $.ajax({.
    ..
    }).then( function( ){
    // success
    }, function( ){
    // error
    })
  8. 利用promisedeferred对象解决延迟注册问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var dtd = $.Deferred(); // 新建一个deferred对象
    var wait = function(dtd){
    var tasks = function(){
    alert("执行完毕!");
    dtd.resolve(); // 改变deferred对象的执行状态
    };
    setTimeout(tasks,5000);
      return dtd;
    };
  9. HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。

ECMAScript 5兼容性

尽量采用ES5方法,特别数组mapfilterforEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscorelodash 常用辅助库.

HTML、CSS、JavaScript分离

  1. 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中
    分离在不同类型文件,文件link。
  2. HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。
  3. CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。
  4. 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。
  5. 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + flux架构、Knockout等。
  6. 对于兼容性可用Modernizr规范库辅助。

使用jsHint

  1. 前端项目中推荐引入 jshint插件来规范项目编码规范。以及一套完善的IDE配置。
  2. 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。

前端工具

  1. 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。
  2. 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。
  3. 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。

本文转载自破狼,原文略有修改,侵权即删.
原文链接:前端javascript规范
原文作者:破狼

]]>
+

类型

原始值:相当于传值(JavaScript对象都提供了字面量),使用字面量创建对象。

  • string
  • number
  • boolean
  • null
  • undefined
1
2
3
4
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9

复杂类型:相当于传引用

  • object
  • array
  • function
1
2
3
4
var foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9

对象

  1. 使用字面值创建对象
    1
    2
    3
    4
    5
    // bad
    var item = new Object();

    // good
    var item = {};
  2. 不要使用保留字 reserved words 作为键
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    var superman = {
    class: 'superhero',
    default: { clark: 'kent' },
    private: true
    };

    // good
    var superman = {
    klass: 'superhero',
    defaults: { clark: 'kent' },
    hidden: true
    };

数组

  1. 使用字面值创建数组
    1
    2
    3
    4
    5
    // bad
    var items = new Array();

    // good
    var items = [];
  2. 如果你不知道数组的长度,使用push
    1
    2
    3
    4
    5
    6
    7
    var someStack = [];

    // bad
    someStack[someStack.length] = 'abracadabra';

    // good
    someStack.push('abracadabra');
  3. 当你需要拷贝数组时使用slice . jsPerf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var len = items.length,
    itemsCopy = [],
    i;

    // bad
    for (i = 0; i < len; i++) {
    itemsCopy[i] = items[i];
    }

    // good
    itemsCopy = items.slice();
  4. 使用slice类数组的对象转成数组.
    1
    2
    3
    4
    function trigger() {
    var args = [].slice.apply(arguments);
    ...
    }

字符串

  1. 对字符串使用单引号 ''(因为大多时候我们的字符串。特别html会出现")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    var name = "Bob Parr";

    // good
    var name = 'Bob Parr';

    // bad
    var fullName = "Bob " + this.lastName;

    // good
    var fullName = 'Bob ' + this.lastName;
  2. 超过80(也有规定140的,项目具体可制定)个字符的字符串应该使用字符串连接换行
    !!!: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

    // bad
    var errorMessage = 'This is a super long error that \
    was thrown because of Batman. \
    When you stop to think about \
    how Batman had anything to do \
    with this, you would get nowhere \
    fast.';

    // good
    var errorMessage = 'This is a super long error that ' +
    'was thrown because of Batman.' +
    'When you stop to think about ' +
    'how Batman had anything to do ' +
    'with this, you would get nowhere ' +
    'fast.';
  3. 编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.
    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
    var items,
    messages,
    length, i;

    messages = [{
    state: 'success',
    message: 'This one worked.'
    },{
    state: 'success',
    message: 'This one worked as well.'
    },{
    state: 'error',
    message: 'This one did not work.'
    }];

    length = messages.length;

    // bad
    function inbox(messages) {
    items = '<ul>';
    for (i = 0; i < length; i++) {
    items += '<li>' + messages[i].message + '</li>';
    }
    return items + '</ul>';
    }

    // good
    function inbox(messages) {
    items = [];
    for (i = 0; i < length; i++) {
    items[i] = messages[i].message;
    }
    return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
    }

函数

  1. 函数表达式:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 匿名函数表达式
    var anonymous = function() {
    return true;
    };

    // 有名函数表达式
    var named = function named() {
    return true;
    };

    // 立即调用函数表达式
    (function() {
    console.log('Welcome to the Internet. Please follow me.');
    })();
  2. 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
  3. : ECMA-262定义把定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    if (currentUser) {
    function test() {
    console.log('Nope.');
    }
    }

    // good
    if (currentUser) {
    var test = function test() {
    console.log('Yup.');
    };
    }
  4. 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function nope(name, options, arguments) {
    // ...stuff...
    }

    // good
    function yup(name, options, args) {
    // ...stuff...
    }

属性

  1. 当使用变量和特殊非法变量名时,访问属性时可以使用中括号(. 优先).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var luke = {
    jedi: true,
    age: 28
    };

    function getProp(prop) {
    return luke[prop];
    }

    var isJedi = getProp('jedi');

变量

  1. 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。
    1
    2
    3
    4
    5
    // bad
    superPower = new SuperPower();

    // good
    var superPower = new SuperPower();
  2. 使用一个 var 以及新行声明多个变量,缩进4个空格。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    var items = getItems();
    var goSportsTeam = true;
    var dragonball = 'z';

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  3. 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

    // bad
    var i, items = getItems(),
    dragonball,
    goSportsTeam = true,
    len;

    // good
    var items = getItems(),
    goSportsTeam = true,
    dragonball,
    length,
    i;
  4. 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
    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
    // bad
    function() {
    test();
    console.log('doing stuff..');

    //..other stuff..

    var name = getName();

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // good
    function() {
    var name = getName();

    test();
    console.log('doing stuff..');

    //..other stuff..

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // bad
    function() {
    var name = getName();

    if (!arguments.length) {
    return false;
    }

    return true;
    }

    // good
    function() {
    if (!arguments.length) {
    return false;
    }

    var name = getName();

    return true;
    }

条件表达式和等号

  1. 合理使用 ===!== 以及 ==!=.
  2. 合理使用表达式逻辑操作运算.
  3. 条件表达式的强制类型转换遵循以下规则:
  • 对象 被计算为 true
  • Undefined 被计算为 false
  • Null 被计算为 false
  • 布尔值 被计算为 布尔的值
  • 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
  • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true
    1
    2
    3
    4
    if ([0]) {
    // true
    // An array is an object, objects evaluate to true
    }
  1. 使用快捷方式.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (name !== '') {
    // ...stuff...
    }

    // good
    if (name) {
    // ...stuff...
    }

    // bad
    if (collection.length > 0) {
    // ...stuff...
    }

    // good
    if (collection.length) {
    // ...stuff...
    }
  2. 阅读 Truth Equality and JavaScript 了解更多

  1. 给所有多行的块使用大括号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (test)
    return false;

    // good
    if (test) return false;

    // good
    if (test) {
    return false;
    }

    // bad
    function() { return false; }

    // good
    function() {
    return false;
    }

注释

  1. 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值
    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
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {

    // ...stuff...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    *
    * @param <String> tag
    * @return <Element> element
    */
    function make(tag) {

    // ...stuff...

    return element;
    }
  2. 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.
    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
    // bad
    var active = true; // is current tab

    // good
    // is current tab
    var active = true;

    // bad
    function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }

    // good
    function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }
  3. 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXMETODO 帮助其他人迅速理解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function Calculator() {

    // FIXME: shouldn't use a global here
    total = 0;

    return this;
    }


    function Calculator() {

    // TODO: total should be configurable by an options param
    this.total = 0;

    return this;
    }
  4. 满足规范的文档,在需要文档的时候,可以尝试jsdoc.

空白

  1. 缩进、格式化能帮助团队更快得定位修复代码BUG.
  2. 将tab设为4个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    function() {
    ∙∙var name;
    }

    // bad
    function() {
    var name;
    }

    // good
    function() {
    ∙∙∙∙var name;
    }
  3. 大括号前放一个空格
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    function test(){
    console.log('test');
    }

    // good
    function test() {
    console.log('test');
    }

    // bad
    dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });

    // good
    dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });
  4. 在做长方法链时使用缩进.
    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
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // good
    $('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

    // bad
    var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

    // good
    var leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .class('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

逗号

  1. 不要将逗号放前面
    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
    // bad
    var once
    , upon
    , aTime;

    // good
    var once,
    upon,
    aTime;

    // bad
    var hero = {
    firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
    };

    // good
    var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
    };
  2. 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
    };

    var heroes = [
    'Batman',
    'Superman',
    ];

    // good
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
    };

    var heroes = [
    'Batman',
    'Superman'
    ];

分号

  1. 语句结束一定要加分号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    (function() {
    var name = 'Skywalker'
    return name
    })()

    // good
    (function() {
    var name = 'Skywalker';
    return name;
    })();

    // good
    ;(function() {
    var name = 'Skywalker';
    return name;
    })();

类型转换

  1. 在语句的开始执行类型转换.
  2. 字符串:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  => this.reviewScore = 9;

    // bad
    var totalScore = this.reviewScore + '';

    // good
    var totalScore = '' + this.reviewScore;

    // bad
    var totalScore = '' + this.reviewScore + ' total score';

    // good
    var totalScore = this.reviewScore + ' total score';
  3. 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)
    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
    var inputValue = '4';

    // bad
    var val = new Number(inputValue);

    // bad
    var val = +inputValue;

    // bad
    var val = inputValue >> 0;

    // bad
    var val = parseInt(inputValue);

    // good
    var val = Number(inputValue);

    // good
    var val = parseInt(inputValue, 10);

    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var val = inputValue >> 0;
  4. 布尔值:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var age = 0;

    // bad
    var hasAge = new Boolean(age);

    // good
    var hasAge = Boolean(age);

    // good
    var hasAge = !!age;

命名约定

  1. 避免单个字符名,让你的变量名有描述意义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function q() {
    // ...stuff...
    }

    // good
    function query() {
    // ..stuff..
    }
  2. 当命名对象、函数和实例时使用驼峰命名规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // bad
    var OBJEcttsssss = {};
    var this_is_my_object = {};
    var this-is-my-object = {};
    function c() {};
    var u = new user({
    name: 'Bob Parr'
    });

    // good
    var thisIsMyObject = {};
    function thisIsMyFunction() {};
    var user = new User({
    name: 'Bob Parr'
    });
  3. 当命名构造函数或类时使用驼峰式大写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    function user(options) {
    this.name = options.name;
    }

    var bad = new user({
    name: 'nope'
    });

    // good
    function User(options) {
    this.name = options.name;
    }

    var good = new User({
    name: 'yup'
    });
  4. 命名私有属性时前面加个下划线 _
    1
    2
    3
    4
    5
    6
    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';

    // good
    this._firstName = 'Panda';
  5. 当保存对 this 的引用时使用 self(python 风格),避免this issue . Angular建议使用vm(MVVM模式中view-model)
    1
    2
    3
    4
    5
    6
    7
    // good
    function() {
    var self = this;
    return function() {
    console.log(self);
    };
    }

存取器

  1. 属性的存取器函数不是必需的
  2. 如果你确实有存取器函数的话使用getVal()setVal(‘hello’),java getter、setter风格或者jQuery风格
  3. 如果属性是布尔值,使用isVal()hasVal()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    if (!dragon.age()) {
    return false;
    }

    // good
    if (!dragon.hasAge()) {
    return false;
    }
  4. 可以创建get()set()函数,但是要保持一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Jedi(options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    Jedi.prototype.set = function(key, val) {
    this[key] = val;
    };

    Jedi.prototype.get = function(key) {
    return this[key];
    };

构造器

  1. 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function Jedi() {
    console.log('new jedi');
    }

    // bad
    Jedi.prototype = {
    fight: function fight() {
    console.log('fighting');
    },

    block: function block() {
    console.log('blocking');
    }
    };

    // good
    Jedi.prototype.fight = function fight() {
    console.log('fighting');
    };

    Jedi.prototype.block = function block() {
    console.log('blocking');
    };
  2. 方法可以返回 this 帮助方法可链。
    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
    // bad
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return true;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    };

    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined

    // good
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return this;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    return this;
    };

    var luke = new Jedi();

    luke.jump()
    .setHeight(20);
  3. 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Jedi(options) {
    options || (options = {});
    this.name = options.name || 'no name';
    }

    Jedi.prototype.getName = function getName() {
    return this.name;
    };

    Jedi.prototype.toString = function toString() {
    return 'Jedi - ' + this.getName();
    };

事件

  1. 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    $(this).trigger('listingUpdated', listing.id);

    ...

    $(this).on('listingUpdated', function(e, listingId) {
    // do something with listingId
    });


    // good
    $(this).trigger('listingUpdated', { listingId : listing.id });

    ...

    $(this).on('listingUpdated', function(e, data) {
    // do something with data.listingId
    });

模块

  1. 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
  2. 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
  3. 总是在模块顶部声明 'use strict';,引入JSHint规范
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // fancyInput/fancyInput.js

    function(global) {
    'use strict';

    var previousFancyInput = global.FancyInput;

    function FancyInput(options) {
    this.options = options || {};
    }

    FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
    };

    global.FancyInput = FancyInput;
    })(this);

jQuery

  1. 对于jQuery对象以$开头,以和原生DOM节点区分。
    1
    2
    3
    4
    5
    // bad
    var menu = $(".menu");

    // good
    var $menu = $(".menu");
  2. 缓存jQuery查询
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // bad
    function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
    'background-color': 'pink'
    });
    }

    // good
    function setSidebar() {
    var $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
    'background-color': 'pink'
    });
    }
  3. 对DOM查询使用级联的 $('.sidebar ul')$('.sidebar ul')jsPerf
  4. 对有作用域的jQuery对象查询使用 find
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $('.sidebar', 'ul').hide();

    // bad
    $('.sidebar').find('ul').hide();

    // good
    $('.sidebar ul').hide();

    // good
    $('.sidebar > ul').hide();

    // good (slower)
    $sidebar.find('ul');

    // good (faster)
    $($sidebar[0]).find('ul');
  5. 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。
    1
    2
    3
    $(function(){
    //do your page init.
    });
  6. 事件利用jQuery.on从页面分离到JavaScript文件。
    1
    2
    3
    4
    5
    6
    7
    // bad
    <a id="myLink" href="#" onclick="myEventHandler();"></a>

    // good
    <a id="myLink" href="#"></a>

    $("#myLink").on("click", myEventHandler);
  7. 对于Ajax使用promise方式。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    $.ajax({
    ...
    success : function(){
    },
    error : function(){
    }
    })

    // good
    $.ajax({.
    ..
    }).then( function( ){
    // success
    }, function( ){
    // error
    })
  8. 利用promisedeferred对象解决延迟注册问题。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var dtd = $.Deferred(); // 新建一个deferred对象
    var wait = function(dtd){
    var tasks = function(){
    alert("执行完毕!");
    dtd.resolve(); // 改变deferred对象的执行状态
    };
    setTimeout(tasks,5000);
      return dtd;
    };
  9. HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。

ECMAScript 5兼容性

尽量采用ES5方法,特别数组mapfilterforEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscorelodash 常用辅助库.

HTML、CSS、JavaScript分离

  1. 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中
    分离在不同类型文件,文件link。
  2. HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。
  3. CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。
  4. 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。
  5. 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + flux架构、Knockout等。
  6. 对于兼容性可用Modernizr规范库辅助。

使用jsHint

  1. 前端项目中推荐引入 jshint插件来规范项目编码规范。以及一套完善的IDE配置。
  2. 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。

前端工具

  1. 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。
  2. 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。
  3. 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。

本文转载自破狼,原文略有修改,侵权即删.
原文链接:前端javascript规范
原文作者:破狼

]]>
@@ -421,9 +421,9 @@ https://ioliu.cn/2015/about-javascript-spcial-technique/ 2015-05-07T02:21:08.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z -

这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们。
## 遍历一个obj的属性到数组
1
2
3
4
5
6
7
function getAttr(obj){
var a=[];
for(a[a.length] in obj);
return a;
}
console.log(getAttr({'name':'zhangsan','age':'20'}));//输出:['name','age']

乍一看可能比较蒙,不过仔细分析还是不难理解的。常见用法是`for(var key in obj)`,这里`key`初始也是`undefined`的,`a[a.length]`整体也是`undefined`,所以二者其实是等价的。 在`for`循环中,`obj`的属性会依次赋值给`key`,同样,也依次赋值给`a[a.length]`,这里`length`一直在变,就巧妙地挨个赋值给数组的每一个元素了。

重复字符串(如abc=>abcabc)

1
2
3
function repeat(target,n){
return (new Array(n+1).join(target));
}

改进版本:

1
2
3
4
function repeat(target,n){
return Array.prototype.join.call({length:n+1},target);
//之所以要创建带length属性的对象,是因为调用数组原型方法时,必须是一个类数组对象,而类数组对象的条件就是length为非负整数
}

不新建数组,而是用拥有length属性的对象替代,然后调用数组的join方法,性能提升很大.
再改进:

1
2
3
4
5
6
7
var repeat=(function(){
var join=Array.prototype.join,obj={};
return function(target,n){
obj.length=n+1;
return join.call(obj,target);
}
})();

利用闭包将对象join方法缓存起来,不用每次都新建对象和寻找方法

for循环

for循环中,当第二项为false时会终止循环,这里并不一定存在比较,可以直接赋值,如果赋值为undefined之类的值时,转成bool值也为假,因此也会终止,比如遍历数组可以写成:

1
for(var i=arr.length,element;element=arr[—-i];){…}

这里,第二项一定是arr[--i]而非arr[i--],如果是后者的话,上来就是undefined,就不会执行循环体,或者for(var i=0,element;element=arr[i++];){…}

NaN

NaN是JS中唯一不等于自己的值,因此可以用来判断一个变量是否真的为NaN:a!==a

/+等算术运算符

</+等运算符会强制符号两边的表达式执行valueOf然后比较,所以如果两边是函数或者对象,而又重写了该对象的valueOf方法,就会自动执行两边的方法。如:

1
2
var a={valueOf:function(){console.log("aaa");}},b={valueOf:function(){console.log("bbb");}};
a < b;//会输出:aaa;bbb;false

闭包

理解闭包需学会三个基本事实:

  1. JS允许你引用在当前函数意外定义的变量
  2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这是因为JS的函数值包含里比调用它们时执行所需要的代码更多的信息
  3. 闭包可以更新外部变量的值。这是因为闭包存储的是外部变量的引用而非值副本。如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function box(){
    var val=undefined;
    return {
    set:function(x){val=x;},
    get:function(){return val;}
    };
    }
    var b=box();
    b.get();//“undefined”
    b.set(5);
    b.get();//5
    这一点很重要,比如在函数的for循环体内返回闭包或者有闭包取for循环的计数器值,那么这个闭包取到的永远是for循环结束时i的最终值,因为闭包存储的是它的引用而非当时的值副本。

块级作用域

JS没有块级作用域,因此通常情况下函数内部的所有变量都是绑定到函数作用域的,也就是说相当于都在函数一开始就声明了的,一个例外就是try/catch中的变量是块级的,只属于try/catch块。

嵌套函数

众所周知,在函数内部声明函数是可以的,但是在在函数内的局部块里声明,可能会出现问题:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
function f(){return “local”}
var result=[];
if(x){
result.push(f());
}
result.push(f());
return result;
}
test(true);//[“local”,”local”]
test(false);//[“local”]

将函数声明到if块中:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
var result=[];
if(x){
function f(){return “local”}
result.push(f());
}
result.push(f());
return result;
}
test(true);//?
test(false);//?

结果会如何呢?理论上讲,JS没有块级作用域,因此f()的作用域是整个test函数,因此合理猜测应该是与上一次输出相同,全部为”local”,可是并不是所有的JS执行环境都如此行事,有的会根据是否执行包含f的代码块来有条件地绑定函数f(绑定即意味着将该变量绑定到其最近的作用域,而赋值是发生在代码实际执行到赋值那一步的时候进行的)。
因此最好的办法是如果要声明嵌套函数,都在其富函数的最外层声明,要么就不要声明函数,而是使用var声明和函数表达式来实现:

1
2
3
4
5
6
7
8
9
10
function f(){return “global”;}
function test(x){
var result=[];
if(x){
var g=function(){return “local”}
result.push(g());
}
result.push(f());
return result;
}

hasOwnProperty

用js创建字典的时候,如果是利用对象的方式(因为JS对象的核心是一个字符串属性名称和属性值的映射表),会遇到一个问题就是原型污染,因为获取字典属性值的时候用hasOwnProperty还好,如果用for in遍历的话,不仅会遍历对象本身,包括它的原型,因此如果在其他地方污染了Object的原型,那么for in就会产生非预期的结果,这时可能会用hasOwnProperty来先检测该对象本身是否含有属性来避免原型污染,然而更极端的情况是连hasOwnProperty这个原型方法都有可能被污染。
避免原型污染的方法是在创建字典对象的时候用Object.create(null)来创建一个完全空对象,这个对象没有原型,这个方法是ES5的,在没有这个方法可用的时候,最好是创建字典类,然后在字典类里用数组来存储有序集合,自己维护这个集合。

类数组对象

JS中的类数组对象可以享用数组的大部分原型方法如map
类数组对象是指满足两个条件的对象:
一是具备合理范围值内的length属性
二是length属性大于该对象的最大索引,索引是一个合理范围的证书,它的字符串表示的是对象的一个key;
但是数组的一个原型方法contact是不能被类数组对象调用的,因此需要先用[].slice.call把类数组对象转换为真正的数组比如[].slice.call(arguments)

结构类型

并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类的实例,而是直接返回对象,对象具备预期的方法和属性,比如:

1
2
3
4
5
6
7
SomeObj.someWidget=function(opts){
return {
a:blabla,
b:function(){...},
c:blabla
}
}

JavaScript 自动插入分号

JavaScript 具备自动插入分号的能力,但是自动插入分号并不是万能的,其有三条规则:

  1. 只在}标记之前、一个或多个换行之后以及程序输入的结尾被插入

  2. 分号只在随后的输入标记不能被解析时插入

    !!这一点很重要,比如:
    a = b
    (fn());
    是不会在a=b之后自动插入分号的,因为a=b(f())是可以被解析的,因此像(,[,+,-,/开头的时候,需要特别注意上一行可能不会自动插入。
    还有一些情况,尽管不会出现解析错误,JS仍然会强制插入分号,这就是所谓的JS语法限制产生式。它不允许在两个字符间出现换行,最危险的就是return语句,如
    return
    {};
    会被强制插入而成为
    return;
    {};
    类似的还有:throw语句、带有显示标签的break或着continue语句、后置自增或自减运算符

  3. 分号不会作为分隔符在for循环空语句的头部被自动插入

因此,最好的办法是在自己的js文件的最开始防御性地插入;,这样在合并js文件的时候就不会出问题了。

本文转载自博客园,原文略有删减,侵权即删.
原文链接:你可能不知道的一些JavaScript 奇技淫巧
原文作者:FirstLovt

]]>
+

这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们。
## 遍历一个obj的属性到数组
1
2
3
4
5
6
7
function getAttr(obj){
var a=[];
for(a[a.length] in obj);
return a;
}
console.log(getAttr({'name':'zhangsan','age':'20'}));//输出:['name','age']

乍一看可能比较蒙,不过仔细分析还是不难理解的。常见用法是`for(var key in obj)`,这里`key`初始也是`undefined`的,`a[a.length]`整体也是`undefined`,所以二者其实是等价的。 在`for`循环中,`obj`的属性会依次赋值给`key`,同样,也依次赋值给`a[a.length]`,这里`length`一直在变,就巧妙地挨个赋值给数组的每一个元素了。

重复字符串(如abc=>abcabc)

1
2
3
function repeat(target,n){
return (new Array(n+1).join(target));
}

改进版本:

1
2
3
4
function repeat(target,n){
return Array.prototype.join.call({length:n+1},target);
//之所以要创建带length属性的对象,是因为调用数组原型方法时,必须是一个类数组对象,而类数组对象的条件就是length为非负整数
}

不新建数组,而是用拥有length属性的对象替代,然后调用数组的join方法,性能提升很大.
再改进:

1
2
3
4
5
6
7
var repeat=(function(){
var join=Array.prototype.join,obj={};
return function(target,n){
obj.length=n+1;
return join.call(obj,target);
}
})();

利用闭包将对象join方法缓存起来,不用每次都新建对象和寻找方法

for循环

for循环中,当第二项为false时会终止循环,这里并不一定存在比较,可以直接赋值,如果赋值为undefined之类的值时,转成bool值也为假,因此也会终止,比如遍历数组可以写成:

1
for(var i=arr.length,element;element=arr[—-i];){…}

这里,第二项一定是arr[--i]而非arr[i--],如果是后者的话,上来就是undefined,就不会执行循环体,或者for(var i=0,element;element=arr[i++];){…}

NaN

NaN是JS中唯一不等于自己的值,因此可以用来判断一个变量是否真的为NaN:a!==a

/+等算术运算符

</+等运算符会强制符号两边的表达式执行valueOf然后比较,所以如果两边是函数或者对象,而又重写了该对象的valueOf方法,就会自动执行两边的方法。如:

1
2
var a={valueOf:function(){console.log("aaa");}},b={valueOf:function(){console.log("bbb");}};
a < b;//会输出:aaa;bbb;false

闭包

理解闭包需学会三个基本事实:

  1. JS允许你引用在当前函数意外定义的变量
  2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这是因为JS的函数值包含里比调用它们时执行所需要的代码更多的信息
  3. 闭包可以更新外部变量的值。这是因为闭包存储的是外部变量的引用而非值副本。如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function box(){
    var val=undefined;
    return {
    set:function(x){val=x;},
    get:function(){return val;}
    };
    }
    var b=box();
    b.get();//“undefined”
    b.set(5);
    b.get();//5
    这一点很重要,比如在函数的for循环体内返回闭包或者有闭包取for循环的计数器值,那么这个闭包取到的永远是for循环结束时i的最终值,因为闭包存储的是它的引用而非当时的值副本。

块级作用域

JS没有块级作用域,因此通常情况下函数内部的所有变量都是绑定到函数作用域的,也就是说相当于都在函数一开始就声明了的,一个例外就是try/catch中的变量是块级的,只属于try/catch块。

嵌套函数

众所周知,在函数内部声明函数是可以的,但是在在函数内的局部块里声明,可能会出现问题:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
function f(){return “local”}
var result=[];
if(x){
result.push(f());
}
result.push(f());
return result;
}
test(true);//[“local”,”local”]
test(false);//[“local”]

将函数声明到if块中:

1
2
3
4
5
6
7
8
9
10
11
12
function f(){return “global”;}
function test(x){
var result=[];
if(x){
function f(){return “local”}
result.push(f());
}
result.push(f());
return result;
}
test(true);//?
test(false);//?

结果会如何呢?理论上讲,JS没有块级作用域,因此f()的作用域是整个test函数,因此合理猜测应该是与上一次输出相同,全部为”local”,可是并不是所有的JS执行环境都如此行事,有的会根据是否执行包含f的代码块来有条件地绑定函数f(绑定即意味着将该变量绑定到其最近的作用域,而赋值是发生在代码实际执行到赋值那一步的时候进行的)。
因此最好的办法是如果要声明嵌套函数,都在其富函数的最外层声明,要么就不要声明函数,而是使用var声明和函数表达式来实现:

1
2
3
4
5
6
7
8
9
10
function f(){return “global”;}
function test(x){
var result=[];
if(x){
var g=function(){return “local”}
result.push(g());
}
result.push(f());
return result;
}

hasOwnProperty

用js创建字典的时候,如果是利用对象的方式(因为JS对象的核心是一个字符串属性名称和属性值的映射表),会遇到一个问题就是原型污染,因为获取字典属性值的时候用hasOwnProperty还好,如果用for in遍历的话,不仅会遍历对象本身,包括它的原型,因此如果在其他地方污染了Object的原型,那么for in就会产生非预期的结果,这时可能会用hasOwnProperty来先检测该对象本身是否含有属性来避免原型污染,然而更极端的情况是连hasOwnProperty这个原型方法都有可能被污染。
避免原型污染的方法是在创建字典对象的时候用Object.create(null)来创建一个完全空对象,这个对象没有原型,这个方法是ES5的,在没有这个方法可用的时候,最好是创建字典类,然后在字典类里用数组来存储有序集合,自己维护这个集合。

类数组对象

JS中的类数组对象可以享用数组的大部分原型方法如map
类数组对象是指满足两个条件的对象:
一是具备合理范围值内的length属性
二是length属性大于该对象的最大索引,索引是一个合理范围的证书,它的字符串表示的是对象的一个key;
但是数组的一个原型方法contact是不能被类数组对象调用的,因此需要先用[].slice.call把类数组对象转换为真正的数组比如[].slice.call(arguments)

结构类型

并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类的实例,而是直接返回对象,对象具备预期的方法和属性,比如:

1
2
3
4
5
6
7
SomeObj.someWidget=function(opts){
return {
a:blabla,
b:function(){...},
c:blabla
}
}

JavaScript 自动插入分号

JavaScript 具备自动插入分号的能力,但是自动插入分号并不是万能的,其有三条规则:

  1. 只在}标记之前、一个或多个换行之后以及程序输入的结尾被插入

  2. 分号只在随后的输入标记不能被解析时插入

    !!这一点很重要,比如:
    a = b
    (fn());
    是不会在a=b之后自动插入分号的,因为a=b(f())是可以被解析的,因此像(,[,+,-,/开头的时候,需要特别注意上一行可能不会自动插入。
    还有一些情况,尽管不会出现解析错误,JS仍然会强制插入分号,这就是所谓的JS语法限制产生式。它不允许在两个字符间出现换行,最危险的就是return语句,如
    return
    {};
    会被强制插入而成为
    return;
    {};
    类似的还有:throw语句、带有显示标签的break或着continue语句、后置自增或自减运算符

  3. 分号不会作为分隔符在for循环空语句的头部被自动插入

因此,最好的办法是在自己的js文件的最开始防御性地插入;,这样在合并js文件的时候就不会出问题了。

本文转载自博客园,原文略有删减,侵权即删.
原文链接:你可能不知道的一些JavaScript 奇技淫巧
原文作者:FirstLovt

]]>
@@ -456,7 +456,7 @@ https://ioliu.cn/2015/hexo-your-blog/ 2015-05-06T02:21:08.000Z - 2024-03-28T08:06:05.972Z + 2024-07-23T05:14:42.487Z

今天把博客移到了Hexo,感觉蛮不错的 ^_^ .

简介

hexo 是一款基于Node.js的静态博客框架。目前在GitHub上已有4k+ star 和 700+ fork (官网)。
是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

特性

  • 风一般的速度:
    Hexo基于Node.js,支持多进程,几百篇文章也可以秒生成。
  • 流畅的撰写:
    支持GitHub Flavored Markdown和所有Octopress插件
  • 扩展性:
    Hexo支持EJSSwigStylus。通过插件支持HamlJadeLess.

快速入门

安装

安装 Hexo 相当简单。然而在安装前,您必须检查电脑中是否已安装下列应用程序:

如果您的电脑中已经安装上述必备程序,那么恭喜您!接下来只需要使用 npm 即可完成 Hexo 的安装。

1
npm install -g hexo-cli 

仅需一步就把 Hexo 本体和所有相依套件安装完毕,很简单吧?

升级

更新hexo到最新版

1
npm update hexo -g  

初始化

1
2
3
hexo init <folder>
cd <floder>
npm install

如果指定 <folder>,便会在目前的资料夹建立一个名为 <folder> 的新文件夹;否则会在目前文件夹初始化。

新建

1
hexo new [layout] <title>

新建一篇文章。如果没有设置 layout 的话,默认使用 _config.yml 中的 default_layout 参数代替。如果标题包含空格的话,请使用引号括起来。

生成静态文件

1
2
hexo g
//或者 hexo generate

启动服务

1
2
hexo s
//或者 hexo server

启动服务后,打开浏览器输入 http://localhost:4000 回车,即可看到效果.

部署

1
2
hexo d
//可以通过hexo d -g 命令完成生成和部署

如果出现错误,可能是没有安装部署插件,请执行下面的命令安装插件:

1
npm install hexo-deploy-git --save-dev

Hexo官网:[http://Hexo.io]
部署Hexo

]]>
diff --git a/baidusitemap.xml b/baidusitemap.xml index 14161fc9..bd5682f1 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -2,62 +2,62 @@ https://ioliu.cn/2016/MarkDown-incomplete-Guide/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2015/about-javascript-spcial-technique/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2017/add-a-lock-to-your-website/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2017/add-valine-comments-to-your-blog/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2016/commonly-used-media-queries/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2017/country-city-and-language/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2016/css-content-and-special-characters/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2015/generating-ssh-key/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2017/git-command-backup/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2015/hexo-your-blog/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2016/judgment-variable-type/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2017/mysql-tutorial/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2015/the-front-end-javascript-specification/ - 2024-03-28 + 2024-07-23 https://ioliu.cn/2024/upgrade-debian-kernel-version/ - 2024-03-28 + 2024-07-23 \ No newline at end of file diff --git a/books/index.html b/books/index.html index 407a2c81..f88693e4 100644 --- a/books/index.html +++ b/books/index.html @@ -1 +1 @@ -书单 | 云淡风轻
\ No newline at end of file +书单 | 云淡风轻
\ No newline at end of file diff --git a/categories/index.html b/categories/index.html index 9827b41c..f33c78de 100644 --- a/categories/index.html +++ b/categories/index.html @@ -1 +1 @@ -分类 | 云淡风轻

分类

\ No newline at end of file +分类 | 云淡风轻

分类

\ No newline at end of file diff --git "a/categories/\345\205\266\344\273\226/index.html" "b/categories/\345\205\266\344\273\226/index.html" index 39858566..bca1d527 100644 --- "a/categories/\345\205\266\344\273\226/index.html" +++ "b/categories/\345\205\266\344\273\226/index.html" @@ -1 +1 @@ -分类: 其他 | 云淡风轻
\ No newline at end of file +分类: 其他 | 云淡风轻
\ No newline at end of file diff --git "a/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" "b/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" index f51f35bc..eef4c93c 100644 --- "a/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" +++ "b/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" @@ -1 +1 @@ -分类: 学习笔记 | 云淡风轻

分类: 学习笔记

\ No newline at end of file +分类: 学习笔记 | 云淡风轻

分类: 学习笔记

\ No newline at end of file diff --git a/content.json b/content.json index c6f61375..36c6423b 100644 --- a/content.json +++ b/content.json @@ -1 +1 @@ -{"meta":{"title":"云淡风轻","subtitle":"一个安静的角落","description":"隐约雷鸣,阴霾天空,但盼风雨来,能留你在此","author":"云淡风轻","url":"https://ioliu.cn","root":"/"},"pages":[{"title":"Sorry , Page Not Found","date":"2015-05-08T09:50:17.000Z","updated":"2024-03-28T08:06:05.972Z","comments":false,"path":"404.html","permalink":"https://ioliu.cn/404.html","excerpt":"","text":"404 SORRY , PAGE NOT FOUND 首页                  上页"},{"title":"404 Not Found:该页无法显示","date":"2024-03-28T08:06:05.972Z","updated":"2024-03-28T08:06:05.972Z","comments":false,"path":"/404.html","permalink":"https://ioliu.cn/404.html","excerpt":"","text":""},{"title":"关于","date":"2024-03-28T08:06:05.972Z","updated":"2024-03-28T08:06:05.972Z","comments":false,"path":"about/index.html","permalink":"https://ioliu.cn/about/index.html","excerpt":"","text":"这个人很懒,什么都没有留下!"},{"title":"书单","date":"2024-03-28T08:06:05.972Z","updated":"2024-03-28T08:06:05.972Z","comments":false,"path":"books/index.html","permalink":"https://ioliu.cn/books/index.html","excerpt":"","text":""},{"title":"分类","date":"2024-03-28T08:06:05.972Z","updated":"2024-03-28T08:06:05.972Z","comments":false,"path":"categories/index.html","permalink":"https://ioliu.cn/categories/index.html","excerpt":"","text":""},{"title":"友情链接","date":"2024-03-28T08:06:05.976Z","updated":"2024-03-28T08:06:05.976Z","comments":true,"path":"links/index.html","permalink":"https://ioliu.cn/links/index.html","excerpt":"","text":"名称:云淡风轻 头像:https://ioliu.cn/images/avatar.jpg 链接:https://ioliu.cn/ 介绍:一个安静的角落"},{"title":"Repositories","date":"2024-03-28T08:06:05.976Z","updated":"2024-03-28T08:06:05.976Z","comments":false,"path":"repository/index.html","permalink":"https://ioliu.cn/repository/index.html","excerpt":"","text":""},{"title":"标签","date":"2024-03-28T08:06:05.976Z","updated":"2024-03-28T08:06:05.976Z","comments":false,"path":"tags/index.html","permalink":"https://ioliu.cn/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"在Debian 11上升级内核并启用BBR加速","slug":"upgrade-debian-kernel-version","date":"2024-03-23T14:53:34.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2024/upgrade-debian-kernel-version/","permalink":"https://ioliu.cn/2024/upgrade-debian-kernel-version/","excerpt":"","text":"如果你正在使用Debian 11并且希望提升你的系统性能,升级到最新的内核版本并启用BBR加速可能是一个不错的选择。以下是一篇指南,将带你了解如何安全地升级内核以及如何启用BBR来优化你的网络连接。 升级到新版内核第一步:备份你的系统在进行任何重大系统更改之前,备份是非常重要的。你可以使用如Timeshift等工具来备份你的系统。 第二步:修改软件源为了安装最新的内核,我们可能需要添加Debian的Backports源。以下是添加Backports源的步骤: 打开/etc/apt/sources.list文件: 1sudo nano /etc/apt/sources.list 在文件末尾添加以下行: 12deb http://deb.debian.org/debian bullseye-backports main contrib non-freedeb-src http://deb.debian.org/debian bullseye-backports main contrib non-free 保存并退出编辑器。 更新软件包列表: 1sudo apt update 第三步:安装新内核使用Backports源安装新内核: 12sudo apt-get -t bullseye-backports install linux-image-6.x.x-x-amd64sudo apt-get -t bullseye-backports install linux-headers-6.x.x-x-amd64 请确保替换命令中的版本号为你想要安装的实际版本。 第四步:更新GRUB并重启安装完新内核后,更新GRUB: 1sudo update-grub 然后重启你的系统: 1sudo reboot 清除旧内核第一步:列出当前内核使用以下命令查看当前安装的内核: 12dpkg --list | grep linux-imagedpkg --list | grep linux-headers 第二步:删除旧内核选择你不再需要的内核版本,并使用apt-get purge命令进行删除: 12sudo apt-get purge linux-image-5.x.x-x-amd64sudo apt-get purge linux-headers-5.x.x-x-amd64 第三步:更新GRUB再次更新GRUB配置: 1sudo update-grub 启用BBR加速第一步:加载TCP BBR模块编辑/etc/sysctl.conf文件,在文件末尾添加以下两行: 12net.core.default_qdisc=fqnet.ipv4.tcp_congestion_control=bbr 第二步:应用新的系统配置应用新的配置: 1sudo sysctl -p 第三步:验证BBR是否启用运行以下命令: 1sysctl net.ipv4.tcp_congestion_control 如果输出显示bbr,则BBR已启用。 结语现在,你的Debian 11系统应该运行在最新的内核上,并且已经启用了BBR加速。这将帮助你提高系统的整体性能和网络连接的速度。请确保在执行以上操作时仔细检查,并始终保持系统的备份。 参考 Debian Backports Instructions Timeshift on GitHub Google BBR Congestion Control Algorithm","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"bbr","slug":"bbr","permalink":"https://ioliu.cn/tags/bbr/"},{"name":"linux","slug":"linux","permalink":"https://ioliu.cn/tags/linux/"}]},{"title":"Git中的一些骚操作","slug":"git-command-backup","date":"2017-11-10T06:30:25.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2017/git-command-backup/","permalink":"https://ioliu.cn/2017/git-command-backup/","excerpt":"","text":"最近因为Valine,所以经常用到Git。当然,工作中也有用到,但基本上是用的图形化。 这里最Git的相关操作命令做个备份,以备不时之需。 可能不定时更新。 配置自动换行1git config --global core.autocrlf input # 提交时自动将换行符转成lf 多账号配置SSH修改~/.ssh/config文件(Windows平台) 1234567891011121314151617181920# 配置 Github.comHost github.com HostName github.com IdentityFile C:\\\\path\\\\to\\\\.ssh\\\\id_rsa_github PreferredAuthentications publickey User YourName# 配置 Coding.netHost git.coding.net HostName git.coding.net IdentityFile C:\\\\path\\\\to\\\\.ssh\\\\id_rsa_coding PreferredAuthentications publickey User YourName# 配置 Gitee.comHost gitee.com HostName gitee.com IdentityFile C:\\\\path\\\\to\\\\.ssh\\\\id_rsa_gitee PreferredAuthentications publickey User YourName pull 强制覆盖本地文件12git fetch --all git reset --hard origin/master push 强制覆盖远程文件1git push -f origin master 保持fork之后的项目和上游同步团队协作,为了规范,一般都是fork组织的仓库到自己帐号下,再提交pr,组织的仓库一直保持更新,下面介绍如何保持自己fork之后的仓库与上游仓库同步。 下面以我 fork 团队的博客仓库为例 点击 fork 组织仓库到自己帐号下,然后就可以在自己的帐号下 clone 相应的仓库 使用 git remote -v 查看当前的远程仓库地址,输出如下: 12origin git@github.com:ibrother/staticblog.github.io.git (fetch)origin git@github.com:ibrother/staticblog.github.io.git (push) 可以看到从自己帐号 clone 下来的仓库,远程仓库地址是与自己的远程仓库绑定的(这不是废话吗) 接下来运行: 1git remote add upstream https://github.com/staticblog/staticblog.github.io.git 这条命令就算添加一个别名为 upstream(上游)的地址,指向之前 fork 的原仓库地址。git remote -v 输出如下: 1234origin git@github.com:ibrother/staticblog.github.io.git (fetch)origin git@github.com:ibrother/staticblog.github.io.git (push)upstream https://github.com/staticblog/staticblog.github.io.git (fetch)upstream https://github.com/staticblog/staticblog.github.io.git (push) 之后运行下面几条命令,就可以保持本地仓库和上游仓库同步了 123git fetch upstreamgit checkout mastergit merge upstream/master 接着就是熟悉的推送本地仓库到远程仓库 1git push origin master From staticblog .","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Git","slug":"Git","permalink":"https://ioliu.cn/tags/Git/"},{"name":"Command","slug":"Command","permalink":"https://ioliu.cn/tags/Command/"}]},{"title":"Valine -- 一款极简的评论系统","slug":"add-valine-comments-to-your-blog","date":"2017-08-07T06:30:25.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2017/add-valine-comments-to-your-blog/","permalink":"https://ioliu.cn/2017/add-valine-comments-to-your-blog/","excerpt":"","text":"Valine - 一款极简的无后端评论系统. 2017年6月1日,在你等超龄儿童欢度节日的时候,多说躺下了。2017年8月1日,不甘寂寞的网易云跟帖也跟多说随风而去了。 2017年8月7日,一款基于Leancloud的极简风评论系统诞生:Valine。 食用方法获取 APP ID 和 APP KEY 点击这里登录或注册Leancloud 点这里创建应用,应用名看个人喜好。 选择刚刚创建的应用>设置>选择应用 Key,然后你就能看到你的APP ID和APP KEY了,参考下图: 为了您的数据安全,请填写应用>设置>安全设置中的Web 安全域名,如下图: 页面中的设置页面中的食用方法炒鸡简单,来来来,我们用代码说话: 123456789101112131415161718192021222324<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Valine - A simple comment system based on Leancloud.</title> <!--Leancloud 操作库:--> <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script> <!--Valine 的核心代码库:--> <script src="./dist/Valine.min.js"></script></head><body> <div class="comment"></div> <script> new Valine({ // AV 对象来自上面引入av-min.js(老司机们不要开车➳♡゛扎心了老铁) av: AV, el: '.comment', // app_id: 'Your APP ID', // 这里填写上面得到的APP ID app_key: 'Your APP KEY', // 这里填写上面得到的APP KEY placeholder: 'ヾノ≧∀≦)o来啊,快活啊!' // [v1.0.7 new]留言框占位提示文字 }); </script></body></html> 看吧,我是不是没说大话(_(:з」∠)_一本正经的胡说八道)。 评论数据管理插播一下,关于评论数据管理,请自行登录Leancloud应用管理。具体步骤:登录>选择你创建的应用>存储>选择ClassComment,然后就可以尽情的发挥你的权利啦(~ ̄▽ ̄)~ 更多配置信息请移步:https://valine.js.org –EOF–","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Valine","slug":"Valine","permalink":"https://ioliu.cn/tags/Valine/"},{"name":"Comment System","slug":"Comment-System","permalink":"https://ioliu.cn/tags/Comment-System/"},{"name":"评论系统","slug":"评论系统","permalink":"https://ioliu.cn/tags/%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/"}]},{"title":"不同的国家/地区与语言缩写代码","slug":"country-city-and-language","date":"2017-06-29T07:30:08.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2017/country-city-and-language/","permalink":"https://ioliu.cn/2017/country-city-and-language/","excerpt":"","text":"国家/地区 语言代码 国家地区 语言代码 简体中文(中国) zh-cn 简体中文(台湾地区) zh-tw 繁体中文(香港) zh-hk 英语(香港) en-hk 英语(美国) en-us 英语(英国) en-gb 英语(全球) en-ww 英语(加拿大) en-ca 英语(澳大利亚) en-au 英语(爱尔兰) en-ie 英语(芬兰) en-fi 芬兰语(芬兰) fi-fi 英语(丹麦) en-dk 丹麦语(丹麦) da-dk 英语(以色列) en-il 希伯来语(以色列) he-il 英语(南非) en-za 英语(印度) en-in 英语(挪威) en-no 英语(新加坡) en-sg 英语(新西兰) en-nz 英语(印度尼西亚) en-id 英语(菲律宾) en-ph 英语(泰国) en-th 英语(马来西亚) en-my 英语(阿拉伯) en-xa 韩文(韩国) ko-kr 日语(日本) ja-jp 荷兰语(荷兰) nl-nl 荷兰语(比利时) nl-be 葡萄牙语(葡萄牙) pt-pt 葡萄牙语(巴西) pt-br 法语(法国) fr-fr 法语(卢森堡) fr-lu 法语(瑞士) fr-ch 法语(比利时) fr-be 法语(加拿大) fr-ca 西班牙语(拉丁美洲) es-la 西班牙语(西班牙) es-es 西班牙语(阿根廷) es-ar 西班牙语(美国) es-us 西班牙语(墨西哥) es-mx 西班牙语(哥伦比亚) es-co 西班牙语(波多黎各) es-pr 德语(德国) de-de 德语(奥地利) de-at 德语(瑞士) de-ch 俄语(俄罗斯) ru-ru 意大利语(意大利) it-it 希腊语(希腊) el-gr 挪威语(挪威) no-no 匈牙利语(匈牙利) hu-hu 土耳其语(土耳其) tr-tr 捷克语(捷克共和国) cs-cz 斯洛文尼亚语 sl-sl 波兰语(波兰) pl-pl 瑞典语(瑞典) sv-se 西班牙语 (智利) es-cl","categories":[{"name":"其他","slug":"其他","permalink":"https://ioliu.cn/categories/%E5%85%B6%E4%BB%96/"}],"tags":[{"name":"国家/地区","slug":"国家-地区","permalink":"https://ioliu.cn/tags/%E5%9B%BD%E5%AE%B6-%E5%9C%B0%E5%8C%BA/"},{"name":"语言缩写","slug":"语言缩写","permalink":"https://ioliu.cn/tags/%E8%AF%AD%E8%A8%80%E7%BC%A9%E5%86%99/"}]},{"title":"从删库到跑路 -- MySql 不算初体验的初体验","slug":"mysql-tutorial","date":"2017-03-24T03:00:25.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2017/mysql-tutorial/","permalink":"https://ioliu.cn/2017/mysql-tutorial/","excerpt":"","text":"最近准备找时间把bing壁纸项目重构,但由于虚拟主机快要过期了,所以目前的首要任务是将数据库从阿里云的虚拟主机转移到我自己的服务器上。 因为多年前学过SQLServer、Oracle、MySql等数据库,但许久未用,技艺生疏,所以这里是不算初体验的初体验。 本文将执行三步走计划: 安装 登录 使用 安装在Debian上安装MySql很简单,运行如下命令就基本OK: 1$ apt-get install mysql-server mysql-client 其中mysql-server是服务器程序,mysql-client是客户端程序。安装过程中会有如下提示,需要设置mysql数据库密码;输入要设置的密码后,回车即可继续安装。 如果出现Unable to locate package mysql-server等错误,请先执行apt-get update后重试。 登录安装成功后,mysql会自动启动,可以通过ps -ef | grep mysql查看mysql是否运行。登陆mysql: 123# login$ mysql -u root -pEnter password: # 输入密码 其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。 查看数据库show databases;: 12345678910$ mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys |+--------------------+4 rows in set (0.00 sec) 使用创建数据库12$ mysql> create database DB_name;Query OK, 1 row affected (0.05 sec) 查看刚刚创建的数据库1234567891011$ mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || DB_name || mysql || performance_schema || sys |+--------------------+5 rows in set (0.00 sec) 使用刚刚创建的数据库12$ mysql> use DB_name;Database changed 创建表12345$ mysql> CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 查看表1234567$ mysql> SHOW CREATE table person;CREATE TABLE `person` ( `number` int(11) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, `birthday` date DEFAULT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8; 查看表的所有列12345678$ mysql> SHOW FULL COLUMNS from person;+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+| number | int(11) | NULL | YES | | NULL | | select,insert,update,references | || name | varchar(255) | utf8_general_ci | YES | | NULL | | select,insert,update,references | || birthday | date | NULL | YES | | NULL | | select,insert,update,references | |+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+ 创建临时表12345$ mysql> CREATE TEMPORARY TABLE temp_person ( number INT(11), name VARCHAR(255), birthday DATE ); 删除表123$ mysql> DROP TABLE temp_person;# or$ mysql> DROP TABLE IF EXISTS temp_person; 创建用户命令: 1$mysql> CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明: username:你将创建的用户名 host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符% password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器 例子: 12345$mysql> CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';$mysql> CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '123456';$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '';$mysql> CREATE USER 'pig'@'%'; 授权命令: 1$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' 说明: privileges:用户的操作权限,如SELECT,INSERT,UPDATE等,如果要授予所的权限则使用ALL databasename:数据库名 tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*例子:12$mysql> GRANT SELECT, INSERT ON test.user TO 'pig'@'%';$mysql> GRANT ALL ON *.* TO 'pig'@'%'; 注意 用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令: 1$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION; 设置与更改用户密码命令: 1$mysql> SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword'); 如果是当前登陆用户用: 1>$mysql> SET PASSWORD = PASSWORD("newpassword");例子: 1$mysql> SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456"); 撤销用户权限命令: 1$mysql> REVOKE privilege ON databasename.tablename FROM 'username'@'host'; 说明:privilege, databasename, tablename:同授权部分例子: 1$mysql> REVOKE SELECT ON *.* FROM 'pig'@'%'; 注意: 假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):GRANT SELECT ON test.user TO 'pig'@'%',则在使用REVOKE SELECT ON *.* FROM 'pig'@'%'; 命令并不能撤销该用户对test数据库中user表的SELECT 操作。 相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%', 则REVOKE SELECT ON test.user FROM 'pig'@'%'; 命令也不能撤销该用户对test数据库中user表的SELECT权限。 具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看。 删除用户 1$mysql> DROP USER 'username'@'host'; 最后能看到这里,那就先要恭喜你了,你已经成功达成建库、建表、建用户到删表、删库、删用户等成就。那还等什么?赶紧跑路吧ε=ε=ε=┏(゜ロ゜;)┛ 附: MySql官网 MySql Tutorial Mysql创建用户并授权命令","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"MySql","slug":"MySql","permalink":"https://ioliu.cn/tags/MySql/"},{"name":"数据库","slug":"数据库","permalink":"https://ioliu.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"}]},{"title":"给你的网站加把锁 -- Let's Encrypt 完全体验","slug":"add-a-lock-to-your-website","date":"2017-03-21T10:30:25.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2017/add-a-lock-to-your-website/","permalink":"https://ioliu.cn/2017/add-a-lock-to-your-website/","excerpt":"","text":"今天抽时间将所有的网站SSL证书都更新了成 Let’s Encrypt 了。采用了certbot 这样的自动化工具,配置管理起来非常容易(一本正经的胡说八道),这里将对整个体验过程做个详细记录。 了解 Let’s Encrypt The project aims to make encrypted connections in the World Wide Web the default case. By getting rid of payment, web server configuration, validation emails and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.On a Linux web server, execution of only two commands is sufficient to set up HTTPS encryption, acquire and install certificates within 20 to 30 seconds. Let’s Encrypt 是一个2015年末推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。 获取 Let’s EncryptLet’s Encrypt 证书生成不需要手动进行,官方推荐 Certbot 这套自动化工具来实现。4步轻松搞定: 下载安装 certbot (Let’s Encrypt项目的自动化工具) 获得SSL证书 修改Nginx配置文件 续订 1. 安装 Certbot根据 Certbot 官网指南,Debian 8上执行如下命令,安装certbot: 12$ sudo apt-get update$ sudo apt-get install certbot -t jessie-backports 等安装完成,certbot就可以使用了。 2. 获取SSL证书Let’s Encrypt提供了通过各种插件获取SSL证书的各种方法。不同的是Apache的插件,大多数的插件只会帮助你得到,你必须手动配置你的Web服务器使用证书。仅获取证书而不安装证书的插件称为“验证器”,因为它们用于验证服务器是否应颁发证书。下面将使用Webroot的插件来获取SSL证书。 如何使用 Webroot 插件:Webroot 的工作插件放置在一个特殊的文件/.well-known目录文档根目录下,它可以打开(通过Web服务器)内由让我们的加密服务进行验证。 根据配置的不同,你可能需要明确允许访问/.well-known目录。 为了确保该目录可供Let’s Encrypt进行验证,让我们快速更改我们的Nginx配置。编辑/etc/nginx/conf.d/example.com.conf文件,并将下面代码添加进去: 123location ~ /.well-known { allow all;} 使用nginx -t测试配置文件是否正确,在正确的情况下,重新让Nginx重新加载配置文件: 1$ sudo systemctl reload nginx 使用certbot命令获取证书:1$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is -w:指定网站所在目录 -d:指定要生成证书的域名,如果你想多个域名保存在一个证书里(最多四个)(如example.com、www.example.com、thing.is、m.thing.is),请确保使用适当的webroot路径和域名替换命令中的相对应部分。 接下来,同意加密订阅协议: 如果一切顺利,你应该看到一个类似下面的输出消息: IMPORTANT NOTES: Congratulations! Your certificate and chain have been saved at/etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expireon 2017-06-19. To obtain a new or tweaked version of thiscertificate in the future, simply run certbot again. Tonon-interactively renew all of your certificates, run “certbotrenew” If you like Certbot, please consider supporting our work by: Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donateDonating to EFF: https://eff.org/donate-le 证书文件如果运行顺利,所有服务器所需要的证书就已经生成好了。他们被放在了 /etc/letsencrypt/live/example.com/ 下: 12345$ ls /etc/letsencrypt/live/example.com/cert.pem #server cert only privkey.pem #private key chain.pem #intermediates fullchain.pem #server cert + intermediates 3.修改Nginx配置文件到这里已经成功一大半了,只需要配置 Nginx 支持刚刚生成的证书。最佳实践可以参考Mozilla SSL Configuration Generator。注意去掉HSTS的勾(勾上会强制https,并且很难消除后续影响)。 请根据自己的服务配置修改和添加内容,重点只需要关注6行: 123456789101112server { listen 443 ssl http2; .... ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_dhparam /etc/nginx/ssl/dhparam.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/root_ca_cert_plus_intermediates; resolver <IP DNS resolver>; ....} dhparam.pem可以通过以下命令生成: 12$ sudo mkdir /etc/nginx/ssl$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 Nginx 配置完成后重启,用浏览器测试是否一切正常。 4.续订Let's Encrypt证书有效期只有3个月,所以,需要定时renew。我将使用corntab来执行renew命令: 1$ sudo crontab -e 添加以下行: 130 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log && /bin/systemctl reload nginx 保存,并退出。这个定时任务将在每个星期一的凌晨两点半执行certbot renew命令,并重启Nginx。最后将日志输出到/var/log/le-renewal.log。 测试你的网站 SSL 安全性Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。这意味着你网站的HTTPS已经启用成功啦,为自己鼓个掌。 (๑•̀ㅂ•́)و✧。 附:还有一种方法,不需要访问你的网站目录,但需要临时停止Nginx服务器(需要用到80端口): 停止Nginx 域名解析到你的服务器IP 执行命令:certbot certonly --standalone -d example.com -d www.example.com 然后的步骤就和上面一样啦~~~ 以上。","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"ssl","slug":"ssl","permalink":"https://ioliu.cn/tags/ssl/"},{"name":"cerbot","slug":"cerbot","permalink":"https://ioliu.cn/tags/cerbot/"}]},{"title":"判断变量类型的一些方法","slug":"judgment-variable-type","date":"2016-09-13T14:10:01.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2016/judgment-variable-type/","permalink":"https://ioliu.cn/2016/judgment-variable-type/","excerpt":"","text":"久了不用,就会发现,以前会的东西都会忘记掉(或者是完全想不起来了),不知道你们有没有遇到过这个情况 - -! 这里只是对判断变量类型方法的一些记录,方便以后能够随时查看。 typeof要判断变量类型,首先想到的就是typeof,但用了才知道,其结果完全不是理想中的: 123456typeof {}; //"object"typeof []; //"object"typeof ""; //"string"typeof 0; //"number"typeof function(){};//"function"typeof true;//"boolean" 由上面代码可以看出,数组也是对象,所以typeof不是我们理想中的解决方案。 当然,有的童鞋可能会说,由于length是Array特有的属性(非绝对),那是不是可以用length+typeof来判断。 当然,这是可以的: 12345var arr = [1,2];if(typeof arr === 'object'){ console.log(typeof arr.length === "number" ? "array" : "object");//这里输出 "array"}//...其他的就不一一罗列了 不过这个方法不通用,如果{key:value}对象中有 length 字段呢,如: 123456//这种情况对于上面的代码就不适用了var obj = { name:"square", length:50, width:50}; instanceof第二种解决方案就是使用instanceof,不过使用instanceof会出现[] instanceof Object === true的情况。这样就需要优先判断Array: 1234567891011121314151617var a = [1,2,3];var b = {name:'zhangsan',sex:123};var fn = function(){};var detectType = function(o){ if(o instanceof Array){ return 'Array' }else if( o instanceof Object ){ return 'Object'; }else{ return 'param is no object type'; }}console.log( detectType(a) ); // Arrayconsole.log( detectType(b) ); // Objectconsole.log( detectType(1) ); // param is no object typeconsole.log( detectType(true) ); // param is no object typeconsole.log( detectType('a') ); // param is no object type Object.prototype.toString.call还有一种最靠谱的办法就是Object.prototype.toString.call: 12345678910Object.prototype.toString.call([]) //"[object Array]"Object.prototype.toString.call(Object) //"[object Function]"Object.prototype.toString.call(function x(){}) //"[object Function]"Object.prototype.toString.call("") //"[object String]"Object.prototype.toString.call({}) //"[object Object]"Object.prototype.toString.call(null) //"[object Null]"Object.prototype.toString.call(undefined) //"[object Undefined]"Object.prototype.toString.call(/test/) //"[object RegExp]"Object.prototype.toString.call(new Date()) //"[object Date]" 参考文档 Object.prototype.toString()","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"变量类型","slug":"变量类型","permalink":"https://ioliu.cn/tags/%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B/"}]},{"title":"CSS 内容和特殊字符","slug":"css-content-and-special-characters","date":"2016-09-06T06:10:01.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2016/css-content-and-special-characters/","permalink":"https://ioliu.cn/2016/css-content-and-special-characters/","excerpt":"","text":"当我写这个主题theme的时候,我想在我的列表元素(list elements)上用CSS内容(CSS content)属性添加一些**向右双角引号(right-pointing double-angle quotation marks)(<<)**。 所以,我在里面添加了&raquo;,然而,它并不工作! 我花了一点时间去了解到,你不能使用常规的 HTML 实体内容。相反,你必须使用 Unicode 十六进制格式,它看起来像这样:\\bb。 这是一些你可以轻而易举找到的东西,只因为它出现在了众多课程和参考书里。 将HTML实体转换成Unicode十六进制代码这里有很多的HTML实体对应表,但是没有更多的 Unicode十六进制表,所以很方便的知道二者之间的转换。你需要知道所有的HTML十进制单位(它们看起来像这样&#123;,而不是像这样&quot;)。那数字,你猜到了吧,就是十进制格式。我们需要将其转换成Unicode十六进制(我知道,你震惊了!)。 如果你不是一个程序员或者数学天才,可能你不熟悉到底该怎么做(具体请Google)。OK,其实这并不难,但有一个更快捷的方式: 打开类似于经典的Windows计算器,切换到“程序员”视图(View > Programmer)。点击Dec(十进制)单选按钮,输入你的数字然后点击Hex(十六进制)按钮,你就会得到你的十六进制数字。 然后把刚刚得到的数字放到\\之后,你就得到了你自己的Unicode十六进制字符。 更容易的方法 - HTML实体(HTML Entity)和 Unicode 十六进制 对应表这个方法不需要你手动的将十进制转成十六进制,这个图表能够给你一些常见的(或者不是那么常见的)符号的参考:","categories":[],"tags":[{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"CSS","slug":"CSS","permalink":"https://ioliu.cn/tags/CSS/"},{"name":"译文","slug":"译文","permalink":"https://ioliu.cn/tags/%E8%AF%91%E6%96%87/"}],"author":"@Christian Snodgrass"},{"title":"JavaScript 最佳实践: 提升你代码质量的一些提示&技巧","slug":"javascript-best-practices-tips-and-tricks-to-level-up-your-code","date":"2016-09-02T06:10:01.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/","permalink":"https://ioliu.cn/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/","excerpt":"","text":"每天学习新事物是成为一个伟大的人的一部分。而对开发者而言,持续不断学习新的东西是我们工作中的一部分,无论这些东西是否是你主动想学的。 在本教程中,我会指出一些重要的 JavaScript 最佳实践,因此你不必觉得学习它是条艰难的路。准备提升你的代码吧! 避免全局污染(Avoid polluting the global scope)声明变量(Declaring variables)是很有趣的。有时候,你可能声明了全局变量,即使你不想声明它。在如今的浏览器中,全局变量存储在window对象中。因此,有很多有趣的东西发生在那里,你可能会重写默认值。让我们假设你有一个HTML文件,其中包含一个<script>标签(或者在加载的 JavaScript 文件中包含): 12var foo = 42;console.log(foo); 这很显然会在控制台输出42。但是,因为这段代码没有在函数中执行,上下文将是一个全局的。因此,变量是附加到window对象的。这意味着window.foo的值也是42。 这是危险的,因为你可以重写已经存在的全局变量: 12345function print(){ //do something...}print(); 因为我们重写了原生的打印弹窗(native print popup),所以当我们执行window.print() (或者只执行print())的时候不会打开打印弹窗(print popup)。 这个问题很好解决,我们需要一个立即调用(called immediately) 的包装函数(wrapping function) (译者注:作者这里可能是要表达一个闭包函数closure function或者是匿名函数anonymous function),像下面的代码: 12345678910// Declare an anonymous function// 声明一个匿名函数(function () { var foo = 42; console.log(window.foo); // → undefined console.log(foo); // → 42})();//^ and call it immediately 另外,你应该选择发送window和其他的全局变量(如:document)作为函数的参数(这可能会提高性能): 12345(function (global, doc) { global.setTimeout(function () { doc.body.innerHTML = "Hello!"; }, 1000);})(window, document); 因此,使用包装函数来防止创建不必要的全局变量。注意,这不是说我在接下来的代码片段使用包装函数,我们应该把关注点放在代码本身。 💡小提示: browserify是另外一种防止创建不必要的全局变量的方式。它和 Node.js 采用的是同样的方式,使用的require function。 学习更多关于浏览器开发者工具请点击 Web 开发指南 顺便说一句,Node.js 会在函数里自动打包你的文件,它们看起来像这样: 12(function (exports, require, module, __filename, __dirname) {// ... 因此,如果这让你认为require函数是全局的那就错了。它只不过是一个函数的参数罢了。 你知道吗?由于window对象本身就是一个包含全局变量的全局变量,因此它的引用是自身: 12window.window.window// => Window {...} 那是因为window对象是一个环路对象(circular object),下面演示怎么创建一个这样的对象: 12345678910// Create an Objectvar foo = {};// Point a key value to the object itself// 设置一个key,值为它本身foo.bar = foo;// The `foo` object just became a circular one:foo.bar.bar.bar// → foo 或者,去展现你对JavaScript 的爱,你可以做得更好:Yes,你可以无限的扩展这个对象(大概直到你的浏览器崩溃). 使用严格模式(use strict)严格的使用use strict!这只不过是(译者注:这里原作者可能是想表达不仅仅是)在你的代码脚本中添加字符串而已。举个栗子: 12345678// This is bad, since you do create a global without having anyone to tell you(function () { a = 42; console.log(a); // → 42})();console.log(a);// → 42 使用use strict,你可以得到更多的确切的错误: 12345(function () { "use strict"; a = 42; // Error: Uncaught ReferenceError: a is not defined})(); 你可能会奇怪,为什么不能将use strict 写在函数体外。当然,这是可以的,但它将会应用为全局的范围。这仍然是不错的,但如果你的代码中含有来自其他库的代码,这也会受其影响,或者你把所有的东西都绑定在一个文件里。 严格相等(Strict equal)这是短的。如果你使用==对比a和b(像在其他编程语言),在 JavaScript 中,你可能这种非常奇怪的运行方式:如果你有一个字符串和一个数字,他们是相等的(==): 12"42" == 42// → true 由于显而易见的原因(如 验证(validations)),最好使用严格相等(===): 12"42" === 42// → false 使用断言(&&/||)根据你的需要,你可以使用逻辑运算符是你的代码更简短。默认值: 123456789101112131415"" || "foo"// → "foo"undefined || 42// → 42// Note that if you want to handle 0 there, you need// to check if a number was provided:var a = 0;a || 42// → 42// This is a ternary operator—works like an inline if-else statementvar b = typeof a === "number" ? a : 42;// → 0 检查是否是一个真正的if表达式,你可以简单的这么做: 123456expr && doSomething();// Instead of:if (expr) { doSomething();} 你可能会不赞同我这里的写法,但是这是比较理想的。如果你不想用这种方式丑化你的代码,但那些 JavaScript 压缩工具实际上会这么做。 如果你问我,尽管这些代码比较短,但它仍然是人类可读的。 类型转换有几种方式来转换这些东西,这取决于你想怎么做。最常见的方式是: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849// From anything to a numbervar foo = "42";var myNumber = +foo; // shortcut for Number(foo)// → 42// Tip: you can convert it directly into a negative numbervar negativeFoo = -foo; // or -Number(foo)// → -42// From object to array// Tip: `arguments` is an object and in general you want to use it as arrayvar args = { 0: "foo", 1: "bar", length: 2 };Array.prototype.slice.call(args)// → [ 'foo', 'bar' ]// Anything to boolean/// Non non p is a boolean pvar t = 1;var f = 0;!!t// → true!!f// → false/// And non-p is a boolean non-p!t// → false!f// → true// Anything to stringvar foo = 42;"" + foo // shortcut for String(foo)// → "42"foo = { hello: "world" };JSON.stringify(foo);// → '{ "hello":"world" }'JSON.stringify(foo, null, 4); // beautify the things// →// '{// "hello": "world"// }'// Note you cannot JSON.stringify circular structuresJSON.stringify(window);// ⚠ TypeError: JSON.stringify cannot serialize cyclic structures. 代码样式/样式指南在新项目中,遵循整个文件相同的代码风格。对于现有的,采用已经存在的代码风格,除非你只是决定改变它(提示:同你的合作者商讨)。即使你创建并记录你的代码风格,请始终遵循它。 这里是不同的现有的代码样式: Google JavaScript Style Guide airbnb/javascript … there are others too my style guide 附加提示其他重要的 JavaScript 最佳实践,你应该记住的是使用工具帮助你格式化你的代码。这是其中的一些: js-beautify: Beautifies your code UglifyJS(2): Uglifies/minimifies your code jshint: Detects errors/potential problems in your JavaScript code jscs: A configurable style guide checker 最后一件事:Debug your Code Happy programming! 致谢:@屠夫 、@QistChan、@nApolin、@Ant","categories":[],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"译文","slug":"译文","permalink":"https://ioliu.cn/tags/%E8%AF%91%E6%96%87/"},{"name":"技巧","slug":"技巧","permalink":"https://ioliu.cn/tags/%E6%8A%80%E5%B7%A7/"}],"author":"@johnnyb"},{"title":"MarkDown 不完全指南","slug":"MarkDown-incomplete-Guide","date":"2016-05-18T06:21:08.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2016/MarkDown-incomplete-Guide/","permalink":"https://ioliu.cn/2016/MarkDown-incomplete-Guide/","excerpt":"","text":"MarkdownA markdown example shows how to write a markdown file. This document integrates core syntax and extensions (GMF). Block ElementsParagraphs and Line BreaksParagraphsHTML Tag: <p> One or more blank lines. (A blank line is a line containing nothing but spaces or tabs is considered blank.) Code: 1234This will be inline.This is second paragraph. Preview: This will beinline. This is second paragraph. Line BreaksHTML Tag: <br /> End a line with two or more spaces. Code: 12This will be not inline. Preview: This will be notinline. HeadersMarkdown supports two styles of headers, Setext and atx. SetextHTML Tags: <h1>, <h2> “Underlined” using equal signs (=) as <h1> and dashes (-) as <h2> in any number. Code:1234This is an H1=============This is an H2-------------Preview:***This is an H1This is an H2 atxHTML Tags: <h1>, <h2>, <h3>, <h4>, <h5>, <h6> Uses 1-6 hash characters (#) at the start of the line, corresponding to <h1> - <h6>. Code: 123# This is an H1## This is an H2###### This is an H6 Preview: This is an H1This is an H2This is an H6 Optionally, you may “close” atx-style headers. The closing hashes don’t need to match the number of hashes used to open the header. Code: 123# This is an H1 ### This is an H2 ##### This is an H3 ###### Preview: This is an H1This is an H2This is an H3 BlockquotesHTML Tag: <blockquote> Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and put a > before every line. Code: 123456> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.> > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse> id sem consectetuer libero luctus adipiscing. Preview: This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisseid sem consectetuer libero luctus adipiscing. Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph. Code: 123456> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisseid sem consectetuer libero luctus adipiscing. Preview: This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisseid sem consectetuer libero luctus adipiscing. Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >. Code: 12345> This is the first level of quoting.>> > This is nested blockquote.>> Back to the first level. Preview: This is the first level of quoting. This is nested blockquote. Back to the first level. Blockquotes can contain other Markdown elements, including headers, lists, and code blocks. Code: 12345678> ## This is a header.> > 1. This is the first list item.> 2. This is the second list item.> > Here's some example code:> > return shell_exec("echo $input | $markdown_script"); Preview: This is a header. This is the first list item. This is the second list item. Here’s some example code: return shell_exec("echo $input | $markdown_script"); ListsMarkdown supports ordered (numbered) and unordered (bulleted) lists. UnorderedHTML Tag: <ul> Unordered lists use asterisks (*), pluses (+), and hyphens (-). Code: 123* Red* Green* Blue Preview: Red Green Blue is equivalent to: Code: 123+ Red+ Green+ Blue and: Code: 123- Red- Green- Blue OrderedHTML Tag: <ol> Ordered lists use numbers followed by periods: Code: 1231. Bird2. McHale3. Parish Preview: Bird McHale Parish It’s possible to trigger an ordered list by accident, by writing something like this: Code: 11986. What a great season. Preview: What a great season. You can backslash-escape (\\) the period: Code: 11986\\. What a great season. Preview: 1986. What a great season. IndentedBlockquoteTo put a blockquote within a list item, the blockquote’s > delimiters need to be indented: Code: 1234* A list item with a blockquote: > This is a blockquote > inside a list item. Preview: A list item with a blockquote: This is a blockquoteinside a list item. Code BlockTo put a code block within a list item, the code block needs to be indented twice — 8 spaces or two tabs: Code: 123* A list item with a code block: <code goes here> Preview: A list item with a code block: <code goes here> Nested ListCode: 12345* A * A1 * A2* B* C Preview: A A1 A2 B C Code BlocksHTML Tag: <pre> Indent every line of the block by at least 4 spaces or 1 tab. Code: 123This is a normal paragraph: This is a code block. Preview: This is a normal paragraph: This is a code block. A code block continues until it reaches a line that is not indented (or the end of the article). Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities. Code: 123<div class="thanclass"> &copy; 2004 Foo Corporation</div> Preview: © 2004 Foo Corporation *** Following sections Fenced Code Blocks and Syntax Highlighting are extensions, you can use the other way to write the code block. #### Fenced Code Blocks Just wrap your code in \\`\\`\\` \\`\\`\\` (as shown below) and you won't need to indent it by four spaces. Code: Here’s an example:```function test() { console.log(“notice the blank line before this function?”);}``` Preview: Here’s an example: 123function test() { console.log("notice the blank line before this function?");} Syntax HighlightingIn your fenced block, add an optional language identifier and we’ll run it through syntax highlighting (Support Languages). Code: ```rubyrequire ‘redcarpet’markdown = Redcarpet.new(“Hello World!”)puts markdown.to_html``` Preview: 123require 'redcarpet'markdown = Redcarpet.new("Hello World!")puts markdown.to_html Horizontal RulesHTML Tag: <hr />Places three or more hyphens (-), asterisks (*), or underscores (_) on a line by themselves. You may use spaces between the hyphens or asterisks. Code: 123456* * *********- - ----------------------------------------___ TableHTML Tag: <table> It’s an extension. Separates column by pipe (|) and header by dashes (-), and uses colon (:) for alignment. The outer pipes (|) and alignment are optional. There are 3 delimiters each cell at least for separating header. Code: 12345678910111213| Left | Center | Right ||:-----|:------:|------:||aaa |bbb |ccc ||ddd |eee |fff | A | B ---|---123|456A |B --|--12|45 Preview: Left Center Right aaa bbb ccc ddd eee fff A B 123 456 A B 12 45 Span ElementsLinksHTML Tag: <a> Markdown supports two style of links: inline and reference. InlineInline link format like this: [Link Text](URL "Title") Title is optional. Code: 123This is [an example](http://example.com/ "Title") inline link.[This link](http://example.net/) has no title attribute. Preview: This is an example inline link. This link has no title attribute. If you’re referring to a local resource on the same server, you can use relative paths: Code: 1See my [Tags](/tags/) page for details. Preview: See my Tags page for details. ReferenceYou could predefine link references. Format like this: [id]: URL "Title" Title is also optional. And the you refer the link, format like this: [Link Text][id] Code: 12[id]: http://example.com/ "Optional Title Here"This is [an example][id] reference-style link. Preview: This is 点我跳转到百度 reference-style link. That is: Square brackets containing the link identifier (not case sensitive, optionally indented from the left margin using up to three spaces); followed by a colon; followed by one or more spaces (or tabs); followed by the URL for the link; The link URL may, optionally, be surrounded by angle brackets. optionally followed by a title attribute for the link, enclosed in double or single quotes, or enclosed in parentheses. The following three link definitions are equivalent: Code: 1234[foo]: http://example.com/ "Optional Title Here"[foo]: http://example.com/ 'Optional Title Here'[foo]: http://example.com/ (Optional Title Here)[foo]: <http://example.com/> "Optional Title Here" Uses an empty set of square brackets, the link text itself is used as the name. Code: 12[Google]: http://google.com/[Google][] Preview: Google EmphasisHTML Tags: <em>, <strong> Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. One delimiter will be <em>; *double delimiters will be <strong>. Code: 1234567*single asterisks*_single underscores_**double asterisks**__double underscores__ Preview: single asterisks single underscores double asterisks double underscores But if you surround an * or _ with spaces, it’ll be treated as a literal asterisk or underscore. You can backslash escape it: Code: 1*this text is surrounded by literal asterisks* Preview: *this text is surrounded by literal asterisks* CodeHTML Tag: <code> Wraps it with backtick quotes (`). Code: 1Use the `printf()` function. Preview: Use the printf() function. To include a literal backtick character within a code span, you can use multiple backticks as the opening and closing delimiters: Code: 1``There is a literal backtick (`) here.`` Preview: There is a literal backtick (`) here. The backtick delimiters surrounding a code span may include spaces — one after the opening, one before the closing. This allows you to place literal backtick characters at the beginning or end of a code span: Code: 123A single backtick in a code span: `` ` ``A backtick-delimited string in a code span: `` `foo` `` Preview: A single backtick in a code span: ` A backtick-delimited string in a code span: `foo` ImagesHTML Tag: <img /> Markdown uses an image syntax that is intended to resemble the syntax for links, allowing for two styles: inline and reference. InlineInline image syntax looks like this: ![Alt text](URL "Title") Title is optional. Code: 123![Alt text](/path/to/img.jpg)![Alt text](/path/to/img.jpg "Optional title") Preview: That is: An exclamation mark: !; followed by a set of square brackets, containing the alt attribute text for the image; followed by a set of parentheses, containing the URL or path to the image, and an optional title attribute enclosed in double or single quotes. ReferenceReference-style image syntax looks like this: ![Alt text][id] Code: 12[img id]: url/to/image "Optional title attribute"![Alt text][img id] Preview: StrikethroughHTML Tag: <del> It’s an extension. GFM adds syntax to strikethrough text. Code: 1~~Mistaken text.~~ Preview: Mistaken text. MiscellaneousAutomatic LinksMarkdown supports a shortcut style for creating “automatic” links for URLs and email addresses: simply surround the URL or email address with angle brackets. Code: 123<http://example.com/><address@example.com> Preview: http://example.com/ address@example.com GFM will autolink standard URLs. Code: 1https://github.com/xcss Preview: https://github.com/xcss Backslash EscapesMarkdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax. Code: 1\\*literal asterisks\\* Preview: *literal asterisks* Markdown provides backslash escapes for the following characters: Code: 123456789101112\\ backslash` backtick* asterisk_ underscore{} curly braces[] square brackets() parentheses# hash mark+ plus sign- minus sign (hyphen). dot! exclamation mark Inline HTMLFor any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags. Code: 123456789This is a regular paragraph.<table> <tr> <td>Foo</td> </tr></table>This is another regular paragraph. Preview: This is a regular paragraph. Foo This is another regular paragraph. *** Note that Markdown formatting syntax is **not processed within block-level HTML tags**. Unlike block-level HTML tags, Markdown syntax is processed within span-level tags. Code: 12345<span>**Work**</span><div> **No Work**</div> Preview: Work **No Work** *** 参考文档: http://www.markdown.cn/","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"MarkDown","slug":"MarkDown","permalink":"https://ioliu.cn/tags/MarkDown/"},{"name":"Guide","slug":"Guide","permalink":"https://ioliu.cn/tags/Guide/"}]},{"title":"响应式设计 (Responsive Design) 中常用的媒体查询","slug":"commonly-used-media-queries","date":"2016-05-11T11:21:08.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2016/commonly-used-media-queries/","permalink":"https://ioliu.cn/2016/commonly-used-media-queries/","excerpt":"","text":"现在Web朝着响应式的趋势发展,媒体查询在创建响应式网站中起到了主要作用。 没有媒体查询几乎不能实现响应式设计,利用媒体查询,我们可以针对特定的设备,如显示器、智能手机和平板,写CSS。 媒体查询是响应式设计的核心 在这篇文章中我将分享一些到目前为止我收集到的常用媒体查询。在一些示例中,我可能是错误的,但是不用担心,因为我针对这个开通了评论功能。我把它们分为显示器媒体查询、智能手机媒体查询和平板媒体查询 显示器媒体查询显示器媒体查询是以屏幕大小为基础划分的 640px123@media screen and (max-width: 640px){ /*some rules*/} 800px123@media screen and (max-width: 800px){ /*some rules*/} 1024px123@media screen and (max-width: 1024px){ /*some rules*/} 智能手机媒体查询适用于大部分主流智能手机 iPhone(2G-4S)12345678/*Landscape Mode*/@media screen and (max-device-width: 480px) and (orientation:landscape){ /*some rules*/}/* Portrait Mode */@media screen and (max-device-width: 320px) and (orientation:portrait){ /*some rules*/} iPhone 41234@media only screen and (-webkit-min-device-pixel-ratio : 1.5),only screen and (min-device-pixel-ratio : 1.5){ /*some rules*/} iPhone 512345@media only screenand (min-device-width : 320px)and (max-device-width : 568px){ /*some rules*/} iPhone 612345678910111213141516171819202122232425262728293031@media only screen and (min-device-width: 375px) and (max-device-width: 667px)and (orientation : portrait) { /*iPhone 6 Portrait*/}@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (orientation : landscape) { /*iPhone 6 landscape*/}@media only screen and (min-device-width: 414px) and (max-device-width: 736px)and (orientation : portrait) { /*iPhone 6+ Portrait*/}@media only screen and (min-device-width: 414px) and (max-device-width: 736px)and (orientation : landscape) { /*iPhone 6+ landscape*/}@media only screen and (max-device-width: 640px), only screen and (max-device-width: 667px),only screen and (max-width: 480px){ /*iPhone 6 and iPhone 6+ portrait and landscape*/}@media only screen and (max-device-width: 640px),only screen and (max-device-width: 667px),only screen and (max-width: 480px) and (orientation : portrait){ /*iPhone 6 and iPhone 6+ portrait*/}@media only screen and (max-device-width: 640px),only screen and (max-device-width: 667px),only screen and (max-width: 480px) and (orientation : landscape){ /*iPhone 6 and iPhone 6+ landscape*/} HTC Evo,BlackBerry Torch,HTC Thunderbolt,HD2123@media screen and (max-device-width: 480px){ /*some rules*/} 平板媒体查询iPad / iPad 2 / iPad 312345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 768px) and (orientation: portrait){ /*some rules*/} iPad Mini123456@media only screenand (min-device-width : 768px)and (max-device-width : 1024px)and (-webkit-min-device-pixel-ratio: 1){ /*some rules*/} Samsung Galaxy Tab 10.1 / Motorola Xoom / Lenovo Thinkpad Tablet / Sony Tablet S12345678/* Landscape Mode */@media (max-device-width: 1280px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 800px) and (orientation: portrait){ /*some rules*/} HTC Flyer / BlackBerry PlayBook12345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 600px) and (orientation: portrait){ /*some rules*/} HP TouchPad12345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 768px) and (orientation: portrait){ /*some rules*/} T-Mobile G-Slate12345678/* Landscape Mode */@media (max-device-width: 1280px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 768px) and (orientation: portrait){ /*some rules*/} ViewSonic ViewPad 1012345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 600px) and (orientation: portrait){ /*some rules*/} Dell Streak 712345678/* Landscape Mode */@media (max-device-width: 800px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 400px) and (orientation: portrait){ /*some rules*/} ASUS Eee Pad Transformer12345678/* Landscape Mode */@media (max-device-width: 1080px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 800px) and (orientation: portrait){ /*some rules*/} 其他参考文档 七个高度有效的媒体查询技巧 iPads和iPhones的Media Queries media-queries-for-standard-devices 本文转载自淡忘~浅思,略有删改,侵权即删.原文链接: Some Media Queries for Responsive Design译文链接: 【译】Responsive Design常用的媒体查询","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Media Query","slug":"Media-Query","permalink":"https://ioliu.cn/tags/Media-Query/"},{"name":"响应式","slug":"响应式","permalink":"https://ioliu.cn/tags/%E5%93%8D%E5%BA%94%E5%BC%8F/"},{"name":"媒体查询","slug":"媒体查询","permalink":"https://ioliu.cn/tags/%E5%AA%92%E4%BD%93%E6%9F%A5%E8%AF%A2/"}]},{"title":"生成 SSH Key 免密码提交 GitHub","slug":"generating-ssh-key","date":"2015-12-13T02:19:18.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2015/generating-ssh-key/","permalink":"https://ioliu.cn/2015/generating-ssh-key/","excerpt":"","text":"之前上传文件到 GitHub 的时候,一直都是用的账号密码登录,每次提交都弹个窗体出来,感觉烦死了。。。今天有空,就来捣鼓下 SSH Key。 Step1. 检查是否已经存在 SSH Key运行 Git Bush 客户端,执行以下代码: 12$ ls -al ~/.ssh # 如果存在,将会列出.ssh 目录下的所有文件 12# 如果不存在则会给出如下提示ls: cannot open directory /Users/you/.ssh: Permission denied 检查列出来的目录,看看是否已经有了一个 SSH Key。默认情况下,key 的文件名是下列之一: > id_dsa.pub > id_ecdsa.pub > id_ed25519.pub > id_rsa.pub 如果已经存在(如 id_rsa 和 id_rsa.pub)而且你想使用已经存在的密钥对直接连接 GitHub ,那么可以跳过 Step2,直接进入 Step3 Step2. 生成 SSH Key复制下面的代码(记得请将email修改成自己的email地址): 12$ ssh-keygen -t rsa -b 4096 -C "your_name@example.com" Generating public/private rsa key pair. 这里 GitHub 的建议是保持默认,所以只需要按 Enter 继续: 1Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press Enter] 如果存在,将会提示是否覆盖: 12/Users/you/.ssh/id_rsa already exists.Overwrite (y/n)? 继续后会提示输入密码: 12Enter passphrase (empty for no passphrase): [Type a passphrase]Enter same passphrase again: [Type passphrase again] 然后你就会得到你的 SSH Key 的指纹,看起来像下面的代码: 1234Your identification has been saved in /Users/you/.ssh/id_rsa.Your public key has been saved in /Users/you/.ssh/id_rsa.pub.The key fingerprint is:01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com Step3. 添加 SSH Key 到 GitHub先拷贝 id_rsa.pub 文件的内容,可以用编辑器打开然后复制,也可以用 git 命令复制: 1$ clip < ~/.ssh/id_rsa.pub 进入 GitHub 账户设置,点击左边 SSH Key ,点击 Add SSH key ,粘贴刚刚复制的内容,然后保存。输入 GitHub 账户的密码就能看到刚刚添加的 SSH Key 了。 Step4. 测试是否添加成功在 Git Bush 中输入下面的代码,然后回车 12$ ssh -T git@GitHub.com# Attempts to ssh to GitHub 会得到如下的指纹提示:键入yes 123The authenticity of host 'GitHub.com (207.97.227.239)' can't be established.RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.Are you sure you want to continue connecting (yes/no)? 如果出现下面的提示,恭喜你,验证成功。 1Hi username! You've successfully authenticated, but GitHub does not provide shell access. 如果你看到的是 access denied(拒绝访问) ,可以点击这里 ,查看解决办法。 然后将https替换成ssh重新下载下代码,就OK了~~~ Good Luck ** 参考文档 ** Generating SSH keys","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"GitHub","slug":"GitHub","permalink":"https://ioliu.cn/tags/GitHub/"},{"name":"SSH Key","slug":"SSH-Key","permalink":"https://ioliu.cn/tags/SSH-Key/"},{"name":"免密码","slug":"免密码","permalink":"https://ioliu.cn/tags/%E5%85%8D%E5%AF%86%E7%A0%81/"}]},{"title":"前端 JavaScript 规范","slug":"the-front-end-javascript-specification","date":"2015-05-12T04:53:34.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2015/the-front-end-javascript-specification/","permalink":"https://ioliu.cn/2015/the-front-end-javascript-specification/","excerpt":"","text":"类型原始值:相当于传值(JavaScript对象都提供了字面量),使用字面量创建对象。 string number boolean null undefined 1234var foo = 1, bar = foo;bar = 9;console.log(foo, bar); // => 1, 9 复杂类型:相当于传引用 object array function 1234var foo = [1, 2], bar = foo;bar[0] = 9;console.log(foo[0], bar[0]); // => 9, 9 对象 使用字面值创建对象 12345// badvar item = new Object();// goodvar item = {}; 不要使用保留字 reserved words 作为键 12345678910111213// badvar superman = { class: 'superhero', default: { clark: 'kent' }, private: true};// goodvar superman = { klass: 'superhero', defaults: { clark: 'kent' }, hidden: true}; 数组 使用字面值创建数组 12345// badvar items = new Array();// goodvar items = []; 如果你不知道数组的长度,使用push 1234567var someStack = [];// badsomeStack[someStack.length] = 'abracadabra';// goodsomeStack.push('abracadabra'); 当你需要拷贝数组时使用slice . jsPerf 1234567891011var len = items.length, itemsCopy = [], i;// badfor (i = 0; i < len; i++) { itemsCopy[i] = items[i];}// gooditemsCopy = items.slice(); 使用slice将类数组的对象转成数组.1234function trigger() { var args = [].slice.apply(arguments); ...} 字符串 对字符串使用单引号 ''(因为大多时候我们的字符串。特别html会出现")1234567891011// badvar name = "Bob Parr";// goodvar name = 'Bob Parr';// badvar fullName = "Bob " + this.lastName;// goodvar fullName = 'Bob ' + this.lastName; 超过80(也有规定140的,项目具体可制定)个字符的字符串应该使用字符串连接换行!!!: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion 123456789101112131415161718// badvar errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';// badvar errorMessage = 'This is a super long error that \\was thrown because of Batman. \\When you stop to think about \\how Batman had anything to do \\with this, you would get nowhere \\fast.';// goodvar errorMessage = 'This is a super long error that ' + 'was thrown because of Batman.' + 'When you stop to think about ' + 'how Batman had anything to do ' + 'with this, you would get nowhere ' + 'fast.'; 编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.12345678910111213141516171819202122232425262728293031323334var items, messages, length, i;messages = [{ state: 'success', message: 'This one worked.'},{ state: 'success', message: 'This one worked as well.'},{ state: 'error', message: 'This one did not work.'}];length = messages.length;// badfunction inbox(messages) { items = '<ul>'; for (i = 0; i < length; i++) { items += '<li>' + messages[i].message + '</li>'; } return items + '</ul>';}// goodfunction inbox(messages) { items = []; for (i = 0; i < length; i++) { items[i] = messages[i].message; } return '<ul><li>' + items.join('</li><li>') + '</li></ul>';} 函数 函数表达式:1234567891011121314// 匿名函数表达式var anonymous = function() { return true;};// 有名函数表达式var named = function named() { return true;};// 立即调用函数表达式(function() { console.log('Welcome to the Internet. Please follow me.');})(); 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。 注: ECMA-262定义把块定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.12345678910111213// badif (currentUser) { function test() { console.log('Nope.'); }}// goodif (currentUser) { var test = function test() { console.log('Yup.'); };} 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.123456789// badfunction nope(name, options, arguments) { // ...stuff...}// goodfunction yup(name, options, args) { // ...stuff...} 属性 当使用变量和特殊非法变量名时,访问属性时可以使用中括号(. 优先).12345678910var luke = { jedi: true, age: 28};function getProp(prop) { return luke[prop];}var isJedi = getProp('jedi'); 变量 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。12345// badsuperPower = new SuperPower();// goodvar superPower = new SuperPower(); 使用一个 var 以及新行声明多个变量,缩进4个空格。123456789// badvar items = getItems();var goSportsTeam = true;var dragonball = 'z';// goodvar items = getItems(), goSportsTeam = true, dragonball = 'z'; 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。1234567891011121314151617// badvar i, len, dragonball, items = getItems(), goSportsTeam = true;// badvar i, items = getItems(), dragonball, goSportsTeam = true, len;// goodvar items = getItems(), goSportsTeam = true, dragonball, length, i; 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253// badfunction() { test(); console.log('doing stuff..'); //..other stuff.. var name = getName(); if (name === 'test') { return false; } return name;}// goodfunction() { var name = getName(); test(); console.log('doing stuff..'); //..other stuff.. if (name === 'test') { return false; } return name;}// badfunction() { var name = getName(); if (!arguments.length) { return false; } return true;}// goodfunction() { if (!arguments.length) { return false; } var name = getName(); return true;} 条件表达式和等号 合理使用 === 和 !== 以及 == 和 !=. 合理使用表达式逻辑操作运算. 条件表达式的强制类型转换遵循以下规则: 对象 被计算为 true Undefined 被计算为 false Null 被计算为 false 布尔值 被计算为 布尔的值 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true 1234if ([0]) { // true // An array is an object, objects evaluate to true} 使用快捷方式.12345678910111213141516171819// badif (name !== '') { // ...stuff...}// goodif (name) { // ...stuff...}// badif (collection.length > 0) { // ...stuff...}// goodif (collection.length) { // ...stuff...} 阅读 Truth Equality and JavaScript 了解更多 块 给所有多行的块使用大括号12345678910111213141516171819// badif (test) return false;// goodif (test) return false;// goodif (test) { return false;}// badfunction() { return false; }// goodfunction() { return false;} 注释 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值123456789101112131415161718192021222324252627// bad// make() returns a new element// based on the passed in tag name//// @param <String> tag// @return <Element> elementfunction make(tag) { // ...stuff... return element;}// good/** * make() returns a new element * based on the passed in tag name * * @param <String> tag * @return <Element> element */function make(tag) { // ...stuff... return element;} 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.12345678910111213141516171819202122232425// badvar active = true; // is current tab// good// is current tabvar active = true;// badfunction getType() { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; return type;}// goodfunction getType() { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; return type;} 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXME 或 TODO 帮助其他人迅速理解12345678910111213141516function Calculator() { // FIXME: shouldn't use a global here total = 0; return this;}function Calculator() { // TODO: total should be configurable by an options param this.total = 0; return this;} 满足规范的文档,在需要文档的时候,可以尝试jsdoc. 空白 缩进、格式化能帮助团队更快得定位修复代码BUG. 将tab设为4个空格1234567891011121314// badfunction() {∙∙var name;}// badfunction() {∙var name;}// goodfunction() {∙∙∙∙var name;} 大括号前放一个空格123456789101112131415161718192021// badfunction test(){ console.log('test');}// goodfunction test() { console.log('test');}// baddog.set('attr',{ age: '1 year', breed: 'Bernese Mountain Dog'});// gooddog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog'}); 在做长方法链时使用缩进.1234567891011121314151617181920212223242526// bad$('#items').find('.selected').highlight().end().find('.open').updateCount();// good$('#items') .find('.selected') .highlight() .end() .find('.open') .updateCount();// badvar leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) .attr('width', (radius + margin) * 2).append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led);// goodvar leds = stage.selectAll('.led') .data(data) .enter().append('svg:svg') .class('led', true) .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led); 逗号 不要将逗号放前面12345678910111213141516171819202122232425// badvar once , upon , aTime;// goodvar once, upon, aTime;// badvar hero = { firstName: 'Bob' , lastName: 'Parr' , heroName: 'Mr. Incredible' , superPower: 'strength'};// goodvar hero = { firstName: 'Bob', lastName: 'Parr', heroName: 'Mr. Incredible', superPower: 'strength'}; 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。123456789101112131415161718192021// badvar hero = { firstName: 'Kevin', lastName: 'Flynn',};var heroes = [ 'Batman', 'Superman',];// goodvar hero = { firstName: 'Kevin', lastName: 'Flynn'};var heroes = [ 'Batman', 'Superman']; 分号 语句结束一定要加分号1234567891011121314151617// bad(function() { var name = 'Skywalker' return name})()// good(function() { var name = 'Skywalker'; return name;})();// good;(function() { var name = 'Skywalker'; return name;})(); 类型转换 在语句的开始执行类型转换. 字符串:12345678910111213// => this.reviewScore = 9;// badvar totalScore = this.reviewScore + '';// goodvar totalScore = '' + this.reviewScore;// badvar totalScore = '' + this.reviewScore + ' total score';// goodvar totalScore = this.reviewScore + ' total score'; 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)123456789101112131415161718192021222324252627var inputValue = '4';// badvar val = new Number(inputValue);// badvar val = +inputValue;// badvar val = inputValue >> 0;// badvar val = parseInt(inputValue);// goodvar val = Number(inputValue);// goodvar val = parseInt(inputValue, 10);// good/** * parseInt was the reason my code was slow. * Bitshifting the String to coerce it to a * Number made it a lot faster. */var val = inputValue >> 0; 布尔值:12345678910var age = 0;// badvar hasAge = new Boolean(age);// goodvar hasAge = Boolean(age);// goodvar hasAge = !!age; 命名约定 避免单个字符名,让你的变量名有描述意义。123456789// badfunction q() { // ...stuff...}// goodfunction query() { // ..stuff..} 当命名对象、函数和实例时使用驼峰命名规则123456789101112131415// badvar OBJEcttsssss = {};var this_is_my_object = {};var this-is-my-object = {};function c() {};var u = new user({ name: 'Bob Parr'});// goodvar thisIsMyObject = {};function thisIsMyFunction() {};var user = new User({ name: 'Bob Parr'}); 当命名构造函数或类时使用驼峰式大写1234567891011121314151617// badfunction user(options) { this.name = options.name;}var bad = new user({ name: 'nope'});// goodfunction User(options) { this.name = options.name;}var good = new User({ name: 'yup'}); 命名私有属性时前面加个下划线 _123456// badthis.__firstName__ = 'Panda';this.firstName_ = 'Panda';// goodthis._firstName = 'Panda'; 当保存对 this 的引用时使用 self(python 风格),避免this issue . Angular建议使用vm(MVVM模式中view-model)1234567// goodfunction() { var self = this; return function() { console.log(self); };} 存取器 属性的存取器函数不是必需的 如果你确实有存取器函数的话使用getVal() 和 setVal(‘hello’),java getter、setter风格或者jQuery风格 如果属性是布尔值,使用isVal() 或 hasVal()123456789// badif (!dragon.age()) { return false;}// goodif (!dragon.hasAge()) { return false;} 可以创建get()和set()函数,但是要保持一致12345678910111213function Jedi(options) { options || (options = {}); var lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber);}Jedi.prototype.set = function(key, val) { this[key] = val;};Jedi.prototype.get = function(key) { return this[key];}; 构造器 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。1234567891011121314151617181920212223function Jedi() { console.log('new jedi');}// badJedi.prototype = { fight: function fight() { console.log('fighting'); }, block: function block() { console.log('blocking'); }};// goodJedi.prototype.fight = function fight() { console.log('fighting');};Jedi.prototype.block = function block() { console.log('blocking');}; 方法可以返回 this 帮助方法可链。1234567891011121314151617181920212223242526272829// badJedi.prototype.jump = function() { this.jumping = true; return true;};Jedi.prototype.setHeight = function(height) { this.height = height;};var luke = new Jedi();luke.jump(); // => trueluke.setHeight(20) // => undefined// goodJedi.prototype.jump = function() { this.jumping = true; return this;};Jedi.prototype.setHeight = function(height) { this.height = height; return this;};var luke = new Jedi();luke.jump() .setHeight(20); 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。123456789101112function Jedi(options) { options || (options = {}); this.name = options.name || 'no name';}Jedi.prototype.getName = function getName() { return this.name;};Jedi.prototype.toString = function toString() { return 'Jedi - ' + this.getName();}; 事件 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器123456789101112131415161718// bad$(this).trigger('listingUpdated', listing.id);...$(this).on('listingUpdated', function(e, listingId) { // do something with listingId});// good$(this).trigger('listingUpdated', { listingId : listing.id });...$(this).on('listingUpdated', function(e, data) { // do something with data.listingId}); 模块 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它 总是在模块顶部声明 'use strict';,引入JSHint规范123456789101112131415161718// fancyInput/fancyInput.js(function(global) { 'use strict'; var previousFancyInput = global.FancyInput; function FancyInput(options) { this.options = options || {}; } FancyInput.noConflict = function noConflict() { global.FancyInput = previousFancyInput; return FancyInput; }; global.FancyInput = FancyInput;})(this); jQuery 对于jQuery对象以$开头,以和原生DOM节点区分。12345// badvar menu = $(".menu");// goodvar $menu = $(".menu"); 缓存jQuery查询12345678910111213141516171819202122// badfunction setSidebar() { $('.sidebar').hide(); // ...stuff... $('.sidebar').css({ 'background-color': 'pink' });}// goodfunction setSidebar() { var $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... $sidebar.css({ 'background-color': 'pink' });} 对DOM查询使用级联的 $('.sidebar ul') 或 $('.sidebar ul'),jsPerf 对有作用域的jQuery对象查询使用 find1234567891011121314151617// bad$('.sidebar', 'ul').hide();// bad$('.sidebar').find('ul').hide();// good$('.sidebar ul').hide();// good$('.sidebar > ul').hide();// good (slower)$sidebar.find('ul');// good (faster)$($sidebar[0]).find('ul'); 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。123$(function(){ //do your page init. }); 事件利用jQuery.on从页面分离到JavaScript文件。1234567// bad<a id="myLink" href="#" onclick="myEventHandler();"></a>// good<a id="myLink" href="#"></a>$("#myLink").on("click", myEventHandler); 对于Ajax使用promise方式。1234567891011121314151617// bad$.ajax({ ... success : function(){ }, error : function(){ } })// good$.ajax({. ..}).then( function( ){ // success}, function( ){ // error}) 利用promise的deferred对象解决延迟注册问题。123456789var dtd = $.Deferred(); // 新建一个deferred对象var wait = function(dtd){ var tasks = function(){ alert("执行完毕!"); dtd.resolve(); // 改变deferred对象的执行状态 }; setTimeout(tasks,5000); return dtd;}; HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。 ECMAScript 5兼容性尽量采用ES5方法,特别数组map、filter、forEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscore、lodash 常用辅助库. 参考Kangax的 ES5 compatibility table HTML、CSS、JavaScript分离 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中分离在不同类型文件,文件link。 HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。 CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + flux架构、Knockout等。 对于兼容性可用Modernizr规范库辅助。 使用jsHint 前端项目中推荐引入 jshint插件来规范项目编码规范。以及一套完善的IDE配置。 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。 前端工具 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。 本文转载自破狼,原文略有修改,侵权即删.原文链接:前端javascript规范原文作者:破狼","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"规范","slug":"规范","permalink":"https://ioliu.cn/tags/%E8%A7%84%E8%8C%83/"}]},{"title":"你可能不知道的一些JavaScript 奇技淫巧","slug":"about-javascript-spcial-technique","date":"2015-05-07T02:21:08.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2015/about-javascript-spcial-technique/","permalink":"https://ioliu.cn/2015/about-javascript-spcial-technique/","excerpt":"","text":"这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们。 ## 遍历一个obj的属性到数组 1234567function getAttr(obj){ var a=[]; for(a[a.length] in obj); return a;}console.log(getAttr({'name':'zhangsan','age':'20'}));//输出:['name','age'] 乍一看可能比较蒙,不过仔细分析还是不难理解的。常见用法是`for(var key in obj)`,这里`key`初始也是`undefined`的,`a[a.length]`整体也是`undefined`,所以二者其实是等价的。 在`for`循环中,`obj`的属性会依次赋值给`key`,同样,也依次赋值给`a[a.length]`,这里`length`一直在变,就巧妙地挨个赋值给数组的每一个元素了。 重复字符串(如abc=>abcabc)123function repeat(target,n){ return (new Array(n+1).join(target));} 改进版本: 1234function repeat(target,n){ return Array.prototype.join.call({length:n+1},target); //之所以要创建带length属性的对象,是因为调用数组原型方法时,必须是一个类数组对象,而类数组对象的条件就是length为非负整数} 不新建数组,而是用拥有length属性的对象替代,然后调用数组的join方法,性能提升很大.再改进: 1234567var repeat=(function(){ var join=Array.prototype.join,obj={}; return function(target,n){ obj.length=n+1; return join.call(obj,target); }})(); 利用闭包将对象和join方法缓存起来,不用每次都新建对象和寻找方法 for循环for循环中,当第二项为false时会终止循环,这里并不一定存在比较,可以直接赋值,如果赋值为undefined之类的值时,转成bool值也为假,因此也会终止,比如遍历数组可以写成: 1for(var i=arr.length,element;element=arr[—-i];){…} 这里,第二项一定是arr[--i]而非arr[i--],如果是后者的话,上来就是undefined,就不会执行循环体,或者for(var i=0,element;element=arr[i++];){…} NaNNaN是JS中唯一不等于自己的值,因此可以用来判断一个变量是否真的为NaN:a!==a /、+等算术运算符</+等运算符会强制符号两边的表达式执行valueOf然后比较,所以如果两边是函数或者对象,而又重写了该对象的valueOf方法,就会自动执行两边的方法。如: 12var a={valueOf:function(){console.log("aaa");}},b={valueOf:function(){console.log("bbb");}}; a < b;//会输出:aaa;bbb;false 闭包理解闭包需学会三个基本事实: JS允许你引用在当前函数意外定义的变量 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这是因为JS的函数值包含里比调用它们时执行所需要的代码更多的信息 闭包可以更新外部变量的值。这是因为闭包存储的是外部变量的引用而非值副本。如:1234567891011function box(){ var val=undefined; return { set:function(x){val=x;}, get:function(){return val;} };}var b=box();b.get();//“undefined”b.set(5);b.get();//5 这一点很重要,比如在函数的for循环体内返回闭包或者有闭包取for循环的计数器值,那么这个闭包取到的永远是for循环结束时i的最终值,因为闭包存储的是它的引用而非当时的值副本。 块级作用域JS没有块级作用域,因此通常情况下函数内部的所有变量都是绑定到函数作用域的,也就是说相当于都在函数一开始就声明了的,一个例外就是try/catch中的变量是块级的,只属于try/catch块。 嵌套函数众所周知,在函数内部声明函数是可以的,但是在在函数内的局部块里声明,可能会出现问题: 123456789101112function f(){return “global”;}function test(x){ function f(){return “local”} var result=[]; if(x){ result.push(f()); } result.push(f()); return result;}test(true);//[“local”,”local”]test(false);//[“local”] 将函数声明到if块中: 123456789101112function f(){return “global”;}function test(x){ var result=[]; if(x){ function f(){return “local”} result.push(f()); } result.push(f()); return result;} test(true);//?test(false);//? 结果会如何呢?理论上讲,JS没有块级作用域,因此f()的作用域是整个test函数,因此合理猜测应该是与上一次输出相同,全部为”local”,可是并不是所有的JS执行环境都如此行事,有的会根据是否执行包含f的代码块来有条件地绑定函数f(绑定即意味着将该变量绑定到其最近的作用域,而赋值是发生在代码实际执行到赋值那一步的时候进行的)。因此最好的办法是如果要声明嵌套函数,都在其富函数的最外层声明,要么就不要声明函数,而是使用var声明和函数表达式来实现: 12345678910function f(){return “global”;}function test(x){ var result=[]; if(x){ var g=function(){return “local”} result.push(g()); } result.push(f()); return result;} hasOwnProperty用js创建字典的时候,如果是利用对象的方式(因为JS对象的核心是一个字符串属性名称和属性值的映射表),会遇到一个问题就是原型污染,因为获取字典属性值的时候用hasOwnProperty还好,如果用for in遍历的话,不仅会遍历对象本身,包括它的原型,因此如果在其他地方污染了Object的原型,那么for in就会产生非预期的结果,这时可能会用hasOwnProperty来先检测该对象本身是否含有属性来避免原型污染,然而更极端的情况是连hasOwnProperty这个原型方法都有可能被污染。避免原型污染的方法是在创建字典对象的时候用Object.create(null)来创建一个完全空对象,这个对象没有原型,这个方法是ES5的,在没有这个方法可用的时候,最好是创建字典类,然后在字典类里用数组来存储有序集合,自己维护这个集合。 类数组对象JS中的类数组对象可以享用数组的大部分原型方法如map等类数组对象是指满足两个条件的对象: 一是具备合理范围值内的length属性 二是length属性大于该对象的最大索引,索引是一个合理范围的证书,它的字符串表示的是对象的一个key;但是数组的一个原型方法contact是不能被类数组对象调用的,因此需要先用[].slice.call把类数组对象转换为真正的数组比如[].slice.call(arguments)。 结构类型并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类的实例,而是直接返回对象,对象具备预期的方法和属性,比如: 1234567SomeObj.someWidget=function(opts){ return { a:blabla, b:function(){...}, c:blabla }} JavaScript 自动插入分号JavaScript 具备自动插入分号的能力,但是自动插入分号并不是万能的,其有三条规则: 只在}标记之前、一个或多个换行之后以及程序输入的结尾被插入 分号只在随后的输入标记不能被解析时插入 !!这一点很重要,比如: a = b (fn()); 是不会在a=b之后自动插入分号的,因为a=b(f())是可以被解析的,因此像(,[,+,-,/开头的时候,需要特别注意上一行可能不会自动插入。 还有一些情况,尽管不会出现解析错误,JS仍然会强制插入分号,这就是所谓的JS语法限制产生式。它不允许在两个字符间出现换行,最危险的就是return语句,如 return{}; 会被强制插入而成为 return;{}; 类似的还有:throw语句、带有显示标签的break或着continue语句、后置自增或自减运算符 分号不会作为分隔符在for循环空语句的头部被自动插入 因此,最好的办法是在自己的js文件的最开始防御性地插入;,这样在合并js文件的时候就不会出问题了。 本文转载自博客园,原文略有删减,侵权即删.原文链接:你可能不知道的一些JavaScript 奇技淫巧原文作者:FirstLovt","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"JavaScript技巧","slug":"JavaScript技巧","permalink":"https://ioliu.cn/tags/JavaScript%E6%8A%80%E5%B7%A7/"},{"name":"结构类型","slug":"结构类型","permalink":"https://ioliu.cn/tags/%E7%BB%93%E6%9E%84%E7%B1%BB%E5%9E%8B/"},{"name":"数组遍历","slug":"数组遍历","permalink":"https://ioliu.cn/tags/%E6%95%B0%E7%BB%84%E9%81%8D%E5%8E%86/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"}]},{"title":"Hello World for Hexo","slug":"hexo-your-blog","date":"2015-05-06T02:21:08.000Z","updated":"2024-03-28T08:06:05.972Z","comments":true,"path":"2015/hexo-your-blog/","permalink":"https://ioliu.cn/2015/hexo-your-blog/","excerpt":"","text":"今天把博客移到了Hexo,感觉蛮不错的 ^_^ . 简介hexo 是一款基于Node.js的静态博客框架。目前在GitHub上已有4k+ star 和 700+ fork (官网)。是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。 特性 风一般的速度: Hexo基于Node.js,支持多进程,几百篇文章也可以秒生成。 流畅的撰写: 支持GitHub Flavored Markdown和所有Octopress的插件。 扩展性: Hexo支持EJS、Swig和Stylus。通过插件支持Haml、Jade和Less. 快速入门安装安装 Hexo 相当简单。然而在安装前,您必须检查电脑中是否已安装下列应用程序: Node.js Git 如果您的电脑中已经安装上述必备程序,那么恭喜您!接下来只需要使用 npm 即可完成 Hexo 的安装。 1npm install -g hexo-cli 仅需一步就把 Hexo 本体和所有相依套件安装完毕,很简单吧? 升级更新hexo到最新版 1npm update hexo -g 初始化123hexo init <folder>cd <floder>npm install 如果指定 <folder>,便会在目前的资料夹建立一个名为 <folder> 的新文件夹;否则会在目前文件夹初始化。 新建1hexo new [layout] <title> 新建一篇文章。如果没有设置 layout 的话,默认使用 _config.yml 中的 default_layout 参数代替。如果标题包含空格的话,请使用引号括起来。 生成静态文件12hexo g//或者 hexo generate 启动服务12hexo s//或者 hexo server 启动服务后,打开浏览器输入 http://localhost:4000 回车,即可看到效果. 部署12hexo d//可以通过hexo d -g 命令完成生成和部署 如果出现错误,可能是没有安装部署插件,请执行下面的命令安装插件: 1npm install hexo-deploy-git --save-dev Hexo官网:[http://Hexo.io]部署Hexo","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Hexo","slug":"Hexo","permalink":"https://ioliu.cn/tags/Hexo/"},{"name":"免费博客","slug":"免费博客","permalink":"https://ioliu.cn/tags/%E5%85%8D%E8%B4%B9%E5%8D%9A%E5%AE%A2/"}]}],"categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"name":"其他","slug":"其他","permalink":"https://ioliu.cn/categories/%E5%85%B6%E4%BB%96/"}],"tags":[{"name":"bbr","slug":"bbr","permalink":"https://ioliu.cn/tags/bbr/"},{"name":"linux","slug":"linux","permalink":"https://ioliu.cn/tags/linux/"},{"name":"Git","slug":"Git","permalink":"https://ioliu.cn/tags/Git/"},{"name":"Command","slug":"Command","permalink":"https://ioliu.cn/tags/Command/"},{"name":"Valine","slug":"Valine","permalink":"https://ioliu.cn/tags/Valine/"},{"name":"Comment System","slug":"Comment-System","permalink":"https://ioliu.cn/tags/Comment-System/"},{"name":"评论系统","slug":"评论系统","permalink":"https://ioliu.cn/tags/%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/"},{"name":"国家/地区","slug":"国家-地区","permalink":"https://ioliu.cn/tags/%E5%9B%BD%E5%AE%B6-%E5%9C%B0%E5%8C%BA/"},{"name":"语言缩写","slug":"语言缩写","permalink":"https://ioliu.cn/tags/%E8%AF%AD%E8%A8%80%E7%BC%A9%E5%86%99/"},{"name":"MySql","slug":"MySql","permalink":"https://ioliu.cn/tags/MySql/"},{"name":"数据库","slug":"数据库","permalink":"https://ioliu.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"},{"name":"ssl","slug":"ssl","permalink":"https://ioliu.cn/tags/ssl/"},{"name":"cerbot","slug":"cerbot","permalink":"https://ioliu.cn/tags/cerbot/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"变量类型","slug":"变量类型","permalink":"https://ioliu.cn/tags/%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B/"},{"name":"CSS","slug":"CSS","permalink":"https://ioliu.cn/tags/CSS/"},{"name":"译文","slug":"译文","permalink":"https://ioliu.cn/tags/%E8%AF%91%E6%96%87/"},{"name":"技巧","slug":"技巧","permalink":"https://ioliu.cn/tags/%E6%8A%80%E5%B7%A7/"},{"name":"MarkDown","slug":"MarkDown","permalink":"https://ioliu.cn/tags/MarkDown/"},{"name":"Guide","slug":"Guide","permalink":"https://ioliu.cn/tags/Guide/"},{"name":"Media Query","slug":"Media-Query","permalink":"https://ioliu.cn/tags/Media-Query/"},{"name":"响应式","slug":"响应式","permalink":"https://ioliu.cn/tags/%E5%93%8D%E5%BA%94%E5%BC%8F/"},{"name":"媒体查询","slug":"媒体查询","permalink":"https://ioliu.cn/tags/%E5%AA%92%E4%BD%93%E6%9F%A5%E8%AF%A2/"},{"name":"GitHub","slug":"GitHub","permalink":"https://ioliu.cn/tags/GitHub/"},{"name":"SSH Key","slug":"SSH-Key","permalink":"https://ioliu.cn/tags/SSH-Key/"},{"name":"免密码","slug":"免密码","permalink":"https://ioliu.cn/tags/%E5%85%8D%E5%AF%86%E7%A0%81/"},{"name":"规范","slug":"规范","permalink":"https://ioliu.cn/tags/%E8%A7%84%E8%8C%83/"},{"name":"JavaScript技巧","slug":"JavaScript技巧","permalink":"https://ioliu.cn/tags/JavaScript%E6%8A%80%E5%B7%A7/"},{"name":"结构类型","slug":"结构类型","permalink":"https://ioliu.cn/tags/%E7%BB%93%E6%9E%84%E7%B1%BB%E5%9E%8B/"},{"name":"数组遍历","slug":"数组遍历","permalink":"https://ioliu.cn/tags/%E6%95%B0%E7%BB%84%E9%81%8D%E5%8E%86/"},{"name":"Hexo","slug":"Hexo","permalink":"https://ioliu.cn/tags/Hexo/"},{"name":"免费博客","slug":"免费博客","permalink":"https://ioliu.cn/tags/%E5%85%8D%E8%B4%B9%E5%8D%9A%E5%AE%A2/"}]} \ No newline at end of file +{"meta":{"title":"云淡风轻","subtitle":"一个安静的角落","description":"隐约雷鸣,阴霾天空,但盼风雨来,能留你在此","author":"云淡风轻","url":"https://ioliu.cn","root":"/"},"pages":[{"title":"Sorry , Page Not Found","date":"2015-05-08T09:50:17.000Z","updated":"2024-07-23T05:14:42.487Z","comments":false,"path":"404.html","permalink":"https://ioliu.cn/404.html","excerpt":"","text":"404 SORRY , PAGE NOT FOUND 首页                  上页"},{"title":"404 Not Found:该页无法显示","date":"2024-07-23T05:14:42.487Z","updated":"2024-07-23T05:14:42.487Z","comments":false,"path":"/404.html","permalink":"https://ioliu.cn/404.html","excerpt":"","text":""},{"title":"关于","date":"2024-07-23T05:14:42.487Z","updated":"2024-07-23T05:14:42.487Z","comments":false,"path":"about/index.html","permalink":"https://ioliu.cn/about/index.html","excerpt":"","text":"这个人很懒,什么都没有留下!"},{"title":"书单","date":"2024-07-23T05:14:42.487Z","updated":"2024-07-23T05:14:42.487Z","comments":false,"path":"books/index.html","permalink":"https://ioliu.cn/books/index.html","excerpt":"","text":""},{"title":"分类","date":"2024-07-23T05:14:42.487Z","updated":"2024-07-23T05:14:42.487Z","comments":false,"path":"categories/index.html","permalink":"https://ioliu.cn/categories/index.html","excerpt":"","text":""},{"title":"友情链接","date":"2024-07-23T05:14:42.491Z","updated":"2024-07-23T05:14:42.491Z","comments":true,"path":"links/index.html","permalink":"https://ioliu.cn/links/index.html","excerpt":"","text":"名称:云淡风轻 头像:https://ioliu.cn/images/avatar.jpg 链接:https://ioliu.cn/ 介绍:一个安静的角落"},{"title":"Repositories","date":"2024-07-23T05:14:42.491Z","updated":"2024-07-23T05:14:42.491Z","comments":false,"path":"repository/index.html","permalink":"https://ioliu.cn/repository/index.html","excerpt":"","text":""},{"title":"标签","date":"2024-07-23T05:14:42.491Z","updated":"2024-07-23T05:14:42.491Z","comments":false,"path":"tags/index.html","permalink":"https://ioliu.cn/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"在Debian 11上升级内核并启用BBR加速","slug":"upgrade-debian-kernel-version","date":"2024-03-23T14:53:34.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2024/upgrade-debian-kernel-version/","permalink":"https://ioliu.cn/2024/upgrade-debian-kernel-version/","excerpt":"","text":"如果你正在使用Debian 11并且希望提升你的系统性能,升级到最新的内核版本并启用BBR加速可能是一个不错的选择。以下是一篇指南,将带你了解如何安全地升级内核以及如何启用BBR来优化你的网络连接。 升级到新版内核第一步:备份你的系统在进行任何重大系统更改之前,备份是非常重要的。你可以使用如Timeshift等工具来备份你的系统。 第二步:修改软件源为了安装最新的内核,我们可能需要添加Debian的Backports源。以下是添加Backports源的步骤: 打开/etc/apt/sources.list文件: 1sudo nano /etc/apt/sources.list 在文件末尾添加以下行: 12deb http://deb.debian.org/debian bullseye-backports main contrib non-freedeb-src http://deb.debian.org/debian bullseye-backports main contrib non-free 保存并退出编辑器。 更新软件包列表: 1sudo apt update 第三步:安装新内核使用Backports源安装新内核: 12sudo apt-get -t bullseye-backports install linux-image-6.x.x-x-amd64sudo apt-get -t bullseye-backports install linux-headers-6.x.x-x-amd64 请确保替换命令中的版本号为你想要安装的实际版本。 第四步:更新GRUB并重启安装完新内核后,更新GRUB: 1sudo update-grub 然后重启你的系统: 1sudo reboot 清除旧内核第一步:列出当前内核使用以下命令查看当前安装的内核: 12dpkg --list | grep linux-imagedpkg --list | grep linux-headers 第二步:删除旧内核选择你不再需要的内核版本,并使用apt-get purge命令进行删除: 12sudo apt-get purge linux-image-5.x.x-x-amd64sudo apt-get purge linux-headers-5.x.x-x-amd64 第三步:更新GRUB再次更新GRUB配置: 1sudo update-grub 启用BBR加速第一步:加载TCP BBR模块编辑/etc/sysctl.conf文件,在文件末尾添加以下两行: 12net.core.default_qdisc=fqnet.ipv4.tcp_congestion_control=bbr 第二步:应用新的系统配置应用新的配置: 1sudo sysctl -p 第三步:验证BBR是否启用运行以下命令: 1sysctl net.ipv4.tcp_congestion_control 如果输出显示bbr,则BBR已启用。 结语现在,你的Debian 11系统应该运行在最新的内核上,并且已经启用了BBR加速。这将帮助你提高系统的整体性能和网络连接的速度。请确保在执行以上操作时仔细检查,并始终保持系统的备份。 参考 Debian Backports Instructions Timeshift on GitHub Google BBR Congestion Control Algorithm","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"bbr","slug":"bbr","permalink":"https://ioliu.cn/tags/bbr/"},{"name":"linux","slug":"linux","permalink":"https://ioliu.cn/tags/linux/"}]},{"title":"Git中的一些骚操作","slug":"git-command-backup","date":"2017-11-10T06:30:25.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2017/git-command-backup/","permalink":"https://ioliu.cn/2017/git-command-backup/","excerpt":"","text":"最近因为Valine,所以经常用到Git。当然,工作中也有用到,但基本上是用的图形化。 这里最Git的相关操作命令做个备份,以备不时之需。 可能不定时更新。 配置自动换行1git config --global core.autocrlf input # 提交时自动将换行符转成lf 多账号配置SSH修改~/.ssh/config文件(Windows平台) 1234567891011121314151617181920# 配置 Github.comHost github.com HostName github.com IdentityFile C:\\\\path\\\\to\\\\.ssh\\\\id_rsa_github PreferredAuthentications publickey User YourName# 配置 Coding.netHost git.coding.net HostName git.coding.net IdentityFile C:\\\\path\\\\to\\\\.ssh\\\\id_rsa_coding PreferredAuthentications publickey User YourName# 配置 Gitee.comHost gitee.com HostName gitee.com IdentityFile C:\\\\path\\\\to\\\\.ssh\\\\id_rsa_gitee PreferredAuthentications publickey User YourName pull 强制覆盖本地文件12git fetch --all git reset --hard origin/master push 强制覆盖远程文件1git push -f origin master 保持fork之后的项目和上游同步团队协作,为了规范,一般都是fork组织的仓库到自己帐号下,再提交pr,组织的仓库一直保持更新,下面介绍如何保持自己fork之后的仓库与上游仓库同步。 下面以我 fork 团队的博客仓库为例 点击 fork 组织仓库到自己帐号下,然后就可以在自己的帐号下 clone 相应的仓库 使用 git remote -v 查看当前的远程仓库地址,输出如下: 12origin git@github.com:ibrother/staticblog.github.io.git (fetch)origin git@github.com:ibrother/staticblog.github.io.git (push) 可以看到从自己帐号 clone 下来的仓库,远程仓库地址是与自己的远程仓库绑定的(这不是废话吗) 接下来运行: 1git remote add upstream https://github.com/staticblog/staticblog.github.io.git 这条命令就算添加一个别名为 upstream(上游)的地址,指向之前 fork 的原仓库地址。git remote -v 输出如下: 1234origin git@github.com:ibrother/staticblog.github.io.git (fetch)origin git@github.com:ibrother/staticblog.github.io.git (push)upstream https://github.com/staticblog/staticblog.github.io.git (fetch)upstream https://github.com/staticblog/staticblog.github.io.git (push) 之后运行下面几条命令,就可以保持本地仓库和上游仓库同步了 123git fetch upstreamgit checkout mastergit merge upstream/master 接着就是熟悉的推送本地仓库到远程仓库 1git push origin master From staticblog .","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Git","slug":"Git","permalink":"https://ioliu.cn/tags/Git/"},{"name":"Command","slug":"Command","permalink":"https://ioliu.cn/tags/Command/"}]},{"title":"Valine -- 一款极简的评论系统","slug":"add-valine-comments-to-your-blog","date":"2017-08-07T06:30:25.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2017/add-valine-comments-to-your-blog/","permalink":"https://ioliu.cn/2017/add-valine-comments-to-your-blog/","excerpt":"","text":"Valine - 一款极简的无后端评论系统. 2017年6月1日,在你等超龄儿童欢度节日的时候,多说躺下了。2017年8月1日,不甘寂寞的网易云跟帖也跟多说随风而去了。 2017年8月7日,一款基于Leancloud的极简风评论系统诞生:Valine。 食用方法获取 APP ID 和 APP KEY 点击这里登录或注册Leancloud 点这里创建应用,应用名看个人喜好。 选择刚刚创建的应用>设置>选择应用 Key,然后你就能看到你的APP ID和APP KEY了,参考下图: 为了您的数据安全,请填写应用>设置>安全设置中的Web 安全域名,如下图: 页面中的设置页面中的食用方法炒鸡简单,来来来,我们用代码说话: 123456789101112131415161718192021222324<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Valine - A simple comment system based on Leancloud.</title> <!--Leancloud 操作库:--> <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script> <!--Valine 的核心代码库:--> <script src="./dist/Valine.min.js"></script></head><body> <div class="comment"></div> <script> new Valine({ // AV 对象来自上面引入av-min.js(老司机们不要开车➳♡゛扎心了老铁) av: AV, el: '.comment', // app_id: 'Your APP ID', // 这里填写上面得到的APP ID app_key: 'Your APP KEY', // 这里填写上面得到的APP KEY placeholder: 'ヾノ≧∀≦)o来啊,快活啊!' // [v1.0.7 new]留言框占位提示文字 }); </script></body></html> 看吧,我是不是没说大话(_(:з」∠)_一本正经的胡说八道)。 评论数据管理插播一下,关于评论数据管理,请自行登录Leancloud应用管理。具体步骤:登录>选择你创建的应用>存储>选择ClassComment,然后就可以尽情的发挥你的权利啦(~ ̄▽ ̄)~ 更多配置信息请移步:https://valine.js.org –EOF–","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Valine","slug":"Valine","permalink":"https://ioliu.cn/tags/Valine/"},{"name":"Comment System","slug":"Comment-System","permalink":"https://ioliu.cn/tags/Comment-System/"},{"name":"评论系统","slug":"评论系统","permalink":"https://ioliu.cn/tags/%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/"}]},{"title":"不同的国家/地区与语言缩写代码","slug":"country-city-and-language","date":"2017-06-29T07:30:08.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2017/country-city-and-language/","permalink":"https://ioliu.cn/2017/country-city-and-language/","excerpt":"","text":"国家/地区 语言代码 国家地区 语言代码 简体中文(中国) zh-cn 简体中文(台湾地区) zh-tw 繁体中文(香港) zh-hk 英语(香港) en-hk 英语(美国) en-us 英语(英国) en-gb 英语(全球) en-ww 英语(加拿大) en-ca 英语(澳大利亚) en-au 英语(爱尔兰) en-ie 英语(芬兰) en-fi 芬兰语(芬兰) fi-fi 英语(丹麦) en-dk 丹麦语(丹麦) da-dk 英语(以色列) en-il 希伯来语(以色列) he-il 英语(南非) en-za 英语(印度) en-in 英语(挪威) en-no 英语(新加坡) en-sg 英语(新西兰) en-nz 英语(印度尼西亚) en-id 英语(菲律宾) en-ph 英语(泰国) en-th 英语(马来西亚) en-my 英语(阿拉伯) en-xa 韩文(韩国) ko-kr 日语(日本) ja-jp 荷兰语(荷兰) nl-nl 荷兰语(比利时) nl-be 葡萄牙语(葡萄牙) pt-pt 葡萄牙语(巴西) pt-br 法语(法国) fr-fr 法语(卢森堡) fr-lu 法语(瑞士) fr-ch 法语(比利时) fr-be 法语(加拿大) fr-ca 西班牙语(拉丁美洲) es-la 西班牙语(西班牙) es-es 西班牙语(阿根廷) es-ar 西班牙语(美国) es-us 西班牙语(墨西哥) es-mx 西班牙语(哥伦比亚) es-co 西班牙语(波多黎各) es-pr 德语(德国) de-de 德语(奥地利) de-at 德语(瑞士) de-ch 俄语(俄罗斯) ru-ru 意大利语(意大利) it-it 希腊语(希腊) el-gr 挪威语(挪威) no-no 匈牙利语(匈牙利) hu-hu 土耳其语(土耳其) tr-tr 捷克语(捷克共和国) cs-cz 斯洛文尼亚语 sl-sl 波兰语(波兰) pl-pl 瑞典语(瑞典) sv-se 西班牙语 (智利) es-cl","categories":[{"name":"其他","slug":"其他","permalink":"https://ioliu.cn/categories/%E5%85%B6%E4%BB%96/"}],"tags":[{"name":"国家/地区","slug":"国家-地区","permalink":"https://ioliu.cn/tags/%E5%9B%BD%E5%AE%B6-%E5%9C%B0%E5%8C%BA/"},{"name":"语言缩写","slug":"语言缩写","permalink":"https://ioliu.cn/tags/%E8%AF%AD%E8%A8%80%E7%BC%A9%E5%86%99/"}]},{"title":"从删库到跑路 -- MySql 不算初体验的初体验","slug":"mysql-tutorial","date":"2017-03-24T03:00:25.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2017/mysql-tutorial/","permalink":"https://ioliu.cn/2017/mysql-tutorial/","excerpt":"","text":"最近准备找时间把bing壁纸项目重构,但由于虚拟主机快要过期了,所以目前的首要任务是将数据库从阿里云的虚拟主机转移到我自己的服务器上。 因为多年前学过SQLServer、Oracle、MySql等数据库,但许久未用,技艺生疏,所以这里是不算初体验的初体验。 本文将执行三步走计划: 安装 登录 使用 安装在Debian上安装MySql很简单,运行如下命令就基本OK: 1$ apt-get install mysql-server mysql-client 其中mysql-server是服务器程序,mysql-client是客户端程序。安装过程中会有如下提示,需要设置mysql数据库密码;输入要设置的密码后,回车即可继续安装。 如果出现Unable to locate package mysql-server等错误,请先执行apt-get update后重试。 登录安装成功后,mysql会自动启动,可以通过ps -ef | grep mysql查看mysql是否运行。登陆mysql: 123# login$ mysql -u root -pEnter password: # 输入密码 其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。 查看数据库show databases;: 12345678910$ mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys |+--------------------+4 rows in set (0.00 sec) 使用创建数据库12$ mysql> create database DB_name;Query OK, 1 row affected (0.05 sec) 查看刚刚创建的数据库1234567891011$ mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || DB_name || mysql || performance_schema || sys |+--------------------+5 rows in set (0.00 sec) 使用刚刚创建的数据库12$ mysql> use DB_name;Database changed 创建表12345$ mysql> CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 查看表1234567$ mysql> SHOW CREATE table person;CREATE TABLE `person` ( `number` int(11) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, `birthday` date DEFAULT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8; 查看表的所有列12345678$ mysql> SHOW FULL COLUMNS from person;+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+| number | int(11) | NULL | YES | | NULL | | select,insert,update,references | || name | varchar(255) | utf8_general_ci | YES | | NULL | | select,insert,update,references | || birthday | date | NULL | YES | | NULL | | select,insert,update,references | |+----------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+ 创建临时表12345$ mysql> CREATE TEMPORARY TABLE temp_person ( number INT(11), name VARCHAR(255), birthday DATE ); 删除表123$ mysql> DROP TABLE temp_person;# or$ mysql> DROP TABLE IF EXISTS temp_person; 创建用户命令: 1$mysql> CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明: username:你将创建的用户名 host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符% password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器 例子: 12345$mysql> CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';$mysql> CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '123456';$mysql> CREATE USER 'pig'@'%' IDENTIFIED BY '';$mysql> CREATE USER 'pig'@'%'; 授权命令: 1$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' 说明: privileges:用户的操作权限,如SELECT,INSERT,UPDATE等,如果要授予所的权限则使用ALL databasename:数据库名 tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*例子:12$mysql> GRANT SELECT, INSERT ON test.user TO 'pig'@'%';$mysql> GRANT ALL ON *.* TO 'pig'@'%'; 注意 用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令: 1$mysql> GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION; 设置与更改用户密码命令: 1$mysql> SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword'); 如果是当前登陆用户用: 1>$mysql> SET PASSWORD = PASSWORD("newpassword");例子: 1$mysql> SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456"); 撤销用户权限命令: 1$mysql> REVOKE privilege ON databasename.tablename FROM 'username'@'host'; 说明:privilege, databasename, tablename:同授权部分例子: 1$mysql> REVOKE SELECT ON *.* FROM 'pig'@'%'; 注意: 假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):GRANT SELECT ON test.user TO 'pig'@'%',则在使用REVOKE SELECT ON *.* FROM 'pig'@'%'; 命令并不能撤销该用户对test数据库中user表的SELECT 操作。 相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%', 则REVOKE SELECT ON test.user FROM 'pig'@'%'; 命令也不能撤销该用户对test数据库中user表的SELECT权限。 具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看。 删除用户 1$mysql> DROP USER 'username'@'host'; 最后能看到这里,那就先要恭喜你了,你已经成功达成建库、建表、建用户到删表、删库、删用户等成就。那还等什么?赶紧跑路吧ε=ε=ε=┏(゜ロ゜;)┛ 附: MySql官网 MySql Tutorial Mysql创建用户并授权命令","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"MySql","slug":"MySql","permalink":"https://ioliu.cn/tags/MySql/"},{"name":"数据库","slug":"数据库","permalink":"https://ioliu.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"}]},{"title":"给你的网站加把锁 -- Let's Encrypt 完全体验","slug":"add-a-lock-to-your-website","date":"2017-03-21T10:30:25.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2017/add-a-lock-to-your-website/","permalink":"https://ioliu.cn/2017/add-a-lock-to-your-website/","excerpt":"","text":"今天抽时间将所有的网站SSL证书都更新了成 Let’s Encrypt 了。采用了certbot 这样的自动化工具,配置管理起来非常容易(一本正经的胡说八道),这里将对整个体验过程做个详细记录。 了解 Let’s Encrypt The project aims to make encrypted connections in the World Wide Web the default case. By getting rid of payment, web server configuration, validation emails and dealing with expired certificates it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.On a Linux web server, execution of only two commands is sufficient to set up HTTPS encryption, acquire and install certificates within 20 to 30 seconds. Let’s Encrypt 是一个2015年末推出的数字证书认证机构,将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程,为安全网站提供免费的SSL/TLS证书。 获取 Let’s EncryptLet’s Encrypt 证书生成不需要手动进行,官方推荐 Certbot 这套自动化工具来实现。4步轻松搞定: 下载安装 certbot (Let’s Encrypt项目的自动化工具) 获得SSL证书 修改Nginx配置文件 续订 1. 安装 Certbot根据 Certbot 官网指南,Debian 8上执行如下命令,安装certbot: 12$ sudo apt-get update$ sudo apt-get install certbot -t jessie-backports 等安装完成,certbot就可以使用了。 2. 获取SSL证书Let’s Encrypt提供了通过各种插件获取SSL证书的各种方法。不同的是Apache的插件,大多数的插件只会帮助你得到,你必须手动配置你的Web服务器使用证书。仅获取证书而不安装证书的插件称为“验证器”,因为它们用于验证服务器是否应颁发证书。下面将使用Webroot的插件来获取SSL证书。 如何使用 Webroot 插件:Webroot 的工作插件放置在一个特殊的文件/.well-known目录文档根目录下,它可以打开(通过Web服务器)内由让我们的加密服务进行验证。 根据配置的不同,你可能需要明确允许访问/.well-known目录。 为了确保该目录可供Let’s Encrypt进行验证,让我们快速更改我们的Nginx配置。编辑/etc/nginx/conf.d/example.com.conf文件,并将下面代码添加进去: 123location ~ /.well-known { allow all;} 使用nginx -t测试配置文件是否正确,在正确的情况下,重新让Nginx重新加载配置文件: 1$ sudo systemctl reload nginx 使用certbot命令获取证书:1$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is -w:指定网站所在目录 -d:指定要生成证书的域名,如果你想多个域名保存在一个证书里(最多四个)(如example.com、www.example.com、thing.is、m.thing.is),请确保使用适当的webroot路径和域名替换命令中的相对应部分。 接下来,同意加密订阅协议: 如果一切顺利,你应该看到一个类似下面的输出消息: IMPORTANT NOTES: Congratulations! Your certificate and chain have been saved at/etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expireon 2017-06-19. To obtain a new or tweaked version of thiscertificate in the future, simply run certbot again. Tonon-interactively renew all of your certificates, run “certbotrenew” If you like Certbot, please consider supporting our work by: Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donateDonating to EFF: https://eff.org/donate-le 证书文件如果运行顺利,所有服务器所需要的证书就已经生成好了。他们被放在了 /etc/letsencrypt/live/example.com/ 下: 12345$ ls /etc/letsencrypt/live/example.com/cert.pem #server cert only privkey.pem #private key chain.pem #intermediates fullchain.pem #server cert + intermediates 3.修改Nginx配置文件到这里已经成功一大半了,只需要配置 Nginx 支持刚刚生成的证书。最佳实践可以参考Mozilla SSL Configuration Generator。注意去掉HSTS的勾(勾上会强制https,并且很难消除后续影响)。 请根据自己的服务配置修改和添加内容,重点只需要关注6行: 123456789101112server { listen 443 ssl http2; .... ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_dhparam /etc/nginx/ssl/dhparam.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/root_ca_cert_plus_intermediates; resolver <IP DNS resolver>; ....} dhparam.pem可以通过以下命令生成: 12$ sudo mkdir /etc/nginx/ssl$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 Nginx 配置完成后重启,用浏览器测试是否一切正常。 4.续订Let's Encrypt证书有效期只有3个月,所以,需要定时renew。我将使用corntab来执行renew命令: 1$ sudo crontab -e 添加以下行: 130 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log && /bin/systemctl reload nginx 保存,并退出。这个定时任务将在每个星期一的凌晨两点半执行certbot renew命令,并重启Nginx。最后将日志输出到/var/log/le-renewal.log。 测试你的网站 SSL 安全性Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。这意味着你网站的HTTPS已经启用成功啦,为自己鼓个掌。 (๑•̀ㅂ•́)و✧。 附:还有一种方法,不需要访问你的网站目录,但需要临时停止Nginx服务器(需要用到80端口): 停止Nginx 域名解析到你的服务器IP 执行命令:certbot certonly --standalone -d example.com -d www.example.com 然后的步骤就和上面一样啦~~~ 以上。","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"ssl","slug":"ssl","permalink":"https://ioliu.cn/tags/ssl/"},{"name":"cerbot","slug":"cerbot","permalink":"https://ioliu.cn/tags/cerbot/"}]},{"title":"判断变量类型的一些方法","slug":"judgment-variable-type","date":"2016-09-13T14:10:01.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2016/judgment-variable-type/","permalink":"https://ioliu.cn/2016/judgment-variable-type/","excerpt":"","text":"久了不用,就会发现,以前会的东西都会忘记掉(或者是完全想不起来了),不知道你们有没有遇到过这个情况 - -! 这里只是对判断变量类型方法的一些记录,方便以后能够随时查看。 typeof要判断变量类型,首先想到的就是typeof,但用了才知道,其结果完全不是理想中的: 123456typeof {}; //"object"typeof []; //"object"typeof ""; //"string"typeof 0; //"number"typeof function(){};//"function"typeof true;//"boolean" 由上面代码可以看出,数组也是对象,所以typeof不是我们理想中的解决方案。 当然,有的童鞋可能会说,由于length是Array特有的属性(非绝对),那是不是可以用length+typeof来判断。 当然,这是可以的: 12345var arr = [1,2];if(typeof arr === 'object'){ console.log(typeof arr.length === "number" ? "array" : "object");//这里输出 "array"}//...其他的就不一一罗列了 不过这个方法不通用,如果{key:value}对象中有 length 字段呢,如: 123456//这种情况对于上面的代码就不适用了var obj = { name:"square", length:50, width:50}; instanceof第二种解决方案就是使用instanceof,不过使用instanceof会出现[] instanceof Object === true的情况。这样就需要优先判断Array: 1234567891011121314151617var a = [1,2,3];var b = {name:'zhangsan',sex:123};var fn = function(){};var detectType = function(o){ if(o instanceof Array){ return 'Array' }else if( o instanceof Object ){ return 'Object'; }else{ return 'param is no object type'; }}console.log( detectType(a) ); // Arrayconsole.log( detectType(b) ); // Objectconsole.log( detectType(1) ); // param is no object typeconsole.log( detectType(true) ); // param is no object typeconsole.log( detectType('a') ); // param is no object type Object.prototype.toString.call还有一种最靠谱的办法就是Object.prototype.toString.call: 12345678910Object.prototype.toString.call([]) //"[object Array]"Object.prototype.toString.call(Object) //"[object Function]"Object.prototype.toString.call(function x(){}) //"[object Function]"Object.prototype.toString.call("") //"[object String]"Object.prototype.toString.call({}) //"[object Object]"Object.prototype.toString.call(null) //"[object Null]"Object.prototype.toString.call(undefined) //"[object Undefined]"Object.prototype.toString.call(/test/) //"[object RegExp]"Object.prototype.toString.call(new Date()) //"[object Date]" 参考文档 Object.prototype.toString()","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"变量类型","slug":"变量类型","permalink":"https://ioliu.cn/tags/%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B/"}]},{"title":"CSS 内容和特殊字符","slug":"css-content-and-special-characters","date":"2016-09-06T06:10:01.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2016/css-content-and-special-characters/","permalink":"https://ioliu.cn/2016/css-content-and-special-characters/","excerpt":"","text":"当我写这个主题theme的时候,我想在我的列表元素(list elements)上用CSS内容(CSS content)属性添加一些**向右双角引号(right-pointing double-angle quotation marks)(<<)**。 所以,我在里面添加了&raquo;,然而,它并不工作! 我花了一点时间去了解到,你不能使用常规的 HTML 实体内容。相反,你必须使用 Unicode 十六进制格式,它看起来像这样:\\bb。 这是一些你可以轻而易举找到的东西,只因为它出现在了众多课程和参考书里。 将HTML实体转换成Unicode十六进制代码这里有很多的HTML实体对应表,但是没有更多的 Unicode十六进制表,所以很方便的知道二者之间的转换。你需要知道所有的HTML十进制单位(它们看起来像这样&#123;,而不是像这样&quot;)。那数字,你猜到了吧,就是十进制格式。我们需要将其转换成Unicode十六进制(我知道,你震惊了!)。 如果你不是一个程序员或者数学天才,可能你不熟悉到底该怎么做(具体请Google)。OK,其实这并不难,但有一个更快捷的方式: 打开类似于经典的Windows计算器,切换到“程序员”视图(View > Programmer)。点击Dec(十进制)单选按钮,输入你的数字然后点击Hex(十六进制)按钮,你就会得到你的十六进制数字。 然后把刚刚得到的数字放到\\之后,你就得到了你自己的Unicode十六进制字符。 更容易的方法 - HTML实体(HTML Entity)和 Unicode 十六进制 对应表这个方法不需要你手动的将十进制转成十六进制,这个图表能够给你一些常见的(或者不是那么常见的)符号的参考:","categories":[],"tags":[{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"CSS","slug":"CSS","permalink":"https://ioliu.cn/tags/CSS/"},{"name":"译文","slug":"译文","permalink":"https://ioliu.cn/tags/%E8%AF%91%E6%96%87/"}],"author":"@Christian Snodgrass"},{"title":"JavaScript 最佳实践: 提升你代码质量的一些提示&技巧","slug":"javascript-best-practices-tips-and-tricks-to-level-up-your-code","date":"2016-09-02T06:10:01.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/","permalink":"https://ioliu.cn/2016/javascript-best-practices-tips-and-tricks-to-level-up-your-code/","excerpt":"","text":"每天学习新事物是成为一个伟大的人的一部分。而对开发者而言,持续不断学习新的东西是我们工作中的一部分,无论这些东西是否是你主动想学的。 在本教程中,我会指出一些重要的 JavaScript 最佳实践,因此你不必觉得学习它是条艰难的路。准备提升你的代码吧! 避免全局污染(Avoid polluting the global scope)声明变量(Declaring variables)是很有趣的。有时候,你可能声明了全局变量,即使你不想声明它。在如今的浏览器中,全局变量存储在window对象中。因此,有很多有趣的东西发生在那里,你可能会重写默认值。让我们假设你有一个HTML文件,其中包含一个<script>标签(或者在加载的 JavaScript 文件中包含): 12var foo = 42;console.log(foo); 这很显然会在控制台输出42。但是,因为这段代码没有在函数中执行,上下文将是一个全局的。因此,变量是附加到window对象的。这意味着window.foo的值也是42。 这是危险的,因为你可以重写已经存在的全局变量: 12345function print(){ //do something...}print(); 因为我们重写了原生的打印弹窗(native print popup),所以当我们执行window.print() (或者只执行print())的时候不会打开打印弹窗(print popup)。 这个问题很好解决,我们需要一个立即调用(called immediately) 的包装函数(wrapping function) (译者注:作者这里可能是要表达一个闭包函数closure function或者是匿名函数anonymous function),像下面的代码: 12345678910// Declare an anonymous function// 声明一个匿名函数(function () { var foo = 42; console.log(window.foo); // → undefined console.log(foo); // → 42})();//^ and call it immediately 另外,你应该选择发送window和其他的全局变量(如:document)作为函数的参数(这可能会提高性能): 12345(function (global, doc) { global.setTimeout(function () { doc.body.innerHTML = "Hello!"; }, 1000);})(window, document); 因此,使用包装函数来防止创建不必要的全局变量。注意,这不是说我在接下来的代码片段使用包装函数,我们应该把关注点放在代码本身。 💡小提示: browserify是另外一种防止创建不必要的全局变量的方式。它和 Node.js 采用的是同样的方式,使用的require function。 学习更多关于浏览器开发者工具请点击 Web 开发指南 顺便说一句,Node.js 会在函数里自动打包你的文件,它们看起来像这样: 12(function (exports, require, module, __filename, __dirname) {// ... 因此,如果这让你认为require函数是全局的那就错了。它只不过是一个函数的参数罢了。 你知道吗?由于window对象本身就是一个包含全局变量的全局变量,因此它的引用是自身: 12window.window.window// => Window {...} 那是因为window对象是一个环路对象(circular object),下面演示怎么创建一个这样的对象: 12345678910// Create an Objectvar foo = {};// Point a key value to the object itself// 设置一个key,值为它本身foo.bar = foo;// The `foo` object just became a circular one:foo.bar.bar.bar// → foo 或者,去展现你对JavaScript 的爱,你可以做得更好:Yes,你可以无限的扩展这个对象(大概直到你的浏览器崩溃). 使用严格模式(use strict)严格的使用use strict!这只不过是(译者注:这里原作者可能是想表达不仅仅是)在你的代码脚本中添加字符串而已。举个栗子: 12345678// This is bad, since you do create a global without having anyone to tell you(function () { a = 42; console.log(a); // → 42})();console.log(a);// → 42 使用use strict,你可以得到更多的确切的错误: 12345(function () { "use strict"; a = 42; // Error: Uncaught ReferenceError: a is not defined})(); 你可能会奇怪,为什么不能将use strict 写在函数体外。当然,这是可以的,但它将会应用为全局的范围。这仍然是不错的,但如果你的代码中含有来自其他库的代码,这也会受其影响,或者你把所有的东西都绑定在一个文件里。 严格相等(Strict equal)这是短的。如果你使用==对比a和b(像在其他编程语言),在 JavaScript 中,你可能这种非常奇怪的运行方式:如果你有一个字符串和一个数字,他们是相等的(==): 12"42" == 42// → true 由于显而易见的原因(如 验证(validations)),最好使用严格相等(===): 12"42" === 42// → false 使用断言(&&/||)根据你的需要,你可以使用逻辑运算符是你的代码更简短。默认值: 123456789101112131415"" || "foo"// → "foo"undefined || 42// → 42// Note that if you want to handle 0 there, you need// to check if a number was provided:var a = 0;a || 42// → 42// This is a ternary operator—works like an inline if-else statementvar b = typeof a === "number" ? a : 42;// → 0 检查是否是一个真正的if表达式,你可以简单的这么做: 123456expr && doSomething();// Instead of:if (expr) { doSomething();} 你可能会不赞同我这里的写法,但是这是比较理想的。如果你不想用这种方式丑化你的代码,但那些 JavaScript 压缩工具实际上会这么做。 如果你问我,尽管这些代码比较短,但它仍然是人类可读的。 类型转换有几种方式来转换这些东西,这取决于你想怎么做。最常见的方式是: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849// From anything to a numbervar foo = "42";var myNumber = +foo; // shortcut for Number(foo)// → 42// Tip: you can convert it directly into a negative numbervar negativeFoo = -foo; // or -Number(foo)// → -42// From object to array// Tip: `arguments` is an object and in general you want to use it as arrayvar args = { 0: "foo", 1: "bar", length: 2 };Array.prototype.slice.call(args)// → [ 'foo', 'bar' ]// Anything to boolean/// Non non p is a boolean pvar t = 1;var f = 0;!!t// → true!!f// → false/// And non-p is a boolean non-p!t// → false!f// → true// Anything to stringvar foo = 42;"" + foo // shortcut for String(foo)// → "42"foo = { hello: "world" };JSON.stringify(foo);// → '{ "hello":"world" }'JSON.stringify(foo, null, 4); // beautify the things// →// '{// "hello": "world"// }'// Note you cannot JSON.stringify circular structuresJSON.stringify(window);// ⚠ TypeError: JSON.stringify cannot serialize cyclic structures. 代码样式/样式指南在新项目中,遵循整个文件相同的代码风格。对于现有的,采用已经存在的代码风格,除非你只是决定改变它(提示:同你的合作者商讨)。即使你创建并记录你的代码风格,请始终遵循它。 这里是不同的现有的代码样式: Google JavaScript Style Guide airbnb/javascript … there are others too my style guide 附加提示其他重要的 JavaScript 最佳实践,你应该记住的是使用工具帮助你格式化你的代码。这是其中的一些: js-beautify: Beautifies your code UglifyJS(2): Uglifies/minimifies your code jshint: Detects errors/potential problems in your JavaScript code jscs: A configurable style guide checker 最后一件事:Debug your Code Happy programming! 致谢:@屠夫 、@QistChan、@nApolin、@Ant","categories":[],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"译文","slug":"译文","permalink":"https://ioliu.cn/tags/%E8%AF%91%E6%96%87/"},{"name":"技巧","slug":"技巧","permalink":"https://ioliu.cn/tags/%E6%8A%80%E5%B7%A7/"}],"author":"@johnnyb"},{"title":"MarkDown 不完全指南","slug":"MarkDown-incomplete-Guide","date":"2016-05-18T06:21:08.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2016/MarkDown-incomplete-Guide/","permalink":"https://ioliu.cn/2016/MarkDown-incomplete-Guide/","excerpt":"","text":"MarkdownA markdown example shows how to write a markdown file. This document integrates core syntax and extensions (GMF). Block ElementsParagraphs and Line BreaksParagraphsHTML Tag: <p> One or more blank lines. (A blank line is a line containing nothing but spaces or tabs is considered blank.) Code: 1234This will be inline.This is second paragraph. Preview: This will beinline. This is second paragraph. Line BreaksHTML Tag: <br /> End a line with two or more spaces. Code: 12This will be not inline. Preview: This will be notinline. HeadersMarkdown supports two styles of headers, Setext and atx. SetextHTML Tags: <h1>, <h2> “Underlined” using equal signs (=) as <h1> and dashes (-) as <h2> in any number. Code:1234This is an H1=============This is an H2-------------Preview:***This is an H1This is an H2 atxHTML Tags: <h1>, <h2>, <h3>, <h4>, <h5>, <h6> Uses 1-6 hash characters (#) at the start of the line, corresponding to <h1> - <h6>. Code: 123# This is an H1## This is an H2###### This is an H6 Preview: This is an H1This is an H2This is an H6 Optionally, you may “close” atx-style headers. The closing hashes don’t need to match the number of hashes used to open the header. Code: 123# This is an H1 ### This is an H2 ##### This is an H3 ###### Preview: This is an H1This is an H2This is an H3 BlockquotesHTML Tag: <blockquote> Markdown uses email-style > characters for blockquoting. It looks best if you hard wrap the text and put a > before every line. Code: 123456> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.> > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse> id sem consectetuer libero luctus adipiscing. Preview: This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisseid sem consectetuer libero luctus adipiscing. Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph. Code: 123456> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisseid sem consectetuer libero luctus adipiscing. Preview: This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisseid sem consectetuer libero luctus adipiscing. Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by adding additional levels of >. Code: 12345> This is the first level of quoting.>> > This is nested blockquote.>> Back to the first level. Preview: This is the first level of quoting. This is nested blockquote. Back to the first level. Blockquotes can contain other Markdown elements, including headers, lists, and code blocks. Code: 12345678> ## This is a header.> > 1. This is the first list item.> 2. This is the second list item.> > Here's some example code:> > return shell_exec("echo $input | $markdown_script"); Preview: This is a header. This is the first list item. This is the second list item. Here’s some example code: return shell_exec("echo $input | $markdown_script"); ListsMarkdown supports ordered (numbered) and unordered (bulleted) lists. UnorderedHTML Tag: <ul> Unordered lists use asterisks (*), pluses (+), and hyphens (-). Code: 123* Red* Green* Blue Preview: Red Green Blue is equivalent to: Code: 123+ Red+ Green+ Blue and: Code: 123- Red- Green- Blue OrderedHTML Tag: <ol> Ordered lists use numbers followed by periods: Code: 1231. Bird2. McHale3. Parish Preview: Bird McHale Parish It’s possible to trigger an ordered list by accident, by writing something like this: Code: 11986. What a great season. Preview: What a great season. You can backslash-escape (\\) the period: Code: 11986\\. What a great season. Preview: 1986. What a great season. IndentedBlockquoteTo put a blockquote within a list item, the blockquote’s > delimiters need to be indented: Code: 1234* A list item with a blockquote: > This is a blockquote > inside a list item. Preview: A list item with a blockquote: This is a blockquoteinside a list item. Code BlockTo put a code block within a list item, the code block needs to be indented twice — 8 spaces or two tabs: Code: 123* A list item with a code block: <code goes here> Preview: A list item with a code block: <code goes here> Nested ListCode: 12345* A * A1 * A2* B* C Preview: A A1 A2 B C Code BlocksHTML Tag: <pre> Indent every line of the block by at least 4 spaces or 1 tab. Code: 123This is a normal paragraph: This is a code block. Preview: This is a normal paragraph: This is a code block. A code block continues until it reaches a line that is not indented (or the end of the article). Within a code block, ampersands (&) and angle brackets (< and >) are automatically converted into HTML entities. Code: 123<div class="thanclass"> &copy; 2004 Foo Corporation</div> Preview: © 2004 Foo Corporation *** Following sections Fenced Code Blocks and Syntax Highlighting are extensions, you can use the other way to write the code block. #### Fenced Code Blocks Just wrap your code in \\`\\`\\` \\`\\`\\` (as shown below) and you won't need to indent it by four spaces. Code: Here’s an example:```function test() { console.log(“notice the blank line before this function?”);}``` Preview: Here’s an example: 123function test() { console.log("notice the blank line before this function?");} Syntax HighlightingIn your fenced block, add an optional language identifier and we’ll run it through syntax highlighting (Support Languages). Code: ```rubyrequire ‘redcarpet’markdown = Redcarpet.new(“Hello World!”)puts markdown.to_html``` Preview: 123require 'redcarpet'markdown = Redcarpet.new("Hello World!")puts markdown.to_html Horizontal RulesHTML Tag: <hr />Places three or more hyphens (-), asterisks (*), or underscores (_) on a line by themselves. You may use spaces between the hyphens or asterisks. Code: 123456* * *********- - ----------------------------------------___ TableHTML Tag: <table> It’s an extension. Separates column by pipe (|) and header by dashes (-), and uses colon (:) for alignment. The outer pipes (|) and alignment are optional. There are 3 delimiters each cell at least for separating header. Code: 12345678910111213| Left | Center | Right ||:-----|:------:|------:||aaa |bbb |ccc ||ddd |eee |fff | A | B ---|---123|456A |B --|--12|45 Preview: Left Center Right aaa bbb ccc ddd eee fff A B 123 456 A B 12 45 Span ElementsLinksHTML Tag: <a> Markdown supports two style of links: inline and reference. InlineInline link format like this: [Link Text](URL "Title") Title is optional. Code: 123This is [an example](http://example.com/ "Title") inline link.[This link](http://example.net/) has no title attribute. Preview: This is an example inline link. This link has no title attribute. If you’re referring to a local resource on the same server, you can use relative paths: Code: 1See my [Tags](/tags/) page for details. Preview: See my Tags page for details. ReferenceYou could predefine link references. Format like this: [id]: URL "Title" Title is also optional. And the you refer the link, format like this: [Link Text][id] Code: 12[id]: http://example.com/ "Optional Title Here"This is [an example][id] reference-style link. Preview: This is 点我跳转到百度 reference-style link. That is: Square brackets containing the link identifier (not case sensitive, optionally indented from the left margin using up to three spaces); followed by a colon; followed by one or more spaces (or tabs); followed by the URL for the link; The link URL may, optionally, be surrounded by angle brackets. optionally followed by a title attribute for the link, enclosed in double or single quotes, or enclosed in parentheses. The following three link definitions are equivalent: Code: 1234[foo]: http://example.com/ "Optional Title Here"[foo]: http://example.com/ 'Optional Title Here'[foo]: http://example.com/ (Optional Title Here)[foo]: <http://example.com/> "Optional Title Here" Uses an empty set of square brackets, the link text itself is used as the name. Code: 12[Google]: http://google.com/[Google][] Preview: Google EmphasisHTML Tags: <em>, <strong> Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. One delimiter will be <em>; *double delimiters will be <strong>. Code: 1234567*single asterisks*_single underscores_**double asterisks**__double underscores__ Preview: single asterisks single underscores double asterisks double underscores But if you surround an * or _ with spaces, it’ll be treated as a literal asterisk or underscore. You can backslash escape it: Code: 1*this text is surrounded by literal asterisks* Preview: *this text is surrounded by literal asterisks* CodeHTML Tag: <code> Wraps it with backtick quotes (`). Code: 1Use the `printf()` function. Preview: Use the printf() function. To include a literal backtick character within a code span, you can use multiple backticks as the opening and closing delimiters: Code: 1``There is a literal backtick (`) here.`` Preview: There is a literal backtick (`) here. The backtick delimiters surrounding a code span may include spaces — one after the opening, one before the closing. This allows you to place literal backtick characters at the beginning or end of a code span: Code: 123A single backtick in a code span: `` ` ``A backtick-delimited string in a code span: `` `foo` `` Preview: A single backtick in a code span: ` A backtick-delimited string in a code span: `foo` ImagesHTML Tag: <img /> Markdown uses an image syntax that is intended to resemble the syntax for links, allowing for two styles: inline and reference. InlineInline image syntax looks like this: ![Alt text](URL "Title") Title is optional. Code: 123![Alt text](/path/to/img.jpg)![Alt text](/path/to/img.jpg "Optional title") Preview: That is: An exclamation mark: !; followed by a set of square brackets, containing the alt attribute text for the image; followed by a set of parentheses, containing the URL or path to the image, and an optional title attribute enclosed in double or single quotes. ReferenceReference-style image syntax looks like this: ![Alt text][id] Code: 12[img id]: url/to/image "Optional title attribute"![Alt text][img id] Preview: StrikethroughHTML Tag: <del> It’s an extension. GFM adds syntax to strikethrough text. Code: 1~~Mistaken text.~~ Preview: Mistaken text. MiscellaneousAutomatic LinksMarkdown supports a shortcut style for creating “automatic” links for URLs and email addresses: simply surround the URL or email address with angle brackets. Code: 123<http://example.com/><address@example.com> Preview: http://example.com/ address@example.com GFM will autolink standard URLs. Code: 1https://github.com/xcss Preview: https://github.com/xcss Backslash EscapesMarkdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax. Code: 1\\*literal asterisks\\* Preview: *literal asterisks* Markdown provides backslash escapes for the following characters: Code: 123456789101112\\ backslash` backtick* asterisk_ underscore{} curly braces[] square brackets() parentheses# hash mark+ plus sign- minus sign (hyphen). dot! exclamation mark Inline HTMLFor any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags. Code: 123456789This is a regular paragraph.<table> <tr> <td>Foo</td> </tr></table>This is another regular paragraph. Preview: This is a regular paragraph. Foo This is another regular paragraph. *** Note that Markdown formatting syntax is **not processed within block-level HTML tags**. Unlike block-level HTML tags, Markdown syntax is processed within span-level tags. Code: 12345<span>**Work**</span><div> **No Work**</div> Preview: Work **No Work** *** 参考文档: http://www.markdown.cn/","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"MarkDown","slug":"MarkDown","permalink":"https://ioliu.cn/tags/MarkDown/"},{"name":"Guide","slug":"Guide","permalink":"https://ioliu.cn/tags/Guide/"}]},{"title":"响应式设计 (Responsive Design) 中常用的媒体查询","slug":"commonly-used-media-queries","date":"2016-05-11T11:21:08.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2016/commonly-used-media-queries/","permalink":"https://ioliu.cn/2016/commonly-used-media-queries/","excerpt":"","text":"现在Web朝着响应式的趋势发展,媒体查询在创建响应式网站中起到了主要作用。 没有媒体查询几乎不能实现响应式设计,利用媒体查询,我们可以针对特定的设备,如显示器、智能手机和平板,写CSS。 媒体查询是响应式设计的核心 在这篇文章中我将分享一些到目前为止我收集到的常用媒体查询。在一些示例中,我可能是错误的,但是不用担心,因为我针对这个开通了评论功能。我把它们分为显示器媒体查询、智能手机媒体查询和平板媒体查询 显示器媒体查询显示器媒体查询是以屏幕大小为基础划分的 640px123@media screen and (max-width: 640px){ /*some rules*/} 800px123@media screen and (max-width: 800px){ /*some rules*/} 1024px123@media screen and (max-width: 1024px){ /*some rules*/} 智能手机媒体查询适用于大部分主流智能手机 iPhone(2G-4S)12345678/*Landscape Mode*/@media screen and (max-device-width: 480px) and (orientation:landscape){ /*some rules*/}/* Portrait Mode */@media screen and (max-device-width: 320px) and (orientation:portrait){ /*some rules*/} iPhone 41234@media only screen and (-webkit-min-device-pixel-ratio : 1.5),only screen and (min-device-pixel-ratio : 1.5){ /*some rules*/} iPhone 512345@media only screenand (min-device-width : 320px)and (max-device-width : 568px){ /*some rules*/} iPhone 612345678910111213141516171819202122232425262728293031@media only screen and (min-device-width: 375px) and (max-device-width: 667px)and (orientation : portrait) { /*iPhone 6 Portrait*/}@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (orientation : landscape) { /*iPhone 6 landscape*/}@media only screen and (min-device-width: 414px) and (max-device-width: 736px)and (orientation : portrait) { /*iPhone 6+ Portrait*/}@media only screen and (min-device-width: 414px) and (max-device-width: 736px)and (orientation : landscape) { /*iPhone 6+ landscape*/}@media only screen and (max-device-width: 640px), only screen and (max-device-width: 667px),only screen and (max-width: 480px){ /*iPhone 6 and iPhone 6+ portrait and landscape*/}@media only screen and (max-device-width: 640px),only screen and (max-device-width: 667px),only screen and (max-width: 480px) and (orientation : portrait){ /*iPhone 6 and iPhone 6+ portrait*/}@media only screen and (max-device-width: 640px),only screen and (max-device-width: 667px),only screen and (max-width: 480px) and (orientation : landscape){ /*iPhone 6 and iPhone 6+ landscape*/} HTC Evo,BlackBerry Torch,HTC Thunderbolt,HD2123@media screen and (max-device-width: 480px){ /*some rules*/} 平板媒体查询iPad / iPad 2 / iPad 312345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 768px) and (orientation: portrait){ /*some rules*/} iPad Mini123456@media only screenand (min-device-width : 768px)and (max-device-width : 1024px)and (-webkit-min-device-pixel-ratio: 1){ /*some rules*/} Samsung Galaxy Tab 10.1 / Motorola Xoom / Lenovo Thinkpad Tablet / Sony Tablet S12345678/* Landscape Mode */@media (max-device-width: 1280px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 800px) and (orientation: portrait){ /*some rules*/} HTC Flyer / BlackBerry PlayBook12345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 600px) and (orientation: portrait){ /*some rules*/} HP TouchPad12345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 768px) and (orientation: portrait){ /*some rules*/} T-Mobile G-Slate12345678/* Landscape Mode */@media (max-device-width: 1280px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 768px) and (orientation: portrait){ /*some rules*/} ViewSonic ViewPad 1012345678/* Landscape Mode */@media (max-device-width: 1024px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 600px) and (orientation: portrait){ /*some rules*/} Dell Streak 712345678/* Landscape Mode */@media (max-device-width: 800px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 400px) and (orientation: portrait){ /*some rules*/} ASUS Eee Pad Transformer12345678/* Landscape Mode */@media (max-device-width: 1080px) and (orientation: landscape){ /*some rules*/}/* Portrait Mode */@media (max-device-width: 800px) and (orientation: portrait){ /*some rules*/} 其他参考文档 七个高度有效的媒体查询技巧 iPads和iPhones的Media Queries media-queries-for-standard-devices 本文转载自淡忘~浅思,略有删改,侵权即删.原文链接: Some Media Queries for Responsive Design译文链接: 【译】Responsive Design常用的媒体查询","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Media Query","slug":"Media-Query","permalink":"https://ioliu.cn/tags/Media-Query/"},{"name":"响应式","slug":"响应式","permalink":"https://ioliu.cn/tags/%E5%93%8D%E5%BA%94%E5%BC%8F/"},{"name":"媒体查询","slug":"媒体查询","permalink":"https://ioliu.cn/tags/%E5%AA%92%E4%BD%93%E6%9F%A5%E8%AF%A2/"}]},{"title":"生成 SSH Key 免密码提交 GitHub","slug":"generating-ssh-key","date":"2015-12-13T02:19:18.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2015/generating-ssh-key/","permalink":"https://ioliu.cn/2015/generating-ssh-key/","excerpt":"","text":"之前上传文件到 GitHub 的时候,一直都是用的账号密码登录,每次提交都弹个窗体出来,感觉烦死了。。。今天有空,就来捣鼓下 SSH Key。 Step1. 检查是否已经存在 SSH Key运行 Git Bush 客户端,执行以下代码: 12$ ls -al ~/.ssh # 如果存在,将会列出.ssh 目录下的所有文件 12# 如果不存在则会给出如下提示ls: cannot open directory /Users/you/.ssh: Permission denied 检查列出来的目录,看看是否已经有了一个 SSH Key。默认情况下,key 的文件名是下列之一: > id_dsa.pub > id_ecdsa.pub > id_ed25519.pub > id_rsa.pub 如果已经存在(如 id_rsa 和 id_rsa.pub)而且你想使用已经存在的密钥对直接连接 GitHub ,那么可以跳过 Step2,直接进入 Step3 Step2. 生成 SSH Key复制下面的代码(记得请将email修改成自己的email地址): 12$ ssh-keygen -t rsa -b 4096 -C "your_name@example.com" Generating public/private rsa key pair. 这里 GitHub 的建议是保持默认,所以只需要按 Enter 继续: 1Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press Enter] 如果存在,将会提示是否覆盖: 12/Users/you/.ssh/id_rsa already exists.Overwrite (y/n)? 继续后会提示输入密码: 12Enter passphrase (empty for no passphrase): [Type a passphrase]Enter same passphrase again: [Type passphrase again] 然后你就会得到你的 SSH Key 的指纹,看起来像下面的代码: 1234Your identification has been saved in /Users/you/.ssh/id_rsa.Your public key has been saved in /Users/you/.ssh/id_rsa.pub.The key fingerprint is:01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com Step3. 添加 SSH Key 到 GitHub先拷贝 id_rsa.pub 文件的内容,可以用编辑器打开然后复制,也可以用 git 命令复制: 1$ clip < ~/.ssh/id_rsa.pub 进入 GitHub 账户设置,点击左边 SSH Key ,点击 Add SSH key ,粘贴刚刚复制的内容,然后保存。输入 GitHub 账户的密码就能看到刚刚添加的 SSH Key 了。 Step4. 测试是否添加成功在 Git Bush 中输入下面的代码,然后回车 12$ ssh -T git@GitHub.com# Attempts to ssh to GitHub 会得到如下的指纹提示:键入yes 123The authenticity of host 'GitHub.com (207.97.227.239)' can't be established.RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.Are you sure you want to continue connecting (yes/no)? 如果出现下面的提示,恭喜你,验证成功。 1Hi username! You've successfully authenticated, but GitHub does not provide shell access. 如果你看到的是 access denied(拒绝访问) ,可以点击这里 ,查看解决办法。 然后将https替换成ssh重新下载下代码,就OK了~~~ Good Luck ** 参考文档 ** Generating SSH keys","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"GitHub","slug":"GitHub","permalink":"https://ioliu.cn/tags/GitHub/"},{"name":"SSH Key","slug":"SSH-Key","permalink":"https://ioliu.cn/tags/SSH-Key/"},{"name":"免密码","slug":"免密码","permalink":"https://ioliu.cn/tags/%E5%85%8D%E5%AF%86%E7%A0%81/"}]},{"title":"前端 JavaScript 规范","slug":"the-front-end-javascript-specification","date":"2015-05-12T04:53:34.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2015/the-front-end-javascript-specification/","permalink":"https://ioliu.cn/2015/the-front-end-javascript-specification/","excerpt":"","text":"类型原始值:相当于传值(JavaScript对象都提供了字面量),使用字面量创建对象。 string number boolean null undefined 1234var foo = 1, bar = foo;bar = 9;console.log(foo, bar); // => 1, 9 复杂类型:相当于传引用 object array function 1234var foo = [1, 2], bar = foo;bar[0] = 9;console.log(foo[0], bar[0]); // => 9, 9 对象 使用字面值创建对象 12345// badvar item = new Object();// goodvar item = {}; 不要使用保留字 reserved words 作为键 12345678910111213// badvar superman = { class: 'superhero', default: { clark: 'kent' }, private: true};// goodvar superman = { klass: 'superhero', defaults: { clark: 'kent' }, hidden: true}; 数组 使用字面值创建数组 12345// badvar items = new Array();// goodvar items = []; 如果你不知道数组的长度,使用push 1234567var someStack = [];// badsomeStack[someStack.length] = 'abracadabra';// goodsomeStack.push('abracadabra'); 当你需要拷贝数组时使用slice . jsPerf 1234567891011var len = items.length, itemsCopy = [], i;// badfor (i = 0; i < len; i++) { itemsCopy[i] = items[i];}// gooditemsCopy = items.slice(); 使用slice将类数组的对象转成数组.1234function trigger() { var args = [].slice.apply(arguments); ...} 字符串 对字符串使用单引号 ''(因为大多时候我们的字符串。特别html会出现")1234567891011// badvar name = "Bob Parr";// goodvar name = 'Bob Parr';// badvar fullName = "Bob " + this.lastName;// goodvar fullName = 'Bob ' + this.lastName; 超过80(也有规定140的,项目具体可制定)个字符的字符串应该使用字符串连接换行!!!: 如果过度使用,长字符串连接可能会对性能有影响. jsPerf & Discussion 123456789101112131415161718// badvar errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';// badvar errorMessage = 'This is a super long error that \\was thrown because of Batman. \\When you stop to think about \\how Batman had anything to do \\with this, you would get nowhere \\fast.';// goodvar errorMessage = 'This is a super long error that ' + 'was thrown because of Batman.' + 'When you stop to think about ' + 'how Batman had anything to do ' + 'with this, you would get nowhere ' + 'fast.'; 编程时使用join而不是字符串连接来构建字符串,特别是IE: jsPerf.12345678910111213141516171819202122232425262728293031323334var items, messages, length, i;messages = [{ state: 'success', message: 'This one worked.'},{ state: 'success', message: 'This one worked as well.'},{ state: 'error', message: 'This one did not work.'}];length = messages.length;// badfunction inbox(messages) { items = '<ul>'; for (i = 0; i < length; i++) { items += '<li>' + messages[i].message + '</li>'; } return items + '</ul>';}// goodfunction inbox(messages) { items = []; for (i = 0; i < length; i++) { items[i] = messages[i].message; } return '<ul><li>' + items.join('</li><li>') + '</li></ul>';} 函数 函数表达式:1234567891011121314// 匿名函数表达式var anonymous = function() { return true;};// 有名函数表达式var named = function named() { return true;};// 立即调用函数表达式(function() { console.log('Welcome to the Internet. Please follow me.');})(); 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。 注: ECMA-262定义把块定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.12345678910111213// badif (currentUser) { function test() { console.log('Nope.'); }}// goodif (currentUser) { var test = function test() { console.log('Yup.'); };} 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.123456789// badfunction nope(name, options, arguments) { // ...stuff...}// goodfunction yup(name, options, args) { // ...stuff...} 属性 当使用变量和特殊非法变量名时,访问属性时可以使用中括号(. 优先).12345678910var luke = { jedi: true, age: 28};function getProp(prop) { return luke[prop];}var isJedi = getProp('jedi'); 变量 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。12345// badsuperPower = new SuperPower();// goodvar superPower = new SuperPower(); 使用一个 var 以及新行声明多个变量,缩进4个空格。123456789// badvar items = getItems();var goSportsTeam = true;var dragonball = 'z';// goodvar items = getItems(), goSportsTeam = true, dragonball = 'z'; 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。1234567891011121314151617// badvar i, len, dragonball, items = getItems(), goSportsTeam = true;// badvar i, items = getItems(), dragonball, goSportsTeam = true, len;// goodvar items = getItems(), goSportsTeam = true, dragonball, length, i; 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253// badfunction() { test(); console.log('doing stuff..'); //..other stuff.. var name = getName(); if (name === 'test') { return false; } return name;}// goodfunction() { var name = getName(); test(); console.log('doing stuff..'); //..other stuff.. if (name === 'test') { return false; } return name;}// badfunction() { var name = getName(); if (!arguments.length) { return false; } return true;}// goodfunction() { if (!arguments.length) { return false; } var name = getName(); return true;} 条件表达式和等号 合理使用 === 和 !== 以及 == 和 !=. 合理使用表达式逻辑操作运算. 条件表达式的强制类型转换遵循以下规则: 对象 被计算为 true Undefined 被计算为 false Null 被计算为 false 布尔值 被计算为 布尔的值 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true 1234if ([0]) { // true // An array is an object, objects evaluate to true} 使用快捷方式.12345678910111213141516171819// badif (name !== '') { // ...stuff...}// goodif (name) { // ...stuff...}// badif (collection.length > 0) { // ...stuff...}// goodif (collection.length) { // ...stuff...} 阅读 Truth Equality and JavaScript 了解更多 块 给所有多行的块使用大括号12345678910111213141516171819// badif (test) return false;// goodif (test) return false;// goodif (test) { return false;}// badfunction() { return false; }// goodfunction() { return false;} 注释 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值123456789101112131415161718192021222324252627// bad// make() returns a new element// based on the passed in tag name//// @param <String> tag// @return <Element> elementfunction make(tag) { // ...stuff... return element;}// good/** * make() returns a new element * based on the passed in tag name * * @param <String> tag * @return <Element> element */function make(tag) { // ...stuff... return element;} 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.12345678910111213141516171819202122232425// badvar active = true; // is current tab// good// is current tabvar active = true;// badfunction getType() { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; return type;}// goodfunction getType() { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; return type;} 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXME 或 TODO 帮助其他人迅速理解12345678910111213141516function Calculator() { // FIXME: shouldn't use a global here total = 0; return this;}function Calculator() { // TODO: total should be configurable by an options param this.total = 0; return this;} 满足规范的文档,在需要文档的时候,可以尝试jsdoc. 空白 缩进、格式化能帮助团队更快得定位修复代码BUG. 将tab设为4个空格1234567891011121314// badfunction() {∙∙var name;}// badfunction() {∙var name;}// goodfunction() {∙∙∙∙var name;} 大括号前放一个空格123456789101112131415161718192021// badfunction test(){ console.log('test');}// goodfunction test() { console.log('test');}// baddog.set('attr',{ age: '1 year', breed: 'Bernese Mountain Dog'});// gooddog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog'}); 在做长方法链时使用缩进.1234567891011121314151617181920212223242526// bad$('#items').find('.selected').highlight().end().find('.open').updateCount();// good$('#items') .find('.selected') .highlight() .end() .find('.open') .updateCount();// badvar leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) .attr('width', (radius + margin) * 2).append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led);// goodvar leds = stage.selectAll('.led') .data(data) .enter().append('svg:svg') .class('led', true) .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led); 逗号 不要将逗号放前面12345678910111213141516171819202122232425// badvar once , upon , aTime;// goodvar once, upon, aTime;// badvar hero = { firstName: 'Bob' , lastName: 'Parr' , heroName: 'Mr. Incredible' , superPower: 'strength'};// goodvar hero = { firstName: 'Bob', lastName: 'Parr', heroName: 'Mr. Incredible', superPower: 'strength'}; 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。123456789101112131415161718192021// badvar hero = { firstName: 'Kevin', lastName: 'Flynn',};var heroes = [ 'Batman', 'Superman',];// goodvar hero = { firstName: 'Kevin', lastName: 'Flynn'};var heroes = [ 'Batman', 'Superman']; 分号 语句结束一定要加分号1234567891011121314151617// bad(function() { var name = 'Skywalker' return name})()// good(function() { var name = 'Skywalker'; return name;})();// good;(function() { var name = 'Skywalker'; return name;})(); 类型转换 在语句的开始执行类型转换. 字符串:12345678910111213// => this.reviewScore = 9;// badvar totalScore = this.reviewScore + '';// goodvar totalScore = '' + this.reviewScore;// badvar totalScore = '' + this.reviewScore + ' total score';// goodvar totalScore = this.reviewScore + ' total score'; 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)123456789101112131415161718192021222324252627var inputValue = '4';// badvar val = new Number(inputValue);// badvar val = +inputValue;// badvar val = inputValue >> 0;// badvar val = parseInt(inputValue);// goodvar val = Number(inputValue);// goodvar val = parseInt(inputValue, 10);// good/** * parseInt was the reason my code was slow. * Bitshifting the String to coerce it to a * Number made it a lot faster. */var val = inputValue >> 0; 布尔值:12345678910var age = 0;// badvar hasAge = new Boolean(age);// goodvar hasAge = Boolean(age);// goodvar hasAge = !!age; 命名约定 避免单个字符名,让你的变量名有描述意义。123456789// badfunction q() { // ...stuff...}// goodfunction query() { // ..stuff..} 当命名对象、函数和实例时使用驼峰命名规则123456789101112131415// badvar OBJEcttsssss = {};var this_is_my_object = {};var this-is-my-object = {};function c() {};var u = new user({ name: 'Bob Parr'});// goodvar thisIsMyObject = {};function thisIsMyFunction() {};var user = new User({ name: 'Bob Parr'}); 当命名构造函数或类时使用驼峰式大写1234567891011121314151617// badfunction user(options) { this.name = options.name;}var bad = new user({ name: 'nope'});// goodfunction User(options) { this.name = options.name;}var good = new User({ name: 'yup'}); 命名私有属性时前面加个下划线 _123456// badthis.__firstName__ = 'Panda';this.firstName_ = 'Panda';// goodthis._firstName = 'Panda'; 当保存对 this 的引用时使用 self(python 风格),避免this issue . Angular建议使用vm(MVVM模式中view-model)1234567// goodfunction() { var self = this; return function() { console.log(self); };} 存取器 属性的存取器函数不是必需的 如果你确实有存取器函数的话使用getVal() 和 setVal(‘hello’),java getter、setter风格或者jQuery风格 如果属性是布尔值,使用isVal() 或 hasVal()123456789// badif (!dragon.age()) { return false;}// goodif (!dragon.hasAge()) { return false;} 可以创建get()和set()函数,但是要保持一致12345678910111213function Jedi(options) { options || (options = {}); var lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber);}Jedi.prototype.set = function(key, val) { this[key] = val;};Jedi.prototype.get = function(key) { return this[key];}; 构造器 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。1234567891011121314151617181920212223function Jedi() { console.log('new jedi');}// badJedi.prototype = { fight: function fight() { console.log('fighting'); }, block: function block() { console.log('blocking'); }};// goodJedi.prototype.fight = function fight() { console.log('fighting');};Jedi.prototype.block = function block() { console.log('blocking');}; 方法可以返回 this 帮助方法可链。1234567891011121314151617181920212223242526272829// badJedi.prototype.jump = function() { this.jumping = true; return true;};Jedi.prototype.setHeight = function(height) { this.height = height;};var luke = new Jedi();luke.jump(); // => trueluke.setHeight(20) // => undefined// goodJedi.prototype.jump = function() { this.jumping = true; return this;};Jedi.prototype.setHeight = function(height) { this.height = height; return this;};var luke = new Jedi();luke.jump() .setHeight(20); 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。123456789101112function Jedi(options) { options || (options = {}); this.name = options.name || 'no name';}Jedi.prototype.getName = function getName() { return this.name;};Jedi.prototype.toString = function toString() { return 'Jedi - ' + this.getName();}; 事件 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器123456789101112131415161718// bad$(this).trigger('listingUpdated', listing.id);...$(this).on('listingUpdated', function(e, listingId) { // do something with listingId});// good$(this).trigger('listingUpdated', { listingId : listing.id });...$(this).on('listingUpdated', function(e, data) { // do something with data.listingId}); 模块 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它 总是在模块顶部声明 'use strict';,引入JSHint规范123456789101112131415161718// fancyInput/fancyInput.js(function(global) { 'use strict'; var previousFancyInput = global.FancyInput; function FancyInput(options) { this.options = options || {}; } FancyInput.noConflict = function noConflict() { global.FancyInput = previousFancyInput; return FancyInput; }; global.FancyInput = FancyInput;})(this); jQuery 对于jQuery对象以$开头,以和原生DOM节点区分。12345// badvar menu = $(".menu");// goodvar $menu = $(".menu"); 缓存jQuery查询12345678910111213141516171819202122// badfunction setSidebar() { $('.sidebar').hide(); // ...stuff... $('.sidebar').css({ 'background-color': 'pink' });}// goodfunction setSidebar() { var $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... $sidebar.css({ 'background-color': 'pink' });} 对DOM查询使用级联的 $('.sidebar ul') 或 $('.sidebar ul'),jsPerf 对有作用域的jQuery对象查询使用 find1234567891011121314151617// bad$('.sidebar', 'ul').hide();// bad$('.sidebar').find('ul').hide();// good$('.sidebar ul').hide();// good$('.sidebar > ul').hide();// good (slower)$sidebar.find('ul');// good (faster)$($sidebar[0]).find('ul'); 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。123$(function(){ //do your page init. }); 事件利用jQuery.on从页面分离到JavaScript文件。1234567// bad<a id="myLink" href="#" onclick="myEventHandler();"></a>// good<a id="myLink" href="#"></a>$("#myLink").on("click", myEventHandler); 对于Ajax使用promise方式。1234567891011121314151617// bad$.ajax({ ... success : function(){ }, error : function(){ } })// good$.ajax({. ..}).then( function( ){ // success}, function( ){ // error}) 利用promise的deferred对象解决延迟注册问题。123456789var dtd = $.Deferred(); // 新建一个deferred对象var wait = function(dtd){ var tasks = function(){ alert("执行完毕!"); dtd.resolve(); // 改变deferred对象的执行状态 }; setTimeout(tasks,5000); return dtd;}; HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。 ECMAScript 5兼容性尽量采用ES5方法,特别数组map、filter、forEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscore、lodash 常用辅助库. 参考Kangax的 ES5 compatibility table HTML、CSS、JavaScript分离 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中分离在不同类型文件,文件link。 HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。 CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + flux架构、Knockout等。 对于兼容性可用Modernizr规范库辅助。 使用jsHint 前端项目中推荐引入 jshint插件来规范项目编码规范。以及一套完善的IDE配置。 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。 前端工具 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。 本文转载自破狼,原文略有修改,侵权即删.原文链接:前端javascript规范原文作者:破狼","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"规范","slug":"规范","permalink":"https://ioliu.cn/tags/%E8%A7%84%E8%8C%83/"}]},{"title":"你可能不知道的一些JavaScript 奇技淫巧","slug":"about-javascript-spcial-technique","date":"2015-05-07T02:21:08.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2015/about-javascript-spcial-technique/","permalink":"https://ioliu.cn/2015/about-javascript-spcial-technique/","excerpt":"","text":"这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们。 ## 遍历一个obj的属性到数组 1234567function getAttr(obj){ var a=[]; for(a[a.length] in obj); return a;}console.log(getAttr({'name':'zhangsan','age':'20'}));//输出:['name','age'] 乍一看可能比较蒙,不过仔细分析还是不难理解的。常见用法是`for(var key in obj)`,这里`key`初始也是`undefined`的,`a[a.length]`整体也是`undefined`,所以二者其实是等价的。 在`for`循环中,`obj`的属性会依次赋值给`key`,同样,也依次赋值给`a[a.length]`,这里`length`一直在变,就巧妙地挨个赋值给数组的每一个元素了。 重复字符串(如abc=>abcabc)123function repeat(target,n){ return (new Array(n+1).join(target));} 改进版本: 1234function repeat(target,n){ return Array.prototype.join.call({length:n+1},target); //之所以要创建带length属性的对象,是因为调用数组原型方法时,必须是一个类数组对象,而类数组对象的条件就是length为非负整数} 不新建数组,而是用拥有length属性的对象替代,然后调用数组的join方法,性能提升很大.再改进: 1234567var repeat=(function(){ var join=Array.prototype.join,obj={}; return function(target,n){ obj.length=n+1; return join.call(obj,target); }})(); 利用闭包将对象和join方法缓存起来,不用每次都新建对象和寻找方法 for循环for循环中,当第二项为false时会终止循环,这里并不一定存在比较,可以直接赋值,如果赋值为undefined之类的值时,转成bool值也为假,因此也会终止,比如遍历数组可以写成: 1for(var i=arr.length,element;element=arr[—-i];){…} 这里,第二项一定是arr[--i]而非arr[i--],如果是后者的话,上来就是undefined,就不会执行循环体,或者for(var i=0,element;element=arr[i++];){…} NaNNaN是JS中唯一不等于自己的值,因此可以用来判断一个变量是否真的为NaN:a!==a /、+等算术运算符</+等运算符会强制符号两边的表达式执行valueOf然后比较,所以如果两边是函数或者对象,而又重写了该对象的valueOf方法,就会自动执行两边的方法。如: 12var a={valueOf:function(){console.log("aaa");}},b={valueOf:function(){console.log("bbb");}}; a < b;//会输出:aaa;bbb;false 闭包理解闭包需学会三个基本事实: JS允许你引用在当前函数意外定义的变量 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这是因为JS的函数值包含里比调用它们时执行所需要的代码更多的信息 闭包可以更新外部变量的值。这是因为闭包存储的是外部变量的引用而非值副本。如:1234567891011function box(){ var val=undefined; return { set:function(x){val=x;}, get:function(){return val;} };}var b=box();b.get();//“undefined”b.set(5);b.get();//5 这一点很重要,比如在函数的for循环体内返回闭包或者有闭包取for循环的计数器值,那么这个闭包取到的永远是for循环结束时i的最终值,因为闭包存储的是它的引用而非当时的值副本。 块级作用域JS没有块级作用域,因此通常情况下函数内部的所有变量都是绑定到函数作用域的,也就是说相当于都在函数一开始就声明了的,一个例外就是try/catch中的变量是块级的,只属于try/catch块。 嵌套函数众所周知,在函数内部声明函数是可以的,但是在在函数内的局部块里声明,可能会出现问题: 123456789101112function f(){return “global”;}function test(x){ function f(){return “local”} var result=[]; if(x){ result.push(f()); } result.push(f()); return result;}test(true);//[“local”,”local”]test(false);//[“local”] 将函数声明到if块中: 123456789101112function f(){return “global”;}function test(x){ var result=[]; if(x){ function f(){return “local”} result.push(f()); } result.push(f()); return result;} test(true);//?test(false);//? 结果会如何呢?理论上讲,JS没有块级作用域,因此f()的作用域是整个test函数,因此合理猜测应该是与上一次输出相同,全部为”local”,可是并不是所有的JS执行环境都如此行事,有的会根据是否执行包含f的代码块来有条件地绑定函数f(绑定即意味着将该变量绑定到其最近的作用域,而赋值是发生在代码实际执行到赋值那一步的时候进行的)。因此最好的办法是如果要声明嵌套函数,都在其富函数的最外层声明,要么就不要声明函数,而是使用var声明和函数表达式来实现: 12345678910function f(){return “global”;}function test(x){ var result=[]; if(x){ var g=function(){return “local”} result.push(g()); } result.push(f()); return result;} hasOwnProperty用js创建字典的时候,如果是利用对象的方式(因为JS对象的核心是一个字符串属性名称和属性值的映射表),会遇到一个问题就是原型污染,因为获取字典属性值的时候用hasOwnProperty还好,如果用for in遍历的话,不仅会遍历对象本身,包括它的原型,因此如果在其他地方污染了Object的原型,那么for in就会产生非预期的结果,这时可能会用hasOwnProperty来先检测该对象本身是否含有属性来避免原型污染,然而更极端的情况是连hasOwnProperty这个原型方法都有可能被污染。避免原型污染的方法是在创建字典对象的时候用Object.create(null)来创建一个完全空对象,这个对象没有原型,这个方法是ES5的,在没有这个方法可用的时候,最好是创建字典类,然后在字典类里用数组来存储有序集合,自己维护这个集合。 类数组对象JS中的类数组对象可以享用数组的大部分原型方法如map等类数组对象是指满足两个条件的对象: 一是具备合理范围值内的length属性 二是length属性大于该对象的最大索引,索引是一个合理范围的证书,它的字符串表示的是对象的一个key;但是数组的一个原型方法contact是不能被类数组对象调用的,因此需要先用[].slice.call把类数组对象转换为真正的数组比如[].slice.call(arguments)。 结构类型并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类的实例,而是直接返回对象,对象具备预期的方法和属性,比如: 1234567SomeObj.someWidget=function(opts){ return { a:blabla, b:function(){...}, c:blabla }} JavaScript 自动插入分号JavaScript 具备自动插入分号的能力,但是自动插入分号并不是万能的,其有三条规则: 只在}标记之前、一个或多个换行之后以及程序输入的结尾被插入 分号只在随后的输入标记不能被解析时插入 !!这一点很重要,比如: a = b (fn()); 是不会在a=b之后自动插入分号的,因为a=b(f())是可以被解析的,因此像(,[,+,-,/开头的时候,需要特别注意上一行可能不会自动插入。 还有一些情况,尽管不会出现解析错误,JS仍然会强制插入分号,这就是所谓的JS语法限制产生式。它不允许在两个字符间出现换行,最危险的就是return语句,如 return{}; 会被强制插入而成为 return;{}; 类似的还有:throw语句、带有显示标签的break或着continue语句、后置自增或自减运算符 分号不会作为分隔符在for循环空语句的头部被自动插入 因此,最好的办法是在自己的js文件的最开始防御性地插入;,这样在合并js文件的时候就不会出问题了。 本文转载自博客园,原文略有删减,侵权即删.原文链接:你可能不知道的一些JavaScript 奇技淫巧原文作者:FirstLovt","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"JavaScript技巧","slug":"JavaScript技巧","permalink":"https://ioliu.cn/tags/JavaScript%E6%8A%80%E5%B7%A7/"},{"name":"结构类型","slug":"结构类型","permalink":"https://ioliu.cn/tags/%E7%BB%93%E6%9E%84%E7%B1%BB%E5%9E%8B/"},{"name":"数组遍历","slug":"数组遍历","permalink":"https://ioliu.cn/tags/%E6%95%B0%E7%BB%84%E9%81%8D%E5%8E%86/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"}]},{"title":"Hello World for Hexo","slug":"hexo-your-blog","date":"2015-05-06T02:21:08.000Z","updated":"2024-07-23T05:14:42.487Z","comments":true,"path":"2015/hexo-your-blog/","permalink":"https://ioliu.cn/2015/hexo-your-blog/","excerpt":"","text":"今天把博客移到了Hexo,感觉蛮不错的 ^_^ . 简介hexo 是一款基于Node.js的静态博客框架。目前在GitHub上已有4k+ star 和 700+ fork (官网)。是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。 特性 风一般的速度: Hexo基于Node.js,支持多进程,几百篇文章也可以秒生成。 流畅的撰写: 支持GitHub Flavored Markdown和所有Octopress的插件。 扩展性: Hexo支持EJS、Swig和Stylus。通过插件支持Haml、Jade和Less. 快速入门安装安装 Hexo 相当简单。然而在安装前,您必须检查电脑中是否已安装下列应用程序: Node.js Git 如果您的电脑中已经安装上述必备程序,那么恭喜您!接下来只需要使用 npm 即可完成 Hexo 的安装。 1npm install -g hexo-cli 仅需一步就把 Hexo 本体和所有相依套件安装完毕,很简单吧? 升级更新hexo到最新版 1npm update hexo -g 初始化123hexo init <folder>cd <floder>npm install 如果指定 <folder>,便会在目前的资料夹建立一个名为 <folder> 的新文件夹;否则会在目前文件夹初始化。 新建1hexo new [layout] <title> 新建一篇文章。如果没有设置 layout 的话,默认使用 _config.yml 中的 default_layout 参数代替。如果标题包含空格的话,请使用引号括起来。 生成静态文件12hexo g//或者 hexo generate 启动服务12hexo s//或者 hexo server 启动服务后,打开浏览器输入 http://localhost:4000 回车,即可看到效果. 部署12hexo d//可以通过hexo d -g 命令完成生成和部署 如果出现错误,可能是没有安装部署插件,请执行下面的命令安装插件: 1npm install hexo-deploy-git --save-dev Hexo官网:[http://Hexo.io]部署Hexo","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"Hexo","slug":"Hexo","permalink":"https://ioliu.cn/tags/Hexo/"},{"name":"免费博客","slug":"免费博客","permalink":"https://ioliu.cn/tags/%E5%85%8D%E8%B4%B9%E5%8D%9A%E5%AE%A2/"}]}],"categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://ioliu.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"name":"其他","slug":"其他","permalink":"https://ioliu.cn/categories/%E5%85%B6%E4%BB%96/"}],"tags":[{"name":"bbr","slug":"bbr","permalink":"https://ioliu.cn/tags/bbr/"},{"name":"linux","slug":"linux","permalink":"https://ioliu.cn/tags/linux/"},{"name":"Git","slug":"Git","permalink":"https://ioliu.cn/tags/Git/"},{"name":"Command","slug":"Command","permalink":"https://ioliu.cn/tags/Command/"},{"name":"Valine","slug":"Valine","permalink":"https://ioliu.cn/tags/Valine/"},{"name":"Comment System","slug":"Comment-System","permalink":"https://ioliu.cn/tags/Comment-System/"},{"name":"评论系统","slug":"评论系统","permalink":"https://ioliu.cn/tags/%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/"},{"name":"国家/地区","slug":"国家-地区","permalink":"https://ioliu.cn/tags/%E5%9B%BD%E5%AE%B6-%E5%9C%B0%E5%8C%BA/"},{"name":"语言缩写","slug":"语言缩写","permalink":"https://ioliu.cn/tags/%E8%AF%AD%E8%A8%80%E7%BC%A9%E5%86%99/"},{"name":"MySql","slug":"MySql","permalink":"https://ioliu.cn/tags/MySql/"},{"name":"数据库","slug":"数据库","permalink":"https://ioliu.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"},{"name":"ssl","slug":"ssl","permalink":"https://ioliu.cn/tags/ssl/"},{"name":"cerbot","slug":"cerbot","permalink":"https://ioliu.cn/tags/cerbot/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://ioliu.cn/tags/JavaScript/"},{"name":"前端","slug":"前端","permalink":"https://ioliu.cn/tags/%E5%89%8D%E7%AB%AF/"},{"name":"变量类型","slug":"变量类型","permalink":"https://ioliu.cn/tags/%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B/"},{"name":"CSS","slug":"CSS","permalink":"https://ioliu.cn/tags/CSS/"},{"name":"译文","slug":"译文","permalink":"https://ioliu.cn/tags/%E8%AF%91%E6%96%87/"},{"name":"技巧","slug":"技巧","permalink":"https://ioliu.cn/tags/%E6%8A%80%E5%B7%A7/"},{"name":"MarkDown","slug":"MarkDown","permalink":"https://ioliu.cn/tags/MarkDown/"},{"name":"Guide","slug":"Guide","permalink":"https://ioliu.cn/tags/Guide/"},{"name":"Media Query","slug":"Media-Query","permalink":"https://ioliu.cn/tags/Media-Query/"},{"name":"响应式","slug":"响应式","permalink":"https://ioliu.cn/tags/%E5%93%8D%E5%BA%94%E5%BC%8F/"},{"name":"媒体查询","slug":"媒体查询","permalink":"https://ioliu.cn/tags/%E5%AA%92%E4%BD%93%E6%9F%A5%E8%AF%A2/"},{"name":"GitHub","slug":"GitHub","permalink":"https://ioliu.cn/tags/GitHub/"},{"name":"SSH Key","slug":"SSH-Key","permalink":"https://ioliu.cn/tags/SSH-Key/"},{"name":"免密码","slug":"免密码","permalink":"https://ioliu.cn/tags/%E5%85%8D%E5%AF%86%E7%A0%81/"},{"name":"规范","slug":"规范","permalink":"https://ioliu.cn/tags/%E8%A7%84%E8%8C%83/"},{"name":"JavaScript技巧","slug":"JavaScript技巧","permalink":"https://ioliu.cn/tags/JavaScript%E6%8A%80%E5%B7%A7/"},{"name":"结构类型","slug":"结构类型","permalink":"https://ioliu.cn/tags/%E7%BB%93%E6%9E%84%E7%B1%BB%E5%9E%8B/"},{"name":"数组遍历","slug":"数组遍历","permalink":"https://ioliu.cn/tags/%E6%95%B0%E7%BB%84%E9%81%8D%E5%8E%86/"},{"name":"Hexo","slug":"Hexo","permalink":"https://ioliu.cn/tags/Hexo/"},{"name":"免费博客","slug":"免费博客","permalink":"https://ioliu.cn/tags/%E5%85%8D%E8%B4%B9%E5%8D%9A%E5%AE%A2/"}]} \ No newline at end of file diff --git a/css/style.css b/css/style.css index bb65a6f4..c55577c6 100644 --- a/css/style.css +++ b/css/style.css @@ -1,4 +1,4 @@ -/* build time:Thu Mar 28 2024 16:06:19 GMT+0800 (China Standard Time)*/ +/* build time:Tue Jul 23 2024 13:15:10 GMT+0800 (China Standard Time)*/ @charset "UTF-8";/*! * Bootstrap v3.3.7 (http://getbootstrap.com) * Copyright 2011-2016 Twitter, Inc. diff --git a/index.html b/index.html index 1d9ad140..3161a2f0 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -云淡风轻
\ No newline at end of file +云淡风轻
\ No newline at end of file diff --git a/links/index.html b/links/index.html index 4bed640e..446c55c8 100644 --- a/links/index.html +++ b/links/index.html @@ -1 +1 @@ -友情链接 | 云淡风轻
\ No newline at end of file +友情链接 | 云淡风轻
\ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html index 7e7bc955..4cfd395f 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -1 +1 @@ -云淡风轻
\ No newline at end of file +云淡风轻
\ No newline at end of file diff --git a/repository/index.html b/repository/index.html index 57725f4e..2335694b 100644 --- a/repository/index.html +++ b/repository/index.html @@ -1,4 +1,4 @@ -Repositories | 云淡风轻

Repositories

I have 0 projects on Github

正在加载...

Repositories | 云淡风轻

Repositories

I have 0 projects on Github

正在加载...

标签: CSS | 云淡风轻
\ No newline at end of file +标签: CSS | 云淡风轻
\ No newline at end of file diff --git a/tags/Command/index.html b/tags/Command/index.html index 6601434b..664fa188 100644 --- a/tags/Command/index.html +++ b/tags/Command/index.html @@ -1 +1 @@ -标签: Command | 云淡风轻
\ No newline at end of file +标签: Command | 云淡风轻
\ No newline at end of file diff --git a/tags/Comment-System/index.html b/tags/Comment-System/index.html index 6ae098ca..bcb8b3d5 100644 --- a/tags/Comment-System/index.html +++ b/tags/Comment-System/index.html @@ -1 +1 @@ -标签: Comment System | 云淡风轻
\ No newline at end of file +标签: Comment System | 云淡风轻
\ No newline at end of file diff --git a/tags/Git/index.html b/tags/Git/index.html index 30199b31..9059bbf4 100644 --- a/tags/Git/index.html +++ b/tags/Git/index.html @@ -1 +1 @@ -标签: Git | 云淡风轻
\ No newline at end of file +标签: Git | 云淡风轻
\ No newline at end of file diff --git a/tags/GitHub/index.html b/tags/GitHub/index.html index cf7b45fb..8803fe8b 100644 --- a/tags/GitHub/index.html +++ b/tags/GitHub/index.html @@ -1 +1 @@ -标签: GitHub | 云淡风轻
\ No newline at end of file +标签: GitHub | 云淡风轻
\ No newline at end of file diff --git a/tags/Guide/index.html b/tags/Guide/index.html index d1673e55..ec98761a 100644 --- a/tags/Guide/index.html +++ b/tags/Guide/index.html @@ -1 +1 @@ -标签: Guide | 云淡风轻
\ No newline at end of file +标签: Guide | 云淡风轻
\ No newline at end of file diff --git a/tags/Hexo/index.html b/tags/Hexo/index.html index 5fc2ced4..a2ce8c76 100644 --- a/tags/Hexo/index.html +++ b/tags/Hexo/index.html @@ -1 +1 @@ -标签: Hexo | 云淡风轻
\ No newline at end of file +标签: Hexo | 云淡风轻
\ No newline at end of file diff --git a/tags/JavaScript/index.html b/tags/JavaScript/index.html index f6d82d00..69d0b862 100644 --- a/tags/JavaScript/index.html +++ b/tags/JavaScript/index.html @@ -1 +1 @@ -标签: JavaScript | 云淡风轻
\ No newline at end of file +标签: JavaScript | 云淡风轻
\ No newline at end of file diff --git "a/tags/JavaScript\346\212\200\345\267\247/index.html" "b/tags/JavaScript\346\212\200\345\267\247/index.html" index a7644550..9e57e471 100644 --- "a/tags/JavaScript\346\212\200\345\267\247/index.html" +++ "b/tags/JavaScript\346\212\200\345\267\247/index.html" @@ -1 +1 @@ -标签: JavaScript技巧 | 云淡风轻
\ No newline at end of file +标签: JavaScript技巧 | 云淡风轻
\ No newline at end of file diff --git a/tags/MarkDown/index.html b/tags/MarkDown/index.html index 1ffabab8..e69082e1 100644 --- a/tags/MarkDown/index.html +++ b/tags/MarkDown/index.html @@ -1 +1 @@ -标签: MarkDown | 云淡风轻
\ No newline at end of file +标签: MarkDown | 云淡风轻
\ No newline at end of file diff --git a/tags/Media-Query/index.html b/tags/Media-Query/index.html index 71bcbb1a..752429e6 100644 --- a/tags/Media-Query/index.html +++ b/tags/Media-Query/index.html @@ -1 +1 @@ -标签: Media Query | 云淡风轻
\ No newline at end of file +标签: Media Query | 云淡风轻
\ No newline at end of file diff --git a/tags/MySql/index.html b/tags/MySql/index.html index 014862ff..2e00b294 100644 --- a/tags/MySql/index.html +++ b/tags/MySql/index.html @@ -1 +1 @@ -标签: MySql | 云淡风轻
\ No newline at end of file +标签: MySql | 云淡风轻
\ No newline at end of file diff --git a/tags/SSH-Key/index.html b/tags/SSH-Key/index.html index bf7bef65..8d986b44 100644 --- a/tags/SSH-Key/index.html +++ b/tags/SSH-Key/index.html @@ -1 +1 @@ -标签: SSH Key | 云淡风轻
\ No newline at end of file +标签: SSH Key | 云淡风轻
\ No newline at end of file diff --git a/tags/Valine/index.html b/tags/Valine/index.html index f95b54b3..bf8953c6 100644 --- a/tags/Valine/index.html +++ b/tags/Valine/index.html @@ -1 +1 @@ -标签: Valine | 云淡风轻
\ No newline at end of file +标签: Valine | 云淡风轻
\ No newline at end of file diff --git a/tags/bbr/index.html b/tags/bbr/index.html index fae3297c..da27fde7 100644 --- a/tags/bbr/index.html +++ b/tags/bbr/index.html @@ -1 +1 @@ -标签: bbr | 云淡风轻
\ No newline at end of file +标签: bbr | 云淡风轻
\ No newline at end of file diff --git a/tags/cerbot/index.html b/tags/cerbot/index.html index b2d60963..98f61fc0 100644 --- a/tags/cerbot/index.html +++ b/tags/cerbot/index.html @@ -1 +1 @@ -标签: cerbot | 云淡风轻
\ No newline at end of file +标签: cerbot | 云淡风轻
\ No newline at end of file diff --git a/tags/index.html b/tags/index.html index 8dbfeb26..c9358211 100644 --- a/tags/index.html +++ b/tags/index.html @@ -1 +1 @@ -标签 | 云淡风轻
\ No newline at end of file +标签 | 云淡风轻
\ No newline at end of file diff --git a/tags/linux/index.html b/tags/linux/index.html index 1d53bef1..e3374c13 100644 --- a/tags/linux/index.html +++ b/tags/linux/index.html @@ -1 +1 @@ -标签: linux | 云淡风轻
\ No newline at end of file +标签: linux | 云淡风轻
\ No newline at end of file diff --git a/tags/ssl/index.html b/tags/ssl/index.html index 7030ae5d..476e483b 100644 --- a/tags/ssl/index.html +++ b/tags/ssl/index.html @@ -1 +1 @@ -标签: ssl | 云淡风轻
\ No newline at end of file +标签: ssl | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\205\215\345\257\206\347\240\201/index.html" "b/tags/\345\205\215\345\257\206\347\240\201/index.html" index d04bc720..6cf392e5 100644 --- "a/tags/\345\205\215\345\257\206\347\240\201/index.html" +++ "b/tags/\345\205\215\345\257\206\347\240\201/index.html" @@ -1 +1 @@ -标签: 免密码 | 云淡风轻
\ No newline at end of file +标签: 免密码 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\205\215\350\264\271\345\215\232\345\256\242/index.html" "b/tags/\345\205\215\350\264\271\345\215\232\345\256\242/index.html" index 9197df89..3c908604 100644 --- "a/tags/\345\205\215\350\264\271\345\215\232\345\256\242/index.html" +++ "b/tags/\345\205\215\350\264\271\345\215\232\345\256\242/index.html" @@ -1 +1 @@ -标签: 免费博客 | 云淡风轻
\ No newline at end of file +标签: 免费博客 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\211\215\347\253\257/index.html" "b/tags/\345\211\215\347\253\257/index.html" index 36b3b35e..1aadf6db 100644 --- "a/tags/\345\211\215\347\253\257/index.html" +++ "b/tags/\345\211\215\347\253\257/index.html" @@ -1 +1 @@ -标签: 前端 | 云淡风轻
\ No newline at end of file +标签: 前端 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\217\230\351\207\217\347\261\273\345\236\213/index.html" "b/tags/\345\217\230\351\207\217\347\261\273\345\236\213/index.html" index 2164523f..21035261 100644 --- "a/tags/\345\217\230\351\207\217\347\261\273\345\236\213/index.html" +++ "b/tags/\345\217\230\351\207\217\347\261\273\345\236\213/index.html" @@ -1 +1 @@ -标签: 变量类型 | 云淡风轻
\ No newline at end of file +标签: 变量类型 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\223\215\345\272\224\345\274\217/index.html" "b/tags/\345\223\215\345\272\224\345\274\217/index.html" index d4fe6c39..f694c5b0 100644 --- "a/tags/\345\223\215\345\272\224\345\274\217/index.html" +++ "b/tags/\345\223\215\345\272\224\345\274\217/index.html" @@ -1 +1 @@ -标签: 响应式 | 云淡风轻
\ No newline at end of file +标签: 响应式 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\233\275\345\256\266-\345\234\260\345\214\272/index.html" "b/tags/\345\233\275\345\256\266-\345\234\260\345\214\272/index.html" index 3c79c256..aea39877 100644 --- "a/tags/\345\233\275\345\256\266-\345\234\260\345\214\272/index.html" +++ "b/tags/\345\233\275\345\256\266-\345\234\260\345\214\272/index.html" @@ -1 +1 @@ -标签: 国家/地区 | 云淡风轻
\ No newline at end of file +标签: 国家/地区 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\345\252\222\344\275\223\346\237\245\350\257\242/index.html" "b/tags/\345\252\222\344\275\223\346\237\245\350\257\242/index.html" index 2fd16b2b..e325c1fe 100644 --- "a/tags/\345\252\222\344\275\223\346\237\245\350\257\242/index.html" +++ "b/tags/\345\252\222\344\275\223\346\237\245\350\257\242/index.html" @@ -1 +1 @@ -标签: 媒体查询 | 云淡风轻
\ No newline at end of file +标签: 媒体查询 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\346\212\200\345\267\247/index.html" "b/tags/\346\212\200\345\267\247/index.html" index fb4c5ffa..6955977f 100644 --- "a/tags/\346\212\200\345\267\247/index.html" +++ "b/tags/\346\212\200\345\267\247/index.html" @@ -1 +1 @@ -标签: 技巧 | 云淡风轻
\ No newline at end of file +标签: 技巧 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\346\225\260\346\215\256\345\272\223/index.html" "b/tags/\346\225\260\346\215\256\345\272\223/index.html" index 0135a250..3478cb39 100644 --- "a/tags/\346\225\260\346\215\256\345\272\223/index.html" +++ "b/tags/\346\225\260\346\215\256\345\272\223/index.html" @@ -1 +1 @@ -标签: 数据库 | 云淡风轻
\ No newline at end of file +标签: 数据库 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\346\225\260\347\273\204\351\201\215\345\216\206/index.html" "b/tags/\346\225\260\347\273\204\351\201\215\345\216\206/index.html" index 91412a31..43227e7c 100644 --- "a/tags/\346\225\260\347\273\204\351\201\215\345\216\206/index.html" +++ "b/tags/\346\225\260\347\273\204\351\201\215\345\216\206/index.html" @@ -1 +1 @@ -标签: 数组遍历 | 云淡风轻
\ No newline at end of file +标签: 数组遍历 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\347\273\223\346\236\204\347\261\273\345\236\213/index.html" "b/tags/\347\273\223\346\236\204\347\261\273\345\236\213/index.html" index d60a0125..18f17a42 100644 --- "a/tags/\347\273\223\346\236\204\347\261\273\345\236\213/index.html" +++ "b/tags/\347\273\223\346\236\204\347\261\273\345\236\213/index.html" @@ -1 +1 @@ -标签: 结构类型 | 云淡风轻
\ No newline at end of file +标签: 结构类型 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\350\247\204\350\214\203/index.html" "b/tags/\350\247\204\350\214\203/index.html" index db382ed8..6b021000 100644 --- "a/tags/\350\247\204\350\214\203/index.html" +++ "b/tags/\350\247\204\350\214\203/index.html" @@ -1 +1 @@ -标签: 规范 | 云淡风轻
\ No newline at end of file +标签: 规范 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\350\257\204\350\256\272\347\263\273\347\273\237/index.html" "b/tags/\350\257\204\350\256\272\347\263\273\347\273\237/index.html" index 229d58a6..138b9a5b 100644 --- "a/tags/\350\257\204\350\256\272\347\263\273\347\273\237/index.html" +++ "b/tags/\350\257\204\350\256\272\347\263\273\347\273\237/index.html" @@ -1 +1 @@ -标签: 评论系统 | 云淡风轻
\ No newline at end of file +标签: 评论系统 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\350\257\221\346\226\207/index.html" "b/tags/\350\257\221\346\226\207/index.html" index 438c907e..b7d96b70 100644 --- "a/tags/\350\257\221\346\226\207/index.html" +++ "b/tags/\350\257\221\346\226\207/index.html" @@ -1 +1 @@ -标签: 译文 | 云淡风轻
\ No newline at end of file +标签: 译文 | 云淡风轻
\ No newline at end of file diff --git "a/tags/\350\257\255\350\250\200\347\274\251\345\206\231/index.html" "b/tags/\350\257\255\350\250\200\347\274\251\345\206\231/index.html" index d3573687..c83e26a3 100644 --- "a/tags/\350\257\255\350\250\200\347\274\251\345\206\231/index.html" +++ "b/tags/\350\257\255\350\250\200\347\274\251\345\206\231/index.html" @@ -1 +1 @@ -标签: 语言缩写 | 云淡风轻
\ No newline at end of file +标签: 语言缩写 | 云淡风轻
\ No newline at end of file