JavaScript代码可以直接嵌入到网页的任何地方,不过我们通常把它们放到head中
<html>
<head>
<script>
alert('Hello World');
script>
head>
<body>
...
body>
html>
由包含的代码就是JavaScript代码,它将直接被浏览器执行
第二种方法就是把JavaScript代码放到一个单独的.js文件里,然后在HTML中通过
来引入这个文件
<html>
<head>
<script src="/static/js/abc.js">script>
head>
<body>
...
body>
html>
把JavaScript代码放入一个单独的.js文件中更利于维护代码,并且多个页面可以各自引用同一份.js文件
可以在同一页面中引入多个.js文件,还可以在页面中多次编写,浏览器按顺序依次执行
有时你也会看到标签里还设置了一个
type
属性
其实这是没有必要的,因为默认的type就是Javascript,所以不必显式的指定它
JavaScript中的每个语句都以;
结束,语句块用{...}
完整的赋值语句:
var x = 1;
下面的一行代码是一个字符串,但也可以视为一个完整的语句
'Hello World!';
JavaScript语法与Java类似,每个语句以;
结束,语句块用{...}
。
下面的语句是一个完整的赋值语句:
var x = 1;
下面的代码表示一个字符串,但也可以被视为一个完整的语句
'Hello, World!';
以//
开头直到行末的字符被视为行注释
// 这事一行注释
alert('hello'); //这也是注释
另一种注释是用/*...*/
,它可以把多行字符包括起来
/* 从这里开始是块注释
仍然是注释
仍然是注释
注释结束*/
JavaScript严格区分大小写
JavaScript不区分整数和浮点数,统一使用Number
表示
123; // 整数123
0.456; // 浮点数0.456
1.2345e3; // 科学计数法表示1.2345x1000,等同于1234.5
-99; // 负数
NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示
Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为Infinity
Number可以直接做四则运算,规则和数学一致
1 + 2; // 3
(1 + 2) * 5 / 2; // 7.5
2 / 0; // Infinity
0 / 0; // NaN
10 % 3; // 1,求余运算
10.5 % 3; // 1.5,求余运算
字符串是以单引号'或双引号"括起来的任意文本,比如'abc',"xyz"
等等
布尔值和布尔代数的表示完全一致,一个布尔值只有true
、false
两种值,要么是true
,要么是false
true; // 这是一个true值
false; // 这是一个false值
2 > 1; // 这是一个true值
2 >= 3; // 这是一个false值
&&
运算是与运算,只有所有都为true
,&&
运算结果才是true
:
true && true; // 这个&&语句计算结果为true
true && false; // 这个&&语句计算结果为false
false && true && false; // 这个&&语句计算结果为false
||
运算是或运算,只要其中有一个为true,||
运算结果就是true
:
false || false; // 这个||语句计算结果为false
true || false; // 这个||语句计算结果为true
false || true || false; // 这个||语句计算结果为true
!
运算是非运算,它是一个单目运算符,把true
变成false
,false
变成true
:
! true; // 结果为false
! false; // 结果为true
! (2 > 5); // 结果为true
当我们对Number做比较时,可以通过比较运算符得到一个布尔值
实际上,JavaScript允许对任意数据类型做比较:
要特别注意相等运算符==
,JavaScript在设计时,有两种比较运算符:
第一种是==
比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===
比较,它不会自动转换数据类型,如果数据类型不一致,返回false
,如果一致,再比较。
由于JavaScript这个设计缺陷,不要使用==
比较,始终坚持使用===
比较。
另一个例外是NaN,这个特殊的Number与所有其他值都不相等,包括它自己:
NaN === NaN; // false
唯一能判断NaN
的方法是通过isNaN()
函数:
isNaN(NaN); // true
null
表示一个“空”的值,它和0以及空字符串''不同,0是一个数值,''表示长度为0的字符串,而null
表示“空”。
在JavaScript中,还有一个和null
类似的undefined
,它表示“未定义”。
数组是一组按顺序排列的集合,集合的每个值称为元素。JavaScript的数组可以包括任意数据类型
[1, 2, 3.14, 'Hello', null, true];
另一种创建数组的方法是通过Array()
函数实现:
new Array(1, 2, 3); // 创建了数组[1, 2, 3]
数组的元素可以通过索引来访问。请注意,索引的起始值为0
:
var arr = [1, 2, 3.14, 'Hello', null, true];
arr[0]; // 返回索引为0的元素,即1
arr[5]; // 返回索引为5的元素,即true
arr[6]; // 索引超出了范围,返回undefined
JavaScript的对象是一组由键-值组成的无序集合
var person = {
name: 'Bob',
age: 20,
tags: ['js', 'web', 'mobile'],
city: 'Beijing',
hasCar: true,
zipcode: null
};
JavaScript对象的键都是字符串类型,值可以是任意数据类型
要获取一个对象的属性,我们用对象变量.属性名的方式:
person.name; // 'Bob'
person.zipcode; // null
变量在JavaScript中就是用一个变量名表示,变量名是大小写英文、数字、$
和_
的组合,且不能用数字开头。变量名也不能JavaScript的关键字,如if
、while
等。申明一个变量用var
语句
var a; // 申明了变量a,此时a的值为undefined
var $b = 1; // 申明了变量$b,同时给$b赋值,此时$b的值为1
var s_007 = '007'; // s_007是一个字符串
var Answer = true; // Answer是一个布尔值true
var t = null; // t的值是null
在JavaScript中,使用等号=
对变量进行赋值。可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,但是要注意只能用var
申明一次
var a = 123; // a的值是整数123
a = 'ABC'; // a变为字符串
如果一个变量没有通过var
申明就被使用,那么该变量就自动被申明为全局变量
i = 10; // i现在是全局变量
为了修补JavaScript这一严重设计缺陷,ECMA在后续规范中推出了strict
模式,在strict
模式下运行的JavaScript代码,强制通过var
申明变量,未使用var
申明变量就使用的,将导致运行错误
启用strict模式的方法是在JavaScript代码的第一行写上
'use strict';
下面的代码测试你的浏览器是否支持strict
模式
'use strict';
// 如果浏览器支持strict模式,
// 下面的代码将报ReferenceError错误:
abc = 'Hello, world';
alert(abc);
JavaScript的字符串就是用''
或""
括起来的字符表示。
如果字符串内部既包含'
又包含"
,可以用转义字符``来标识
多行字符串用\n
来写,但在ES6中增加了``的方式来定义多行字符串
`这是一个
多行
字符串
`
常见的字符串操作如下:
var s = 'Hello, World!';
s.length; // 13
var s = 'Hello, World!';
s[0]; // 'H'
s[6]; // ' '
s[7]; // 'W'
s[13]; // undefined 超出范围的索引不会报错,但一律返回undefined
需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果
toUpperCase()
把一个字符串全部变为大写var s = 'Hello';
s.toUpperCase(); // 'HELLO'
toLowerCase()
把一个字符串全部变为小写var s = 'Hello';
s.toLowerCase(); // 'hello'
indexOf()
会搜索指定字符串出现的位置var s = 'hello, world';
s.indexOf('world'); // 7
s.indexOf('World'); // 没有找到自定的子串,返回-1
substring()
返回指定索引区间的子串var s = 'hello, world';
s.substring(0, 5); // 从索引0开始到5(不包括5), 返回'hello'
s.substring(7); // 从索引7开始到结束, 返回'world'
JavaScript的
Array
可以包含任意数据类型,并通过索引来访问每个元素
要得到Array
的长度,使用length
属性
var arr = [1, 2, 3.14, 'Hello', null, true];
arr.length; // 6
如果直接给Array
的length
赋一个新值会导致Array
大小发生变化
var arr = [1, 2, 3];
arr.length; // 3
arr.length = 6;
arr; // arr变为[1, 2, 3, undefined, undefined, undefined]
arr.length = 2;
arr; // arr变为[1, 2]
请注意,如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化:
var arr = [1, 2, 3];
arr[5] = 'x';
arr; // arr变为[1, 2, 3, undefined, undefined, 'x']
Array
也可以通过indexOf()
来搜索一个指定的元素的位置:
var arr = [10, 20, '30', 'xyz'];
arr.indexOf(10); // 元素10的索引为0
arr.indexOf(20); // 元素20的索引为1
arr.indexOf(30); // 元素30没有找到,返回-1
arr.indexOf('30'); // 元素'30'的索引为2
slice()
就是对应String
的substring()
,它截取Array的部分元素,然后返回一个新的Array:
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
如果不给slice()
传递任何参数,它就会从头到尾截取所有元素。利用这一点,我们可以很容易地复制一个Array
:
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
var aCopy = arr.slice();
aCopy; // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
aCopy === arr; // false
push()
向Array的末尾添加若干元素,pop()
则把Array
的最后一个元素删除掉:
var arr = [1, 2];
arr.push('A', 'B'); // 返回Array新的长度: 4
arr; // [1, 2, 'A', 'B']
arr.pop(); // pop()返回'B'
arr; // [1, 2, 'A']
arr.pop(); arr.pop(); arr.pop(); // 连续pop 3次
arr; // []
arr.pop(); // 空数组继续pop不会报错,而是返回undefined
arr; // []
如果要往Array
的头部添加若干元素,使用unshift()
方法,shift()
方法则把Array
的第一个元素删掉:
var arr = [1, 2];
arr.unshift('A', 'B'); // 返回Array新的长度: 4
arr; // ['A', 'B', 1, 2]
arr.shift(); // 'A'
arr; // ['B', 1, 2]
arr.shift(); arr.shift(); arr.shift(); // 连续shift 3次
arr; // []
arr.shift(); // 空数组继续shift不会报错,而是返回undefined
arr; // []
sort()
可以对当前Array
进行排序,它会直接修改当前Array
的元素位置,直接调用时,按照默认顺序排序:
var arr = ['B', 'C', 'A'];
arr.sort();
arr; // ['A', 'B', 'C']
reverse()
把整个Array
的元素给掉个个,也就是反转:
var arr = ['one', 'two', 'three'];
arr.reverse();
arr; // ['three', 'two', 'one']
splice()
方法是修改Array
的“万能方法”,它可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素:
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 从索引2开始删除3个元素,然后再添加两个元素:
arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite']
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 只删除,不添加:
arr.splice(2, 2); // ['Google', 'Facebook']
arr; // ['Microsoft', 'Apple', 'Oracle']
// 只添加,不删除:
arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因为没有删除任何元素
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
concat()
方法把当前的Array
和另一个Array
连接起来,并返回一个新的Array
:
var arr = ['A', 'B', 'C'];
var added = arr.concat([1, 2, 3]);
added; // ['A', 'B', 'C', 1, 2, 3]
arr; // ['A', 'B', 'C']
join()
方法是一个非常实用的方法,它把当前Array
的每个元素都用指定的字符串连接起来,然后返回连接后的字符串:
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'
如果数组的某个元素又是一个Array,则可以形成多维数组,例如:
var arr = [[1, 2, 3], [400, 500, 600], '-'];
JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成
var xiaoming = {
name: '小明',
birth: 1990,
school: 'No.1 Middle School',
height: 1.70,
weight: 65,
score: null
};
JavaScript用一个{...}
表示一个对象,键值对以xxx: xxx
形式申明,用,
隔开
JavaScript规定,访问不存在的属性不报错,而是返回undefined:
var xiaoming = {
name: '小明'
};
xiaoming.age; // undefined
由于JavaScript的对象是动态类型,你可以自由地给一个对象添加或删除属性:
var xiaoming = {
name: '小明'
};
xiaoming.age; // undefined
xiaoming.age = 18; // 新增一个age属性
xiaoming.age; // 18
delete xiaoming.age; // 删除age属性
xiaoming.age; // undefined
delete xiaoming['name']; // 删除name属性
xiaoming.name; // undefined
delete xiaoming.school; // 删除一个不存在的school属性也不会报错
如果我们要检测xiaoming是否拥有某一属性,可以用in
操作符:
var xiaoming = {
name: '小明',
birth: 1990,
school: 'No.1 Middle School',
height: 1.70,
weight: 65,
score: null
};
'name' in xiaoming; // true
'grade' in xiaoming; // false
但in
操作符并不准确,因为访问的属性可能是当前对象继承而来的
要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()
方法:
var xiaoming = {
name: '小明'
};
xiaoming.hasOwnProperty('name'); // true
xiaoming.hasOwnProperty('toString'); // false
JavaScript使用if () { ... } else { ... }
来进行条件判断
var age = 20;
if (age >= 18) { // 如果age >= 18为true,则执行if语句块
alert('adult');
} else { // 否则执行else语句块
alert('teenager');
}
请永远都是写上{ }
如果还要更细致地判断条件,可以使用多个if...else...的组合:
var age = 3;
if (age >= 18) {
alert('adult');
} else if (age >= 6) {
alert('teenager');
} else {
alert('kid');
}
JavaScript的循环有两种,一种是for
循环,通过初始条件、结束条件和递增条件来循环执行语句块:
var x = 0;
var i;
for (i=1; i<=10000; i++) {
x = x + i;
}
x; // 50005000
for
循环最常用的地方是利用索引来遍历数组:
var arr = ['Apple', 'Google', 'Microsoft'];
var i, x;
for (i=0; ilength; i++) {
x = arr[i];
alert(x);
}
for
循环的一个变体是for ... in
循环,它可以把一个对象的所有属性依次循环出来:
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
alert(key); // 'name', 'age', 'city'
}
要过滤掉对象继承的属性,用hasOwnProperty()
来实现:
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
if (o.hasOwnProperty(key)) {
alert(key); // 'name', 'age', 'city'
}
}
由于Array
也是对象,而它的每个元素的索引被视为对象的属性,因此,for ... in
循环可以直接循环出Array
的索引:
var a = ['A', 'B', 'C'];
for (var i in a) {
alert(i); // '0', '1', '2'
alert(a[i]); // 'A', 'B', 'C'
}
while
循环只有一个判断条件,条件满足,就不断循环,条件不满足时则退出循环
var x = 0;
var n = 99;
while (n > 0) {
x = x + n;
n = n - 2;
}
x; // 2500
do { ... } while()
循环,它和while
循环的唯一区别在于,不是在每次循环开始的时候判断条件,而是在每次循环完成的时候判断条件:
var n = 0;
do {
n = n + 1;
} while (n < 100);
n; // 100
JavaScript的默认对象表示方式{}可以视为其他语言中的Map
或Dictionary
的数据结构,即一组键值对
但JavaScript的对象中的键必须是字符串,实际上它可以是Number或其他数据类型
为了解决这个问题,ES6引入了新的数据类型Map
,下面的代码可以测试浏览器是否支持
'use strict';
var m = new Map();
var s = new Set();
alert('你的浏览器支持Map和Set');
Map是一组键值对的结构,具有极快额查找速度
在JavaScript中实现一个Map
结构如下:
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); //95
初始化Map
需要一个二维数组,或者直接初始化一个空的Map
,下面是它具有的方法:
var m = new Map(); //初始化一个空的Map
m.set('Adam', 67); //添加新的key-value
m.set('Bob', 59);
m.has('Adam'); //判断是否存在key:‘Adam’,返回true
m.get('Adam'); //67
m.delete('Adam'); //删除key:'Adam'
m.get('Adam'); //undefined
一个key只能对应一个value,所以,多次给一个key赋值,会把前面的覆盖掉
var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); //88
Set
和Map
类似,也是一组key的集合,但不存储value,它里面没有重复的key
要创建一个Set
,需要提供一个Array并输入,或者可以直接定义一个空的Set
var s1 = new Set([1, 2, 3]);
var s2 = new Set();
重复的key会在Set
中被自动过滤掉,使用add和delete方法来给Set添加和删除元素
var s = new Set();
s.add(4);
var s = new Set([1, 2, 3]);
s; //Set {1, 2, 3}
s.delete(3);
s; //Set {1, 2}
ES6引入了新的
iterable
类型,Array
,Map
,Set
都属于iterable
类型
具有iterable
类型的集合可以通过新的for...of
循环来遍历,它是ES6引入的新语法
通过下面的代码来测试你的浏览器是否支持
'use strict';
var a = [1, 2, 3];
for(let x of a) {}
alert('你的浏览器支持for...of语法');
用for...of
循环遍历集合
var a = ['A', 'B', 'C'];
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
var s = new Set(['A', 'B', 'C']);
for(let x of a) { //遍历Array
console.log(x);
}
for(let x of s) { //遍历Set
console.log(x);
}
for(let x of m) { //遍历Map
console.log(x[0] + '=' + x[1]);
}
for...of
和for...in
有什么区别呢?
for...in
循环由于历史问题,实际上它遍历的是对象的属性名称,那么Array也是一种对象,Array的每个元素的下标被视为属性,当我们手动给Array添加了额外的元素后,for...in
循环会出现额外的情况
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for(var x in a) {
console.log(x); //0, 1, 2, name
}
而for...of
循环解决了这个问题,它只遍历集合本身的元素
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for(var x of a) {
console.log(x); //'A','B','C'
}
在iterable中,还有一个内置方法forEach
,它接收一个函数,每次迭代就自动回调该函数
var a = ['A', 'B', 'C'];
a.forEach(function(element, index, array) {
//element:指向当前元素的值
//index: 指向当前索引
//arrya: 指向Array对象本身
console.log(element);
});
forEach
方法是ES5.1标准引入的。
Set
与Array
类似,但Set
没有索引,因此回调函数的前两个参数都是元素本身
var s = new Set(['A', 'B', 'C']);
s.forEach(function(element, sameElement, set) {
console.log(element);
});
Map
的回调参数依次为value
、key
和map
本身
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function(value, key, map) {
console.log(value);
});
forEach
的回调函数中的参数不必全部写完,如只需要Array的元素值
var a = ['A', 'B', 'C'];
a.forEach(function(element) {
console.log(element);
});
from: http://www.jianshu.com/p/80b612534691