基本类型和引用类型的值前端
ECMAScript变量可能包含两种不一样数据类型的值:
浏览器
1.基本类型值:指简单的数据段。(5种基本数据类型:Undefined、Null、Boolean、Number和String,这5种基本数据类型是按值访问的,能够直接操做保存在变量中的实际的值)函数
2.引用类型值:指那些可能由多个值构成的对象。(引用类型的值是保存在内存中的对象。与其余语言不一样,JavaScript不容许直接访问内存中的位置,不能直接操做对象的内存空间)spa
动态属性指针
定义基本类型值和引用类型值的方式都是建立一个变量并为该变量赋值。code
对于引用变量的值,能够添加其属性和方法,也能够改变和删除其属性和方法:对象
var person = new Object(); // 建立一个对象并保存在变量person中 person.name = "benjamin"; // 给person对象添加一个name的属性,并将字符串值"benjamin"赋值给这个属性 console.log(person.name); // 经过点运算符访问这个属性,结果输出"benjamin"
若是对象不被销毁或这个属性不被删除,这个属性将会一直存在。blog
而对于基本类型的值,则不能添加属性,虽然不会致使任何错误:ip
var person = "susan"; // 建立一个变量person赋值基本类型字符串值"susan" person.age = 27; // 伪装能加属性age并赋值数值类型27 console.log(person.age); // 结果输出undefined(属性丢失,添加失败,但不会报错)
以上说明了只能给引用类型值动态添加、改变和删除属性(person.age = undefined)。内存
复制变量值
1.基本类型值的复制:
从一个变量向另外一个变量复制基本类型的值,会在变量对象上建立一个新值,而后把该值复制到为新变量分配的位置上。
var num1 = 666; // num1中保存了666 var num2 = num1; // 用num1的值来初始化num2,num2中也保存了值666 console.log(num2); // 结果输出666
这里num2中的666和num1中的666是彻底独立的,对这两个变量进行任何操做都不会相互影响。
2.引用类型值的复制:
从一个变量向另外一个变量复制引用类型的值时,一样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不一样的是,这个值的副本其实是一个指针(原来的变量存储的值也是指针),而这个指针指向存储在堆中的一个对象。复制操做结束后,两个变量实际上将引用同一个对象。所以若是改变其中一个变量,就会影响另一个变量。
var obj1 = new Object(); var obj2 = obj1; obj1.name = "benjamin"; console.log(obj2.name); // 结果输出"benjamin"
传递参数
ECMAScript中全部函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另外一个变量同样。基本类型值的传递如同基本类型变量的复制同样,引用类型值的传递如同引用类型变量的复制同样。
基本类型值的传递:
function addOne(num) { // 参数num其实是函数的局部变量 num += 1; return num; } var count = 1; var result = addOne(count); // count的值(数值1)被复制给参数num,变量count和参数num互相不认识,仅仅具备相同的值 console.log(count); // 1,没有变化(函数内部参数num变化不影响外部count变量),说明是传参num是按值传递,不是按引用传递 console.log(result); // 2
引用类型值的传递:
function setName(obj) { obj.name = "kevin"; // obj和person引用的是同一个对象,对obj的任何操做都直接影响person obj = new Object(); // 改变了obj的值(指针),接下来的任何操做都和person变量指向的对象无关 obj.name = "mark"; // 不影响原来的person } var person = new Object(); // 变量person中存储的值其实是指针,该指针指向一个对象 setName(person); // 在函数内部,obj和person引用的是同一个对象(按值传递,传递的是指针) console.log(person.name); // 结果输出"kevin"
若是person是按引用传递的,那么在执行obj = new Object()的时候,person指向的name属性值为"kevin"的对象就会被覆盖为新的、name属性值为"mark"的对象(事实上没有)。事实上,当在函数内部重写obj的时候,这个局部变量引用的就是一个局部对象了,这个局部对象会在函数执行完毕以后当即被销毁。
检测类型
1.typeof操做符
主要用于检测基本数据类型,肯定一个变量是否字符串、数值、布尔值、仍是undefined。若是变量的值是一个对象或null,则返回"object"。
var s = "james"; var b = true; var i = 25; var u; var n = null; var o = new Object(); console.log(typeof s); // "string" console.log(typeof i); // "number" console.log(typeof b); // "boolean" console.log(typeof u); // "undefined" console.log(typeof n); // "object" console.log(typeof o); // "object"
typeof操做符检测基本数据类型颇有用,可是对于检测引用类型的值用处不大,由于一般咱们须要知道的是某个值是什么类型的对象,而不是只知道它是对象。
2.instanceof操做符
用于检测引用数据类型。若是变量给定引用类型的实例(根据原型链识别),那么instanceof操做符就会返回true,不然返回false。
var people = new Array(); var person = "ben"; console.log(people instanceof Object); // true console.log(people instanceof Array); // true console.log(people instanceof RegExp); // false console.log(person instanceof Object); // false
ECMAScript规定全部引用类型的值都是Object的实例。使用instanceof操做符检测基本类型的值,该操做符始终会返回false,由于基本类型不是对象。
执行环境及做用域(难)
几个概念:
1.执行环境(execution context)
执行环境定义了变量或函数有权访问的其余数据,决定了它们各自的行为。
全局执行环境是最外围的一个执行环境。在Web浏览器中,全局执行环境能够认为是window对象,所以全部全局变量和函数都是做为window对象的属性和方法建立的。
每一个函数都有本身的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行以后,栈会将其环境弹出,把控制权返回给以前的执行环境。ECMAScript程序中的执行流正是由这个方便的机制控制着。
当某个执行环境中的全部代码执行完毕后,该环境被销毁,保存在其中的全部变量和函数也随之销毁(全局执行环境直到应用程序退出,例如关闭网页或浏览器的时候才会被销毁)。
2.变量对象(variable object)
每一个执行环境都有一个与之关联的变量对象,环境中定义的全部变量和函数都保存在这个对象中。虽然咱们在编写代码没法访问这个对象,但解析器在处理数据时会在后台使用它。
3.做用域链(scope chain)
当代码在一个环境中执行时,会建立变量对象的一个做用域链。做用域链的用途是保证对执行环境有权访问的全部变量和函数的有序访问。
做用域链的前端始终是当前执行的代码所在环境的变量对象。
若是这个环境是函数,则将其活动对象做为变量对象。活动对象在最开始时只包含一个变量,即arguments对象。做用域链的下一个变量对象来自包含环境,而下一个变量对象则来自下一个包含环境,这样一直延续到全局执行环境,全局执行环境的变量始终都是做用域链中的最后一个对象。
4.活动对象(activation object)
当函数被调用时,一个特殊的对象,即活动对象将会被建立,这个对象中包含形参和arguments对象。活动对象以后会做为函数上下文的变量对象来使用。
这样理解:活动对象除了变量和函数声明以外,它还存储了形参和arguments对象。