JavaScript基本概念、变量及数据类型、函数及参数、作用域与执行环境、垃圾收集机制。
三个部分
- ECMAScript JS本身
- ES 6 就是不同阶段的规范
- DOM
- 针对HTML的编程接口
- BOM
- 浏览器对象模型
- 操作浏览器本身
变量
ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。换句话说,每个变量仅仅是一个用于保存值的占位符而已。
由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。
基本类型与引用类型
ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。
基本类型值指的是简单的数据段
- 5 种基本数据类型:Undefined、Null、Boolean、Number 和String
- 在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型
- 按值访问,因为可以操作保存在变量中的实际的值。
- 赋值时,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上
- 在内存中占据固定大小的空间,因此被保存在栈内存中
引用类型的值是保存在内存中的对象。
- 与其他语言不同,JavaScript 不允许直接访问内存中的位置,
也就是说不能直接操作对象的内存空间。 - 在操作对象时,实际上是在操作对象的引用而不是实际的对象。
- 为此,引用类型的值是按引用访问
- 存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量
- 引用类型的值是对象,保存在堆内存中
- 与其他语言不同,JavaScript 不允许直接访问内存中的位置,
确定一个值是哪种基本类型可以使用
typeof
操作符,而确定一个值是哪种引用类型可以使用instanceof
操作符。
基本数据类型
1. undefined
当一个变量声明但未初始化时,就会被赋予undefined值。
var msg;
msg == undefined // true 可以使用undefined关键字
typeof(msg) == "undefined" //true typeof运算符返回的是字符串
2. null
当一个变量是为了保存一个对象,但没办法立即初始化的时候,应该为之分配一个null 值
3. boolean
其它数据类型转化为布尔型的转化规则。
数据类型 | 转换为true | 转换为false |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | “”(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN |
Object | 任何对象 | null |
Undefined | n/a | undefined |
4. number
NaN (not a number)
用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以0 都会导致错误,从而停止代码执行。但在ECMAScript 中,任何数值除以0 会返回NaN,因此不会影响其他代码的执行。
- 任何涉及NaN的操作(NaN + 1)都会返回NaN
- NaN与任何值都不相等,包括NaN本身
NaN == Nan //false
isNaN()函数。这个函数接受一个参数,该参数可以是任何类型,而函数会帮我们确定这个参数是否”不是数值”
alert(isNaN(NaN)); //true alert(isNaN(10)); //false(10 是一个数值) alert(isNaN("10")); //false(可以被转换成数值10) alert(isNaN("blue")); //true(不能转换成数值) alert(isNaN(true)); //false(可以被转换成数值1)
4. string
5. object
操作符
一元
- 递增与递减
- 一元加和一元减
- 一元加操作符以一个加号(+)表示,放在数值前面,对数值不会产生任何影响
- 在对非数值应用一元加操作符时,该操作符会像Number()转型函数一样对这个值执行转换。
位操作符
按位非 not
- 执行按位非的结果就是返回数值的反码
位非操作的本质:操作数的负值减1。
var num1 = 25; // 二进制00000000000000000000000000011001 var num2 = ~num1; // 二进制11111111111111111111111111100110 alert(num2); // -26
按位与 and
- 或 or
- 异或 xor
- 左移
- 有符号右移
- 无符号右移
布尔运算符
- 逻辑非
无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反。
逻辑非操作符也可以用于将一个值转换为与其对应的布尔值。而同时使用两个逻辑非操作符,实际上就会模拟Boolean()转型函数的行为
- 逻辑与
- 逻辑或
相等运算符
- 相等于不相等
这两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性。
- 全等于不全等
除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不相等操作符没有什么区别。全等操作符由3 个等于号(===)表示,它只在两个操作数未经转换就相等的情况下返回true
函数及参数
ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。ECMAScript 中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。
实际上,在函数体内可以通过arguments 对象来访问这个参数数组,从而获取传递给函数的每一个参数。
arguments 对象只是与数组类似(它并不是Array的实例)。
即不显式地使用命名参数:
function sayHi() {
alert("Hello " + arguments[0] + "," + arguments[1]);
}
这个特性(即不存在函数签名的问题)使得js没有重载机制,但是可以通过判定参数列表的长度arguments.length
模拟重载。
传递参数
ECMAScript 中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制(地址)一样。
基本类型的值传递
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,没有变化 如果是引用传递 这里也会变成30
alert(result); //30
引用类型的值传递
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
在把person 传递给setName()后,其name属性被设置为”Nicholas”。然后,又将一个新对象赋给变量obj,同时将其name属性设置为”Greg”。
- 如果person 是按引用传递的,那么person 就会自动被修改为指向其name 属性值为”Greg”的新对象。
- 但是,当接下来再访问person.name 时,显示的值仍然是”Nicholas”。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持未变。
作用域与执行环境
所有变量(包括基本类型和引用类型)都存在于一个执行环境(也称为作用域)当中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。
- 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;
- 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
- 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境;
- 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
- 变量的执行环境有助于确定应该何时释放内存。
只有函数function才会形成作用域,其它例如for语句等不会形成作用域。
也就是说:JavaScript 没有块级作用域。
在其他类C 的语言中,由花括号封闭的代码块都有自己的作用域(如果用ECMAScript 的话来讲,就是它们自己的执行环境),因而支持根据条件来定义变量。
if (true) {
var color = "blue";
}
alert(color); //"blue"
这里是在一个if 语句中定义了变量color。
- 如果是在C、C++或Java 中,color 会在if语句执行完毕后被销毁。
- 但在JavaScript 中,if 语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境)中
垃圾收集
JavaScript 是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题。
- 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
- “标记清除(mark-and-sweep)”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存。
- 另一种垃圾收集算法是“引用计数”,这种算法的思想是跟踪记录所有值被引用的次数。JavaScript引擎目前都不再使用这种算法;但在IE中访问非原生JavaScript 对象(如DOM 元素)时,这种算法仍然可能会导致问题。
- 当代码中存在循环引用现象时,“引用计数”算法就会导致问题。
- 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。