看似最难的路可能才是最稳最快的——送给正在跟这本圣经死磕的你
一、基本类型和引用类型的值
1.基本类型指的是简单的数据段,包括以下几种:
Boolean Null Undefined Number 和String,这五种类型是按值访问的
而引用类型指的是那些可能有多个值构成的对象,这些对象保存在内存中,按照规定,javascript不能直接访问内存中的位置,也就是说不能够直接操作对象的 内存空间。在操作对象时,实际上操作的是对象的引用而不是对象本身。因此,引用类型的值是按引用访问的
2.动态的属性
定义基本类型值和引用类型值基本方法是类似的:创建一个变量并为该变量赋值。但是当这个值保存到变量后,对于不同类型值可以执行的操作大相径庭。
对于引用的值,我们可以为其添加属性和方法,也可以为其删除和修改属性和方法。赋值和保存对象的某个变量时,操作的是对象的引用,但是为其添加属性时操作的是对象本身。
var person = new Object();
person.name = "Nicholas";
alert(person.name);//Nicholas
如果对象不被销毁或这个属性不被删除,这个属性将一直存在
3.复制变量值
基本类型的值复制:会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
var num1 = 5;
var num2 = num1;
//此时num2也保存了5,但是这个5和num1的5是完全独立的
复制之前:
num1 5
复制之后(都在num2的内存中)
num2 5
num1 5
引用类型的值复制:同样也会将存储在变量对象中的值复制一份放到为新变量分配的内存空间中去,不同的是,这个副本其实是一个指针,而且这个指针指向存储在堆中的一个对象。复制操作完成之后,这两个变量指向的其实是同一个对象,因此改变其中一个变量就等于改变了这个对象,同样会影响到另一个变量。
4.传递参数
ECMAscript中所有函数都是按值传递的,什么意思呢?
在向函数传递引用类型的值的时候,会把这个值在内存中的地址复制一份传递到一个局部变量,这个局部变量也就是argument对象中的一个元素。因此这个局部变量的变化会反映到函数的外部。
传递数值类型时:
function adTen(num){
return num+10;
}
var count = 20;
var result = addTen(count);
alert(count);//还是20,并没有受到影响
alert(result);//30,反映内部的修改
传递对象时:
function setName(obj){
obj.name= "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name);//Nicholas
虽然外部person属性受到影响,但是这是因为person复制给obj后这两个对象的引用指向的是同一个对象,那么怎么来证明对象是按值传递呢?
function setName(obj){
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name);//Nicholas
如果person是按引用传递的,那么person就会被自动修改为指向其name属性为"Greg"的对象,但是事实上并没有。
这说明即使在函数内部改变了参数的值,原始的引用仍然保持不变。
5.检测类型:
1.使用typeof检测null时返回的是Object
2.使用typeof检测函数时返回的是function
3.使用typeof检测正则表达式时返回的是function
但是我们有时候并不关心某个类型是个对象,而是想知道它是什么类型的对象,因此就用到了instanceof
如:
person instanceof Object //返回true
colors instanceof Array //返回true
如果变量是给定引用类型(根据它的原型链来识别)就会返回true,否则返回false.
6.执行环境和作用域
(1)执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量核函数都保存这个在这个对象中
(2)根据ECMAscript实现所在的宿主环境不同,表示执行环境的对象也不一样。在web浏览器中,全局执行环境被认为是window对象
(3)某一个执行环境中的所有代码被执行完了之后会被销毁,其中保存的变量和方法也会被销毁。全局执行环境只有在关闭应用程序的时候才会被销毁,例如关闭浏览器或网页
(4)每一个函数都有自己的执行环境,当控制流执行到某一个函数时,把这个函数的执行环境推入一个环境栈中,当函数执行完整过后,从栈中弹出。
(5)当代码在一个函数中执行时,会创建一个变量对象的一个作用链。作用域的作用,是保证能够对执行环境进行访问的变量和函数的有序访问,作用域链的前端,始终都是当前所执行的代码所在的环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。
(6)作用域对象的下一个变量对象是它的上一级父环境的变量对象,再下一个是上上级父环境的变量对象,直到查找到全局执行环境。由此可知,全局执行环境的变量对象始终是作用域链的最后一个变量对象
(7)标识符解析是沿着作用域链一级一级搜索标识符的过程。搜索过程始终从作用域的前端开始,也就是从最小的执行环境往全局执行环境的方向进行搜索
总结:
a、内部环境可以访问外部环境的变量对象
var color = "red";
function changecolor(){
if(color ==="blue" ){/标识符解析到这里,会首先从作用域链的前端开始查找,发现没有这个变量又到它的父环境中去找
color = "red";//此时这个color变量实际上来着全局执行环境中的color变量
}else if(color ==="red"){
color = "blue";
}
}
b、外部环境不能访问内部环境的变量对象
未完待续......