字面量
字面量是一个常量。
Number
类型,可以是整数或者小数,或者是科学计数如 123e6
。
String
类型,可以用单引号或者双引号,单引号表示内部内容不需要转义,而双引号表示内容需要转义。'a\n\b'
,用双引号与单引号不同。
字面量是常量,我们也可以用new
来创建一个对象变量,但是new生成的是对象Object
:
var x = "John";
var y = new String("John");
(x === y) // 结果为 false,因为 x 是字符串,y 是对象
===
表示绝对相等,必须数据类型和值都相等,这里虽然两者值相等,但是类型不同.
变量与其作用域
变量必须以字母、下划线(_)或美元符号($)开始,后续字母是 字母、数字、下划线或美元符。
变量不声明,无法使用,会报错变量未定义 ,但是以下函数却不会报错:
console.log(v);
var v = "world";
输出结果是 undefined
,因为js的变量提升特性hoisting
,js引擎会把所有变量的声明提升到当前作用域的最前面, 即上述代码相当于 :
var v;
console.log(v);
v = "world";
而在以下写法中 :
var v = "hello";
if(true){
console.log(v);
var v = "world";
}
输出的是hello
,而不是 undefined
, 即在js中的var
是没有块级作用域的,只有函数才拥有作用域。
var v = "hello";
(function(){
console.log(v);
var v = "world";
})();
这种情况输出的是 undefined
。
javascript
是动态语言,变量没有固定类型,其存储空间会随着初始化和赋值而变化。
函数表达式与函数声明的提升不同 :
(function(){
f1();
f2();
var f1 = function(){};
function f2(){}
})();
这里对于f1 、 f2提升的结果为 :
var f1,function f2(){};
这里 f1
会报错ReferenceError: f1 is not defined
, 由于f1是变量,向上提升时,作为一个 undefined
变量,所以无法执行函数,而f2
却以函数定义的方式被提升,所以函数可以正常调用。
在一个函数中,作用域中命名优先级顺序如下:
- 语言内置 : 所有作用域都有
this
和arguments
关键字 - 形式参数 : 函数的参数
- 函数声明 : 内部函数的声明
- 变量声明
命名优先级较高的名字会覆盖较低优先级的命名,如:
(function(){
var foo;
console.log(typeof foo); //function
foo = "foo";
function foo(){}
})();
虽然代码中好像先声明了foo
,但是函数声明会被提到最前面,并覆盖foo
的声明。
在javaScript
中,直接赋值给未声明的变量,则该变量被视为全局变量声明,如 :
hello = "world"
console.log(hello)
这样是可以正常执行的, 且即使该赋值位于函数中,也视为全局变量。但是以下形式 :
console.log(hello)
hello = "world"
就会报错,因为这里没有显式的变量声明,也就是没有变量hoisting
, 所以会报错 变量not defined
。
全局变量,在html
中挂载在window
对象上,而在node.js
中挂载于 global
对象
类型与类型判断
js中有5种不同的数据类型:string
,number
,boolean
,object
,function
。
三种对象类型 : Object
,Date
,Array
.
2个不包含任何值的数据类型 : null
,undefined
。
通过 constructor
属性可以获取所有变量的构造函数,以上各种类型的构造函数分别为 : String()
,Number()
,Boolean()
,Object()
,Function()
,Date()
,Array
函数,而null
和undefined
没有。
我们可以这样校验一个对象是否是数组 :
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
一般我们使用 typeof
来获取类型:
typeof "John" // 返回 string
typeof 3.14 // 返回 number
typeof false // 返回 boolean
typeof [1,2,3,4] // 返回 object
数组是一个特殊的对象类型,所以类型是 object
.
null
在js中表示空值。但使用 typeof(null)
结果为object
undefined
表示没有设置值,类型为undefined
。
需要注意的是
null == undefined
所以如果要判断变量是否为 undefined
时,需要校验type,而不是直接判断是否等于undefined
。
正则表达式
在js中,正则表达式如下 :
/正则表达式主体/修饰符(可选)
而修饰符有以下几种 :
- i : 表示执行对大小写不敏感的匹配
- g : 执行全局匹配(默认是查找到第一个匹配后结束)
- m : 执行多行匹配
使用test()
方法,用于检测字符串是否匹配指定模式 :
/[a-z]*/.test('hello')
使用exec()
方法,检索字符串中所有匹配,该函数返回一个数组,如果未匹配到,返回值为null。
严格模式
严格模式是在ECMAScript5
中新增的,使用指令use strict
,它不是一条语句,而是一个字面量表达式。如 :
"use strict";
x = 3.14; // 报错 (x 未定义)
使用严格模式,来消除语法中的不合理不严谨的地方,保证代码的安全运行。
严格模式的一些内容与es6语法相关。
使用误区
在常规的比较中,数据类型是被忽略的, 如 :
var x = 10;
var y = "10";
if (x == y) // 返回的是true。
所以要进行严格的判断时,需要使用 ===
,同时校验表达式的类型和值。
js中所有的数据类型都是以64为浮点型数据来存储的,而所有编程语言中,对float的精确度是很难确定的,所以 :
var x = 0.1;
var y = 0.2;
console.log((x + y) == 0.3)
以上代码输出的是 false
。
this
在js中,this
指向调用函数的对象。
如果纯粹的函数调用,属于全局性调用,因此this
代表Global
。
如果被某个对象的方法调用,则执行该对象。
如果作为构造函数调用,则通过这个函数生成了一个新的对象,而this指向这个新对象 :
function test(){
this.x = 1;
}
var o = new test();
如果被apply
或call
函数调用,则this指向其第一个参数。
call与apply
call
和apply
用于调用函数,两者的区别,在于call
将自身函数第二个参数开始的参数传入到函数中,而apply
将第二个参数作为数组解析,传入到函数中:
myFunction.call(myObject, 10, 2);
myArray = [10, 2];
myFunction.apply(myObject, myArray)
逻辑运算符
在js逻辑运算中,0、”“、null、false、undefined、NaN都会判为false
使用 &&
和 ||
能够美化代码。
a = b && c
d = e || f
&&
中,如果第一个表达式为假,就不会处理第二个表达式, 所以在a = b && c
, 如果b
不为空,则返回 C,否则返回b.
在||
中,如果第一个表达式为真,就不会处理第二个表达式,所以在 d = e || f
中,如果 e
为空,则返回f。
所以,我们可以用这个特性来美化代码,如 :
if(a >=5){
alert("你好");
}
可以简写成:
a >= 5 && alert("你好");
闭包
闭包是能够读取其他函数内部变量的函数:
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
这里 f2
函数就是一个闭包,它读取了f1函数内部的值 n.
闭包最大的两个用处:
- 读取函数内部的变量
- 让这些变量的值始终保持在内存中。
如在上述函数中,如果我们:
globalvar = f1();
便将f2
的函数保存在一个全局变量中,而f2
依赖于函数f1
,所以f1
函数始终在内存中,不会在调用后,被垃圾回收,而f1
中的局部变量也持久保存了。