JavaScript学习笔记(一)

一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:
核心(ECMAScript) : 描述了JavaScript 的语法和基本对象;
文档对象模型(DOM):描述了处理网页内容的方法和接口;
浏览器对象模型(BOM):描述了与浏览器进行交互的方法和接口。

这里写图片描述


ECMAScript 语法

  • JavaScript 对大小写是敏感的

变量

  • 变量是存储信息的容器。变量是弱类型的,使用 var 关键词来声明变量,可以将它初始化为任意值。声明后未使用的变量,其值实际上是 undefined。
var carname;    //undefined
  • JavaScript 变量可以重新声明,如果重新声明 JavaScript 变量,该变量的值不会丢失:
var carname="Volvo";
var carname;  //Volvo
  • JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型:
var x                // x 为 undefined
var x = 6;           // x 为数字
var x = "Bill";      // x 为字符串
  • 变量声明不是必须的,ECMAScript 的解释程序遇到未声明过的标识符时,用该变量名创建一个全局变量,并将其初始化为指定的值。

  • 字符串可以是引号中的任意文本。您可以使用单引号或双引号:

var carname="Bill Gates";
var carname='Bill Gates';
  • JavaScript 数组:
    下面的代码创建名为 cars 的数组:
var cars=new Array();
cars[0]="Audi";
cars[1]="BMW";
cars[2]="Volvo";

或者 (condensed array):

var cars=new Array("Audi","BMW","Volvo");

或者 (literal array):

var cars=["Audi","BMW","Volvo"];

数组下标是基于零的,所以第一个项目是 [0],第二个是 [1],以此类推。

变量的类型

在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值。

原始值

存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
ECMAScript 有 5 种原始类型(primitive type),即 Undefined、Null、Boolean、Number 和 String。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 - 栈中。这样存储便于迅速查寻变量的值。注意String类型在javascript里是原始类型,它是唯一没有固定大小的原始类型。

引用值

存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。

对变量或值调用 typeof 运算符将返回下列值之一:

  • undefined - 如果变量是 Undefined 类型的
  • boolean - 如果变量是 Boolean 类型的
  • number - 如果变量是 Number 类型的
  • string - 如果变量是 String 类型的
  • object - 如果变量是一种引用类型或 Null 类型的
Undefined 类型

当声明的变量未初始化时,该变量的默认值是 undefined。可以用下面的代码段测试该变量的值是否等于 undefined:

var oTemp;
alert(oTemp == undefined); //true
alert(typeof oTemp); //输出 "undefined"

值 undefined 并不同于未定义的值。但是,typeof 运算符并不真正区分这两种值。即没有声明过的变量也可以用typeof运算符,但是其他运算符不能使用

var oTemp;

alert(typeof oTemp);  //输出 "undefined"
alert(typeof oTemp2);  //输出 "undefined"

alert(oTemp2 == undefined); //这句会报错,oTemp2没有声明
Null 类型

另一种只有一个值的类型是 Null,它只有一个专用值 null,即它的字面量。值 undefined 实际上是从值 null 派生来的,因此 ECMAScript 把它们定义为相等的。

alert(null == undefined);  //输出 "true"

尽管这两个值相等,但它们的含义不同。undefined 是声明了变量但未对其初始化时赋予该变量的值,null 则用于表示尚未存在的对象

NaN 属性

NaN 属性是代表非数字值的特殊值。该属性用于指示某个值不是数字。可以把 Number 对象设置为该值,来指示其不是数字值。可以使用 isNaN() 全局函数来判断一个值是否是 NaN 值。

NaN 与所有值都不相等,包括它自己,即 NaN != NaN


类型转换

转换成字符串

ECMAScript 的 Boolean 值、数字和字符串的原始值的有趣之处在于它们是伪对象,这意味着它们实际上具有属性和方法。都有 toString() 方法,可以把它们的值转换成字符串。

Boolean 类型的 toString() 方法只是输出 “true” 或 “false”。
Number 类型的 toString() 方法比较特殊,它有两种模式,即默认模式和基模式。
采用默认模式,toString() 方法只是用相应的字符串输出数字值(无论是整数、浮点数还是科学计数法)。
采用 Number 类型的 toString() 方法的基模式,可以用不同的基输出数字,例如二进制的基是 2,八进制的基是 8,十六进制的基是 16。

var bFound = false;
alert(bFound.toString());   //输出 "false"

var iNum1 = 10;
var iNum2 = 10.0;
alert(iNum1.toString());    //输出 "10"
alert(iNum2.toString());    //输出 "10"

alert(iNum.toString(2));    //输出 "1010"
alert(iNum.toString(8));    //输出 "12"
alert(iNum.toString(16));   //输出 "A"
转换成数字

ECMAScript 提供了两种把非数字的原始值转换成数字的方法,即 parseInt() 和 parseFloat()。只有对 String 类型调用这些方法,它们才能正确运行;对其他类型返回的都是 NaN。
parseInt() 方法首先查看位置 0 处的字符,判断它是否是个有效数字;如果不是,该方法将返回 NaN,不再继续执行其他操作。但如果该字符是有效数字,该方法将查看位置 1 处的字符,进行同样的测试。这一过程将持续到发现非有效数字的字符为止,此时 parseInt() 将把该字符之前的字符串转换成数字。
parseInt() 方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。基是由 parseInt() 方法的第二个参数指定的。

var iNum1 = parseInt("12345red");   //返回 12345
var iNum1 = parseInt("0xA");    //返回 10
var iNum1 = parseInt("56.9");   //返回 56
var iNum1 = parseInt("red");    //返回 NaN

var iNum1 = parseInt("10", 2);  //返回 2
var iNum2 = parseInt("10", 8);  //返回 8
var iNum3 = parseInt("10", 10); //返回 10
强制类型转换

ECMAScript 中可用的 3 种强制类型转换如下:

  • Boolean(value) - 把给定的值转换成 Boolean 型;
  • Number(value) - 把给定的值转换成数字(可以是整数或浮点数);
  • String(value) - 把给定的值转换成字符串;
Object 对象

ECMAScript 中的所有对象都由这个对象继承而来,Object 对象中的所有属性和方法都会出现在其他对象中。
Object 对象具有下列属性:
constructor
对创建对象的函数的引用(指针)。对于 Object 对象,该指针指向原始的 Object() 函数。
Prototype
对该对象的对象原型的引用。对于所有的对象,它默认返回 Object 对象的一个实例。

instanceof 运算符

在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。与 typeof 方法不同的是,instanceof 方法明确地确认对象为某特定类型。

var oStringObject = new String("hello world");
alert(oStringObject instanceof String); //输出 "true"


运算符

ToBoolean 操作
参数类型结果
Undefinedfalse
Nullfalse
Boolean结果等于输入的参数(不转换)
Number如果参数为 +0, -0 或 NaN,则结果为 false;否则为 true。
String如果参数为空字符串,则结果为 false;否则为 true。
Objecttrue


对undefined 类型进行NOT、AND 和 OR操作会报错。

等性运算符

ECMAScript 提供了两套等性运算符:等号和非等号用于处理原始值,全等号和非全等号用于处理对象。
等号由双等号(==)表示,当且仅当两个运算数相等时,它返回 true。非等号由感叹号加等号(!=)表示,当且仅当两个运算数不相等时,它返回 true。为确定两个运算数是否相等,这两个运算符都会进行类型转换。
执行类型转换的规则如下:

  • 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
  • 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
  • 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。
  • 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。

在比较时,该运算符还遵守下列规则:

  • 值 null 和 undefined 相等。
  • 在检查相等性时,不能把 null 和 undefined 转换成其他值。
  • 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。
  • 如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。

重要提示:即使两个数都是 NaN,等号仍然返回 false,因为根据规则,NaN 不等于 NaN。

表达式
null == undefinedtrue
“NaN” == NaNfalse
5 == NaNfalse
NaN == NaNfalse
NaN != NaNtrue
false == 0true
true == 1true
true == 2false
undefined == 0false
null == 0false
“5” == 5true
全等号和非全等号

全等号由三个等号表示(===),只有在无需类型转换运算数就相等的情况下,才返回 true。
非全等号由感叹号加两个等号(!==)表示,只有在无需类型转换运算数不相等的情况下,才返回 true。

var sNum = "66";
var iNum = 66;
alert(sNum == iNum);    //输出 "true"
alert(sNum === iNum);   //输出 "false"

alert(sNum != iNum);    //输出 "false"
alert(sNum !== iNum);   //输出 "true"


ECMAScript 函数

函数是由这样的方式进行声明的:关键字 function、函数名、一组参数,以及置于括号中的待执行代码。

function functionName(arg0, arg1, ... argN) {
  statements
}
arguments 对象

在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。用 arguments[0] 也可以访问这个值,即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。
arguments.length 可以返回参数的个数,ECMAScript 不会验证传递给函数的参数个数是否等于函数定义的参数个数。任何遗漏的参数都会以 undefined 传递给函数,多余的函数将忽略。JavaScript通过这种方法就实现了类似java里的函数重载。

function howManyArgs() { //函数都可以不声明参数
  alert(arguments.length);
}

howManyArgs("string", 45);
howManyArgs();
howManyArgs(12);
Function 对象(类)

ECMAScript 的函数实际上是功能完整的对象。
Function 类可以表示开发者定义的任何函数。
用 Function 类直接创建函数的语法如下:

var function_name = new Function(arg1, arg2, ..., argN, function_body)

在上面的形式中,每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。


闭包(closure)

函数可以使用函数之外定义的变量。Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

   var n=999;
  function f1(){
    alert(n);
  }
  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

  function f1(){
    var n=999;
  }
  alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

  function f1(){
    n=999;
  }
  f1();
  alert(n); // 999

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

  function f1(){
    var n=999;
    function f2(){
      alert(n); 
    }
    return f2;
  }
  var result=f1();
  result(); // 999

上面代码中的f2函数,就是闭包。闭包可以用在许多地方。它的最大用处有两个:

  • 一个是前面提到的可以读取函数内部的变量
  • 另一个就是让这些变量的值始终保持在内存中

如下代码:

  function f1(){
    var n=999;
    nAdd=function(){n+=1}  //nAdd 就是一个全局变量
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

思考题

代码片段一:

    var name = "The Window";
    var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());  //"The Window"

代码片段二:

   var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  alert(object.getNameFunc()()); //"My Object"


更多精彩Android技术可以关注我们的微信公众号,扫一扫下方的二维码或搜索关注公共号:


Android老鸟

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值