bookmark_border[译] JavaScript之函数

“ 函数是 JavaScript 的精髓 , 同时也是这门语言的魅力所在 ” —— Douglas Crockford

原文地址:The power of JavaScript Functions

函数( Functions )可以说是 JavaScript 语言中最强大的的对象,其他编程语言中很多不同的特性功能,函数可以一人包办。程序( procedures ),方法( methods ),构造函数( constructors ) 甚至是 类( classes )和 模块( modules ) ,所有这些功能,在 javaScript 中都可以用函数实现

在最新版的 Javascript 中,引入了类( Class ) 、方法( method )和构造函数( constructor )等概念,其实这些只不过是用函数包装好的语法糖

一旦你理解了函数的一些细节微妙处,你其实就掌握了相当一部分JavaScript;当然,你还得学习在不同的作用域有效的使用函数,才能更上一层楼

本文的目的就是为你揭开函数的神秘面纱,让你不仅看到它的表象,更能看到它不为人知的精髓

函数对象(Functions as objects)

Javascript 的一个重要的特性:函数是一种特殊类型的对象。声明一个函数和声明一个对象其实没什么两样,因为它会产生一个函数对象

函数对象是第一类对象( first classed object ) : 它可以当作参数传递,可以是其他函数返回的对象,可以把它赋值给一个变量,可以存储在对象或者数组中。它继承自Function.prototype ,所以函数还可以直接调用 bind() , apply() 和 call() 方法

将函数看作是一个特殊类型的对象,对有其他编程语言经验的人员来说,可能是个不小的挑战;但是一旦你接受了这个设定,则对于理解JavaScript非常有帮助

函数结构(Function structure)

有两种方式声明一个函数:

var sum = function(a, b) {
     return a + b; 
}

function sum(a, b) {
    return a + b;
}

关键字function位于声明之前。第 1 种方式,函数名是可选的(上面的示例就没有函数名);第 2 种方式,必须要有函数名

另一个值得注意的是,JavaScript没有”函数签名(function signature)”的概念,你可以传入零个或者多个参数去调用函数,而不用担心会报错;如果函数需要的参数你没传入,那么参数值默认就是undefined。如果你想知道传入的参数是什么?你可以通过 arguments 对象来查看。示例如下:

function sum(a, b) {
    for (let i = 0; i < arguments.length; i++) {
        console.log("argument: " + arguments[i]);
    }
    console.log("sum: " + (a + b));
}

sum();
sum(1, 2, 3);

输出结果:

sum: NaN
argument: 1
argument: 2
argument: 3
sum: 3

函数没有明确要求一定得返回什么,如果一个函数没有明确返回的对象,那么默认返回 undefined. 谨记:

  • 函数签名概念在js中不存在 —— 函数可以被传入任意参数调用
  • 函数永远会返回一个值 —— 如果没明确提供返回的值,那么返回undefined(构造函数除外,它一定会返回新对象)
  • 作为最佳实践,建议总是在函数中返回一个值,或者从不返回任何值

变量作用域(Variable scope)

变量作用域决定了变量的可访问性(可见性) ,在JavaScript中,有两种作用域—全局(global)和本地(local 主要是只函数内的 )

当一个函数被调用,那么一个作用域就形成了,本地变量只能在本地作用域内被访问。

当使用var声明一个变量时,它会自动添加到最直接的可用范围中。在函数中,最直接的可用范围是函数的上下文环境。由于局部变量只能在函数内部识别,所以同名的变量可以用于不同的函数中

Javascript的另一个特殊性是它没有块级范围。块级范围意味着如果一个变量在一个块内声明(for、while、if等),那么它只能在块内访问,不能在块外访问。例如,你可能期望这段代码能正常工作:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
function print_matrix(matrix, n) {
    for (var i = 0; i < n; ++i) {
        row = matrix[i];
        for (var i = 0; i < n; ++i) {
            console.log(row[i]);
        }
    }
}

print_matrix(matrix, 3);

输出结果:1 2 3 问题出在哪儿呢? 因为第一个 for 的变量 i 每次都会在第二个for中重新赋值,这个函数将在第一行之后退出。 为了解决这个问题,在最新版本的Javascript (ECMAScript 6)中引入了关键字let。在块内部使用let声明的变量将具有块级范围。所以简单地改变var,上面的例子就能按照你的期望执行

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
function print_matrix(matrix, n) {
    for (let i = 0; i < n; ++i) {
        row = matrix[i];
        for (let i = 0; i < n; ++i) {
            console.log(row[i]);
        }
    }
}

print_matrix(matrix, 3);

变量提升(Variable hoisting)

提升是Javascript中的一种默认行为,它表示在代码执行之前将所有变量的声明移到其作用域的顶部。所以在函数中声明一个变量并不重要,变量从执行上下文开始就属于那个范围。但是,提升只针对变量声明,而不是变量赋值。所以在到达变量被显式赋值的那一行之前,变量的值是undefined

function myFunction() {
    console.log(myVar); // undefined
    var myVar = 3;
    console.log(myVar); // 3
}

myFunction();

因为变量提升,所以上面的代码相当于下面这段代码:

function myFunction() {
    var myVar;          // 变量定义会被提升到最顶端
    console.log(myVar); // 此时变量并未赋值,所以输出undefined
    myVar = 3;          // 变量赋值不会提升
    console.log(myVar); // 3
}

myFunction();

这适用于任何变量和函数表达式。但是,函数表达式和函数声明之间有一些细微的区别,谨记:

提升会把声明移动到当前作用域最顶端,但是不包括赋值(初始化),在赋值(初始化)之前,变量的值是undefined

函数表达式 vs 函数声明

在继续之前,我有一件事要坦白。文章开头引人注目的引语是不完整的。我漏掉了一部分。让我们看看完整版:

“ 函数是 JavaScript 的精髓 , 同时也是这门语言的魅力所在。当然,像JavaScript中的其他东西一样,它很难确切的掌握 ” —— Douglas Crockford

就比如函数,就有两种声明函数的方法,它们之间还有细微的差别,这就是“不太确切”的一个例子

区别在于浏览器如何将它们加载到执行上下文中。函数表达式的加载方式与其他变量完全相同。当编译器到达这行代码时,它们被赋值(在本例中是函数对象)

但是,函数声明在执行任何代码之前加载。因此,即使函数在调用它的代码行下面声明,它也能工作。谨记:

  • 当你调用一个函数表达式,而它的声明代码在你调用的代码后面时,会报错
  • 当你调用一个函数,哪怕这个函数在你调用的代码后面声明,它依然能正确执行(因为它在编译之前会被提升到当前作用域前面)

为什么函数有这两种定义?

问的好,函数声明是最新的(在ECMAScript 3中引入的),它更有用。让我们记住Javascript是浏览器的语言,用户很少更新浏览器。很多时候,浏览器的新版本只有在用户更新操作系统时才会接触到他们。这就是为什么向后兼容性至关重要

如前所述,从数据类型的角度来看,每个函数都是一个对象。函数对象有三个非常重要的属性来表示函数的身份: this 、arguments 和 prototype

this 是啥?

关于JavaScript的 this ,可以写一篇很长的文章,此处不打算详细介绍。只要记住this 是指向调用它的对象, 所以 this 的值是在函数调用时分配的

当从全局作用域简单地调用一个函数时,this 显然会指向全局作用域本身。这是造成混乱的一个重要原因,这就是为什么在严格模式下运行时,值是未定义的。通常,您不会对这样的函数使用 this , This 对于用作方法的函数非常有用。这样,该方法就可以访问对象属性。

var myObj = {
    name: "John",
    sayName: function (name) {
        console.log("Hi, " + this.name); // 'this' 指向 myObj 
    }
};

myObj.sayName();

“This”在函数用作构造函数时也有重要作用。构造函数没有任何特殊的结构。当使用运算符new调用它时,它是一个构造函数。该操作符在底层创建一个新对象,并通过’ This ‘将其传递给函数

function Car(name) {
   this.name = name;
}

var myCar = new Car("Subaru");
console.log(myCar.name);

在上面的例子中,函数Car被用作一个函数。用大写字母声明它是一种常见的做法,目的很明显,但它只是一个简单的函数。

执行new关键字,其实执行了如下步骤:

  • 创建一个空对象
  • this指向新创建的对象,给新对象增加name属性并赋值
  • 将Car函数的prototype赋值给新对象的prototype
  • 返回创建的对象

每个函数都可以访问从Array.prototype继承的.apply()、.bind()和call()。它们允许使用显式设置的’ this ‘的任何值来调用函数。一般来说有以下四种方式调用一个函数:

  • function form (‘this’ will be the global object or undefined in strict mode)
  • method form (‘this’ will reference the object that made the call)
  • constructor form (‘this’ will be the new object)
  • apply/bind/call form (‘this’ is explicitly set)

函数参数(Function arguments)

如前所述,声明中提供的参数不是可靠的信息来源。可以使用不同数量的参数调用该函数。如果它们太多,则忽略额外的参数。如果它们太少,丢失的值将是未定义的。

幸运的是,函数的arguments属性在这里可以帮助我们。它是一个类似数组的对象,包含调用时提供的参数。它不是一个真正的数组,因为它不是从数组中继承的。原型,并且不能访问用于操作元素的方法。它所拥有的,是长度属性,它确切地知道提供了多少。参数的存储方式与数组完全一样,索引从0开始。

虽然arguments对象不是只读的,但是强烈建议不要修改它。更改arguments对象也会影响已命名的参数,这很容易引起混淆。

它的一个常见用法是创建具有未定义数量的参数的函数。例如,一个函数返回它的参数和:

function sum() {
    var i;
    var total = 0;
    var n = arguments.length;
    for (i = 0; i < n; i++) {
        total += arguments[i];
    }
    return total;
}
console.log(sum(1, 2, 3, 4)); // 10 

记住:

参数对象是关于函数>调用时提供的信息的惟一可靠来源

将参数视为只读结构

函数原型(Function Prototype)

函数的原型对象只有在函数用作构造函数时才有意义。它在Javascript中创建继承时起着关键作用。通过它,使用相同构造函数创建的对象可以共享相同的属性和行为。

原型继承是一个庞大的主题,超出了本文的范围

bookmark_border何为分级基金

想要了解何为分级基金,就必须先了解什么是基金


       话说,深圳有个下沙村,村里的人都以海边捕鱼为生,生活艰苦。某天,有个领导人在深圳的海边画了个圈,深圳就火箭般的速度发展;下沙村临近海边,房地产开发商看到了满满的海景房,于是去下沙村征地,下沙村的村民从贫农变成了富一代


       村民都有钱了,有些人拿着钱去东莞挥霍;有些人赶紧把钱存银行吃利息;还有一部分人呢,想用钱生钱,于是这部分村民一起开会。有人说:要不我们投资房地产,以后房价肯定涨;另一部分人说:我们投资互联网公司吧,那个叫什么腾讯的公司我看就很有潜力;还有一部分说:最近不是股票很火么,要不我们投资股票吧。三个臭皮匠,顶个诸葛亮,各种基金的模型应运而生


       投资房地产的村民,就把钱放在一起,专门投资房地产,而且取个好听的名字,叫做下沙房地产基金。准备投资互联网公司的人也跟风,成立了下沙天使投资基金,更高大上。炒股票的立马跟上,叫做下沙股票基金。于是成立了三个基金,村民们根据自己的钱对应里面的股份,开始准备用钱生钱了


       基金有了,但是村民不是很擅长做投资,于是请来三个博士来管理基金,一个房地产博士,一个互联网博士,一个经济学博士。这就是传说中的基金经理。大家觉的直接把钱给基金经理的话太危险了,万一他拿钱跑路了呢?于是村民们成立了一个公司,下沙基金公司,然后去银行开了个账户。所以基金的管理人是:下沙基金公司;基金托管人是:开户的银行


       有了以上基础知识,我们单独讲下沙股票基金。假如一开始村民一共凑了1亿元,然后分成1亿股。一年后,由于博士买股票太牛了,1亿的基金变成了市值2亿的基金,这样下沙股票基金的持有者,村民的钱就翻倍了,老王当初花100万买了100万股,现在100万股价值200万,这酸爽。不成想,不到一个月,股市大跌,本来值2亿的基金现在变成了只值五千万(因为基金购买的股票全部大跌,所以市值缩水一半),老王那叫一个心疼哟,他的100万股,只值50万了。老王心脏不好,一急之下住院了


       这下博士深深的自责,但股市大跌谁也没想到来的那么快那么猛。还有好多村民天天堵博士家门口,问他怎么不去死?于是博士想了个点子,号召大家开个会。首先是深深的道歉,死是不能死的,要为大家赚回本再说。为了防止这种情况发生,博士有了个新的想法,因为村民有一部分很激进,也有些很保守。他就想,能不能弄个基金,可以拆分成A和B。选A的呢,每年固定收益,当然比存银行收入多点,也保本。选B的呢,不保本,获取除开A每年固定的收益的所有利润,当然如果基金损失也要连A的损失一起承担。这么一说,很多村民听不懂,于是博士就举了个例子:


       假如老王出100块钱,老刘也出100块钱,老王承受风险能力不行,老王的钱就算A;老刘呢,比较激进就算B 。 于是我就有200块钱了,我现在拿着这200块钱去炒股,假如一年后我赚了,200变成了300,那么老王可以拿到100+100%10=110(假如每年规定的固定收益是10%),而老刘呢,就可以拿到300-110=190。假如不幸,我一年后亏了,200变成了150那么老王还是可以拿到110,老刘只能拿到40。这么一说,村民感觉懂了,又有村民问,假如你亏到只剩100怎么办?博士说,这个你不用担心,我会在每时每刻算好一定保证A收益的,假如到了临界点情况我会把基金买的股票全部卖掉,换成现金还给A,保证A的本金和收益,B就对不起了,你选择了风险,你就要承担损失


       这么一说,老王就出院了,这点子靠谱。而且博士还给这个基金一个响亮的名字,下沙股票分级基金,这样以后,老王再也不用住院了。每天拿着稳定的收益妥妥的,下沙村民从此过着幸福的生活——养富二代,富三代

当然,实际上分级基金还涉及到上折,下折,净值,市值等等概念。如果有兴趣深入了解,可以查看我的雪球专栏

bookmark_border什么是财政?

什么是财政?一个人活着,就要赚钱,赚了钱才能花钱,有钱花才能活下去(循环下去,生生不息);一个家庭也是,有收入才能有支出,才能传宗接代壮大家庭;一个企业也是,要生存也要赚钱然后再生产扩大规模;这些都有一些私人性质。但是社会上还有其他的公共部门,比如:政党(组织部,宣传部等),政府(国防部,公安部,消防部等),还有一些事业单位,学校,医院等,我们需要这些公共部门提供服务。比如,我们需要保障人身安全,就需要警察局;我们需要教育,医疗,所以需要学校,医院;以上所有这些部门,统称公共部门


      私人部门,自己赚钱,然后花钱。公共部门呢?需要办公楼,需要车,需要武器等,他们钱怎么来?他们不直接生产东西拿出去卖,本身不创造物质财富。假设要他们自己去筹钱,自己维持运行。那么国防部,公安局可能要钱就轻松些,直接拿抢挨家挨户的要。而民政局,组织部,卫生部等去收钱就没人理他了。而且时间久了,性质会慢慢转变,给的钱多,就给你更好的服务,所以这样明显不行。另外一个办法是,有一个专门的部门来负责所有的公共部门筹集资金,然后再把钱拨给公共部门过日子,这个公共部门,就是财政部


    财政其实说白了,就是 :收钱,花钱。收钱的,现在我们叫做税务局。税务局收钱的方式主要有两种,第一种:收税;第二种:收费。收税都懂,收费是什么?比如:汽车上牌照要交钱,办护照要钱等。收税,权利和义务不是很明显,为什么要交税,因为公共部门要花钱,为什么公共部门花钱要我交税,因为我提供公共服务了,比如保证安全,给你提供医疗,教育等,所以你要交税。你赚了大把钱,如果没有公安局保证你的安全,你就被人抢了;如果没有法院,检察院,你的委屈跟谁诉说。但是,税并不是说,你交的多,你享受的服务就更多。你交100块,他交100万,享受到的服务还是一样的(至少国家的想法是这样,至于具体实际情况另当别论)。比如,还有一些人从来不交税,也享受公共服务,所以交税跟享受公共服务不成比例。但是收费,就比较明显对等关系,用了才收费,比如你买车上牌照,就要交钱,不买车不享受这个服务,就不需要交钱


       钱收上来了,现在就是发下去。国防部,教育部要钱,财务部,税务局自己也要钱。那么问题来了,钱怎么分?国防部给少了,分分钟开坦克来收拾你;给多了其他部门就有意见,财政部太难了。所以,就想出了个办法,你不是要钱么?你就要报一个计划,你今年要花多少钱,详细列出来,这样我也好跟大家交代。比如:国防部你今年要买几辆坦克,手雷,规划好,交给财政部门。财政部就开始审核,根据你们的编制,岗位人数等核定。但是不是财政部审核通过了就直接打钱?不行,万一财政部里面有你干爹呢?所以最后一步,交给我们国家的最高权力机关:人民代表大会去审核(所以每年两会,其实还是有事儿做的,不都是明星去睡觉上镜,还是有人去为民众操心,为国家操心的做实事的),最后人民代表大会批准了,才行。这就是传说中的预算。预算会形成法律文件,具有法律效应


    讲到这里,才能理解,因为有了国家,所以才有财政。没有国家我要这些公共部门干嘛?自己请军队来,自己保护自己,缅甸很多军火商,毒贩就是这样,你敢去问他们收费收税?国家就是一个统治机器,所以才有了这些公共部门,才有了国防,国民的概念,国家是什么性质,就决定财政是什么性质


    马克思列宁主义认为:国家是一个阶级统治和压迫另一个阶级的工具,这叫暴力论。西方学者认为:国家是一个契约,是人民同意把一部分权力转让给你们公共部门,你来组件国家机器,我们来交税交费,你来提供公共商品和服务。就好像双方达成一个合同,一个条约,这就叫契约论。这部契约就叫:宪法


    财政有没有阶级性呢?财政会不会更好的服务统治阶级呢?美国是:美国政府的背后,就是各大资本财团,所以你当总统,主要就是为资产阶级服务。有时候还为军火商服务,军火商说,怎么老不打仗啊,我这东西都卖不出去,特朗普就整点事儿,打几仗,卖卖军火,清清库存。

以上就是关于财政的说明,你懂了吗?

bookmark_border阿里云ECS搭建WordPress

入职猎豹(深圳游戏中心)以后,项目赶,老板狠导致阿里云服务器到期后忘了续费,服务器被回收了,以前所有的文章都没了,甚是可惜

所以就从零开始换成了阿里云ECS服务器(以前用的是菁云服务器),重新搭个博客框架。写篇教程,也当作是重新拾起写作的习惯吧。

WordPress是目前世界上最流行的博客框架,我购买的是阿里云ECS Ubuntu系统的服务器,打开阿里云控制台,选中你买的服务器,点击 “远程连接” 进入以后开始操作以下指令

1.更新资源

Advanced Package Tool,又名apt-get,是一款适用于Unix和Linux系统的应用程序管理器 ,下面两行指令,是更新和升级当前系统软件包

sudo apt-get update
sudo apt-get upgrade

2.安装Apache2

Apache 是当前最流行的Web服务器软件之一,我们的网站内容就是通过它来展示给读者(你也可以安装Nginx),所以必须安装

sudo apt-get install apache2

这一步执行以后,你可以在你自己的电脑浏览器内输入:http://公网ip/,如果能看到apache的介绍页面,那说明安装成功;如果没有, 则打开控制台的服务器实例>本实例安全组>配置规则,添加安全组规则 ,如下图:

设置完毕以后,再刷新浏览器,肯定就可以看到apache的介绍网页了

3.安装Php

因为WordPress是php代码写得,所以肯定得配置php环境,第一行是安装php,第二行是安装相关组件,安装完成后,输入:php -v 可查看是否安装成功

sudo apt-get install php7.0 -y
sudo apt-get install libapache2-mod-php7.0

4.安装MySQL

既然是博客,那博客的内容肯定是要存入数据库的,对吧。所以我们得安装一个数据库,我安装的是MySQL,注意安装过程中会提示设置root密码,一定要记住。安装完成后,输入第二行,准备执行sql命令,第三行则是创建数据库命令(最后一个逗号要加上哦)

sudo apt-get install mysql-server
mysql -u root -p
mysql -> create database wordpress;

5.安装WordPress

最后,安装wordPress,这一步呢,也可以用指令完成,但是很慢。我们可以直接去官网下载包,然后解压。将所有内容上传到 /var/www/html/ 目录下。怎么上传呢?我建议下载 WinScp这款软件远程连接你的服务器。注意,要把这个目录设置成所有用户可读可写,因为我不熟悉linux命令行操作,所以这一步我也是通过WinScp右键文件夹属性操作的。最后,就是设置你的WordPress啦,这些步骤比较简单