参考教程:JavaScript教程
1. 快速入门
1.1 基本语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--JavaScript严格区分大小写-->
<script>
// 1. 定义变量 变量类型 变量名 = 变量值
var score = 1 ;
//alert(num)
// 2. 条件控制
if (score > 60 && score < 70){
alert("60~70");
}else if(score > 70 && score < 80){
alert("70~80");
}else{
alert("other")
}
</script>
</head>
<body>
</body>
</html>
1.2 数据类型
变量
var a = 1;
var [x, y, z] = ['hello', 'JavaScript', 'ES6']; // 解构赋值,一一对应
number
JavaScript不区分小数和整数,统一成Number
123//整数123
123.1//浮点数123.1
1.123e3//科学计数法
-99//负数
NaN //not a number
Infinity // 表示无限大
字符串
‘abc’ “abc”
布尔值
true,false
逻辑运算
&& || !
比较运算符
== // 等于(类型不一样,值一样,也会判断为true)
=== // 绝对等于(类型一样,值一样,结果为true)
这是一个JS的缺陷,坚持不要使用 == 比较
关于 NaN
- NaN === NaN,这个与所有的数值都不相等,包括自己
- 只能通过isNaN(NaN)来判断这个数是否是NaN
数组
两种方法定义:
var arr = [1,2,3,4,5,'hello',null,true];
var arr = new Array(1,2,3,4,5,'hello');
arr[0]
> 1
arr[7]
> undefined
对象
相似于 Python 中的 dict
var person = {
name:'Tom',
age:3,
tags:['js','java','web','...']
}
person.name
> "Tom"
person.age
> 3
2. 数据类型
2.1 字符串
多行字符串
var msg =
`hello
world
你好呀
nihao
` // ``:tab 上面 esc下面
模板字符串
let name = 'Tom'; // let 声明局部作用域变量
const sex = 'boy'; // const 声明常量
var msg = "你好,${name}";
字符串长度
str.length
字符串的不可变性
var str = 'student';
str[0]
> 's'
str[0] = '1'
str
> 'student'
大小写转换
student.toUpperCase(); // 注意是方法,不是属性
student.toLowerCase();
查找位置
student.indexof(‘t’)
截取字符串
student.substring(1)//从第一个字符串截取到最后一个字符串
student.substring(1,3)//[1,3)
2.2 数组
var arr = [1,2,3,4,5,6];
长度
arr.length
假如给arr.lennth赋值,数组大小就会发生变化,如果长度过小,元素就会丢失
通过元素获得下标索引 indexOf()
arr.indexOf(2);
> 1
截取数组 slice()
var arr_new = arr.slice(1,3);
返回一个新的 Array
如果不给slice()
传递任何参数,它就会从头到尾截取所有元素。利用这一点,我们可以很容易地复制一个Array
:
var aCopy = arr.slice();
push(),pop() 尾部
push:压入到尾部
pop:弹出尾部的一个元素
unshift(),shift() 头部
unshift:压入到头部
shift:弹出头部的一个元素
排序 sort()
var arr = ['B', 'C', 'A'];
arr.sort();
arr; // ['A', 'B', 'C']
逆序 reverse()
把整个Array
的元素给掉个个,也就是反转
var arr = ['one', 'two', 'three'];
arr.reverse();
arr; // ['three', 'two', 'one']
连接数组 concat()
返回一个新的Array
var arr = ['A', 'B', 'C'];
var added = arr.concat([1, 2, 3]);
added; // ['A', 'B', 'C', 1, 2, 3]
拼接字符串 join()
把当前Array
的每个元素都用指定的字符串连接起来,然后返回连接后的字符串
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'
splice
增删改添一把手
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']
2.3 对象
var xiaoming = {
name: '小明',
birth: 2002,
school: 'No.1 Middle School',
height: 1.70,
weight: 65,
score: null
};
JavaScript中的所有的键都是字符串,值是任意对象
两种访问属性的方法
xiaoming.name; // '小明'
xiaoming['birth']; // 2002
xiaoming.girlfriend; // undefined
属性不存在返回 undefined
可以动态地给一个对象添加或删除属性
var xiaoming = {
name: '小明'
};
xiaoming.age = 18; // 新增一个age属性
xiaoming.age; // 18
delete xiaoming.age; // 删除age属性
xiaoming.age; // undefined
检测某对象是否拥有某一属性,可以用in
操作符
'name' in xiaoming; // true
判断一个属性是否是这个对象自身拥有的,还是继承来的 hasOwnProperty()
var xiaoming = {
name: '小明'
};
xiaoming.hasOwnProperty('name'); // true
xiaoming.hasOwnProperty('toString'); // false
2.4 map 和 set
map 也是一组键值对的结构
对象的键必须是字符串,而map 可将Number或者其他数据类型作为键
初始化Map
需要传入一个二维数组(构造方法)
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]); // 注意小括号
m.set('Adam', 67); // 增 set
m.delete('Adam'); // 删 delet
m.set('Adam', 77); // 改 set (也就是新增覆盖)
m.get('Adam'); // 查 get
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // undefined
Set:无序不重复的集合
创建一个Set
,需要传入一个Array
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
重复元素在Set
中自动被过滤
s.add(4); // 增 add
s.delete(4); // 删 delete
2.5 iterable
Array
、Map
和Set
都属于iterable
类型。具有iterable
类型的集合可以通过新的for (... of ...)
循环来遍历
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
console.log(x);
}
for (var x of s) { // 遍历Set
console.log(x);
}
for (var x of m) { // 遍历Map
console.log(x[0] + '=' + x[1]);
}
3. 过程控制
if 判断
var age = 3;
if (age >= 18) {
alert('adult');
} else if (age >= 6) {
alert('teenager');
} else {
alert('kid');
}
while循环
var x = 0;
var n = 99;
while (n > 0) {
x = x + n;
n = n - 2;
}
do … while循环
var n = 0;
do {
n = n + 1;
} while (n < 100);
n; // 100
for循环
var arr = ['Apple', 'Google', 'Microsoft'];
var i, x;
for (i=0; i<arr.length; i++) {
x = arr[i];
console.log(x);
}
for …in循环
把一个对象的所有属性依次循环出来
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
console.log(key); // 'name', 'age', 'city'
}
由于Array
也是对象,而它的每个元素的索引被视为对象的属性,因此,for ... in
循环可以直接循环出Array
的索引:
var a = ['A', 'B', 'C'];
for (var i in a) {
console.log(i); // '0', '1', '2'
console.log(a[i]); // 'A', 'B', 'C'
}
注意,for ... in
对Array
的循环得到的是String
而不是Number
。
forEach循环
iterable
内置的forEach
,方法接收一个函数,每次迭代就自动回调该函数
4. 函数
4.1 定义函数
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
定义了一个 abs 函数
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
定义了一个匿名函数,把值赋给了变量abs
,所以可通过变量abs
调用该函数
4.2 函数传参
javaScript可以传任意个参数,也可以不传递参数
未接收值的参数将被赋值 undefined
不会报错
① 用关键字arguments
来处理传入的所有参数
arguments
类似 Array
但它不是一个Array
function foo(x) {
console.log('x = ' + x); // 10
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
x = 10
arg 0 = 10
arg 1 = 20
arg 2 = 30
arguments
常用于判断传入参数的个数
function foo(a, b, c) {
if (arguments.length === 2) {
// 实际拿到的参数是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值
}
// ...
}
② 用关键字reset
来处理传入的额外参数
rest参数只能写在最后,前面用...
标识
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
若传入的参数连正常定义的参数都没填满,rest参数会接收一个空数组(注意不是undefined
)
4.3 变量作用域
JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
'use strict';
function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}
foo();
Hello, undefined
js执行引擎提升了y的声明,但是不会提升变量y的赋值
**全局作用域 **
JavaScript默认有一个全局对象window
,**全局作用域的变量(所有通过 var 声明的变量)**实际上被绑定到window
的一个属性
var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'
定义的函数实际上也是一个全局变量,被绑定到window
上
function foo() {
alert('foo');
}
foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用
JavaScript实际上只有一个全局作用域window
。任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError
错误。
window.alert('调用window.alert()');
// 把alert保存到另一个变量:
var old_alert = window.alert; // 指向
// 给alert赋一个新函数:
window.alert = function () {}
alert('无法用alert()显示了!');
// 恢复alert:
window.alert = old_alert;
alert('又可以用alert()了!');
局部作用域
用let
申明一个块级(局部)作用域的变量
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
i += 1; // SyntaxError:
}
function foo() {
for (var i=0; i<100; i++) {
sum += i;
}
i += 100; // 仍然可以引用变量i
}
用const
声明的常量也是块级作用域的常量
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14
4.4 方法
绑定到对象上的函数称为方法
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.name; // 属性
xiaoming.age(); // 方法,注意括号
在一个方法内部,this
是一个特殊变量,它始终指向当前对象
5. 标准对象
在 JavaScript 中,一切皆对象
null
的类型是object
,Array
的类型也是object
JavaScript还提供了包装对象,如Java中的int
和Integer
这种暧昧关系
var n = new Number(123);
var b = new Boolean(true);
var s = new String('str');
虽然包装对象看上去和原来的值一模一样,显示出来也是一模一样,但他们的类型已经变为object
了
用Number()
、Boolean
和String()
把任何类型的数据转换为number
、boolean
和string
类型(注意不是其包装类型)
5.1 Date
var d = new Date(2020, 7, 4, 20, 15, 30, 123);
d; // Tus Aug 4 2015 20:15:30 GMT+0800 (CST)
注意JavaScript的月份范围用整数表示是0~11,0
表示一月,1
表示二月……,所以要表示8月,我们传入的是7!
var d = new Date(1435146562875); // 传入时间戳
d; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
var now = new Date();
now.getFullYear(); // 年
now.getMonth(); // 月
now.getDate(); // 日
now.getDay(); // 星期
now.getHours(); // 小时
now.getMinutes(); // 分钟
now.getSeconds(); // 秒
now.getMilliseconds(); // 毫秒数
now.getTime(); // 时间戳
5.2 RegExp
正则表达式
创建正则表达式
var re1 = /ABC\-001/; // 直接写出来
var re2 = new RegExp(r'ABC\-001'); // new 出来
判断是否匹配:test
var re = new RegExp(r'^\d{3}\-\d{3,8}$');
re.test('010-12345'); // true
re.test('010-1234x'); // false
切分字符串:split
'a,b, c d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
分组
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345'] // 注意第一项是原串本身
re.exec('010 12345'); // null
全局搜索
var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到结束仍没有匹配到
5.3 JSON
var user = {
name : "xiaoming"
age : 18
sex : "man"
}
// js对象序列化为json
var jsonUser = JSON.stringify(user)
// json反序列化为js对象
var obj = JSON.parson(jsonUser)
补一个Python的:
6. 面对对象编程
6.1 原型继承
使用原型属性进行继承
var Student = {
name : "Student",
run : function() {
console.log(this.name + "is running")
}
};
var xiaoming = {
name : "xiaoming"
};
xiaoming.__proto__ = Student; // “继承”
6.2 class 继承
ES6 引入
// 定义一个学生类
class Student{
// 构造器
constructor(name){
this.name = name
}
// class中定义方法无需 function
hello(){
alert("Hello")
}
}
此时的实例需 new 出来
var xiaoming = new Student("xiaoming")
class XiaoStudent extends Student{
constructor(name,grade){
super(name); // 同Java,需先满足父类的构造器
this.grade = grade;
}
myGrade(){
alert('我是一名小学生');
}
}
var xiaohong = new XiaoStudent("xiaohong",1);
本质上还是原型继承
7. 操作BOM对象
BOM 浏览器对象
window
window
代表浏览器窗口
window.innerWidth
window.innerHeight
window.outerWidth
window.outerHeight
navigator
navigator
对象表示浏览器的信息
navigator.appName // 浏览器名称;
navigator.appVersion // 浏览器版本;
navigator.language // 浏览器设置的语言;
navigator.platform // 操作系统类型;
navigator.userAgent // 浏览器设定的User-Agent字符串
screen
screen.width // 屏幕宽度,以像素为单位;
screen.height // 屏幕高度,以像素为单位;
screen.colorDepth // 返回颜色位数,如8、16、24
location
location
对象表示当前页面的URL信息
location.protocol // 'http'
location.host // 'www.example.com'
location.port // '8080'
location.pathname // '/path/index.html'
location.search // '?a=1&b=2'
location.hash // 'TOP'
调用location.reload()
重新加载当前页面
调用location.assign()
加载一个新页面
document
document
对象表示当前页面的HTML DOM文档树
document.getElementById()
document.getElementsByTagName()
document.cookie // 获取到当前页面的Cookie
history
history.back()
history.forward ()
8. 操作DOM对象
8.1 获取节点
//对应Css选择器
var h1 = document.getElementsByTagName('hl');
var p1 = document.getElementById('p1');
var p2 = document.getElementsByClassName('p2');
var father =document.getElementById('father');
var childrens= father.chi1dren;//获取父节点下的所有子节
// father. firstchild
// father. lastchild
这是原生代码,之后我们尽量都使用jQuery();
8.2 操作节点
var id1 = document.getElementById('id1');
id1.innerText = '456'; // 修改文本的值
id1.innerHTML = '<strong>123</strong>'; // 修改标签内的值
// 操作CSS
id1.style.color = 'yellow';
8.3 删除节点
先获取父节点,再通过父节点删除自己
// 拿到待删除节点:
var self = document.getElementById('to-be-removed');
// 拿到父节点:
var parent = self.parentElement;
// 删除:
var removed = parent.removeChild(self);
removed === self; // true
8.4 插入节点
利用父节点插入一个新的子节点
<!-- HTML结构 -->
<p id="js">JavaScript</p>
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
var list = document.getElementById('list');
var haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);
9. 操作表单
9.1 获取值
// <input type="text" id="email">
var input = document.getElementById('email');
input.value; // '用户输入的值'
这种方式可以应用于text
、password
、hidden
以及select
对于单选框和复选框,value
属性返回的永远是HTML预设的值,而我们需要获得的实际是用户是否“勾上了”选项,所以应该用checked
判断
// <label><input type="radio" name="weekday" id="monday" value="1"> Monday</label>
// <label><input type="radio" name="weekday" id="tuesday" value="2"> Tuesday</label>
var mon = document.getElementById('monday');
var tue = document.getElementById('tuesday');
mon.value; // '1'
tue.value; // '2'
mon.checked; // true或者false
tue.checked; // true或者false
9.2 设置值
直接设置对应属性值即可
// <input type="text" id="email">
var input = document.getElementById('email');
input.value = 'test@example.com'; // 文本框的内容已更新
9.3 提交表单
方式一是通过<form>
元素的submit()
方法提交一个表单
function doSubmitForm() {
var form = document.getElementById('test-form');
// 可以在此修改form的input...
// 提交form:
form.submit();
}
方式二是响应<form>
本身的onsubmit
事件,在提交form时作修改
function checkForm() {
var form = document.getElementById('test-form');
// 可以在此修改form的input...
// 继续下一步:
return true;
}
通过return true
来告诉浏览器继续提交,若return false
,浏览器将不会继续提交form,这种情况通常对应用户输入有误,提示用户错误信息后终止提交form
<!-- HTML结构 -->
<form id="test-register" action="#" target="_blank" onsubmit="return checkRegisterForm()">
<p id="test-error" style="color:red"></p>
<p>
用户名: <input type="text" id="username" name="username">
</p>
<p>
口令: <input type="password" id="password" name="password">
</p>
<p>
重复口令: <input type="password" id="password-2">
</p>
<p>
<button type="submit">提交</button> <button type="reset">重置</button>
</p>
</form>
var checkRegisterForm = function () {
var user=document.getElementById('username').value;
var password=document.getElementById('password').value;
var password_2=document.getElementById('password-2').value;
var reg_user=/^\w{3,10}$/;
var reg_password=/^\w{6,20}$/;
if(reg_user.test(user) && reg_password.test(password) && password ===password_2)
return true;
else
return false;
}