你的位置:首页 > Java教程

[Java教程]【原创教程】JavaScript详解之语法和对象


JavaScript的好的想法:函数、弱类型、动态对象和一个富有表现力的对象字面量表示法。
JavaScript的坏的想法:基于全局变量的编程模型。
 
好了,不管他是好的还是坏的,都是我的最爱,下面直接上干活:
一、JavaScript语法
 
1、空白:空白能可能的表现形式为格式化字符或注释的形式。
     有些空白不能省,有些空白可以被移除。
     注释,/*多行注释*/,不建议在代码块中间使用这种注释,因为可能会出现语法错误,所以多行注释对于被注释的代码来说是不安全的。
比如:
/*
     var r_m_a = /a*/.match(s);
*/
这就导致了一个语法错误,所以建议避免使用/*  */注释,而改使用//单行注释来注释代码。
那么多行注释在什么时候使用呢,在对一个方法或者其他代码块进行语言说明其用途和作者等信息时候使用,比如:
/*返回两个数的和*/
function sum() {.......}
 
2、标识符
标识符由字母、数字或下划线组成的。标识符不能使用下面这些保留字:
abstract
boolean break byte 
case catch char class const continue 
debugger default delete do double
else enum export extends
false final finally float for function
goto
native new null
package private protected public
return 
short static super switch synchronized
this throw throws transient true try typeof
var volatile void
while with
在这个列表中的大部分保留字js都没有使用,这里列出了这么多,你不需要去刻意记忆,用的时候注意下,同时在编译出错的时候能够知道为什么出错了。
 
3、数字
int float double?不不不,JavaScript中只有单一的数字类型,它在内部被表示为64位的浮点数。所以1和1.0是一样的。
其中有些特殊的数字:
     值NaN是一个数值,他表示一个不能产生正常结果的运算结果,NaN不等于任何值,包括他自己,是的没错,他自己都不等于他自己,你还希望谁和它相等呢。那如何检测一个变量是不是NaN呢,用函数isNaN(number)来检测NaN,返回Boolean值;
     值Infinity表示所有大于1.77.....e+308的值,即是无穷大。那无穷小呢,加个负号呗。
数字拥有方法,例如:Math.floor( number ) 发放将一个数字转换为一个整数。
这里有一个需要注意的点,就是数值类型不含有方法,数值对象才有方法,什么是数值类型呢,像1233,231,34等这些都是数值类型,而如果 我这样来:
var  num = 234.567;
这时候mun就是数值对象,它拥有方法。
 
4、字符串
字符串字面量可以被包围在单引号或者双引号中,\ 是转义字符。JavaScript在被创建的时候,Unicode是一个16位的字符集,所以所有的字符都是16位的;字符串是没有字符类型的。要表示一个字符,只须创建仅包含一个字符的字符串即可。
上面有说到“转义字符”,那么什么是转义字符呢,转义字符允许把那些正常情况下不被允许的字符插入到字符串中,比如反斜线、引号和控制字符。 \ u 约定允许指定用数字表示字符码位。
"A" === "\u0041"
字符串有一个length属性,例如:“skylor”.length 是6.
还有一点是需要注意的,字符串是不可变的,一旦字符串被创建了,就永远无法改变它。但是通过 + 运算符去链接其他的字符串从而得到一个新的字符创是很容易的一件事。   且:::两个包含着完全相同字符且字符顺序相同的字符串被认为是相同的字符串。so:
's' + 'k' + 'y' + 'l' + 'o' + 'r' === 'skylor'
这是个true!同样的 字符串也有一些方法。 
 
5、语句
6、表达式
     字面量(比如字符串或数字)、变量、内置的值(true、flase、null、undefined、NaN和Infinity)、以new 前导的调用表达式、以delete前导的属性存取表达式、包在圆括号中的表达式、以一个前缀运算符或者是后面跟着运算符、函数调用、属性存取表达式等。
     运算符的优先级,这里就不说了。
     
7、函数
function关键字定义的大括号抱起来一段代码: function + 函数名 + (+ 参数 +) + { }抱起来的代码段; 
function fn(args ) {
     //函数要实现的功能代码;
}
也可以把函数赋值给一个变量:
var fn = function(args){
     //函数要实现的功能代码;
}
这两个是有区别的;后面再详细说明。
 
二、对象
 
1、对象字面量
var empty_object = {};
 
var  blog_name = {
     "first-name": "Skylor",
     "last-name": "min"
}
对象字面量是可以嵌套的;
 
 
2、检索
两种方法:
[]  一般用中括号的情况是,后面字符串是一个数字,或者是非合法标识符,或者是个变量等
.  一般用点的情况是,它是一个合法的JavaScript标识符且并非保留字。
两个都可以用的时候,推荐用 . 点表示法,因为它更紧凑且可读性更好。
 
3、更新
 
对象中的值可以通过赋值语句来更新。如果有就更新,如果没有就扩充。
 
4、引用
 
对象通过引用来传递,它们永远不会被拷贝。这里有必要讲下拷贝,JavaScript的拷贝我们分为浅拷贝和深拷贝。下面我们来谈谈JavaScript中的浅拷贝以及深拷贝。
首先我们来看看浅拷贝:
什么是浅拷贝,就是对于有嵌套对象的对象进行拷贝的时候,只拷贝了一层,对象里面的Array、object等嵌套的对象都不拷贝过来。简单的没有嵌套对象的对象,我们用浅拷贝是没有问题的,对于复杂点的对象,就出现大问题了。下来我们来看一个具体的例子:
var original = {
     num: 1,
     str: 'old string',
     obj: {
          obj_1: "old obj_1"
     },
     arr: [
         "array string",
           {
               arr_obj_1: "old arr obj 1"
          } 
     ]
}
看上面的这是一个比较复杂的对象,对象的里面包含了对象和数组。我们来构建一个拷贝函数:
var extend = function(result, source){
     for(var key in source) {
         result[key] = source[key];
     }
     return result;
}
好,有了这个拷贝函数,下面我们来测试下程序:
var copy_original = extend({}, original);
copy_original.str = "new String";
copy_original.obj.obj_1 = "new obj tring";
copy_original.arr[1].arr_obj_1 = "new Array obj String";
copy_original.arr[0] = "new Arrat string";
 
以上,我们是不是只改变了我们拷贝过来的copy_original的值啊,那么此时原来的对象ofiginal是不是应该还是原来的值,我们来运行看看就知道了{动手啊,一定要动手}。此时只有str和num保持不变了,其他的和我们拷贝后的对象修改后的值一样了。
这样看来,如果我们不想改变原来的对象,我们需要对对象里面的对象和数组需要特殊待遇一下,当然我们要给她们两特殊照顾,就得先认识她们,下面是认识她们这两个美女的函数:
 
var is = function (obj,type) {
 
  var toString = Object.prototype.toString;
 
  return (type === "null" && obj === null) ||
 
    (type === "undefined" && obj === undefined ) ||
 
    toString.call(obj).slice(8,-1) === type;
 
};
类型识别,用来认识对象和数组来着,有人要说了不是有typeof吗,typeof是不可靠的,因为Array会返回'object'。好,认识了她们,我们再来处理,怎么样才能深拷贝呢,我们的深拷贝函数应该拥有处理特殊处理值为对象或数组的键值对。 对于它们,程序会为目标对象先创建一个新对象与数组,然后再一层层拷下去。我们可以看到它并没有用hasOwnProperty,换言之,连原型中可遍历的属性都给它翻个底朝天。这样一层层的拷贝下去,于是便有了下面的(性能比较差,一般情况下线上项目谨慎使用):
 
 var deepCopy = function(result, source){
 
        for(var key in source) {
 
          var copy = source[key];
 
          if(source === copy) continue;  //如window.window === window,会陷入死循环,需要处理一下
 
          if( is(copy,"Object") || is(copy,"Array") ){
 
            result[key] = deepCopy(result[key] || {}, copy);
 
          } else {
 
            result[key] = copy;
 
          }
 
        }
 
        return result;
 
      };
 
可以用这个深拷贝函数来实践下上面类似的测试程序,得出结论,你便知晓了一切。关于JavaScript的浅拷贝和深拷贝网上的各式各样,但万变不离其宗,知道了为啥,你就能写出属于你自己的deepCopy function。
 
5、原型 prototype
 
每个对象都链接到一个原型对象,并且它可以从中继承属性。所有通过对象字面量创建的对象都链接到Object.prototype 这个JavaScript中标准的对象上。
 
6、反射
 
检查对象并确定对象有什么属性是一件很容易的事,只要试着去检索改属性并验证取得的值,typeof这个操作符,没错,是操作符,对确定属性的类型很有帮助。需要注意的是typeof,原型链中的任何属性也会产生一个值,有两个方法去处理这些不需要的属性:
     第一个是让你的程序检查并剔除函数值。
另一个方法是使用hasOwnProperty 方法,如果对象拥有独有的属性,他将返回true,hasOwnProperty方法不会检查原型链。
ex.hasOwnProperty('number');   //true
ex.hasOwnProperty('constructor'); // false
 
7、枚举
for in 语句可用来遍历一个对象中的所有属性名,上面的深拷贝函数我们就有用到了,该枚举过程将会列出所有的属性-----包括函数和一些你可能不关心的属性,所有有必要过滤掉那些你不想要的值。最为常用的过滤器是hasOwnProperty方法,以及typeof来排除函数:还有一点需要注意的是for in 语句对属性名出线的顺序是不确定的,这一点需要注意下。
 
8、删除
delete运算符可以用来删除对象的属性,会益处对象中确定包含的属性,它不会触及原型链中的任何对象。
有一点需要注意的是,你删除了对象的属性可能会让来自原型链中的属性浮现出来。
 
好,这节课我们讲了JavaScript的基本语法和对象的一些详细内容,后面有些需要多多练习,修改代码调试。我们下期见。