万物科技 学,以致用

JavaScript 2. 基础

2017-06-02
Geng

这部分介绍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, substrslice, 对于数组, 只有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

Comments

你可以请我喝喝茶,聊聊天,鼓励我

Wechat Pay
wechat

Thanks!