1. 什么是JavaScript
JavaScript是世界上最流行的脚本语言,因为你在电脑、手机、平板上浏览的所有的网页,以及无数基于HTML5的手机App,交互逻辑都是由JavaScript驱动的。
简单地说,JavaScript是一种运行在浏览器中的解释型的编程语言。
2. 快速入门
2.1 引入JS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/qj.js"></script>
</head>
<body>
</body>
</html>
alert('hello, world');
2.2 基本语法
alert(num)
console.log(num)
2.3 数据类型
数值、文本、图形、音频、视频
比较运算符
===
NaN与所有的数都不相等
只能使用方法 isNaN()
数组
var num = [1,2,3,4,'hello', 'a', 4.2];
用中括号,可以是不同的数据类型
对象
var person = {
name: "codeslogan",
age: 3,
tag: ['js','java','web']
}
用大括号
命令行调用
person.name
> "codeslogan"
person.age
> 3
person.tag
> ['js','java','web']
2.4 严格检查模式
<script>
'use strict';
let i=1;
</script>
'use strict'; 需要放在JS的第一行,
预防变量定义时的随意性所导致的问题
局部变量用let关键词定义
3. 数据类型详解
3.1 字符串
多行字符串
var msg = `hello
world
java
javascript
javaweb`;
模板字符串
<script>
'use strict';
let str = "hello";
let age = 3;
let msg = `你好呀,${str}`;
</script>
字符串的不可变性
3.2 数组
Array可以包含任何数据类型的数据
长度
arr.length可以通过赋值任意改变
indexOf
获取某元素的下标值
slice()
数组版的substring,用法[a,b)
并返回一个新数组
push() pop()
push()
pop()
unshift() shift()
unshift()
shift()
sort()
排序,且会改变原来数组的值
reverse()
反转,且会改变原来数组里的值
concat()
拼接,不会改变原数组的值,返回一个新数组
连接符 join()
var s = ['A','B', 'C']
s.join('-')
> 'A-B-C'
以join()方法中的符号,将数组元素拼接起来并返回
3.3 对象
键值对
若干个键值对,所有的键都是一个字符串,值可以是任意的对象
person['age'] 可以直接访问age属性
var 对象名 = {
属性名: 属性值,
属性名: 属性值,
属性名: 属性值
}
不存在的属性
使用一个不存在的属性,并不会报错
person.haha
> undefied
动态删减属性
delete person.name
> true
person对象中的name属性被删除
判存
'age' in person
> true
//继承
'toString' in person
> true
判断一个属性是否是自身拥有(不是从父类继承的)
person.hasOwnProperty('toString')
> false
person.hasOwnProperty('age')
> true
3.4 流程控制
<script>
'use strict';
var age = 3;
while (age < 100) {
age += 1;
console.log(age);
}
</script>
for (let i = 0; i < 10; i++) {
console.log(i);
}
foreach遍历数组
E5.1引入
<script>
var num = [12,1,2,3,4,5,6];
num.forEach(function (value) {
console.log(value);
})
</script>
12
1
2
3
4
5
6
3.5 Map & Set
Map:
<script>
'use strict';
var map = new Map([['tom',12],['jason',4], ['adam',21]]);
var age = map.get('tom');
map.set('admin',123456);
map.delete('tom');
console.log(age);
console.log(map)
</script>
Set:无序不重复集合
var set = new Set([1,2,1,1,1,3,4]);
set.add(5);
set.delete(1);
console.log(set.has(2));
Set.prototype.add()
Set.prototype.clear()
Set.prototype.delete()
Set.prototype.entries()
Set.prototype.forEach()
Set.prototype.has()
Set.prototype.values()
Set.prototype[@@iterator]()
3.6 iterator
遍历数组
var num = [1,2,3,4,5,6];
for (let number of num) {
console.log(number);
}
1
2
3
4
5
6
遍历Map
var map = new Map([['jack',18], ['tom',12], ['adam',99]]);
for (let mapElement of map) {
console.log(mapElement)
}
['jack', 18]
['tom', 12]
['adam', 99]
遍历Set
var set = new Set([1,1,1,1,3,2]);
for (let number of set) {
console.log(number);
}
1
3
2
4. 函数及面向对象编程
4.1 函数定义
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
function 指出这是一个函数定义;abs 是函数的名称;(x) 括号内列出函数的参数,多个参数以, 分隔;{ ... } 之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
在这种方式下,function (x) { ... } 是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs ,所以,通过变量abs 就可以调用该函数。
上述两种定义完全等价
注意第二种方式按照完整语法需要在函数体末尾加一个; !!!表示赋值语句结束。
arguments
function foo(x) {
console.log('x = ' + x);
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]);
}
}
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 ]
4.2 变量作用域
'use strict';
function foo() {
var x = 1;
function bar() {
var y = x + 1;
}
var z = y + 1;
}
内部函数可以访问外部变量,反之则不行
变量提升
'use strict';
function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}
Hello, undefined
意味着js会自动将变量的声明提升到整个代码的顶部,但是注意一点,提升的是声明,具体的定义不会跟着提升
因此在输出 y 时,结果仍然是undefined
全局作用域
'use strict';
var course = 'Learn JavaScript';
alert(course);
alert(window.course);
使用window关键字,代表引用全局变量
'use strict';
window.alert('调用window.alert()');
var old_alert = window.alert;
window.alert = function () {}
window.alert = old_alert;
alert('又可以用alert()了!');
在修改window.alert 方法后,发现函数无法再进行输出
可以把调用的alert() 函数看作window 的一个变量
名字空间
全局变量会绑定到window 上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
var MYAPP = {};
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
MYAPP.foo = function () {
return 'foo';
};
把自己的代码全部放入唯一的名字空间MYAPP 中,会大大减少全局变量冲突的可能。
许多著名的JavaScript库都是这么干的:jQuery,YUI,underscore等等。
局部作用域
'use strict';
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
i += 1;
}
关键在于let关键字的使用,定义局部变量
4.3 方法
方法可以看作定义在对象里的一个函数
属性名:function() {
? 函数体
}
var person = {
birth: 2001,
name: 'adam',
age: function () {
var now = new Date().getFullYear();
return now - this.birth;
}
}
另一种写法
属性名: 函数名
function getAge() {
var now = new Date().getFullYear();
return now - this.birth;
}
var person = {
birth: 2001,
name: 'adam',
age: getAge
}
apply
getAge.apply(person,[])
4.4 *闭包
闭包可以理解为函数的嵌套
function final_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
在以上的例子中,我们在final_sum(arr) 中定义中sum 函数,sum函数可以直接使用来自外部函数提供的参数,并且可以将整个内部函数作为返回值返回
当我们调用final_sum() 时,返回的并不是求和结果,而是求和函数:
var f = lazy_sum([1, 2, 3]);
调用函数f 时,才真正计算求和的结果:
f();
4.5 箭头函数
箭头函数相当于匿名函数,并且简化了函数定义
x => x*x
等价于
function (x) {
return x * x;
}
另一种形式
x => {
if (x > 0) {
return x * x;
}
else {
return - x * x;
}
}
4.6 创建对象
var Student = {
name: "adam",
age: 3,
sex: '男',
run: function () {
console.log(this.name + " run")
}
}
var jack = {
name: "jack"
}
jack.__proto__ = Student;
jack继承自Student类,可以调用Student对象的run方法
4.7 class继承
新的关键字class 从ES6开始正式被引入到JavaScript中。class 的目的就是让定义类更简单。
比较一下就可以发现,class 的定义包含了构造函数constructor 和定义在原型对象上的函数hello() (注意没有function 关键字)
<script>
class student {
constructor(name) {
this.name = name;
}
hello() {
alert("hello")
}
}
class graduate extends student {
constructor(name, grade) {
super(name);
this.grade = grade;
}
code() {
alert("I love coding")
}
}
var jack = new student("jack");
var tom = new graduate("tom",3);
</script>
4.8 **原型链继承
5. 常用对象
5.1 date
var date = new Date();
date.getFullYear();
date.getDate();
date.getDay();
date.getHours();
date.getMinutes();
date.getMonth();
date.getSeconds();
date.getTime();
date.toString()
date.toGMTString()
5.2 JSON
是什么?
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
<script>
var user = {
name: "adam",
age: 3,
sex: '男'
}
</script>
json和js对象
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
var obj = {name: 'adam', age: 3, sex: '男'};
var json = '{"name":"adam","age":3,"sex":"男"}';
json格式用单引号'' 包含,键值统一用双引号
JSON 和 JS 对象互转
要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'});
6. Dom(重点)
文档对象模型 document object model
始终记住DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作:
- 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
- 遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
- 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
- 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dom结点</title>
</head>
<body>
<div id="father">
<h1 id="h1">h1</h1>
<p class="p1">p1</p>
<p id="p2">p2</p>
</div>
<script>
var div1 = document.getElementById('father');
var h1 = document.getElementById('h1');
var p1 = document.getElementsByClassName('p1');
var p2 = document.getElementsByName('p');
</script>
</body>
</html>
最常用的方法是
document.getElementById()
document.getElementsByTagName()
以及CSS选择器document.getElementsByClassName() 。
6.1 插入
追加
appendChild 方法加结点添加至此末尾
<p id="js">javascript</p>
<div id="list">
<p id="javase">javase</p>
<p id="javaee">javaee</p>
<p id="javame">javame</p>
</div>
<script>
var
js = document.getElementById("js"),
list = document.getElementById("list");
list.appendChild(js)
</script>
效果
这个节点首先会从原先的位置删除,再插入到新的位置。
从头创建
<script>
var js = document.getElementById("js"),
python = document.createElement('p'),
list = document.getElementById("list");
python.id = "python";
python.innerText = "Python";
list.appendChild(python)
list.appendChild(js)
</script>
document.createElement('p') 通过此方法,创建一个p标签
python.id python.innerText 分别修改其Id与文本
除了添加标签以外,我们可以利用js的这一特性,来添加css样式表
var d = document.createElement('style');
d.setAttribute('type', 'text/css');
d.innerHTML = 'p { color: yellow; background: red }';
document.getElementsByTagName('head')[0].appendChild(d);
<style type="text/css">
p{
color: yellow;
background: red
}
</style>
以上两个操作等价!
insertBefore
var
list = document.getElementById("list"),
ee = document.getElementById("javaee"),
js = document.getElementById("js");
list.insertBefore(js,ee);
Node.insertBefore( newChild: HTMLElement, refChild: Node | null): HTMLElement
6.2 更新
一种是修改innerHTML 属性,这个方式非常强大,不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树:
值得注意的是,innerHTML是属性,而不是方法
var aa = document.getElementById('h1')
aa.innerHTML="<strong>123</strong>"
innerHTML里可以使用html标签,会自动转变为相应的格式
第二种是修改innerText 或textContent 属性,这样可以自动对字符串进行HTML编码,保证无法设置任何HTML标签:
var aa = document.getElementById('h1')
aa.innerText="abcdedf"
aa.textContent="aaa"
两者的区别在于读取属性时,innerText 不返回隐藏元素的文本,而textContent 返回所有文本。
6.3 删除
删除结点,首先定位到要删除的文档标签,可以通过id名
获取当前标签的父元素
通过父元素来移除当前标签,从而达到删除的效果
var self = document.getElementById("p2")
var father = self.parentElement
var remove = father.removeChild(self)
remove === self
注意到删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
当你遍历一个父节点的子节点并进行删除操作时,要注意,children 属性是一个只读属性,并且它在子节点变化时会实时更新。
也就是说存在一个操作,重复删除第一个结点,就可以达到删除所有结点的效果
var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]);
parent.removeChild(parent.children[0]);
7. Bom(重点)
浏览器对象模型
window
window 对象不但充当全局作用域,而且表示浏览器窗口
window 对象有innerWidth 和innerHeight 属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高
对应的,还有一个outerWidth 和outerHeight 属性,可以获取浏览器窗口的整个宽高。
console.log(window.outerHeight)
701
console.log(window.outerWidth)
865
console.log(window.innerHeight)
578
console.log(window.innerWidth)
150
navigator
navigator 对象表示浏览器信息,最常用的属性包括:
-
navigator.appName:浏览器名称; Netscape -
navigator.appVersion:浏览器版本; 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 -
navigator.language:浏览器设置的语言; zh -
navigator.platform:操作系统类型; win32 -
navigator.userAgent:浏览器设定的User-Agent 字符串 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36
请注意,navigator 的信息可以很容易地被用户修改,所以JavaScript读取的值不一定是正确的
screen
screen 对象表示屏幕的信息,常用的属性有:
- screen.width:屏幕宽度,以像素为单位;
- screen.height:屏幕高度,以像素为单位;
- screen.colorDepth:返回颜色位数,如8、16、24
location*
location 对象表示当前页面的URL信息。例如,一个完整的URL:
http://www.example.com:8080/path/index.html?a=1&b=2#TOP
location.protocol;
location.host;
location.port;
location.pathname;
location.search;
location.hash;
document**
document 对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构,document 对象就是整个DOM树的根节点。
document 的title 属性是从HTML文档中的<title>xxx</title> 读取的,但是可以动态改变:
document.title = '努力学习JavaScript!';
cookie
document.cookie
Cookie是由服务器发送的key-value 标示符。因为HTTP协议是无状态的,但是服务器要区分到底是哪个用户发过来的请求,就可以用Cookie来区分。当一个用户成功登录后,服务器发送一个Cookie给浏览器,例如user=ABC123XYZ(加密的字符串)... ,此后,浏览器访问该网站时,会在请求头附上这个Cookie,服务器根据Cookie即可区分出用户。
Cookie还可以存储网站的一些设置,例如,页面显示的语言等等
然而cookie的使用存在极大的安全隐患,js可以读取到页面的cookie,而用户的登录信息通常也存在cookie中。
在html中引入第三方的js代码是允许的,如果存在恶意代码,cookie则会被截取
<html>
<head>
<script src="http://www.foo.com/jquery.js"></script>
</head>
...
</html>
www.foo.com 网站将直接获取到www.example.com 网站的用户登录信息
为了确保安全,服务器端在设置Cookie时,应该始终坚持使用httpOnly 。
现主流的浏览器都有httpOnly这个选项
history
history 对象保存了浏览器的历史记录,JavaScript可以调用history 对象的back() 或forward () ,相当于用户点击了浏览器的“后退”或“前进”按钮。
这个对象属于历史遗留对象,对于现代Web页面来说,由于大量使用AJAX和页面交互,简单粗暴地调用history.back() 可能会让用户感到非常愤怒。
新手开始设计Web页面时喜欢在登录页登录成功时调用history.back() ,试图回到登录前的页面。这是一种错误的方法。
任何情况,你都不应该使用history 这个对象了。
操作表单
html主要表单
HTML表单的输入控件主要有以下几种:
- 文本框,对应的
<input type="text"> ,用于输入文本; - 口令框,对应的
<input type="password"> ,用于输入口令; - 单选框,对应的
<input type="radio"> ,用于选择一项; - 复选框,对应的
<input type="checkbox"> ,用于选择多项; - 下拉框,对应的
<select> ,用于选择一项; - 隐藏文本,对应的
<input type="hidden"> ,用户不可见,但表单提交时会把隐藏文本发送到服务器。
<form action="post">
<p><span>用户名</span> <input type="text", id="username"></p>
</form>
<script>
var user_text = document.getElementById("username");
</script>
这种方式可以应用于text 、password 、hidden 以及select 。
至于单选框和多选框需要利用到checked 关键字
<form method="post">
<p>
<span>用户名</span> <input type="text", id="username">
</p>
<p>
<span>性别</span> <input type="radio" name="sex" value="boy" id="boy">男
<input type="radio" name="sex" value="girl" id="girl">女
</p>
</form>
<script>
var
user_text = document.getElementById("username"),
boy_radio = document.getElementById("boy"),
girl_radio = document.getElementById("girl");
</script>
boy_radio.value
> 'boy'
girl_radio.value
> 'girl'
boy_radio.checked
> false
girl_radio.checked
> true
md5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>submit</title>
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.min.js"></script>
</head>
<body>
<form action="#" method="post" onsubmit="return f()">
<p><span>用户名:</span><input type="text" name="username" id="username"></p>
<p><span>密码:</span><input type="password" id="input-pwd"></p>
<input type="hidden" id="md5-pwd" name="password">
<button type="submit">提交</button>
</form>
<script>
function f() {
var user_name = document.getElementById("username");
var input_pwd = document.getElementById("input-pwd");
var md5_pwd = document.getElementById("md5-pwd");
md5_pwd.value = md5(input_pwd.value);
return true;
}
</script>
</body>
</html>
注意到id 为md5-pwd 的<input> 标记了name="password" ,而用户输入的id 为input-pwd 的<input> 没有name 属性。没有name 属性的<input> 的数据不会被提交
操作文件
<input type="file">
注意:当一个表单包含<input type="file"> 时,表单的enctype 必须指定为multipart/form-data ,method 必须指定为post ,浏览器才能正确编码并以multipart/form-data 格式发送表单的数据。
8. jQuery
8.1 cdn引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
</body>
</html>
8.2 公式
$(selector).action()
selector即css中的选择器
8.3 事件
<a href="" id="test-jQuery">here</a>
<script>
$('#test-jQuery').click(function () {
alert('hello,jQuery')
})
</script>
jQuery对象类似数组,它的每个元素都是一个引用了DOM节点的对象。
选择器与dom对比
jQuery | dom |
---|
$(‘p’).click() | document.getElementsByTagName() | $(’#idname’).click() | document.getElementById() | $(’.classname1’).click() | document.getElementsByClassName() |
详细选择器请见 jQuery官方文档
鼠标事件
事件包括鼠标事件、键盘事件
- click: 鼠标单击时触发;
- dblclick:鼠标双击时触发;
- mouseenter:鼠标进入时触发;
- mouseleave:鼠标移出时触发;
- mousemove:鼠标在DOM内部移动时触发;
- hover:鼠标进入和退出时触发两个函数,相当于mouseenter加上mouseleave。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<style>
#divMove{
width: 400px;
height: 500px;
border: 1px solid red;
}
</style>
</head>
<body>
mouse: <span id="mouseMove"></span>
<div id="divMove">
在这里移动鼠标
</div>
<script>
$(function () {
$('#divMove').mousemove(function (e) {
$('#mouseMove').text('x: ' + e.pageX + ' y: ' + e.pageY);
})
});
</script>
</body>
</html>
$(function () {...}) 的形式,牢记这是document 对象的ready 事件处理函数。
$(function() {...})
= $(document).ready(function () {
});
});
8.4操作dom
修改html和text
$('#test-ul li[class=cpp]').text();
$('#test-ul li[class=cpp]').html();
$('#test-ul li[class=cpp]').text('');
$('#test-ul li[class=cpp]').html('');
修改css
$('#test-ul li[class=cpp]').css("color", "red")
dom的显示与隐藏
var a = $('a[target=_blank]');
a.hide();
a.show();
注意,隐藏DOM节点并未改变DOM树的结构,它只影响DOM节点的显示。这和删除DOM节点是不同的。
获取dom信息
$(window).width();
$(window).height();
var div = $('#test-div');
div.attr('name');
div.attr('name', 'Hello');
div.removeAttr('name');
- width()
- height()
- attr()
- removeAttr
8.5 操作表单
jQuery提供了val() 方法来获取和修改对应的value值
input.val();
input.val('abc@163.com');
参考资料
-
廖雪峰JavaScript教程 -
【狂神说Java】JavaScript最新教程通俗易懂
|