观此文,你仍需有C语言、HTML、CSS基础之基础。

本文规范基本上基于ECMAScript2015(就是ES6)。

你需要认识C语言的分支与循环处理、HTML的常见标签以及CSS的基础选择器。如果你对C语言的函数指针或者函数式编程常用的lambda表达式有所理解的话,将有助你快速上手JavaScript。

(事件那边你要是懂一点WPF的event原理就更好了……不过没人学C#吧……

如何输出

console.log(); //输出信息
console.warn(); //输出警告,是黄色的
console.error(); //输出报错,是红色的(虽然也不会导致程序中止

它们可以通过传入多个参数来实现一次性输出更多数据。

数据类型

通过let声明/定义变量,通过const声明常量。(不再推荐使用var)

例如:

const name = 'Alfred'; //name是常量,必须直接初始化,之后不可变
let age = 19; //age是变量,仍可变

你可与使用typeof运算符来输出一个量的数据类型,例如:

console.log(typeof age); //向控制台输出age的类型(输出number)

string

用单引号或者双引号包围的字符串。

例子中我们有:

const s = 'Hello World';

连接

使用加号可以连接字符串。

可以使用模板字符串来往字符串里面填入数据(使用反引号)。

例如:

let info1 = 'My name is ' + name + ', and I am ' + age + ' years old.'; //使用加法连接
let info2 = `My name is ${name}, and I am ${age} years old.`; //使用模板字符串
//info1 和 info2 两个字符串的内容一致

获取长度

使用字符串的length属性获取字符串长度。

例如:

console.log(s.length); //向控制台输出字符串s的长度(输出11)

转变字符

使用字符串的toUpperCase()方法把字符串里的字母都转成大写,使用toLowerCase()方法把字符串里的字母都转成小写。注意,返回值才是所求的字符串,原字符串并不会改变。

例如:

console.log(s.toUpperCase()); //向控制台输出全为大写字母的字符串s(输出为HELLO WORLD)
console.log(s.toLowerCase()); //向控制台输出全为小写字母的字符串s(输出为hello world)

获取子字符串

使用字符串的substring()方法获取字符串的子串。该方法有两个参数,第一个参数代表子串从原字符串的第几个开始(下标从0开始),第二个参数代表子串在父串的第几个字符前结束。注意,第一个参数所指的字符会被包含在子串中而第二个参数所指的不会。

例如:

console.log(s.substring(2,5));
    //向控制台输出s的自下标为2的字符开始,自下标为5的字符结束的子串(输出为llo)

将字符串分割到数组中

使用字符串的split()方法将字符串分割到数组中。该方法有一个参数,为分割的分隔符,此方法将按此分隔符分割该字符串到数组。如果要分割每个字符,请使用参数''(空字符串)。注意,参数将不出现在分割完的字符串中。

例如:

console.log(s.split(''));
    //输出["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"]
console.log(s.split(' '));
    //输出["Hello", "World"]
console.log(s.split('ell'));
    //输出["H", "o World"]

object

数组

一个数组内可以有多个数据,这些数据可以是不同类型的。

数组下标从0开始,逐项递增。

即使数组被定义为const,但仍可改变数组,只是不能给该量赋值其他数组。

创建数组

有多种方法创建数组:

const array1 = new Array(1, 2); //使用构造函数创建,括号内可以传入一些值以初始化数组(也可以不传)
const array2 = [1, 2, '233']; //直接创建

访问数组元素

直接使用[]即可。

console.log(array1[0]); //向控制台输出array1数组的第一项(下标为0)(输出1)

给数组添加元素

虽然array1只有两个元素,但是要想给它加元素,直接array1[2] = 3即可。注意,如果添加的位置比较不和原来的贴在一起,中间会用empty填充。

array1[2] = 3;
console.log(array1); //输出[1, 2, 3],长度为3
array1[6] = 7;
console.log(array1); //输出[1, 2, 3, empty × 3, 7],长度为7(empty也算长度)

//特殊情况:
const arr = [1, 2];
arr[-2] = 5;
console.log(arr); //输出 [1, 2, -2: 5],长度为2
//要访问下标为-2的元素,可以使用arr[-2]或者arr['-2']

向末尾追加,可以使用数组的push()方法,例如:

array2.push(666);
console.log(array2); //输出[1, 2, '233', 666]

向开头添加,可以使用数组的unshift()方法,例如:

array2.unshift(9);
console.log(array2); //输出[9, 1, 2, '233', 666]

去除数组中的元素

使用数组的pop()方法,可以去除数组的最后一个元素,同时,此方法会返回被去除的元素。(类似于其他语音的pushBack()方法。)例如:

let x = array2.pop();
console.log(array2); //输出[9, 1, 2, '233']
console.log(x); //输出666

检查某个量是不是数组

使用Array.isArray()方法可以检查一个量是不是数组,如果传入的参数是数组,它会返回true;否则,它会返回false。

获取数组中某个值的下标

使用数组的indexOf()方法可以获取数组中该元素(由参数传入)的下标。如果参数内容不存在于数组中,该函数会返回-1。例如:

console.log(array2.indexOf(2)); //输出2
console.log(array2.indexOf(999)); //输出-1

遍历数组

可以通过for...of循环遍历数组的值,例如:

for(let x of array2) {
    console.log(x);
}
//控制台会依次输出9, 1, 2, 233

或者使用数组的forEach()方法进行遍历。该方法需要传入一个参数作为回调函数,该回调函数有一个参数,即为每次遍历时代表的数组的内容,每次遍历执行一次回调函数。例如:

array2.forEach(function(x) { console.log(x); }); //参数为回调匿名函数
array2.forEach(x => console.log(x) ); //使用λ表达式的匿名函数
//控制台会依次输出9, 1, 2, 233

取出数组中对象的特定属性值并生成新数组

可以通过数组的map()方法实现。该方法需要传入一个参数作为回调函数,该回调函数有一个参数,即为每次遍历时代表的数组的内容,每次遍历执行一次回调函数,该回调函数需要返回特定的属性值。此方法的返回值为所求的数组。例如:

//获取数组中所有对象的id
const x = [
    {
        id: 1,
        name: 'Alfred'
    },
    {
        id: 2,
        name: 'John'
    }
]
const ids = x.map(function(i) { return i.id; });
const ids = x.map(i => i.id); //λ表达式版
console.log(ids);
//控制台会输出[1, 2]

筛选数组中满足特定属性值要求的对象并生成新对象数组

可以通过数组的filter()方法实现。该方法需要传入一个参数作为回调函数,该回调函数有一个参数,即为每次遍历时代表的数组的内容,每次遍历执行一次回调函数,该回调函数需要返回一个布尔值,为真的情况下此对象会被加入新数组。此方法的返回值为所求的数组。例如:

//筛选所有id=2的对象
const x = [
    {
        id: 1,
        name: 'Alfred'
    },
    {
        id: 2,
        name: 'John'
    }
]
const id2 = x.filter(function(i) { return i.id === 2; });
const id2 = x.filter(i => i.id === 2); //λ表达式版
console.log(id2);
//控制台会输出[{id: 2, name: "John"}]

对象

对象实际上就是大括号包围的键值对。({key: value})

即使对象被定义为const,但仍可改变对象的内容,只是不能给该量赋值其他对象。

例子中,有:

const person = {
    name: 'Alfred',
    age: 19,
    address: {
        province: 'Zhejiang',
        city: 'Hangzhou'
    }
};

访问对象的单个值

使用.运算符来方位对象的单个值。例如:

console.log(person.age); //输出19

解构对象

可以通过解构对象的方式从对象中取出一定数量的值。例如:

const { name, age, address: {city} } = person; //现在有3个const量分别为name、age和city

添加属性

可以直接为对象添加新的键值对,例如:

person.email = '[email protected]';
//那么person现在是
/*
{ 
    name: 'Alfred', 
    age: 19, 
    address: {
        province: 'Zhejiang', 
        city: 'Hangzhou' },
    email: '[email protected]'
}
*/

遍历对象的属性

可以通过for...in循环遍历对象的属性,例如:

for (x in person) {
    console.log(x);
}
//遍历属性的名字(键),控制台会依次输出name, age, address, email
for (x in person){
    console.log(person[x]);
}
//遍历属性的值,控制台会依次输出Alfred, 19, {province: "Zhejiang", city: "Hangzhou"}, [email protected]

JSON

JSON是一种数据格式,长得很像JavaScript的对象,经常用于传输数据。

使用JSON.stringify()函数可以把JavaScript的object类型数据转换为JSON字符串。例如:

const a = JSON.stringify(person);
console.log(a);
/*输出
{    "name":"Alfred",
    "age":19,
    "address":{"province":"Zhejiang","city":"Hangzhou"},
    "email":"[email protected]"
}
*/

其他

如果你给一个变量赋值为null,那么你用typeof运算符查看这个量的类型的时候,会发现它是object类型。

只定义了而未初始化的变量,它的默认值是undefined

其他待补充。

DOM

如何选择元素

使用document.querySelector()document.querySelectorAll()来选择HTML上的标签。

前者用来选择单个元素,后者可以选择多个元素并将其组入一个NodeList,它类似于数组,可以进行数组的一些操作(比如forEach()遍历和NodeList.children[]来选择第几个元素)。这两个函数的参数是一个字符串,字符串是选择器,形式同CSS的标签选择器、class选择器(加.)和id选择器(加#),例如:

const elem1 = document.querySelector('#id'); //如果实际可选的元素不止一个,则选择第一个
const elem2 = document.querySelectorAll('.item'); //选中了所有.item标记的元素

删除页面元素

可以使用页面元素.remove()方法完成。

elem1.remove(); //移除页面上的以#id标记的元素
elem2.remove(); //移除页面上的所有的.item标记的元素
elem2.lastElementChild.remove(); //移除elem2组合中的最后一个元素

添加页面元素

可以通过document.createElement()方法来创建一个元素。此方法的参数为你要创建的元素的标签名,它的返回值为新创建好的元素DOM对象。要往元素内添加元素,可以使用元素的appendChild()方法,参数为你要插入的元素。特殊地,若要插入文字,参数可以设置为document.createTextNode(),此方法的参数为元素内的字符串。例如:

//在一个ul内插入一个li,li的内容为2333
const ul = document.querySelector('ul') //选中ul
const li = document.createElement('li'); //创建li
li.appendChild(document.createTextNode('2333')); //li内插入字符
ul.appendChild(li); //把li加入ul

获取与编辑页面元素的内容试试

使用元素对象的textContentinnerTextinnerHTML属性可以方便的获取或者更改元素的内容。

elem2.firstElementChild.textContent = 'Hello'; //修改elem2集合中的第一个元素的标签中的文本内容
elem2.firstElementChild.innerText = 'Hello'; //效果同上
elem1.innerHTML = '<a href="xxx">233</a>'; //修改elem1的内嵌html代码

console.log(document.querySelector('h1').textContent); //输出的是文本
console.log(document.querySelector('h1').innerText); //同上
console.log(document.querySelector('h1').innerHTML); //输出的是该元素的内嵌的所有HTML代码与文本

输入框里面的内容,可以通过元素对象的value属性来获取。

获取与编辑页面元素的HTML属性与CSS样式

直接使用元素对象的相应属性并赋值即可。

给HTML元素添加新类使用元素的classList.add()方法实现,该函数接受一个字符串参数,即为要添加的class名;另外有一个方法叫classList.remove(),可以去除元素的某个class。

elem1.style.background = 'red'; //把elem1元素的背景改成红色的(CSS)
elem1.href = 'https://www.baidu.com'; //把elem的href属性设为百度(之前没设置的会新指定)
console.log(elem1.target); //输出elem1元素的target属性的内容

elem1.classList.add('container'); //给elem1的class属性添加一个 container 类(可用于CSS选择)

事件

以一个按钮元素为例。

btn = document.querySelector('.btn');

为一个元素添加监听事件

使用元素的addEventListener()方法可以为特定的元素添加监听事件。该函数有两个参数,第一个参数是一个字符串,代表要监听的事件;第二个参数为在目标元素上监听到该事件时所触发的回调函数。关于这个回调函数,它接受一个参数,这个参数是被监听方法自动传入的事件对象,函数体即该事件触发时执行的行为。该事件对象的target属性即为触发本事件的元素本身。例如,我给这个按钮添加单击按下时的监听事件:

btn.addEventListener('click', e => {
    e.preventDefault(); //阻止该行为的默认事件,比如提交表单、跳转网页等
    console.log('clicked!');
});

常用事件有:

  • click:单击
  • mouseover:鼠标移入、悬浮在上
  • mouseout:鼠标移出
  • submit:表单提交

以及其他的比如输入事件等等。

事件可以用于检查表单格式(我懒得举例子了,建议自己实现一下,获取DOM对象然后在函数体内确认)。

Ending

看到这里就把整个文章看完了,但是你以为你这就可以愉快的写js了吗?

并不!

你要是还想了解更多的JavaScript语言方面的东西,推荐你几本书:《ES6标准入门(第三版)》、《JavaScript高级程序设计(第四版)》和《JavaScript DOM编程艺术》。

Good luck, and good night!