leadscloud

Google SEO|外贸营销推广

函数和变量的声明总是会被解析器悄悄地被“提升”到方法体的最顶部

上面是javascript变量提升的概念。为了更好地理解“变量提升”,我们先来看一段代码:

1
2
3
4
(function (){
console.log(foo);
var foo = "Javascript";
})();

控制台输出:undefined 为什么输出了undefined,而没有报错呢?

原来javascript是函数作用域,解析器会在函数开头处自动去声明局部变量,局部变量都会被放在函数的入口处定义,所以上面的代码实际会被解释成:

1
2
3
4
5
(function (){
var foo;
console.log(foo);
foo = "Javascript";
})();

另外,需要注意Javascript中函数的两种声明方式存在的坑:

function fn(){} //函数声明式
var fn = function(){}; //函数表达式
对于函数声明式,解析器会确保在所有代码执行之前声明已经被解析。而对于函数表达式,与定义其它基本类型变量一样,逐句执行并解析。

我们再来举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 函数声明式 */
(function(){
fn();
function fn() {
console.log('来自函数声明式fn');
}
})();

/* 函数表达式 */
(function(){
fn();
var fn = function() {
console.log('来自函数表达式fn');
}
})();

控制台依次输出:

1
2
来自函数声明式fn
fn is not a function

可以看到,当使用函数声明的形式来定义函数时,可将调用语句写在函数声明之前,而后者,则会报错。

所以在Javascript中,变量的声明会被提升,而变量的赋值则不会。而函数的声明与变量的声明是不一样的,函数的函数体也会被一起提升,但请使用函数声明的形式才能提升。

原文: http://liaokeyu.com/%E6%8A%80%E6%9C%AF/2016/10/18/javascript_hoisting_%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87.html

匿名函数

匿名函数:就是没有函数名的函数。

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
//普通函数 
function box() { //函数名是 box
return'Lee';
}


//匿名函数
function(){ //匿名函数,会报错
return'Lee';
}


//通过表达式自我执行
(functionbox() { //封装成表达式
alert('Lee');
})(); //()表示执行函数,并且传参


//把匿名函数赋值给变量
var box=function(){ //将匿名函数赋给变量
return'Lee';
};
alert(box()); //调用方式和函数调用相似


//函数里的匿名函数
function box() {
return function(){ //函数里的匿名函数,产生闭包
return'Lee';
}
}
alert(box()()); //调用匿名函数

闭包

闭包的英文单词是closure,这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。

闭包的含义:闭包说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕(这点涉及JavaScript作用域链)。

使用闭包有一个优点,也是它的缺点:就是可以把局部变量驻留在内存中,可以避免使用全局变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
function a(){

var name='sun';

return function (){ //通过匿名函数返回 a() 局部变量
return name;
}
}
alert(a()()); //通过a()()来直接调用匿名函数返回值

var b=a();
alert(b()); //另一种调用匿名函数返回值

匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

闭包的经典案例

通过全局变量来累加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var num=0;     //全局变量 
function a(){
num++; //模块级可以调用全局变量,进行累加
}

a(); //1
a(); //2 //执行函数,累加了
alert(num); //输出全局变量

//---------------------------------------------------------------

function a(){
var num=0;
num++;
return num;
}


alert(a()); //1
alert(a()); //1 //无法实现累加,因为局部变量又被初始化了

每次调用,变量num都会被初始化,所以每次调用都会返回1而不是累加。我们可以用普通函数内部嵌套匿名函数,形成一个闭包来使变量驻留在内存中。

使用闭包进行累加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function a(){
var num=0;
return function(){
num++;
return num;
}
}

var b=a(); //获得函数

alert(b()); //1 //调用匿名函数
alert(b()); //2 //第二次调用匿名函数,实现累加


注意 闭包允许内层函数引用父函数中的变量,但是该变量是最终值

看下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* <body>
* <ul>
* <li>one</li>
* <li>two</li>
* <li>three</li>
* <li>one</li>
* </ul>
*/

var lists = document.getElementsByTagName('li');
for(var i = 0 , len = lists.length ; i < len ; i++){
lists[i].onmouseover = function(){
alert(i);
};
}

你会发现当鼠标移过每一个

  • 元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?

    注意事项里已经讲了(最终值)。

    显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数 (function(){ alert(i); }) 内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。

    解决方案一

    1
    2
    3
    4
    5
    6
    7
    8
    var lists = document.getElementsByTagName('li');
    for(var i = 0 , len = lists.length ; i < len ; i++){
    (function(index){
    lists[index].onmouseover = function(){
    alert(index);
    };
    })(i);
    }

    解决方案二

    1
    2
    3
    4
    5
    6
    7
    var lists = document.getElementsByTagName('li');
    for(var i = 0, len = lists.length; i < len; i++){
    lists[i].$$index = i; //通过在Dom元素上绑定$$index属性记录下标
    lists[i].onmouseover = function(){
    alert(this.$$index);
    };
    }

    解决方案三

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function eventListener(list, index){
    list.onmouseover = function(){
    alert(index);
    };
    }
    var lists = document.getElementsByTagName('li');
    for(var i = 0 , len = lists.length ; i < len ; i++){
    eventListener(lists[i] , i);
    }
  • 外贸营销留言板程序开源了!

    Github 地址:

    https://github.com/leadscloud/inquiry


    一个简单的留言板程序,在外贸网站运行测试多年没有任何问题。如果你的公司没有留言板程序,或者现在需要去找一个简单的留言板程序,这个很适合你。

    本人之前在矿山机械行业工作,给公司开发过留言板程序并且运行多年。 这几天我重新写了一个留言板程序,希望可以帮助广大做外贸的同行们。

    特点:

    1. 自动过滤垃圾留言信息
    2. 语言翻译功能集成
    3. 一键复制留言信息

    安装

    1. 把文件上传到服务器根目录
    2. 然后打开install.php, 例如: http://www.yourdomain.com/install.php
    3. 安装完毕会在content目录下生成一个数据库

    表单字段说明

    具体的字段设置你可以在系统根目录下的updata.php里查看。

    姓名与邮箱是必填的,其它都是非必须的。

    submit.html有一个示例文件

    1
    2
    <input type="hidden" name="from_company" value="YourName" />这个隐藏字段代表网站属于哪个牌子。
    <input type="hidden" name="referer" value="http://www.youwantedsite.com" />这个隐藏字段代表你强制把referer改为某个网站。

    字段:

    name email title content country phone address from_company

    config.php 配置文件

    下面是config里的内容。请修改DB_NAME,务必要以.php结尾,防止下载。BING_TRANSLATE_KEY Bing的翻译API,可以去注册一个。Akismet_API_Key 反垃圾服务,wordpress的反垃圾插件就是用它。根据此系统的域名,注册一个。有问题,再联系我,上次调试是没问题的。QQ:75504026

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?php
    //database name
    define('DB_NAME','#inquiry_system.sqlite.php');
    //database prefix
    define('DB_PREFIX','wp');
    //bing translate api key
    //define('ACCOUNT_KEY', 'nujIh3e7l8Xs8CkP44xTHwu4Gaw0vV1xzaSgXZy'); 已废弃
    define('BING_TRANSLATE_KEY', '7724d07b364645asdfds8ca7dfsds49624');
    //Akismet API Key
    define('Akismet_API_Key','aaa7ab1s1df6e9');
    //system root
    define('BLOG_ROOT',dirname(__FILE__));
    ?>

    软件截图

    联系我

    QQ: 75504026

    Email: love4026@gmail.com

    Website: https://leadscloud.github.io

    更新

    2018-4-19

    • bing翻译使用最新版本,去除之前的翻译
    • 复制按钮使用原生的js即可,不用再使用flash技术了

    关键词

    留言板程序 简单留言板 外贸留言板 外贸营销 跨境电商留言板

    https://www.v2ex.com/t/456479
    最近在V2EX上看到有人问,你有技术焦虑吗,提到现在各种技术迭代非常快,很多新兴的技术没有时间去了解。

    下面有一个的回复可以代表技术的更新速度之快

    相比前端,这些都是事????
    reacr, preact, omi, nest,
    vue, nuxt,
    webpack3, webpack4, parcel,
    ng 全家桶,
    ts, es678, 各种 polyfill,
    scss/less/sass, cssnext, postcss, stylus.

    看到这些深有感触,我刚进入工作的时候那时候最多有个jQuery,现在前端和后端几乎没区别了。前端最开始只是html+css编写,现在是各种构建工具,而且一代比一代强,刚学会一个下一个新的工具又出来了。

    到了我这个年纪,不光有技术、学习上的焦虑,应该还有中年焦虑,这应该是很多人都曾有的,工作8年,看到很多人离开,我还在原地,很多事情让我觉得有时能力是一方面,但选择往往很重要,很多时候选择决定了你的位置。

    对于技术,有些是可以沉淀的,像技术原理、算法、数据结构这些,有些是更新变化很快,像前端的构建工具、CSS框架、JS框架。

    我们常去做那些可以沉淀的事情,焦虑可以避免很多。

    每个人到了一定年纪都会遇到那个年纪应该会出现的事情,比如离职、结婚、生育,不到那个阶段你根本体会不了什么感觉,生命是一步一步去体验经历的,焦虑也没有用,路总还是要跟着别人走一遍。

    只要你有前进的动力,就会有”焦虑“,只要不影响到自己的生活,焦虑还是有一定好处的。无论何时,不放弃学习,就不用害怕。

    Elasticsearch简介

    Elasticsearch是一个实时的分布式搜索和分析引擎。它可以帮助你用前所未有的速度去处理大规模数据。

    它可以用于全文搜索,结构化搜索以及分析,当然你也可以将这三者进行组合。

    Elasticsearch是一个建立在全文搜索引擎 Apache Lucene™ 基础上的搜索引擎,可以说Lucene是当今最先进,最高效的全功能开源搜索引擎框架。

    但是Lucene只是一个框架,要充分利用它的功能,需要使用JAVA,并且在程序中集成Lucene。需要很多的学习了解,才能明白它是如何运行的,Lucene确实非常复杂。

    Elasticsearch使用Lucene作为内部引擎,但是在使用它做全文搜索时,只需要使用统一开发好的API即可,而不需要了解其背后复杂的Lucene的运行原理。

    当然Elasticsearch并不仅仅是Lucene这么简单,它不但包括了全文搜索功能,还可以进行以下工作:

    • 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
    • 实时分析的分布式搜索引擎。
    • 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。

    这么多的功能被集成到一台服务器上,你可以轻松地通过客户端或者任何你喜欢的程序语言与ES的RESTful API进行交流。

    Elasticsearch的上手是非常简单的。它附带了很多非常合理的默认值,这让初学者很好地避免一上手就要面对复杂的理论,

    它安装好了就可以使用了,用很小的学习成本就可以变得很有生产力。

    随着越学越深入,还可以利用Elasticsearch更多高级的功能,整个引擎可以很灵活地进行配置。可以根据自身需求来定制属于自己的Elasticsearch。

    使用案例:

    • 维基百科使用Elasticsearch来进行全文搜做并高亮显示关键词,以及提供search-as-you-type、did-you-mean等搜索建议功能。
    • 英国卫报使用Elasticsearch来处理访客日志,以便能将公众对不同文章的反应实时地反馈给各位编辑。
    • StackOverflow将全文搜索与地理位置和相关信息进行结合,以提供more-like-this相关问题的展现。
    • GitHub使用Elasticsearch来检索超过1300亿行代码。
    • 每天,Goldman Sachs使用它来处理5TB数据的索引,还有很多投行使用它来分析股票市场的变动。

    但是Elasticsearch并不只是面向大型企业的,它还帮助了很多类似DataDog以及Klout的创业公司进行了功能的扩展。

    Elasticsearch的优缺点

    优点

    1. Elasticsearch是分布式的。不需要其他组件,分发是实时的,被叫做”Push replication”。
    2. Elasticsearch 完全支持 Apache Lucene 的接近实时的搜索。
    3. 处理多租户(multitenancy)不需要特殊配置,而Solr则需要更多的高级设置。
    4. Elasticsearch 采用 Gateway 的概念,使得完备份更加简单。
    5. 各节点组成对等的网络结构,某些节点出现故障时会自动分配其他节点代替其进行工作。

    缺点

    1. 只有一名开发者(当前Elasticsearch GitHub组织已经不只如此,已经有了相当活跃的维护者)
    2. 还不够自动(不适合当前新的Index Warmup API)

    Solr简介

    Solr(读作“solar”)是Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持。

    Solr是用Java编写、运行在Servlet容器(如 Apache Tomcat 或Jetty)的一个独立的全文搜索服务器。 Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具有类似REST的HTTP/XML和JSON的API。Solr强大的外部配置功能使得无需进行Java编码,便可对其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制。

    因为2010年 Apache Lucene 和 Apache Solr 项目合并,两个项目是由同一个Apache软件基金会开发团队制作实现的。提到技术或产品时,Lucene/Solr或Solr/Lucene是一样的。

    Solr的优缺点

    优点

    1. Solr有一个更大、更成熟的用户、开发和贡献者社区。
    2. 支持添加多种格式的索引,如:HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。
    3. Solr比较成熟、稳定。
    4. 不考虑建索引的同时进行搜索,速度更快。

    缺点

    1. 建立索引时,搜索效率下降,实时索引搜索效率不高。

    Elasticsearch与Solr的比较

    当单纯的对已有数据进行搜索时,Solr更快。

    当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。

    随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。

    综上所述,Solr的架构不适合实时搜索的应用。

    实际生产环境测试

    下图为将搜索引擎从Solr转到Elasticsearch以后的平均查询速度有了50倍的提升。

    Elasticsearch 与 Solr 的比较总结

    • 二者安装都很简单;
    • Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;
    • Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式;
    • Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供;
    • Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。

    Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。

    其他基于Lucene的开源搜索引擎解决方案

    • 直接使用 Lucene

      说明:Lucene 是一个 JAVA 搜索类库,它本身并不是一个完整的解决方案,需要额外的开发工作。

      优点:成熟的解决方案,有很多的成功案例。apache 顶级项目,正在持续快速的进步。庞大而活跃的开发社区,大量的开发人员。它只是一个类库,有足够的定制和优化空间:经过简单定制,就可以满足绝大部分常见的需求;经过优化,可以支持 10亿+ 量级的搜索。

      缺点:需要额外的开发工作。所有的扩展,分布式,可靠性等都需要自己实现;非实时,从建索引到可以搜索中间有一个时间延迟,而当前的“近实时”(Lucene Near Real Time search)搜索方案的可扩展性有待进一步完善

    • Katta

      说明:基于 Lucene 的,支持分布式,可扩展,具有容错功能,准实时的搜索方案。

      优点:开箱即用,可以与 Hadoop 配合实现分布式。具备扩展和容错机制。

      缺点:只是搜索方案,建索引部分还是需要自己实现。在搜索功能上,只实现了最基本的需求。成功案例较少,项目的成熟度稍微差一些。因为需要支持分布式,对于一些复杂的查询需求,定制的难度会比较大。

    • Hadoop contrib/index

      说明:Map/Reduce 模式的,分布式建索引方案,可以跟 Katta 配合使用。

      优点:分布式建索引,具备可扩展性。

      缺点:只是建索引方案,不包括搜索实现。工作在批处理模式,对实时搜索的支持不佳。

    • LinkedIn 的开源方案

      说明:基于 Lucene 的一系列解决方案,包括 准实时搜索 zoie ,facet 搜索实现 bobo ,机器学习算法 decomposer ,摘要存储库 krati ,数据库模式包装 sensei 等等

      优点:经过验证的解决方案,支持分布式,可扩展,丰富的功能实现

      缺点:与 linkedin 公司的联系太紧密,可定制性比较差

    • Lucandra

      说明:基于 Lucene,索引存在 cassandra 数据库中

      优点:参考 cassandra 的优点

      缺点:参考 cassandra 的缺点。另外,这只是一个 demo,没有经过大量验证

    • HBasene

      说明:基于 Lucene,索引存在 HBase 数据库中

      优点:参考 HBase 的优点

      缺点:参考 HBase 的缺点。另外,在实现中,lucene terms 是存成行,但每个 term 对应的 posting lists 是以列的方式存储的。随着单个 term 的 posting lists 的增大,查询时的速度受到的影响会非常大

    原文: http://i.zhcy.tk/blog/elasticsearchyu-solr/

    今天来郑州公司迁移 Google AdWords API 系统,想在上海访问这边的内网,这边是没有固定 IP的,这边就用到了内网穿透利器ngrok 了,这个东西微信开发也会用到。

    ngrok官网的服务因为服务器在国外,所以不是很稳定,我们可以通过开源的代码自己搭建一个ngrok服务器。 下面是主要的操作步骤:

    准备环境

    安装golang及相关依赖

    1
    sudo apt-get install build-essential golang mercurial git

    先进入到自己想安装的目录,并从github clone ngrok的项目

    1
    2
    git clone https://github.com/tutumcloud/ngrok.git ngrok
    cd ngrok/

    通过以下命令生成并替换源码里默认的证书,注意域名xxxx.com修改为你自己的。

    1
    2
    3
    4
    5
    6
    7
    NGROK_DOMAIN="test.lanthy.com"
    openssl genrsa -out base.key 2048
    openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
    openssl genrsa -out server.key 2048
    openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
    openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt
    cp base.pem assets/client/tls/ngrokroot.crt

    编译服务端

    1
    sudo make release-server

    如果一切正常,ngrok/bin 目录下应该有 ngrokd 文件

    通过以下命令启动服务:

    1
    2
    cd ngrok/
    sudo ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="sub.lanthy.com" -httpAddr=":8081" -httpsAddr=":8082"

    其中httpAddr、httpsAddr 分别是 ngrok 用来转发 http、https 服务的端口,可以随意指定。同时ngrokd 还会开一个 4443 端口用来跟客户端通讯(可通过 -tunnelAddr=”:xxx” 指定)。

    这里如果你的服务器配置了iptables规则,需要对外开放使用到的端口,可以本地telnet相应的端口看是否可用,不可用可以通过以下的命令开启:

    1
    2
    3
    4
    5
    6
    /sbin/iptables -I INPUT -p tcp --dport 8081 -j ACCEPT
    /sbin/iptables -I INPUT -p tcp --dport 8082 -j ACCEPT
    /sbin/iptables -I INPUT -p tcp --dport 4443 -j ACCEPT
    /etc/rc.d/init.d/iptables save
    /etc/rc.d/init.d/iptables restart
    /etc/init.d/iptables status

    接下来就是需要在自己的域名提供商那里做域名映射了,这里最好把域名泛解析到相应的服务器:

    *.lanthy.com

    然后启动后,通过浏览器访问 test.lanthy.com:8081 如果页面显示

        Tunnel test.lanthy.com:8081 not found
    

    表示启动成功,可以用客户端连接了。

    编译客户端

    编译linux客户端

    1
    make release-client

    编译后会在ngrok/bin 目录下有 ngrok 文件。

    编译Mac客户端

    1
    sudo GOOS=darwin GOARCH=amd64 make release-client

    编译后会在ngrok/bin/darwin_amd64 目录下有 ngrok 文件。

    编译windows客户端

    1
    sudo GOOS=windows GOARCH=amd64 make release-client

    编译后会在ngrok/bin/windows_amd64 目录下有 ngrok.exe 文件。

    运行测试客户端

    将以上的不同系统版本的客户端下载到相应系统后,同一目录新增配置文件ngrok.cfg:

    1
    2
    server_addr: test.lanthy.com:4443
    trust_host_root_certs: false

    Mac上执行客户端

    映射本地8080端口,自定义子域名test,通过终端执行以下命令:

    1
    ./ngrok -subdomain sub -config=ngrok.cfg 8080

    Windows上执行客户端:

    映射本地8090端口,自定义子域名test,通过DOS界面进入grok客户端的相应目录:

    1
    ngrok -config=ngrok.cfg -subdomain=sub 8080

    如果连接成功,会出现大概以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ngrok                                           (Ctrl+C to quit)

    Tunnel Status online
    Version 1.7/1.7
    Forwarding http://sub.test.lanthy.com:8081 -> 127.0.0.1:8080
    Forwarding https://sub.test.lanthy.com:8082 -> 127.0.0.1:8080
    Web Interface 127.0.0.1:4040

    # Conn 0
    Avg Conn Time 0.00ms

    这样你就就可以通过http://sub.test.lanthy.com:8081 访问内网 127.0.0.1:8080

    SSH 22端口映射

    1
    /root/ngrok/bin/ngrok -config=/root/ngrok/.ngrok -subdomain=test --proto=tcp 22
        使用tcp协议穿透,就不会分配2级域名,改为监控一个随机端口,如 test.lanthy.com:12389
    

    HTTP 80端口映射

    1
    /root/ngrok/bin/ngrok -config=/root/ngrok/.ngrok -subdomain="sub" 80

    后台运行

    1
    /root/ngrok/bin/ngrok -config=/root/ngrok/.ngrok -subdomain=sub --proto=tcp -log=stdout 22 > /dev/null &

    使用固定端口配置

    如果想一次性转发多个端口或者想指定远程的对应端口,需要完善ngrok.cfg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    server_addr: ngrok.lanthy.com:4443
    trust_host_root_certs: false
    tunnels:
    ssh:
    remote_port: 1122
    proto:
    tcp: 22
    ss:
    emote_port: 8388
    proto:
    tcp: 8388
    ftp:
    remote_port: 20
    proto:
    tcp: 20
    ftp2:
    remote_port: 21
    proto:
    tcp: 21
    http:
    subdomain: www
    proto:
    http: 80
    https: 192.168.1.22:443

    使用方法:

    1
    /root/ngrok/bin/ngrok -config=/root/ngrok/.ngrok start http

    启动全部的是 start-all , 不过我这个版本没有这个功能。

    后台运行

    必须加上-log=stdout参数,否则是不行的

    1
    nohup /home/nflg/ngrok/ngrok -config=/home/nflg/ngrok/ngrok.cfg -log=stdout start ssh > /dev/null &

    参考链接:

    https://juejin.im/entry/58adb743b123db006730e691
    https://yii.im/posts/pretty-self-hosted-ngrokd/
    http://ngrok.cn/docs.html

    什么是比特币?

    什么是比特币?

    比特币 (bitcoin) 是一种数字货币。

        小知识:什么是比特(bit) ?
    
        bit 是计算机表示二进制的单位。
        例如:
        1bit 可以表示 0 或者 1 两种状态;
        2bit 可以表示 00/01/10/11 四种状态。
    
        所以,习惯上人们用比特来形容数字化相关的事物,例如:比特币
    

    既然比特币是一种数字货币,那么理解比特币之前,先要了解:什么是货币

    经济学上认为,货币本质上是一般等价物

    什么是一般等价物?

    考虑原始时代的经济:

    A 圈养了一头牛,B 纺织了一块布,为了满足彼此的需求,他们可以约定:

        一头牛 换 一匹布
    

    通过这种原始的物物交换实现了简单的价值流动

    但是,随着社会生产力的提高,这种模式已经不能适应经济发展的要求。

        小思考:为什么物物交换行不通?
    
        1、A 在安阳,B 在梅州,空间上没法物物交换;
        2、A 今天生产了商品甲,下个月才需要商品乙,时间上没法物物交换;
        3、参与市场的各方提供了成千上万的商品,效率上不接受物物交换。
    

    这个时候,需要一种各方都认可的一般等价物来衡量、转换和传递商品的价值,从而实现商品的高效自由流动。

        价值流动:商品 -> 一般等价物 -> 商品
    

    早期,人们使用贝壳来充当一般等价物,后来又使用金、银等贵金属,再发展出纸币,甚至到现在的移动支付。

        小思考:
    
        财、货、贵、贩、赚、账、赁,这些字有什么共同点?
    

    以 ¥人民币 为例,它是以国家信用为背书,充当价值媒介的一般等价物。具有价值尺度、流通手段、贮藏手段、支付手段等职能。

    所以,货币本质上是一般等价物。

    只要你能创造出一种东西:它满足充当一般等价物的条件,那么你就是创造了一种货币!

        小思考:充当一般等价物需要哪些条件?
    
        1、全体参与方认可;
        2、不可伪造;
        3、方便携带、分隔、可以长期保存;
        4、数量可控;
        ......
    

    比特币就是这样一种东西。

    比特币

    这是一个革命性的创举,它打破了古今中外的惯例:货币都由政府的中央银行负责发行,而且只能在特定国家或地区流通。

    要知道,往往只有改朝换代的时候有机会发行全新的货币,可谓百年难遇。现在比特币做到了,而且是全球性地发行和流通,前无古人!

    当前的货币体系

    政府通过国家信用和强制手段保证央行发行的货币被广泛认可和接受。

    例如,通过颁布法律和规章制度:《中华人民共和国中国人民银行法》、《中华人民共和国人民币管理条例》等。

    对于防止伪造,一方面通过技术手段提高纸币的伪造难度;另一方面通过法律手段打击制造、流通假币。

    截至目前,通过央行发行货币是全世界通用的做法,运行良好,但缺点明显。

    显而易见的问题,包括但不限于:

    1. 由于发行权掌握在中心化的央行手中,理论上存在货币超发的可能,从而导致通货膨胀,例如:委内瑞拉、津巴布韦等国家由于通货膨胀,货币体系近乎崩溃;

    2. 即使高压打击,依然无法避免假币出现,最薄弱的环节不在于印制技术,而在于流通中需要人去辨别,而人往往是不可靠的。

    比特币系统是如何运转的?

    2008 年,一个网名为中本聪 (Satoshi Nakamoto) 的人,发表了《比特币:一种点对点式的电子现金系统》的论文,由此掀开了比特币风靡全球的大幕。

        小链接:
    
        论文 PDF 版原文:https://bitcoin.org/bitcoin.pdf
    
        中文翻译: [比特币白皮书:一种点对点的电子现金系统](http://www.8btc.com/wiki/bitcoin-a-peer-to-peer-electronic-cash-system)
    

    由于思维定势,刚接触比特币概念的人,往往有一些认知的误区或盲区:

    1、比特币是不是和硬币或纸币一样有实体形式?
    2、比特币是数字货币,是不是和银行账户一样,在某个服务器的数据库里记录着我的账户下有多少余额?
    3、两个人之间怎么转账?是不是和传统的银行一样:A 的账户 -100,B 的账户 +100?
    4、比特币的数量有多少?最小分割单位是多少?
    5、没有中央银行,那么比特币是谁发行的?
    6、软件、音乐、文档等数字资产可以随便复制,为什么比特币不能拷贝?

    ……

    一大堆问题!是什么?!为什么?!

    当你开始思考这些问题的时候,那么恭喜你,你已经在思考如何设计一种货币系统了。

    真是激动人心,从来没有想过有一天自己也可以设计一套货币系统,而且可以在真实世界运行起来。

    更令人兴奋的是,你有机会参与价值的重新分配,就像淘金。

    接下来,开始揭秘比特币是如何运行的。

    阅读全文 »

    CSS 有哪些样式可以给子元素继承!

    可继承的:font-size,font-weight,line-height,color,cursor
    不可继承的一般是会改变盒子模型的:display,marginborderpaddingheight

    box-sizing常用的属性有哪些? 分别有啥作用?

    box-sizing有两个值:content-box(W3C标准盒模型),border-box(怪异模型),
    这个css 主要是改变盒子模型大小的计算形式
    可能有人会问padding-box,这个之前只有 Firefox 标准实现了,目前50+的版本已经废除;
    用一个栗子来距离,一个div的宽高分别100px,border为5px,padding为5px

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     <style>
    .test {
    box-sizing: content-box;
    border: 5px solid #f00;
    padding:5px;
    width: 100px;
    height: 100px;
    }

    </style>
    <div class="test"></div>
    <!--
    content-box的计算公式会把宽高的定义指向 content,border和 padding 另外计算,
    也就是说 content + padding + border = 120px(盒子实际大小)

    而border-box的计算公式是总的大小涵盖这三者, content 会缩小,来让给另外两者
    content(80px) + padding(5*2px) + border(5*2px) = 100px
    -->

    清除浮动的方式有哪些?比较好的是哪一种?

    常用的一般为三种.clearfix, clear:both,overflow:hidden;

    CSS 中transition和animate有何区别? animate 如何停留在最后一帧!

    这种问题见仁见智,我的回答大体是这样的..待我捋捋.
    transition一般用来做过渡的,而animate则是做动效,算是前者的一个补充拓展;
    过渡的开销比动效小,前者一般用于交互居多,后者用于活动页居多;
    至于如何让animate停留在最后一帧也好办,就它自身参数的一个值就可以了

    1
    2
    animation-fill-mode: forwards;  
    <!--backwards则停留在首帧,both是轮流-->

    让我们来举个栗子….自己新建一个 html 跑一下….

    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
    <!DOCTYPE html>
    <html lang="en">

    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Box-sizing</title>
    <style>
    .test {
    box-sizing: border-box;
    border: 5px solid #f00;
    padding: 5px;
    width: 100px;
    height: 100px;
    position:absolute;
    /*
    简写的姿势排序
    @keyframes name : 动画名
    duration 持续时间
    timing-function 动画频率
    delay 延迟多久开始
    iteration-count 循环次数
    direction 动画方式,往返还是正向
    fill-mode 一般用来处理停留在某一帧
    play-state running 开始,paused 暂停 ....
    更多的参数去查文档吧..我就不一一列举了
    */
    animation: moveChangeColor ease-in 2.5s 1 forwards running;
    }

    @keyframes moveChangeColor {
    from {
    top:0%;
    left:5%;
    background-color:#f00
    }
    to{
    top:0%;
    left:50%;
    background-color:#ced;
    }
    }

    </style>
    </head>

    <body>
    <div class="test"></div>
    </body>

    </html>

    块级元素水平垂直居中的方法

    我们要考虑两种情况,定宽高和不定宽高的;

    方案 N 多种,我记得我很早写过这类的笔记

    网页元素居中攻略记

    CSS样式权重的优先级

        !important > 行内样式 > id > class > tag
    

    CSS特异性

    JS有几种数据类型,其中哪些的基本数据类型有哪些!

    七种数据类型

    • Boolean
    • Null
    • Undefined
    • Number
    • String
    • Symbol (ECMAScript 6 新定义)
    • Object

    其中5种为基本类型: string,number,boolean,null,undefined

    Object 为引用类型(范围挺大),也包括数组、函数,

    Symbol是原始数据类型 ,表示独一无二的值

    nullundefined的差异

    相同点

    在 if判断语句中,值都默认为 false
    大体上两者都是代表无,具体看差异

    不同点

    • null转为数字类型值为0,而undefined转为数字类型为 NaN(Not a Number)
    • undefined是代表调用一个值而该值却没有赋值,这时候默认则为undefined
    • null是一个很特殊的对象,最为常见的一个用法就是作为参数传入(说明该参数不是对象)
    • 设置为null的变量或者对象会被内存收集器回收

    this对象的理解

    简言之: 谁调用指向谁, 运行时的上下文确定, 而非定义的时候就确定;

    强行绑定 this的话,可以用 call,apply,bind,箭头函数….来修改this的指向

    bind的 js简单模拟

    1
    2
    3
    4
    5
    6
    7
    Function.prototype.emulateBind =  function (context) {
    var self = this;
    return function () {
    return self.apply(context);
    }

    }
    阅读全文 »

    微信开发的时候,必须要输入URL而且必须是外网域名,导致本地没法调试,不过使用ngrok可以创建一个内网穿透的服务器,这样就可以使用本地的服务器调试了。

    ngrock下载地址

    开启 ssh 端口

    ./ngrok tcp 22

    这时在外网即可 ssh 访问本机:

    ssh user@0.tcp.ngrok.io -p17840

    开启 http(s) 服务:

    ./ngrok http 80

    免费版并不能自定义域名,每次启动时的端口都会改变

    CentOS6 搭建自己的 ngrok 服务

    https://www.ngrok.cc/
    https://natapp.cn/

    回想2007年,那时候我刚加入Mozilla’s JavaScript团队,那时候的一个典型的JavaScript程序只需要一行代码,听起来像个笑话。

    两年后,Google Maps发布。在这之前,JavaScript主要用来做表单的验证,你用来处理<input onchange=>这个程序当然只需要一行。

    时过境迁,JavaScript项目已经发展到让人叹为观止,社区涌现了许多帮助开发的工具。但是最迫切需要的是一个模块系统,它能将你的工作分散到不同的文件与目录中,在需要的时候他们能彼此之间相互访问,并且可以有效的加载所有代码。所以JavaScript有模块系统这很正常,而且还有多个模块系统(CommonJS、AMD、CMD、UMD)。不仅如此,它还有几个包管理器(npm、bower),用来安装软件还能拷贝一些深度依赖。你可能认为ES6和它的新模块系统出现得有点晚。

    那我们来看看ES6为现存的模块系统添加了什么,以及未来的标准和工具能否建立在这个系统上。首先,让我们看看ES6的模块是什么样子的。

    模块的基础知识

    ES6模块是一个包含了JS代码的文件。没有所谓的module关键词,一个模块看起来和一个脚本文件没什么不一样,除了一下两个区别:

    • ES6的模块自动开启严格模式,即使你没有写"use strict";
    • 在模块中,你可以使用importexprot

    先来谈谈export。在默认情况下,模块中所有的声明都是私有的,如果你希望模块中的某些声明是公开的,并在其他模块中使用它们,你就必须导出它们。这里有一些实现方法,最简单的是添加export关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // kittydar.js - Find the locations of all the cats in an image.
    // (Heather Arthur wrote this library for real)
    // (but she didn't use modules, because it was 2013)

    export function detectCats(canvas, options) {
    var kittydar = new Kittydar(options);
    return kittydar.detectCats(canvas);
    }

    export class Kittydar {
    ... several methods doing image processing ...
    }

    // This helper function isn't exported.
    function resizeCanvas() {
    ...
    }
    ...

    你可以export任何的顶级变量:functionclassvarletconst

    你如果要写一个模块知道这么多就够了!你不必再把所有的东西放到一个立即执行函数或者回调函数里面,只需要在你需要的地方进行声明。由于这个代码是一个模块,而不是一个脚本,所有的声明的作用域都只属于这个模块,而不是所有脚本和模块都能全局访问的。你只要把模块中的声明导出成一组公共模块的API就足够了。

    除了导出,模块里的代码和其他普通代码没有什么区别。它可以访问全局变量,像ObjectArray。如果你的模块在浏览器运行,还能够使用documentXMLHttpRequest

    在另一个文件中,我们可以导入并使用detectCats()函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // demo.js - Kittydar demo program

    import {detectCats} from "kittydar.js";

    function go() {
    var canvas = document.getElementById("catpix");
    var cats = detectCats(canvas);
    drawRectangles(canvas, cats);
    }

    要从一个模块导入多个变量,你可以这样写:

    1
    import {detectCats, Kittydar} from "kittydar.js";

    当你运行一个包含import声明的模块,会先导入要导入的模块并加载,然后根据深度优先的原则遍历依赖图谱来执行对应模块,并跳过已经执行的模块,来避免循环。

    这就是模块基础知识,这真的很简单。;-)

    导出列表

    你可以把你要导出的功能名写在一个列表里,然后用大括号括起来,这样就不用在每个要导出的功能前面加上export标记。

    1
    2
    3
    4
    5
    export {detectCats, Kittydar};

    // no `export` keyword required here
    function detectCats(canvas, options) { ... }
    class Kittydar { ... }

    导出列表并不需要写在文件的第一行,它可以出现在模块文件的顶级作用域的任何位置。你可以有多个导出列表,或者将导出列表与导出声明混合使用,只要不重复导出同一个变量名就行。

    重命名导出和导入

    有时,导入的变量名碰巧与你需要使用的一些变量名冲突了,ES6允许你重命名导入的变量。

    1
    2
    3
    4
    5
    6
    7
    // suburbia.js

    // Both these modules export something named `flip`.
    // To import them both, we must rename at least one.
    import {flip as flipOmelet} from "eggs.js";
    import {flip as flipHouse} from "real-estate.js";
    ...

    同样,你在导出变量的时候也可以重命名它们。这在你想使用不同名字导出相同功能的时候十分方便。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // unlicensed_nuclear_accelerator.js - media streaming without drm
    // (not a real library, but maybe it should be)

    function v1() { ... }
    function v2() { ... }

    export {
    v1 as streamV1,
    v2 as streamV2,
    v2 as streamLatestVersion
    };

    默认的导出

    新的标准在设计上是兼容已经存在的CommonJS和AMD模块的。如果你有一个Node项目,并且你已经执行了npm install lodash。你使用ES6代码能够单独引入Lodash中的函数:

    1
    2
    3
    import {each, map} from "lodash";

    each([3, 2, 1], x => console.log(x));

    如果你已经习惯使用_.each而不是each,你依然想像以前一样使用它。或者, 你想把_当成一个函数来使用,因为这才是Lodash。

    这种情况下,你只要稍微改变下你的写法:不使用花括号来导入模块。

    1
    import _ from "lodash";

    这个写法等同于import {default as _} from "lodash";。所有的CommonJS 和AMD模块在ES6中都能被当作default导出,这个导出和你在CommonJS中使用require()导出得到东西一样,即exports对象。

    ES6模块在设计上可以让你导出更多的东西,但对于现在的CommonJS模块,导出的default模块就是能导出的全部东西了。例如,在写这篇文章时,据我所知,著名的colors模块没有特意去支持ES6语法,这是一个CommonJS模块组成的包,就像npm上的那些包一样,但是你可以直接引入到你的ES6代码中。

    1
    2
    // ES6 equivalent of `var colors = require("colors/safe");`
    import colors from "colors/safe";

    如果你希望自己ES6模块也具有默认导出,这很简单。默认的导出方式并没有什么魔力;他就像其他导出一样,除了它的导出名为default。你可以使用我们之前提到的重命名语法:

    1
    2
    3
    4
    5
    let myObject = {
    field1: value1,
    field2: value2
    };
    export {myObject as default};

    或者使用简写:

    1
    2
    3
    4
    export default {
    field1: value1,
    field2: value2
    };

    export default关键词后面可以跟任何值:一个函数、一个类、一个对象,所有能被命名的变量。

    模块对象

    不好意思,这篇文章有点长。JavaScript并不孤独:因为一些原因,所有的语言中都有模块系统,并且倾向于设计大量杂乱而又无聊的小特性。幸运的是我们只剩下一个话题,噢,不对,是两个。

    1
    import * as cows from "cows";

    当你使用import *的时候,被引入的是一个模块命名空间对象(module namespace object),它的属性是模块的输出。如果“cows”模块导出一个名为moo()的函数,那么在导入“cows”之后,你可以使用cows.moo()来进行调用。

    聚合模块

    有时候一个包的主模块只不过是导入包其他所有的模块,并用统一的方式导出。为了简化这种代码,有一种将导入导出全部合一的简写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // world-foods.js - good stuff from all over

    // import "sri-lanka" and re-export some of its exports
    export {Tea, Cinnamon} from "sri-lanka";

    // import "equatorial-guinea" and re-export some of its exports
    export {Coffee, Cocoa} from "equatorial-guinea";

    // import "singapore" and export ALL of its exports
    export * from "singapore";

    这种export-from表达式类似于import-from后面跟了一个export。这和真正的导入有一些区别,它不会在当前作用域中绑定将要导出的变量。如果你打算在world-foods.js中使用Tea来编写一些代码,请不要使用这种简写,你会发现Tea为定义。

    如果“singapore”导出的命名与其他导出发生了冲突,那就会出现错误,所以请谨慎使用。

    呼,我们已经把语法介绍完了!下面来谈谈一些有趣的事情。

    import到底做了什么?

    不管你信不信,它什么都没做。

    噢,你看起来没那么好骗。那么你会相信标准几乎没有说import到底该怎么做吗?这是件好事吗?(作者貌似很爱开玩笑。)

    ES6将模块的加载细节完全交给了实现,其余的模块执行部分却规定得非常详细

    简单来说,当你告诉JS引擎运行一个模块的时候,它的行为可以归纳为以下四部:

    1. 解析:读取模块的源代码,并检查语法错误。
    2. 加载:加载所有的导入模块(递归进行),这是还未标准化的部分。
    3. 链接:对于每个新加载的模块,在实现上都会创建一个作用域,并把模块中声明的所有变量都绑定在这个作用域上,包括从其他模块导入的变量。如果你想试试import {cake} from "paleo",但是“paleo”模块没真正导出名为cake的变量,你会得到一个错误。这很糟糕,因为你离运行js并品尝蛋糕只有一步之遥。
    4. 运行时间:最后,开始执行加载进来的新的模块中的代码。这时,整个import过程已经完成了,所以前面说代码执行到import这一行声明时,什么都没有发生。

    看到没?我说了什么都不会发生,在编程语言这件事上,我从来都不说慌。

    现在我们可以开始介绍这个系统中有趣的部分了。这有一个非常炫酷的技巧。由于系统没有指定如何加载的这方面的细节,并且你可以通过查看源代码中导入的声明,提前计算出所有的依赖项,所以ES6的实现可以通过预处理器完成所有的工作,然后把所有的模块打包到一个文件中,最后通过网络进行请求一次即可。像webpack这样的工具就是这么做的。

    这是一个优雅的解决方案,因为通过网络加载所有的脚本文件很耗时,假如你请求一个资源后,发现里面有import声明,然后你又得请求更多资源。一个加载器需要非常多的网络请求来回传输。通过webpack,你不仅能在今天就使用ES6的模块话,你还能获得很多好处,并且不需要担心会造成运行时的性能下降。

    原本是有计划制定一个ES6中模块加载的详细规范的,并且已经初步成型。它没有成为标准的原因之一是不知道如何与打包这一特性进行整合。我希望模块化的加载会更加标准化,也希望打包工具会越来越好。

    静态 VS 动态,或者说:规则如何打破规则

    作为一个动态编译语言,令人惊奇的是JavaScript拥有一个静态的模块系统。

    • 所有的importexport只能写在顶级作用域中。你不能在条件判断语句和函数作用域内使用import。
    • 所有导出的变量名必须是显式的,你不能通过遍历一个数组,动态生成一组导出名进行导出。
    • 模块对象都是被冻结的,不能通过polyfill为它添加新的特性。
    • 在所有模块运行之前, 其依赖的模块都必须经过加载、解析、链接的过程,目前没有import懒加载相关的语法。(现在import()方法已经在提案中了)
    • 对于import的错误,无法进行recovery。一个应用可能依赖许多的模块,一旦有一个模块加载失败,这个应用都不会运行。你不能在try/catch中使用import。正是因为es6的模块表现得如此静态,webpack才能在编译的时候检测出代码中的错误。
    • 你没法为一个模块在加载所有依赖项之前添加钩子,这意味着一个模块没有办法控制其依赖项的加载方式。

    如果你的需求是静态的,ES6的模块系统还是相当不错的。但是你有时候你还是向进行一些hack,对吧?

    这就是为什么你使用的模块加载系统会提供一些系统层次的API来配合ES6的静态的import/export语法。例如,webpack有一个API能进行代码的分割,按照你的需求对一些模块进行懒加载。这个API能够打破之前列出的规矩。

    ES6的模块语法非常静态,这很好-在使用一些编译工具时我们都能尝到一些甜头。静态语法的设计可以让它与动态加载器丰富的API进行工作。

    我什么时候才能使用ES6模块?

    如果你今天就想使用,你需要一个预编译器,如 TraceurBabel 。这个系列之前也有相关文章,Gastón I. Silva:如何使用 Babel 和 Broccoli 编译 ES6 代码为 web 可用。Gastón也将案例放在了 GitHub 上。另外这篇文章也介绍了如何使用 Babel 和 webpack。

    ES6 模块系统由 Dave Herman 和 Sam Tobin-Hochstadt进行设计,他们不顾多人(包括我)的反对,多年来始终坚持模块系统是静态的。JonCoppeard正在Firefox上实现ES6的模块化功能。JavaScript Loader的相关标准的工作也正在进行中,预计在HTML中将会被添加类似<script type=module> 这样的东西。

    这便是 ES6 了。

    这太有趣了,我不希望现在就结束。也许我们还能再说一会。我们还能够讨论一些关于ES6规范中零零碎碎的东西,但这些又不足够写成文章。也行会有一些关于ES6未来特性的一些东西,尽请期待下周的ES6 In Depth

    原文链接:ES6 In Depth: Modules

    0%