javascript特性杂谈

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

最近语言学习有些疯狂, 从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不一样, 不具有类似confirmprompt等接口, 我用console.log来输出.

概要

JavaScript本身就是设计为一个前端语言, 据说设计只用了10天, 有些缺陷, 但是的确足够简单. 虽然JavaScript The Definitive Guide和大多数的语言书籍一样厚如砖头, 但是其实语言本身的介绍只有前面近200页, 这个厚度其实也就和R&D中描述的C语言差不多.
也就是因为设计比较简单, JavaScript也被一些人认为不算是现代语言, 不具有现代语言的一些特性.

语法细节

  1. 可选的语句结束符;, 这个很少见. 不过一般的规范都推荐不要真的省.
  2. 支持自增++,自减符号--, 相对Ruby, Python来说, 这个要更习惯.
  3. switch和传统的C语言语法类似, 但是可以支持字符串的case.
  4. 支持NaN, null, undefined这三种表示类似无意义的量的方式, 有的时候这是混乱的根源. 也许还要再加上Infinity.
  5. 与大部分语言一样, javascript也分为原生类型和引用类型, 其中原生类型在拷贝, 参数传递和比较时时通过值的方式, 而引用类型都是通过引用的方式.
  6. 字符串为不可变类型, 任何的改变处理都是生成新字符串. 比较时为值比较. 字符串的值比较我个人认为时更加自然的做法, 比Java那种变态的方式要自然的多. 你几乎要反复的告诉每一个新来的程序员, 字符串的值比较在java中要使用equals函数.
  7. 动态类型语言, 变量通过var定义.
  8. 支持用label方式的break和continue, 用于在多层循环中直接对外层循环进行break和continue.
  9. 完整并且传统的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: 345console.log(4 + 5 + "3");// out: 93

也就是说, 相对一些语言(比如php)会自动的将字符串转为数字来说, javascript是倾向于将数字转为字符串的. 其实因为这种用法过于灵活, 即使是Ruby和Python这样以灵活著称的语言都是不允许这样的自动类型转换的.
更诡异的还不只这些, 对于加法来说是如此, 对于乘法来说又是另外一回事:

console.log("3" * 4);// out: 12console.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: 11obj1(1);// out: 12obj2(2);// out: 22obj2(2);// out: 24

上面的例子较好的展示了闭包的特性, 可以获得上层函数的参数和变量, 并且各自互相独立, 因为闭包对局部状态的保存, 很多时候能当作一个对象来使用.

灵活的参数调用

function add(x, y) {  return x + y;}add(2, 3, 4);add();add(2);// out: 5// out: NaN// out: NaN

上述代码在调用时不会发生错误, 而是直接把后面的参数抛弃掉.
甚至于, 后面的两个参数不够的函数调用, 会返回NaN, 也不会发生错误.
本质上是因为一旦函数调用参数不够时, 后面的参数都会被置为undefined. 所以虽然javascript不支持默认参数, 但是可以模拟出来.

function mul(x, y) {  if (y === undefined) {    return x * 10;  }  return x * y;}mul(10);// out:  100

更灵活的语法是可以通过arguments变量来获取参数, 这样可以支持任意数量的函数参数.

function add() {    var sum = 0;    for (var i = 0, j = arguments.length; i < j; i++) {        sum += arguments[

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/rgjtfc/article/details/84025987