JS笔记
什么是JavaScript
JavaScript是世界上最流行的脚本语言,因为你在电脑、手机、平板上浏览的所有的网页,以及无数基于HTML5的手机App,交互逻辑都是由JavaScript驱动的。
简单地说,JavaScript是一种运行在浏览器中的解释型的编程语言。
快速入门
引入JS
1 |
|
1 | alert('hello, world'); |
2.2 基本语法
1 | alert(num) |
2.3 数据类型
数值、文本、图形、音频、视频
比较运算符
1 | === //一定需要使用三等来判断相等 |
NaN与所有的数都不相等
只能使用方法 isNaN()
数组
1 | var num = [1,2,3,4,'hello', 'a', 4.2]; |
用中括号,可以是不同的数据类型
对象
1 | var person = { |
用大括号
命令行调用
1 | person.name |
2.4 严格检查模式
1 | <script> |
'use strict';
需要放在JS的第一行,
预防变量定义时的随意性所导致的问题
局部变量用let关键词定义
数据类型详解
字符串
多行字符串
1 | var msg = `hello |
模板字符串
1 | <script> |
字符串的不可变性
数组
Array可以包含任何数据类型的数据
长度
arr.length可以通过赋值任意改变
indexOf
获取某元素的下标值
slice()
数组版的substring,用法[a,b)
并返回一个新数组
push() pop()
1 | push() //在数组尾部添加一个值 |
unshift() shift()
1 | unshift() //在数组头部添加一个值 |
sort()
排序,且会改变原来数组的值
reverse()
反转,且会改变原来数组里的值
concat()
拼接,不会改变原数组的值,返回一个新数组
连接符 join()
1 | var s = ['A','B', 'C'] |
以join()方法中的符号,将数组元素拼接起来并返回
对象
键值对
若干个键值对,所有的键都是一个字符串,值可以是任意的对象
person['age']
可以直接访问age属性
1 | var 对象名 = { |
不存在的属性
使用一个不存在的属性,并不会报错
1 | person.haha |
动态删减属性
1 | delete person.name |
person对象中的name属性被删除
判存
1 | 'age' in person |
判断一个属性是否是自身拥有(不是从父类继承的)
1 | person.hasOwnProperty('toString') |
流程控制
1 | <script> |
1 | for (let i = 0; i < 10; i++) { |
foreach遍历数组
E5.1引入
1 | <script> |
1 | 12 |
Map & Set
Map:
1 | <script> |
Set:无序不重复集合
1 | var set = new Set([1,2,1,1,1,3,4]); |
1 | Set.prototype.add() |
iterator
遍历数组
1 | var num = [1,2,3,4,5,6]; |
1 | 1 |
遍历Map
1 | var map = new Map([['jack',18], ['tom',12], ['adam',99]]); |
1 | ['jack', 18] |
遍历Set
1 | var set = new Set([1,1,1,1,3,2]); //不重复无序 |
1 | 1 |
函数及面向对象编程
函数定义
1 | function abs(x) { |
function
指出这是一个函数定义;abs
是函数的名称;(x)
括号内列出函数的参数,多个参数以,
分隔;{ ... }
之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
1 | var abs = function (x) { |
在这种方式下,function (x) { ... }
是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs
,所以,通过变量abs
就可以调用该函数。
上述两种定义完全等价
注意第二种方式按照完整语法需要在函数体末尾加一个;
!!!表示赋值语句结束。
arguments
1 | function foo(x) { |
rest
1 | function foo(a, b, ...rest) { |
1 | foo(1, 2, 3, 4, 5); |
变量作用域
1 | ; |
内部函数可以访问外部变量,反之则不行
变量提升
1 | ; |
1 | Hello, undefined |
意味着js会自动将变量的声明提升到整个代码的顶部,但是注意一点,提升的是声明,具体的定义不会跟着提升
因此在输出 y 时,结果仍然是undefined
全局作用域
1 | ; |
使用window关键字,代表引用全局变量
1 | ; |
在修改window.alert
方法后,发现函数无法再进行输出
可以把调用的alert()
函数看作window
的一个变量
名字空间
全局变量会绑定到window
上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
1 | // 唯一的全局变量MYAPP: |
把自己的代码全部放入唯一的名字空间MYAPP
中,会大大减少全局变量冲突的可能。
许多著名的JavaScript库都是这么干的:jQuery,YUI,underscore等等。
局部作用域
1 | ; |
关键在于let关键字的使用,定义局部变量
方法
方法可以看作定义在对象里的一个函数
属性名:function() {
函数体
}
1 | var person = { |
另一种写法
属性名: 函数名
1 | function getAge() { |
apply
1 | getAge.apply(person,[]) |
*闭包
闭包可以理解为函数的嵌套
1 | function final_sum(arr) { |
在以上的例子中,我们在final_sum(arr)
中定义中sum
函数,sum函数可以直接使用来自外部函数提供的参数,并且可以将整个内部函数作为返回值返回
当我们调用final_sum()
时,返回的并不是求和结果,而是求和函数:
1 | var f = lazy_sum([1, 2, 3]); // function sum() |
调用函数f
时,才真正计算求和的结果:
1 | f(); // 6 |
箭头函数
箭头函数相当于匿名函数,并且简化了函数定义
1 | x => x*x |
等价于
1 | function (x) { |
另一种形式
1 | x => { |
创建对象
1 | var Student = { |
1 | var jack = { |
jack继承自Student类,可以调用Student对象的run方法
class继承
新的关键字class
从ES6开始正式被引入到JavaScript中。class
的目的就是让定义类更简单。
比较一下就可以发现,class
的定义包含了构造函数constructor
和定义在原型对象上的函数hello()
(注意没有function
关键字)
1 | <script> |
**原型链继承
常用对象
date
1 | var date = new Date(); |
1 | date.toString() |
JSON
是什么?
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
1 | <script> |
json和js对象
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
1 | var obj = {name: 'adam', age: 3, sex: '男'}; |
json格式用单引号''
包含,键值统一用双引号
JSON 和 JS 对象互转
要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:
1 | var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'} |
要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
1 | var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}' |
Dom(重点)
文档对象模型 document object model
始终记住DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作:
- 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
- 遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
- 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
- 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。
1 |
|
最常用的方法是
document.getElementById()
document.getElementsByTagName()
以及CSS选择器document.getElementsByClassName()
。
插入
追加
appendChild
方法加结点添加至此末尾
1 | <p id="js">javascript</p> |
效果
这个节点首先会从原先的位置删除,再插入到新的位置。
从头创建
1 | <script> |
document.createElement('p')
通过此方法,创建一个p标签
python.id
python.innerText
分别修改其Id与文本
除了添加标签以外,我们可以利用js的这一特性,来添加css样式表
1 | var d = document.createElement('style'); |
1 | <style type="text/css"> |
以上两个操作等价!
insertBefore
1 | var |
Node.insertBefore
更新
一种是修改innerHTML
属性,这个方式非常强大,不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树:
值得注意的是,innerHTML是属性,而不是方法
1 | var aa = document.getElementById('h1') |
innerHTML里可以使用html标签,会自动转变为相应的格式
第二种是修改innerText
或textContent
属性,这样可以自动对字符串进行HTML编码,保证无法设置任何HTML标签:
1 | var aa = document.getElementById('h1') |
两者的区别在于读取属性时,innerText
不返回隐藏元素的文本,而textContent
返回所有文本。
删除
删除结点,首先定位到要删除的文档标签,可以通过id名
获取当前标签的父元素
通过父元素来移除当前标签,从而达到删除的效果
1 | var self = document.getElementById("p2") |
注意到删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
当你遍历一个父节点的子节点并进行删除操作时,要注意,children
属性是一个只读属性,并且它在子节点变化时会实时更新。
也就是说存在一个操作,重复删除第一个结点,就可以达到删除所有结点的效果
1 | var parent = document.getElementById('parent'); |
Bom(重点)
浏览器对象模型
window
window
对象不但充当全局作用域,而且表示浏览器窗口
window
对象有innerWidth
和innerHeight
属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高
对应的,还有一个outerWidth
和outerHeight
属性,可以获取浏览器窗口的整个宽高。
1 | console.log(window.outerHeight) |
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:
1 http://www.example.com:8080/path/index.html?a=1&b=2#TOP
1 | location.protocol; // 'http' |
document**
document
对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构,document
对象就是整个DOM树的根节点。
document
的title
属性是从HTML文档中的<title>xxx</title>
读取的,但是可以动态改变:
1 | document.title = '努力学习JavaScript!'; |
cookie
1 | document.cookie |
Cookie是由服务器发送的key-value
标示符。因为HTTP协议是无状态的,但是服务器要区分到底是哪个用户发过来的请求,就可以用Cookie来区分。当一个用户成功登录后,服务器发送一个Cookie给浏览器,例如user=ABC123XYZ(加密的字符串)...
,此后,浏览器访问该网站时,会在请求头附上这个Cookie,服务器根据Cookie即可区分出用户。
Cookie还可以存储网站的一些设置,例如,页面显示的语言等等
然而cookie的使用存在极大的安全隐患,js可以读取到页面的cookie,而用户的登录信息通常也存在cookie中。
在html中引入第三方的js代码是允许的,如果存在恶意代码,cookie则会被截取
1 | <!-- 当前页面在wwwexample.com --> |
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">
,用户不可见,但表单提交时会把隐藏文本发送到服务器。
1 | <form action="post"> |
这种方式可以应用于text
、password
、hidden
以及select
。
至于单选框和多选框需要利用到checked
关键字
1 | <form method="post"> |
1 | boy_radio.value |
md5
1 |
|
注意到id
为md5-pwd
的<input>
标记了name="password"
,而用户输入的id
为input-pwd
的<input>
没有name
属性。没有name
属性的<input>
的数据不会被提交
操作文件
1 | <input type="file"> |
注意:当一个表单包含<input type="file">
时,表单的enctype
必须指定为multipart/form-data
,method
必须指定为post
,浏览器才能正确编码并以multipart/form-data
格式发送表单的数据。
jQuery
cdn引入
1 |
|
公式
$(selector).action()
selector即css中的选择器
事件
1 | <a href="" id="test-jQuery">here</a> |
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。
1 |
|
$(function () {...})
的形式,牢记这是document
对象的ready
事件处理函数。
1 | $(function() {...}) |
操作dom
修改html和text
1 | $('#test-ul li[class=cpp]').text(); |
修改css
1 | $('#test-ul li[class=cpp]').css("color", "red") |
dom的显示与隐藏
1 | var a = $('a[target=_blank]'); |
注意,隐藏DOM节点并未改变DOM树的结构,它只影响DOM节点的显示。这和删除DOM节点是不同的。
获取dom信息
1 | $(window).width(); // 800 |
- width()
- height()
- attr()
- removeAttr
操作表单
jQuery提供了val()
方法来获取和修改对应的value值
1 | input.val(); // 'test' |