1. 对象的toString()和valueOf().
- toString() 和Java中的toString() 一样
- valueOf(), 和toString() 都是用来进行类型转换的方法, 但是valueOf只是简单返回对象本身.
1 var d = new Date(2015,12,07); 2 console.log(d.valueOf()); //返回了对象本身,然后再调用对象的toString()
2. JavaScript中变量的特征
- 应当在使用之前声明, 声明如: var i,sum="hello",j=1;
- 可以是任意类型, 可以先使用数字初始化一个变量, 然后再将字符串赋值给这个变量(所以重复声明变量是合法且无害的).
- ECMAScript3中给一个未声明变量赋值,该变量会变成全局对象的一个同名属性, 像全局变量一样工作; 在ECMAScript5中则会报错, 建议都使用var声明(局部变量必须使用var语句声明=>为了避免误改全局变量).
- 在函数体内,局部变量的优先级高于同名的全局变量.
1 var scope = "global"; 2 function checkscope(){ 3 var scope = "local"; 4 return scope; 5 } 6 console.log(checkscope()); //"local"
- 没有块级作用域, 而是函数作用域.
3. 函数作用域和声明提前
- js的函数作用域是指声明在函数内的所有变量在函数体内都始终可见, 这就意味着变量在声明之前就已经可用, 这种行为就称为声明提前. 具体讲就是js函数内声明的所有变量(不涉及初始化和赋值),都被提前至函数体的顶部.
1 function test(obj){ 2 var i=0; 3 if(typeof obj == "object"){ 4 var j=0;//在整个函数体内都是有定义的,不仅仅是这个代码段 5 for(var k=0;k<10;++k){ 6 console.log(k); 7 } 8 console.log(k);//在外部也可以引用. 9 } 10 console.log(j); 11 } 12 test({}); 13 var scope = "global"; 14 function test2(){ 15 console.log(scope);//"undefined", 因为声明提前的原因,这里并不会引用全局变量,同时赋值还没有开始. 16 var scope = "local";//"local" 17 console.log(scope); 18 } 19 test2();
4. 作用域链
- 下面是javascript权威指南里面的解释:
> 将一个局部变量看作是自定义实现的对象的属性, 每一段代码(全局代码或者函数) 都有一个与之关联的作用域链, 这个作用域链是一个对象列表或者链表, 这组对象定义了这段代码 "作用域中" 的变量.
> 变量解析: 当js需要查找变量x的值时, 就从链中的一个对象开始查找, 查找这个对象是否有名为x的属性, 如果过有就直接使用这个属性, 否则继续查找下一个对象, 直到找到或者抛出一个引用错误异常.
> js最顶层代码中(即不包含在任何函数定义内的代码), 作用域链由一个全局对象(如window对象)组成; 在不包含嵌套的函数体内, 作用域链上有两个对象([定义函数参数和局部变量的对象, 全局对象]); 在一个嵌套的函数体内, 作用域链上至少有3个对象.
> 当定义一个函数时, 实际上是保存一个作用域链, 当调用这个函数时, 它创建一个新的对象来存储它的局部变量, 并将这个对象添加至保存的那个作用域链上, 同时创建一个新的更长的表示函数调用作用域的"链".
> 对于嵌套函数而言: 每次调用外部函数时, 内部函数又会重新定义一遍, 因为每次调用外部函数的时候, 作用域链可能都不同.
- 引用一篇讲得比较好的 博文, 概括一下主要就是:
> 函数是对象, 有许多属性, 其中一个内部属性是 [[scope]], 在函数定义时会创建一个对象(scope-chain), [[scope]]属性指向这个对象, 这个对象会保存一个全局对象(包含了所有全局信息).
> 调用函数是, js引擎创建一个execution context对象, 有一个作用域链属性, 这个属性由两部分组成:
- 活动对象: 由函数的参数, 局部变量, 命令参数arg, this组成, 在作用域链的顶端. 调用结束后销毁.
- 其他对象: 全局对象和其他对象就按照函数的作用域链的顺序依次复制到此作用域链的后面.
> 函数执行过程中每遇到一个变量都会从作用域链的头部去遍历解析.
> 优化: 由于全局对象在作用域的后面(至少在活动对象的后面), 所以尽可能使用局部变量(或者将全局变量先保存在局部变量中, 然后在后面多次使用, 如: var doc = document.getElementById("..."); doc.... )
> with语句和 try-catch会改变作用域链
- with: 创建一个包含with语句参数的(如with(document)中的document)的 with对象, 并推到作用域链的顶端. 这样活动对象的位置往后移动了, 所以性能可能会降低. ----避免使用with
- try-catch: 当try发生错误时, 跳到catch中, 然后把异常对象推入一个可变对象并置于作用域的头部, catch中的变量也会被放入在这个对象中, 执行完catch之后会恢复作用域链.---- 委托给处理器方法