javascript小结

一、说明

Javascript是动态语言,由浏览器执行,是解析性语言

二、介绍  (大部分从JavaScript高级程序设计(第2版)摘录)

五种基本数据类型

基本类型值指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存中的一个位置。基本类型有五种,UndefinedNullBooleanNumberString。还有一种复杂数据类型——Object(本质上是由一组无序的名值对组成)

可以使用使用typeof操作符来获得数据类型:

l "undefined"——如果这个值未定义

l "boolean"——如果这个值是布尔值

l "string"——如果这个值是字符串

l "number"——如果这个值是数值

l "object"——如果这个值是对象或null

l "function"——如果这个值是函数

代码:

View Code
 1 var a;
 2 var b = 1;
 3 var c = 'c';
 4 var d = {};
 5 var e = null;
 6 var f = true;
 7 var g=function(){
 8     
 9 };
10 function show() {
11     var aType = 'a:' + typeof a;
12     var bType = 'b:' + typeof b;
13     var cType = 'c:' + typeof c;
14     var dType = 'd:' + typeof d;
15     var eType = 'e:' + typeof e;
16     var fType = 'f:' + typeof f;
17     var gType = 'g:' + typeof g;
18 
19     alert(aType + "\n" + bType + "\n" + cType + "\n" + dType + "\n" + eType + "\n" + fType+"\n"+gType);
20 }

函数

函数使用function关键字来声明,基本语法:

function functionName(arg0,arg1){

statements

}

 

注意下面几点:

l 如果遇到return ; 函数会停止执行并返回undefined

l 所有参数传递都是值,不可能通过引用传递参数

l 参数在内部是用一个数组来表示的。函数接受到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。函数体内可以通过arguments对象来访问这个参数。arguments对象只是与数组类似(并不是Array实例)。

l 没有传递值的命名参数将自动被赋予undefined值

l 如果定义了两个名字相同的函数,则后面的会覆盖前面的。

l 除了什么时候可以通过变量访问函数这一点区别外,函数声明与函数表达式的语法其实是等价的。

l 要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号。

l 函数有两个特殊的对象:arguments和this。arguments还有一个名叫callee的属性(指针),指向拥有这个arguments对象的函数。this引用的是函数据以执行操作的对象。

l 每个函数都包含两个属性:length和prototype。length表示函数希望接受的命名参数的个数。

l 每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

l 每个函数都有一个非标准的caller属性,该属性指向调用当前函数的函数。(只建议将该属性用于调试目的)。

l 函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

l arguments.callee是一个指向正在执行的函数的指针

l JavaScript中没有私有成员的概念,所有对象属性都是公有的。不过,在任何函数中定义的变量,都可以认为是私有变量,因此不能在函数的外部访问这些变量。但有两种方式创建特权方法

l 函数f1内部定义了另外一个函数f2,当f1执行完毕后,当f2仍存在,则其活动对象也不会被销毁,因为f2的作用域仍然在引用这个活动对象,f1的执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中,直到f2被销毁后,f1的活动对象才会被销毁。

 

构造函数

注意下面几点:

l 构造函数在不返回值的情况下,默认会返回新对象实例。

l 寄生构造函数模式:返回的对象与构造函数或者与构造函数的原型属性之前没有关系:也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。

l 组合继承=原型链+构造函数(会用到call或apply),是最常用的继承模式

l 寄生组合式继承是引用类型最理想的继承范式,YUI的YAHOO.lang.extend()方法采用了寄生组合继承,从而让这种模式首次出现在了一个应用非常广泛的javascript库中

引用类型

引用类型值是指那些保存在堆内存中的对象,意思是变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。

 

基本类型和引用类型在内存中保存情况如下图:

注意下面几点:

l 访问对象属性时一般都使用点表示法,不过也可以使用方括号表示法来访问对象属性,但属性必须以字符串的形式放在方括号中。

l Array数组,每一项可以保存任何类型的数据,它的大小是可以动态调整的。

l 使用索引设置数组的值时,如果超过了数组现有项数,数组会自动增加到该索引值加1的长度

l 数组的length属性不是只读的。

l 数组有栈方法和队列方法(IE对JavaScript的实现中存在一个偏差,其unshift方法总是返回undefined而不是数组的新长度)

l 引用类型与基本包装类型的主要区别就是对象的生存期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在与一行代码的执行瞬间,然后立即被销毁。

l 对基本包装类型的实例调用typeof会返回"object",而所有基本包装类型的对象都会被转换为布尔值true。

 

执行环境及作用域

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(如果还能在其他环境中被访问到,则不销毁)

环境的机制

存在环境栈,可把环境推入或弹出。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链。它的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。

作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。全局环境的变量对象始终都是作用域链中的最后一个对象。

标识符解析是沿着作用域链一级一级地搜索标识符的过程。

延长作用域链

try-catch语句的catch块和with语句可以延长作用域链,即当执行流进入其中一个语句时,在作用域链的前端临时增加一个变量对象,作用域链得到加长,该变量对象会在代码执行后被已移除。(作用域增加的临时变量对象都只是只读的,所以在它们中定义的变量,成了函数执行环境的一部分)

注意下面几点:

l JavaScript中没有块级作用域

l 变量在未经声明的情况下被初始化,那么该变量会被自动添加到全局环境中。

l 局部变量会在它们离开执行环境时自动被解除引用(解除的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收)

l 垃圾收集策略:标记清除、引用计数(不常使用,除了IE,如果有循环引用会出现问题,需要手动断开,即赋值为null,不然无法垃圾收集),不建议手动执行垃圾收集

页面注意下面几点:

l 在使用<script>嵌入JavaScript代码时,不能在代码的任何地方出现“</script>”字符串,会产生错误。因为按照解析嵌入式代码的规则,当浏览器遇到字符串“</script>"时,就会认为那是结束的标签。而通过把这个字符串分隔为两部分可以解决这个问题。例如alert("<scr"+"ipt"/>);

l 解析器对<script>元素内部的所有代码求值完毕以前,页面中的 其余内容都不会被浏览器加载或显示。

l 浏览器会按照<script>元素在页面最后能够出现的先后顺序对它们依次进行解析。

l javascript代码放在<head><body>的区别

l 变量定义没有使用var,会看作全局变量

l 大量使用with语句会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用with语句。

l switch可以使用任何数据类型,每个case的值不一定是常量,可以是变量,甚至是表达式。switch语句在比较值时使用的是全等操作符,因此不会发生类型转换(例如,字符串“10”不等于数值10)

 

三、理解

关于引用类型

javaC++中都采用了引用这个概念,但是二者的行为并不一样。java的引用其实更象c++中的指针,而非c++中的引用

引用其实是特殊的"指针",它只是没有指针运算(a++,a- -这些),这样会更安全。所以声明定义一个引用时,它都会在栈中建立一个空间。

var a={};

var b=a;

ab都代表同一个对象,而不是b拥有a的一个副本。

a存放了一个对象的内存地址,然后把地址赋值给了b,所以他们都指向同一个对象。注意的是,ab都拥有自己的栈空间。

 

关于string特殊的基本类型(希望有人可解答我疑问)

Javascript中的基本类型都存放在栈中,并且所占空间大小固定,可是string大小并不固定,它为什么也是基本类型?。下面是我对此的理解:

l 字符串值存放在栈中:

上面所说空间固定,指的是当已经存放了值后,值的大小已经确定了,无法改变。而并不是指string基本类型在存放值之前空间大小已经固定,所以可能出现有a,b两个string类型的值,它们在栈中的空间大小却不一样

赋值操作时:

var a="a";

var b=a;

此时栈中有ab两块空间,存放的值都是"a",注意它们在不同的栈空间中。

l 字符串值存放在堆中:

上面所说空间固定,是指基本类型在存放值之前已经确定空间大小了。则string类型必定是一个引用,它存放指向堆空间的一个地址。可为什么不把它归于基本类型呢?理由如下:

由于效率的原因,我们希望JS只复制对字符串的引用,而不是字符串的内容。但是另一方面,字符串在许多方面都和基本类型的表现相似,而字符串是不可变的这一事实(即没法改变一个字符串值的内容),因此可以将字符串看成行为与基本类型相似的不可变引用类型。

 

关于关键字this

在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象。一般在编译期确定下来,或称为编译期绑定。而在 JavaScript 中,this 是动态绑定,或称为运行期绑定的

我的理解是——this表示的是当前环境的变量对象。

匿名函数是全局性的理由是,它不存在除全局环境之外的任何环境中,也就是说没有引用可以访问得到它。这时的this是全局环境的window对象。

是否为匿名函数,主要看是否有引用指向它。

代码:

View Code
/*
 * 是否为匿名函数,主要看是否有引用指向它
 */

var ob={};

ob.a=function () {
    (function() {//匿名函数
        alert("a this:" + this);
    })();
}


ob.b=function(){
     alert("b this:" + this);
}

ob.c=function(){
    return function(name){
       alert(name+" this:" + this); 
    };
}

ob.d=ob.c();//ob.c()返回一个匿名函数,但是ob.d指向了它,则它不再是匿名函数,this执行ob

function show() {
    ob.a();
    ob.b();
    ob.c()('c');//ob.c()得到一个匿名函数,可是却没有指针指向它,所以执行后this是window
    ob.d('d');
}

参考:JavaScript高级程序设计(第2版)

原文地址:https://www.cnblogs.com/dann/p/2733184.html