变量
JavaScript是弱类型的语言,变量是松散的。所谓松散是可以保存任何类型的变量。即声明不同数据类型的变量使用同一个关键字 var
,变量就是变化的量,变量的作用就是用来装数据的容器。声明变量的时候不用考虑类型,但是处理和计算的时候要考虑类型.
定义变量
定义变量使用关键字 var
来定义变量名。
1 | // 在全局作用域下声明了变量 a |
赋值:
- 赋值运算符为“=”,这个等号不用判断两者是否相同。
- 如果判断是否相同,可使用==(===)。
以上两步可简写为:
1 | var a = "a此时是字符串"; |
注意:
1 | function foo(){ |
上面例子省略了var
操作符, msg 就变成了全局变量,函数外部也能访问到,但不要这样做!。
变量命名规范
- 由字母、数字、下划线、$ 组成且开头不能是数字定义变量名。
- 不能使用特殊符号或者特殊符号开头来定义变量名(_除外)。
- 不能以关键字来定义变量名
- 变量的名称要有实际意义
- 规则中所说的字母包括ASCII和Unicode字母字符,如汉字,但不推荐使用
变量的命名遵守驼峰命名法,首字母小写,第二个单词的首字母大写 例如:userName
- 关键字
1 | break do instanceof typeof |
- 不能使用保留字来定义变量名 (保留字)
1 | abstract enum int short |
注意:在JS中,是严格区分大小写的。
执行环境和作用域
执行环境是 JavaScript 中最为重要的一个概念。定义了变量或函数有权访问其它数据。每个环境中都有一个与之关联的变量对象,我们编写的代码无法访问,但是环境中定义的变量存放在这个对象中。
全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境的不同,表示执行环境的对象也不一样。在 web 浏览器中,全局执行环境被认为是 window 对象,因此所有的全局变量和函数都是作为 window 对象的属性和方法创建的。某个环境中的代码全部执行完,该环境中的变量被销毁,保存在其中的所有的变量和函数定义也随之销毁。全局执行环境直到应用程序退出才销毁。
每个函数都有自己的执行环境。当代码在一个环境中执行时,会创建作用域链。作用域链式保证对执行环境有权访问的所有变量和函数的有序访问。作用域的前端始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始的时候只包含一个变量,即 arguments 对象。作用域中的下一个变量对象来说包含(外部的环境),而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境,全局执行环境的变量对象始终都是作用域链中的最后一个对象。
一个变量的作用域是程序源代码中定义这个变量的区域。全局变量拥有全局作用域,在 JavaScript 代码中任何地方都是有定义的。而在函数内部声明的变量只有在函数体内有定义,它们是局部变量,作用域是局部的。
在函数体内部,局部变量的优先级高于同名的全局变量。
函数作用域和声明提前
块级作用域是指在一对花括号内的代码都具有各自的作用域,而且变量在声明它们的代码之外是不可见的。但是 JavaScript 没有块级作用域的概念。而是使用了函数作用域。JavaScript 的函数作用域是指函数内声明的所有变量在函数体内始终是可见的。
1 | function test(o){ |
作为属性的变量
当声明一个变量时,实际上是定义了一个全局对象的一个属性,当使用 var 声明变量时,创建的这个对象是不可配置的,也就是说这个变量不能通过 delete 操作符来删除。如果在非严格模式下,给一个未声明的全局变量赋值的话, JavaScript 会自动创建一个全局变量。以这种方式创建的变量是全局对象的正常的可配置属性,并且可以删除它们。
作用域链
嵌套的函数体内部,可以访问它上一级作用域中的变量。
延长作用域链:
- try-catch 语句
- with 语句
垃圾收集
- 标记清除
- 引用计数
- 性能问题
- 管理内存
数据类型
javaScript 数据类型有两类: 基本数据类型 和 复杂数据类型,其中基本数据类型(简单类型)有: Number/String/Boolean/Uundefined/Null一种复杂数据类型:object:Array/Date/Math/RegExp/
typeof 操作符
- “undefined” –> 这个值未定义
- “boolean” –> 这个值是布尔值
- “string” –> 这个只是字符串
- “number” –> 这个值是数值
- “object” –> 这个值是对象或null
- “function” –> 这个值是函数
typeof 操作符号后面的操作数可以是变量,也可以是字面量;
typeof 误区:
- null 值返回 “object”;
- Safari5 以及之前的版本、Chrome7 以及之前的版本对正则表达式调用返回”object”,
- 其他浏览器在这种情况下返回”object”
- 未初始化的变量和没有定义的变量操作符 typeof 都返回 “undefined”, 但它们有本质区别
Number 数据类型
字面量: var num = 数字;
包括正数,负数,小数
- 取值范围:
- 能表示的最大值是±1.7976931348623157乘以10的308次方
- 能表示的最小值是±5 乘以10的-324次方
- 表示方式
- 十进制
- 十六进制 以 0x 开头,从 0-9,a(A) 到 f(F)的范围。
- 八进制 以 0 开头,0-7 组成。
- NaN (not a number) 也是 number 类型,NaN 不等于自身
两个都为字符串的变量相减,得到的是NaN.
浮点数:
- 计算浮点数时会丢失精度
- 通常用整数的计算来表示浮点数的计算
- 不要以两个浮点数是否相等作为条件判断的依据(判断范围还是可以的)
String,字符串类型
字面量: var str = “字符串”;
字符串的长度: str.length;
- 凡是用””或者’’引起来的全是字符串类型。
转义字符
- \” 转双引号
- \’ 转单引
- \r 回车
- \n 换行
- \t 制表符
- \f 进纸
- \xnn 以十六进制表示一个字符(n 是 0~F)
- \unnnn 以十六进制代码nnnn表示一个 Unicode 字符 (n 是 0~F)
字符串的特点
ECMAScript 中的字符串是不可变的,也就是说,字符串一旦创建,它们的直就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含心智的字符串填充该变量。如:
1 | var str = "Java"; |
转换为字符串
数值、布尔值、对象和字符串值都有 toString()
方法, 但是 null 和 undefined 没用这个方法。
调用toString() 方法时,大多数情况下不传参数,但是如果传递了一个参数,输出数值的基数。默认情况下,toString() 方法以十进制格式返回数值字符串表示。而通过传递基数,可以输出对应的二进制、八进制、十六进制。
1 | var n = 10; |
在不知道要转换的值是什么类型的时候,可以用 String() 函数,它可以将任意类型转成字符串。
Boolean 布尔类型
- 布尔数据类型两个数据值: true/false
- 实际运算中,true 代表1, false代表0;
Undefined 表示声明但未赋值的变量
在 js 中,一下四种情况的返回值是 undefined
- 变量声明了但没有赋值
- 函数没有返回值默认返回undefined
- 函数传递的实参个数少于形参个数时,未传递的参数值为undefined
- 对象没有定义的属性默认为undefined
Null
用 typeof
判断时值为 object
(值为空)/引用为空,内存里找不到这个变量。
再如:
1 | console.log(undefined == null); // true 两等号判断,两边都转成false |
总的来说,只要意在保存对象的变量还没有真正保存对象,就应该让该变量保存 null 值,这样做体现了 null 作为空对象指针的惯例,也区分了 undefined 和 null。
复杂类型(来自JavaScript高级程序设计)
- object 对象
ECMAScript 中的对象就是一组数据和功能的集合。可以通过 new 操作符后跟要创建的对象类型的名称来创建。而创建 Object 类型的实例并为其添加属性或方法,就可以创建自定义对象,如:
1 | var o = new Object(); |
Object的每个实例具有的属性和方法
- constructor: 保存着用于创建当前对象的函数,即构造函数。
- hasOwnProperty(propertyName): 用于检查给定的属性在当前对象的实例中(而不是在原型中)存在;参数是字符串。
- isPrototypeOf(object): 检查传入的对象是否是传入对象的原型。
- propertyIsEnumerable(propertyName): 检查给定的属性是否能够使用 for-in 语言来枚举。参数是字符串。
- toLocalString(): 返回对象的字符串表示,该字符串与执行环境的地区对应。
- toString(): 返回对象的字符串表示。
- valueOf(): 返回对象的字符串、数值、或布尔值表示。通常与 toString() 方法的返回值相同。
数据类型转换
隐式数据类型转换
变量参与到运算中,程序对变量进行的数据类型转换(不是程序员进行的数据类型)
强制数据类型转换
- 将数字转换为字符串
- String
- 变量.toString ,注意:null 和 undefined 没有 toString() 方法
- 将字符串转换为数字
- Number
- 转换后保留原数据,不会对数据进行四舍五入。
- 非数字类型字符串转换后,比如 undefined,得到 NaN 。
- 如果字符串中包含有效的十六进制格式,则将其转换为相同大小的十进制整数值。
- parseInt
- 对小数转换后保留的是整数部分,不会对数据进行四舍五入。
- 如果是数字后边有非数字字符串,转换后得到的是前边数字的整数部分。
- parseFloat
- 转换为数字类型之后保留原数据,不进行四舍五入。
- 非数字类型字符串转换后,得到 NaN 。
- 如果是数字后边有非数字字符串,转换后得到的是前边数字的部分。
- Number
- 将其他类型转换为布尔类型:所有类型的值都可以转化成布尔值
- Boolean
- 会转化成false的值有:
- 空字符串
- 数值零
- NaN
- undefined
- null
假值:空字符串””/数字0/null/undefined/false/NaN
基本数据类型和复杂数据类型总结
- 基本类型—值类型— String Undefined Number Boolean Null
复杂类型—引用类型– Object 数组–Array,Date….
基本类型的值存储在—- 栈中
复杂类型的地址(引用)存储在栈中,—地址指向的空间中的对象(对象)—对象存储在堆中
- 创建对象并返回对象—返回的是对象的地址(对象在堆空间中的地址)
基本类型传值的时候,传递的是值
复杂类型(引用类型)传递的时候,传递的是:地址(引用)