JavaScrip基本语法
i 先给i自加1,再计算表达式的值。
i先计算表达式的值,再给i自加1。
需要注意的是,每个case代码块内部的break语句不能少,否则会接下去执行下一个case代码块,而不是跳出switch结构。
JavaScript 有三种方法,可以确定一个值到底是什么类型:
- typeof运算符
- instanceof运算符
- Object.prototype.toString方法
区别是这样的:null是一个表示“空”的对象,转为数值时为0;undefined是一个表示”此处无定义”的原始值,转为数值时为NaN。
转换规则是除了下面六个值被转为false,其他值都视为true。
- undefined
- null
- false
- 0
- NaN
- “”或’’(空字符串)
注意,空数组([])和空对象({})对应的布尔值,都是true。
NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。0除以0也会得到NaN。需要注意的是,NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。
Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity。Infinity有正负之分,Infinity表示正的无穷,-Infinity表示负的无穷。
字符串
由于 HTML 语言的属性值使用双引号,所以很多项目约定 JavaScript 语言的字符串只使用单引号,本教程遵守这个约定。
如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠。注意,反斜杠的后面必须是换行符,而不能有其他字符(比如空格),否则会报错。
反斜杠还有三种特殊用法。\HHH 反斜杠后面紧跟三个八进制数(000到377),代表一个字符;\xHH \x后面紧跟两个十六进制数(00到FF),代表一个字符;\uXXXX \u后面紧跟四个十六进制数(0000到FFFF),代表一个字符。
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。
但是,字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符。字符串内部的单个字符无法改变和增删,这些操作会默默地失败。
对象
对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
var obj = {
foo: 'Hello',
bar: 'World'
};
对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。对象的属性之间用逗号分隔,最后一个属性后面可以加逗号(trailing comma),也可以不加。
如果要解释为对象,最好在大括号前加上圆括号。因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象。
with它的作用是操作同一个对象的多个属性时,提供一些书写的方便。
with (对象) {
语句;
}
/ 例一
var obj = {
p1: 1,
p2: 2,
};
with (obj) {
p1 = 4;
p2 = 5;
}
// 等同于
obj.p1 = 4;
obj.p2 = 5;
// 例二
with (document.links[0]){
console.log(href);
console.log(title);
console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);
函数
JavaScript 有三种声明函数的方法:
- function 命令
- 函数表达式
var print = function(s) {
console.log(s);
};
//这种写法的用处有两个,一是可以在函数体内部调用自身,二是方便除错
var f = function f() {};
- Function 构造函数
var add = new Function(
'x',
'y',
'return x + y'
);
// 等同于
function add(x, y) {
return x + y;
}
如果只有一个参数,该参数就是函数体。
如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。但是,如果采用赋值语句定义函数,JavaScript 就会报错。
函数的属性和方法
函数的name属性返回函数的名字。
函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。
函数的toString方法返回一个字符串,内容是函数的源码。
参数的省略
运行时无论提供多少个参数(或者不提供参数),JavaScript 都不会报错。省略的参数的值就变为undefined。需要注意的是,函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。
函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。
但是,如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。
如果有同名的参数,则取最后出现的那个值。
arguments 对象
由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。
arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
闭包
如果出于种种原因,需要得到函数内的局部变量。正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。
function f1() {
var n = 999;
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
闭包就是函数f2,即能够读取其他函数内部变量的函数。由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
闭包的另一个用处,是封装对象的私有属性和私有方法。
立即调用的函数表达式(IIFE)
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。
//简单说,它们的区别是相等运算符(==)比较两个值是否相等
//严格相等运算符(===)比较它们是否为“同一个值”。
//如果两个值不是同一类型,严格相等运算符(===)直接返回false
//而相等运算符(==)会将它们转换成同一个类型,再用严格相等运算符进行比较。
This
但不管是什么场合,this都有一个共同点:它总是返回一个对象。简单说,this就是属性或方法“当前”所在的对象。
由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
var f = function () {
console.log(this.x);
}
var x = 1;
var obj = {
f: f,
x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2