这部分介绍Javascript的基础语法,从声明变量,数组字符串,条件语句一直到循环及其他杂项.
基本风格
- 不需要行尾“;”, 但是不写有可能会有奇怪的问题.
- 一行写一个语句.
- 缩进使用四个空格, 或者两个空格, 不要使用
TAB
.
记得写注释
变量
变量就是一段有名字的数据, 声明方法很简单:
let message;
message = 'Hello';
// 或者直接赋值
let anotherMessage = 'Hi';
// 这三行
let user = 'John';
let age = 25;
let message = 'Hello';
// 等效下面这三行
let user = 'John',
age = 25,
message = 'Hello';
'Hello'
以前都是用var
来声明变量的, 但是现在最好用let
. 具体原因参见奇怪的JS
常量
不能变的就是常量:
const myBirthday = '2017';
myBirthday = '2007'; // 出错
evalmachine.<anonymous>:3
myBirthday = '2007'; // 出错
^
TypeError: Assignment to constant variable.
at evalmachine.<anonymous>:3:12
at ContextifyScript.Script.runInThisContext (vm.js:44:33)
at Object.runInThisContext (vm.js:116:38)
at run ([eval]:617:19)
at onRunRequest ([eval]:388:22)
at onMessage ([eval]:356:17)
at emitTwo (events.js:125:13)
at process.emit (events.js:213:7)
at process.nextTick (internal/child_process.js:755:12)
at _combinedTickCallback (internal/process/next_tick.js:95:7)
数据类型
JavaScript语言有7种不同类型的值:
- 六种原型数据类型:
- Boolean. 布尔值,true 和 false.
- null. 一个表明 null 值的特殊关键字。 JavaScript 是大小写敏感的,因此 null 与 Null、NULL或其他变量完全不同。
- undefined. 变量未定义时的属性。
- Number. 表示数字,例如: 42 或者 3.14159。
- String. 表示字符串,例如:’Howdy’
- Symbol ( 在 ECMAScript 6 中新添加的类型).。一种数据类型,它的实例是唯一且不可改变的。
- 以及Object对象
这些就够了!
简单的数据类型的例子
let age = 15; // Number
console.log('age类型为:' + typeof age);
let height = 1.8; // Number
console.log('heigh类型也为:' + typeof height);
let name = 'wanwu.tech'; // String
console.log('name类型为:' + typeof name);
let isMine = true; // Boolean
console.log('isMine类型为:'+ typeof isMine);
let foo = null; // null
console.log('foo类型为:'+ typeof foo); // 因为历史原因,显示类型为object,但是其实是null
age类型为:number
heigh类型也为:number
name类型为:string
isMine类型为:boolean
foo类型为:object
以上是最基本的数据类型及其定义方法,其他类型将会后面介绍。
字符串
JavaScript的字符串用' '
或" "
括起来的字符表示。但是推荐统一使用单引号’‘。
多行字符串
如果想要定义多行字符串,可以使用反引号:` `
let multiLineString = `这是一个
多行
字符串`;
console.log(multiLineString);
这是一个
多行
字符串
模板字面量
很多现代语言都有类似的概念,可以方便字符串输出。Javascript也要进步,所有在ES6中加入了这个功能。
需要注意:和多行字符串类似,需要使用反引号` `
let name = '万物博客';
let age = 1;
console.log(`我是${name}, 已经建站${age}年了!`);
console.log('name长度为:' + name.length);
我是万物博客, 已经建站1年了!
name长度为:4
索引
字符串索引可以像数组一样, 也可是使用chatAt()
方法
console.log(name[0]);
console.log(name.charAt(0));
万
万
字符串有一些常用的方法,这里先简单介绍基础内容,详细内容以后再介绍。
数组
数组和字符串有千丝万缕的联系,这里看下数组的使用。
let numArray = [1, 2, 3, 4, 5.5, 6.6];
numArray.length;
6
上面例子可以看到,我们创建了一个全是数字的数组。
来看下一个在很多静态语言中不可能的例子:
let complexArray = [1, 2, 3, 'I am a string', ['I', 'am', 'a', 'array'], true, null];
console.log(complexArray);
complexArray.length;
[ 1, 2, 3, 'I am a string', [ 'I', 'am', 'a', 'array' ], true, null ]
7
可以看到,上面的数组包含了众多数据类型,也就是说,Javascript的数组就是一个什么都能装的容器。
来看下这个操作:
complexArray.length = 10;
console.log(complexArray);
[ 1,
2,
3,
'I am a string',
[ 'I', 'am', 'a', 'array' ],
true,
null,
<3 empty items> ]
可以发现,修改数组的长度,竟然可以改变数组!
console.log(complexArray[6]);
console.log(complexArray[7]);
null
undefined
通过索引,我们可以发现,通过修改长度而增加的数组元素,是undefined!
complexArray[7] = 'new value';
complexArray[11] = 'another new value';
console.log(complexArray);
[ 1,
2,
3,
'I am a string',
[ 'I', 'am', 'a', 'array' ],
true,
null,
'new value',
,
,
,
'another new value' ]
上面例子可以看出,可以给原数组索引范围内的元素赋值(修改原值),也可以给原数组索引范围外的元素赋值(赋新值)。
但是以上几个例子虽然给了你更大的能力,但是能力越大,责任越大,千万慎重!
数组和字符串操作
可变性
字符串不可变, 数组可变
let friends = ['Mike', 'Jim', 'Ben'];
friends[0] = 'Linda';
console.log(`我的朋友Mike离开了,我又有了一个新朋友${friends[0]}`);
let name = 'I am immutable';
name[0] = 'Y';
console.log(`我的名字还是${name}, 而且没有报错!`);
我的朋友Mike离开了,我又有了一个新朋友Linda
我的名字还是I am immutable, 而且没有报错!
虽然字符串本身不可变, 但是可以将字符串进行一些变化, 需要的话将变化后的字符串赋给新的字符串.
字符串大小写转换
let upName = name.toUpperCase();
console.log(upName);
let lowName = name.toLowerCase();
console.log(lowName);
I AM IMMUTABLE
i am immutable
出现位置
字符串和数组都可以使用indexOf()
方法给出字符串或者元素第一次出现位置. 如果没有找到, 返回-1
console.log(friends.indexOf('Jim'));
console.log(name.indexOf('am'));
1
2
indexOf()
方法给出的是寻找的元素第一次出现的位置, 想要寻找最后一次出现的位置可以使用lastIndexOf()
:
console.log(name.lastIndexOf('am'));
let longFriends = friends.concat(friends); // 数组相加
console.log(longFriends);
console.log(longFriends.lastIndexOf('Jim'));
2
[ 'Linda', 'Jim', 'Ben', 'Linda', 'Jim', 'Ben' ]
4
判断是否存在
也可以使用indexOf/lastIndexOf
判断是否存在某元素, 如果返回是-1
, 那么就可以认为是不存在:
console.log(friends.indexOf('NO'));
console.log(name.indexOf('NO'));
-1
-1
还可以用includes()
:
console.log(name.includes('I'));
console.log(friends.includes('mike')); // 大小写
true
false
以XXX开始, 以XXX结束
对于数组, 那么很简单, 直接用arr[0]
和arr[arr.length - 1]
即可. 对于字符串, 使用startsWith
, endsWith
:
console.log(name.startsWith('I'));
console.log(name.endsWith('NO'));
true
false
截取部分内容
对于字符串, 是substring
, substr
和 slice
, 对于数组, 只有slice
.
str.slice(start [, end])
数组和字符串都能用, 第二个参数可省略(这样的话就相当于到最后一个), 范围不包括后面的索引,也就是:[第一个索引 第二个索引)
.
let newName = name.slice(0, 6);
console.log(newName);
let newFriends = friends.slice(0, 2);
console.log(newFriends);
let oneFriend = friends.slice(2);
console.log(oneFriend);
I am i
[ 'Linda', 'Jim' ]
[ 'Ben' ]
字符串专用
字符串还可以用str.substring(start [, end])
和str.substr(start [, length])
, 注意二者参数的不同.
let newName = name.substring(1, 6);
console.log(newName);
let anotherNewName = name.substr(1, 6);
console.log(anotherNewName);
am i
am im
可以看到, 不管是substring()
还是slice()
, 输入参数都是一样的. 需要留意的是范围不包括后面的索引,也就是:[第一个索引 第二个索引)
.
这两个方法也可以传入一个参数, 那么就是只返回这个索引的元素到结束:[索引 结束]
let oneName = name.substring(6);
console.log(oneName);
mmutable
[ 'Ben' ]
替换
对于数组来说, 替换直接索引到元素然后赋值即可, 上面已经有过类似操作, 这里不再叙述; 对于字符串来说, 需要使用replace()
方法. 其中第一个参数是旧值, 第二个参数是新值.
let newName = name.replace('m', 'n');
console.log(newName);
I an immutable
但是可以看到, 只替换了一个m, 如果想全部替换, 可以这样(注意写法, g表示global全局):
let newName = name.replace(/m/g, 'n');
console.log(newName);
I an innutable
数组尾部增删
push()
在数组的末尾添加元素,pop()
将数组最后一个元素删除.
let pets = [] // 建立一个空数组
pets.push('cat');
console.log(pets);
pets.push('dog', 'fish');
console.log(pets);
pets.pop();
console.log(pets);
pets.pop();
console.log(pets);
[ 'cat' ]
[ 'cat', 'dog', 'fish' ]
[ 'cat', 'dog' ]
[ 'cat' ]
数组头部增删
类似数组尾部增删操作,使用unshift()
方法在数组头部添加元素,shift()
方法则删除头部第一个元素:
console.log(pets);
pets.unshift('dog');
console.log(pets);
pets.unshift('fish');
console.log(pets);
pets.shift();
console.log(pets);
pets.shift();
console.log(pets);
[ 'cat' ]
[ 'dog', 'cat' ]
[ 'fish', 'dog', 'cat' ]
[ 'dog', 'cat' ]
[ 'cat' ]
数组任意位置增删
如果想对数组任意位置增删,使用splice()
方法,它可以从指定位置添加或着删除文件。
pets = ['dog', 'cat', 'fly', 'bug', 'ox'];
pets.splice(1, 2, 'fish', 'pig', 'cow'); // 从第一个元素开始, 删除两个元素,然后再在此位置添加'fish', 'pig', 'cow'
console.log(pets);
[ 'dog', 'fish', 'pig', 'cow', 'bug', 'ox' ]
pets.splice(1, 2); // 只删除,不添加
console.log(pets);
[ 'dog', 'cow', 'bug', 'ox' ]
pets.splice(1, 0, 'fish', 'pig', 'cow'); // 只添加,不删除
console.log(pets);
[ 'dog', 'fish', 'pig', 'cow', 'cow', 'bug', 'ox' ]
跟据上面例子可见, splice()
参数作用为:splice(操作起始位置, 要删除的个数, 要添加的诸元素)
。如果不写要添加的诸元素,那么只添加不删除。
还可以不写第二个参数,这样等同于第二个参数写0, 方法如下:
pets.splice(1, 'fish', 'pig', 'cow'); // 只添加,不删除
console.log(pets);
[ 'dog', 'pig', 'cow', 'fish', 'pig', 'cow', 'cow', 'bug', 'ox' ]
数组字符串相加
字符串 + 字符串
很简单, 使用+
即可
let firstName = 'Tom';
let lastName = 'Green';
let fullName = firstName + ' ' + lastName;
console.log(fullName);
Tom Green
数组 + 数组
使用前面见过concat()
, 这里看下如何使用.
let boys = ['Jim', 'Mike', 'Tom'];
let girls = ['Lily', 'Jucy', 'Jane'];
let students = boys.concat(girls);
console.log(students);
[ 'Jim', 'Mike', 'Tom', 'Lily', 'Jucy', 'Jane' ]
那么可以使用+
吗? 下面试试:
let studentString = boys + girls;
console.log(studentString);
console.log(typeof studentString);
Jim,Mike,TomLily,Jucy,Jane
string
可见, 使用+
将数组变为了字符串.
数组排序和反转
sort()
可以对数组排序, reverse()
可以反转:
students.sort();
console.log(students);
students.reverse();
console.log(students);
[ 'Jane', 'Jim', 'Jucy', 'Lily', 'Mike', 'Tom' ]
[ 'Tom', 'Mike', 'Lily', 'Jucy', 'Jim', 'Jane' ]
数组和字符串的转换
数组 -> 字符串
可以使用toString()
方法实现, 或者String()
:
console.log(String(students))
studentString = students.toString();
console.log(studentString);
Jim,Mike,Tom,Lily,Jucy,Jane
Jim,Mike,Tom,Lily,Jucy,Jane
我看看到, 转换后每个元素逗号隔开. 那如果我想用其他方式分割呢? 我们可以使用join()
方法:
studentString = students.join('---');
console.log(studentString);
Tom---Mike---Lily---Jucy---Jim---Jane
可见, join()
内的参数就是连接符.
字符串 -> 数组
类似toString()
, 你应该已经猜到了吧? 但是不好意思, 没有这个方法!toArray()
相应join()
, 有一个split()
方法使用:
let studentArr = studentString.split('---');
console.log(studentArr);
[ 'Tom', 'Mike', 'Lily', 'Jucy', 'Jim', 'Jane' ]
可见, 可以split()
参数就是分隔符, 使用思路与join()
一样.
条件和循环
和其他语言没区别, 没新意, 用到了一看就懂, 不说了. 但是一些循环的细节内容会在后面相应部分说明.
细节与杂项
这部分内容过于细节或者比较杂不成系统, 但是遇到了真的头疼, 适合作为参考来看.
数据转换
其他类型-> number
一般来说, 我们使用Number()
方法将字符串转为数字:
let fromString = Number('1111')
console.log(typeof fromString)
number
其他类型 -> string
一般来说, 我们使用String()
方法将字符串转为数字:
let value = true;
console.log(typeof value); // boolean
value = String(value); // now value is a string "true"
console.log(typeof value); // string
boolean
string
神奇的四则运算符
+
和-
可以神奇的帮你转换数据类型到数字
let plusNumber = '1000';
console.log(`The type of plusNumber is ${typeof +plusNumber}`);
let minusNumber = '1000';
console.log(`The type of minusNumber is ${typeof -minusNumber}`);
/* 这两句不行
let mulNumber = '1000';
console.log(`The type of minusNumber is ${typeof *minusNumber}`);
let divNumber = '1000';
console.log(`The type of divNumber is ${typeof /divNumber}`);
*/
The type of plusNumber is number
The type of minusNumber is number
- 但是用
+
也可能会有意想不到的结果
console.log(1 + '2');
console.log(1 - '2');
console.log(1 * '2');
console.log(1 / '2');
12
-1
2
0.5
可见, 除了+
, 其他都是字符串转数字.
判断相等, 用===
, 不要用==
从某范围break
可以使用下面方法从某个范围跳出:
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
// if an empty string or canceled, then break out of both loops
if (j > 1) break outer; // 直接从outer跳出,可以用 continue试试
console.log(j);
}
console.log(i);
}
console.log('Done!');
0
1
Done!
break/continue
只能从内部循环跳到外部循环, 而且跳出的标记必须在前面语句中.
遍历
遍历数组
最熟悉的应该就是这种C语言都有的东西了吧:
let arr = ["Apple", "Orange", "Pear"];
for (let i = 0; i < arr.length; i++) {
console.log( arr[i] );
}
不过我们还可以这样:
let fruits = ["Apple", "Orange", "Plum"];
// 遍历所有元素
for(let fruit of fruits) {
console.log( fruit );
}
Apple
Orange
Plum
你可能发现, 也可以用
for (let key in arr)
, 但是这样不好, 不要用. 这个是针对对象遍历的.
解构赋值(Destructuring assignment)
其实就是分拆数组或者对象, 分别赋值给其他变量.
数组
let names = ["万物", "科技"]
// destructuring assignment
let [firstName, secondName] = names;
console.log(firstName);
console.log(secondName);
[firstName, secondName] = "wanwu.tech".split('.');
console.log(firstName);
console.log(secondName);
万物
科技
wanwu
tech
对象
let options = {
title: "Menu",
width: 100,
height: 200
};
let {width, title, height} = options; // 顺序无关, 而是对应属性名
console.log(title);
console.log(width);
console.log(height);
console.log('\n')
let {noThisOne, whatIsThis, IDoNotKnow} = options; // 如果没有, 那么是undefined
console.log(noThisOne);
console.log(whatIsThis);
console.log(IDoNotKnow);
Menu
100
200
undefined
undefined
undefined
内嵌
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true // 被赋值对象没有这个, 就不用管了
};
// destructuring assignment on multiple lines for clarity
let {
size: { // 内嵌
width,
height
},
items: [item1, item2], // 内嵌
title = "Menu" // options中不存在, 使用默认值
} = options;
console.log(title); // Menu
console.log(width); // 100
console.log(height); // 200
console.log(item1); // Cake
console.log(item2); // Donut
Menu
100
200
Cake
Donut