javascript特性杂谈
最近语言学习有些疯狂, 从Ruby到Lisp, 然后是C#, 既然已经疯狂了, 就顺面学习一下javascript吧. 对javascript的印象一直不佳, 从骂脏话最多的使用者, 到使用者易做图的世界上最被误解的语言, 从所谓的让人抓狂的特性, 到世界上任何可以用javascript实现的东西, 最终都会被javascript实现, 并且, 这是最后一个实现. 出处太多, 不一一列举, 知者已知, 不知者也没有必要为了这些无聊的言论特意找出处了.其实也不是完全没有用过javascript, 以前在开发一个Unity项目的时候用过一下Unity里面的javascript, 只不过那个javascript我甚至都只能称之为UnityScript. 太多太多自己实现的特性, 而又有些不够完整. 现在, 认识一下真正的javascript吧.
Mac OS X 10.8.2, node v0.8.16
需要解释一下, node跟浏览器里嵌入的javascript不一样, 不具有类似confirm和prompt等接口, 我用console.log来输出.
概要
JavaScript本身就是设计为一个前端语言, 据说设计只用了10天, 有些缺陷, 但是的确足够简单. 虽然JavaScript The Definitive Guide和大多数的语言书籍一样厚如砖头, 但是其实语言本身的介绍只有前面近200页, 这个厚度其实也就和R&D中描述的C语言差不多.
也就是因为设计比较简单, JavaScript也被一些人认为不算是现代语言, 不具有现代语言的一些特性.
语法细节
可选的语句结束符;, 这个很少见. 不过一般的规范都推荐不要真的省.
支持自增++,自减符号--, 相对Ruby, Python来说, 这个要更习惯.
switch和传统的C语言语法类似, 但是可以支持字符串的case.
支持NaN, null, undefined这三种表示类似无意义的量的方式, 有的时候这是混乱的根源. 也许还要再加上Infinity.
与大部分语言一样, javascript也分为原生类型和引用类型, 其中原生类型在拷贝, 参数传递和比较时时通过值的方式, 而引用类型都是通过引用的方式.
字符串为不可变类型, 任何的改变处理都是生成新字符串. 比较时为值比较. 字符串的值比较我个人认为时更加自然的做法, 比Java那种易做图的方式要自然的多. 你几乎要反复的告诉每一个新来的程序员, 字符串的值比较在java中要使用equals函数.
动态类型语言, 变量通过var定义.
支持用label方式的break和continue, 用于在多层循环中直接对外层循环进行break和continue.
完整并且传统的try, catch, finally异常机制. 除了C++没有finally不够完整以外, 几乎所有现在语言的异常都是这么设计的了.
字符串
javascript虽然说语法是类C的, 但是起点是Java, 所以尽管设计的面向对象系统虽然不是传统的模版式的, 但是javascript中的字符串都是对象.
"hello, world".length
// out: 12
上述的代码在现在已经不稀奇了, 但是相对C++来说还是更先进的.(可见C++多落后了)
var str = "hello" + "," + "world!";
console.log(str);
// out: hello,world!
字符串支持+操作符作为字符串连接.
javascript有个奇怪的地方是字符串和数字同时使用时:
console.log("3" + 4 + 5);
// out: 345
console.log(4 + 5 + "3");
// out: 93
也就是说, 相对一些语言(比如php)会自动的将字符串转为数字来说, javascript是倾向于将数字转为字符串的. 其实因为这种用法过于灵活, 即使是Ruby和Python这样以灵活著称的语言都是不允许这样的自动类型转换的.
更诡异的还不只这些, 对于加法来说是如此, 对于乘法来说又是另外一回事:
console.log("3" * 4);
// out: 12
console.log("3" * "4");
// out: 12
在乘法运算中, 因为javascript的字符串并没有像Ruby, Python一样对乘法的运算做出特殊解释(字符串的乘法表示重复), 所以默认会将字符串转为整数进行运算, 更诡异的是, 就算是两个字符串, 同样也会不报错的进行整数转换并且运算.
函数
函数在javascript中是第一类值, 同时还支持闭包. 这是javascript构成对象的基础.
function add(x, y) {
return x + y;
}
var sub = function(x, y) {
return x - y;
}
add(2, 3);
sub(5, 3);
// out: 5
// out: 2
有上述两种函数构造形式, 在调用时没有区别. 其中第一种方法和传统的函数定义方式一样, 而第二种实际上就是匿名函数的定义方式了. 只不过因为javascript中函数是第一类值, 所以可以很方便的赋值.
匿名函数
匿名函数也被称为lambda, 是个很方便和有用的特性, 加上对闭包的支持, 以此衍生了很多特性. 也因此成就了javascript类函数语言的特性.
var caller = function(fun, leftParam, rightParam) {
fun(leftParam, rightParam);
}
caller(function(a, b) { console.log(a+b); }, 10, 20);
// out: 30
如上例所示, 匿名函数很重要的一个应用就是用于很方便的构建高阶函数. 也许上例有些太生造, 最常用的一个特性可能就是排序了, 因为排序的规则可能很多, 一般排序函数都允许再传入一个函数作为参数, 来指定排序的规则. 比如再javascript中, 普通的排序函数有些奇怪, 默认是按照字符串排序的. 见下例:
a = [1, 3, 2, 10, 20];
console.log(a.sort());
// out: [ 1, 10, 2, 20, 3 ]
这在大部分时候估计都不是我们要的做法, 默认这样子我是第一次看见, 这就像字符串和整数想加最后变成字符串一样诡异, 也许javascript本身设计的时候是作为前端检验表单啥为主的语言, 所以对字符串这么偏爱吧. 幸运的是, sort函数还是可以传入一个函数作为排序规则的. 见下例:
a = [1, 3, 2, 10, 20];
console.log( a.sort( function(a, b) { return a - b; } ) );
// out: [ 1, 2, 3, 10, 20 ]
因为匿名函数和递归在javascript中使用的都比一般语言要多, 所以提供了arguments.callee用于表示当前调用的函数, 以方便匿名函数的递归调用, 事实上, 相对一般用函数名的递归调用方式, 这种方式要更加符合DRY(Dont Repeat Yourself)原则, 因为当函数名更改的时候, 不用再更改递归调用的函数名了.
var factorial = function(n) {
if (n <= 1) {
return 1;
}
else {
return n * arguments.callee(n - 1);
}
}
factorial(4);
// out: 24
更有意思的是, arguments.callee在javascript的严格模式中是禁止的, 简单的说就是这种调用方法是官方不推荐使用的错误用法, 在将来甚至有可能废除, mozilla的解释是这种更DRY的用例本身很”weak”, 但是却阻止了inline优化的进行, 因为这种方式是通过引用un-inlined函数实现的, 也只有函数un-inlined时, arguments.callee才可以引用到.
事实上, 我觉得这简直是因噎废食的做法, 因为现在虽然是这样实现的, 但是完全可以通过更好的语法分析, 然后进行编译器的优化, 而不是因此废弃这样有用的语法. 这种用法绝对不像是官方说的那么”weak”, 要知道, DRY几乎是软件设计领域头等重要的原则.
闭包
一个闭包就是一个函数和被创建的函数中的范围对象的组合. 因为闭包的强大特性和带来的方便, 很多传统的语言都逐渐了加入了对其的支持, 很多时候, 甚至被视为一个语言是否还算是跟上时代的标志.
function makeIncrementor(base) {
var count = base;
return function(num) {
count += num;
return count;
}
}
obj1 = makeIncrementor(10);
obj2 = makeIncrementor(20);
obj1(1);
// out: 11
obj1(1);
// out: 12
obj2(2);
// out: 22
obj2(2);
// out: 24
上面的例子较好的展示了闭包的特性, 可以获得上层函数的参数和变量, 并且各自互相独立, 因为闭包对局部状态的保存, 很多时候能当作一个对象来使用.
灵活的参数调用
function add(x, y) {
return x + y;
}
add(2, 3, 4);
add();
add(2);
&nbs
补充:web前端 , JavaScript ,
- 更多JAVA疑问解答:
- java怎么在线读取ftp服务器上的文件内容
- 关于程序员的职业规划
- HTML和JSP矛盾吗?
- java小程序如何打包?
- java怎么split路径文件名?
- jsp+javaBean中Column 'ordersPrice' specified twice的错误
- Java TCP/IP Socket网络编程系列
- 大家来讨论一下我到底该用什么好?Swing 还是 JavaFX
- 关于Hibernate实体自身多对一的抓取问题
- 关于apache2+tomcat群集出现的问题
- spring 获取上下文问题
- SSH 导入导出excel 谁有这块的资料吗?
- Ext TreePanel 刷新问题
- springmvc 加载一个jsp页面执行多个方法 报404
- checkbox数组action怎么向页面传值