以下内容转载和参考自:w3school的JavaScript学习内容,HTML JavaScript。
JavaScript 是 ECMAScript 规范的一种实现,ECMAScript6(简称ES6, 2015发布 )之后ECMAScript规范开始以年份命名,如ECMAScript 2016(ES7)、ECMAScript 2017(ES8)。
JavaScript 使 HTML 页面更具动态性和交互性,前面我们都是在代码中一开始就将元素的值、属性、style样式写死,使用JavaScript 的话就可以对这些内容动态的更改设置,如按钮点击的时候对按钮文本进行修改,JavaScript还可以用于表单验证等。
- HTML 定义网页的内容
- CSS 规定网页的样式和布局
- JavaScript 对网页行为进行编程
1、JS使用
使用JavaScript的getElementById() 方法可以访问拥有特定 id 的元素,如下所示,在按钮点击的时候获得id为"demo"元素,并设置其文本为当前日期:
按钮点击事件处理的js中,也可以执行多条语句:
<script> 标签用于定义客户端脚本,<script> 元素即可包含脚本语句,也可通过 src 属性指向外部脚本文件。如下所示的脚步内容获得指定的元素后将其文本设置为"Hello JavaScript!":
innerHTML不仅可以用来设置内容(可以对其设置HTML文本),也可以用来获取内容:
脚本内容中可以定义函数方法,如下所示,当点击“改变文本”按钮的时候会调用displayResult()方法,在该方法中通过getElementById(id)获得了标题元素,然后将标题文本修改为"Have a nice day!":
带参数的方法可以像下面那样定义:
如下为JS中定时器的用法:
<script>
function fun() {
console.log('fun called'); //在调试窗口输出
}
var timer1 = setTimeout(fun, 1000); //只执行一次的定时器:1秒后调用函数fun
var timer2 = setInterval(() => {
console.log(2);
}, 2000); //定时执行的定时器:每2秒执行一次
</script>
Promise对象用于表示一个异步操作最终的完成以及其结果值,可以调用其then()方法来设置异步操作结果回调:
<script>
const promise = navigator.clipboard.writeText("text"); //向剪贴板写入文本(需要是https或localhost),writeText()是一个异步方法,会返回一个 Promise
promise.then(
function (result) { //成功
document.getElementById('label').innerHTML = "S";
},
function (result) { //失败
document.getElementById('label').innerHTML = result;
}
).catch(error => { //Promise被拒绝
console.error(error);
});
</script>
Promise::then()会返回一个新的 Promise,代表了then()第一个或第二个参数的完成,then()最多接受两个参数,分别是Promise兑现和拒绝的回调,该回调返回一个 Promise 对象(即为前面所说的then()返回的Promise),从而形成链式调用:
promise.then(
function () { //成功,不关注result的话可以不传
},
function (result) { //失败
}
).then(function(result){ //上面成功function或失败function返回后调用的方法
result; //因为成功function和失败function都没有显示返回Promise,所以这里的result实际上是undefined
}).then(function(){
}).catch(function(error){
console.error(error);
});
Promise() 只能通过 new 运算符来构造,构造方法的参数为一个executor,executor是带有 resolve 和 reject 两个参数的function(resolve 和 reject的类型也是function),Promise构造的时候会立即调用executor 函数。如下所示,我们模拟了异步方法的内部实现,setTimeout()相当于是一个异步操作,调用executor的第一个参数resolve的话表示Promise兑现,此时,JS会调用Promise.then()的第一个参数,调用executor的第二个参数resolve的话表示Promise拒绝,此时,JS会调用Promise.then()的第二个参数:
<p id="label"><p>
<script>
let asyncFun = function(){
return new Promise((resolve, reject) => {
setTimeout(()=>{
let value = 1;
resolve(`sucess: ${value}`); //异步操作成功
//let value = 0;
//reject(`failed: ${value}`); //异步操作失败
}, 1000);
});
};
asyncFun().then(
function(result) {
document.getElementById('label').innerHTML = result; //输出为sucess: 1
},
function(result) {
document.getElementById('label').innerHTML = result; //输出为failed: 0
}
);
</script>
async用来声明一个方法为异步方法,注意,仅仅是声明一下,该方法是不是异步的还是得靠方法内部实现,如下所示的第一段代码,会先输出1,再输出2。而上面的asyncFun则适合使用async来进行声明,如下所示的第二段代码。
<script>
async function fun() {
console.log('1');
}
timeout();
console.log('2');
</script>
async函数体内可以和await配合使用,这可以避免显式地配置 promise 链(then调用链),使代码更简洁易懂。await 操作符用于等待一个 Promise 兑现并获取它兑现之后的值,它只能在异步方法或者模块顶层中使用。 如下所示,我们修改上面的代码,通过async/await,可以替换上面Promise.then()的调用。fun()方法会像异步方法一样执行:调用fun()后不会阻塞,会继续执行下面的语句,而当asyncFun()中异步操作完成后,await等待的Promise兑现或拒绝(通过返回的result判断),await下面的代码开始执行。
<p id="label"><p>
<script>
function asyncFun(){
return new Promise((resolve, reject) => {
setTimeout(()=>{
let value = 1;
resolve(`sucess: ${value}`); //异步操作成功
//let value = 0;
//reject(`failed: ${value}`); //异步操作失败
}, 1000);
});
};
async function fun(){
let result = await asyncFun();
document.getElementById('label').innerHTML = result;
}
fun();
document.getElementById('label').innerHTML = "wait...";
</script>
我发现,可以使用Promise.then()来实现我们自己的异步操作,如下所示,虽然fun()方法不是异步的,但是then()中的回调是异步的,打印顺序为1,2,3,所以我们可以把想要异步执行的操作放到then()的回调中去。同理,不使用then而是使用async/await的话,也可以把想要异步执行的操作放到await下面:
<script>
async function fun() {
console.log('1');
return '3' //使用async声明的方法返回类型为Promise,所以这里会隐式地包装到一个Promise,相当于是return Promise.resolve('hello async')
}
fun().then(val => {
console.log(val)
});
console.log('2');
</script>
<script>
function fun() {
console.log('1');
return Promise.resolve('3');
}
async function asyFun(){
let result = await fun();
console.log(result);
}
asyFun();
console.log('2');
</script>
通过获得元素的style属性可以设置元素的样式:
除了style属性,还可以JavaScript还可以设置元素的其它属性,如下通过点击“开灯” 、“关灯”按钮设置img的src属性来实现了开灯、关灯图片的变换使用:
综上可知,JS可以接收和处理用户的交互,比如定义一个JS方法来处理按钮的点击,在JS方法中还可以设置元素的内容、样式、图片等。
如下所示,我们在coorDiv的onmousemove(鼠标移动)事件中调用showCoordinates()方法,在coorDiv的onmouseout(鼠标移出)事件中调用clearCoordinates()方法。showCoordinates()方法中是设置XYOutDiv的内容来显示鼠标坐标,clearCoordinates()方法是清除坐标的显示,需要注意的是,这里的坐标不是coorDiv的坐标系而是以整个网页左上角为原点。
可以看到,因为XYoutDiv没有设置大小,所以其一开始其不会显示,只会显示p段落,当showCoordinates()中设置其内容后才会显示。这里有两个问题,一个是coorDiv上面会有空隙,这是因为右边的p段落显示的时候默认会有上面的空隙,如果我们把p段落的margin设为0的话,那么coorDiv和p段落上面都没有了空隙。另一个问题是,coorDiv设置了float:left后,XYoutDiv本应在新的一行即coorDiv下面展示,但是本例中其却在coorDiv右边显示,个人猜测由于未设置XYoutDiv的大小,所以系统将其作为p段落来对待。
从前面可以看到,JS代码可以放到<head>中,也可以放到<body>中,甚至可以兼而有之。因为脚本编译会拖慢显示,所以可以将JS放置<body>中最底部来改善其它内容的显示速度。JS代码还可以放到外部文件中,如果相同的脚本被用于许多不同网页的话就可以将脚本代码单独放置一个文件。使用外部JS文件的另一个优势是,已缓存的 JavaScript 文件可加速页面加载。如下所示,按钮点击的时候会调用myFunction()方法,而myFunction()方法定义在另一个文件中:
也可以使用外部网站的JS文件,如:
<script src="https://www.w3school.com.cn/demo/myScript.js"></script>
2、JS语法功能
JS中有四种方式来输出数据,如下所示,在JS中,变量用var定义,没有赋值的变量其值是 undefined,也可以使用undefined对其进行赋值,如person = undefined:
除了数值,JS中还有其它的类型,typeof运算符可以获得对应的类型,如typeof 3.14返回的是“number”,对对象、数组、null值(var可以赋值为null,null与undefined值相同但类型不同)typeof返回“object”,对undefined值typeof返回"undefined":
var length = true; // 布尔类型 var lastName = "Gates"; // 字符串 var cars = ["Porsche", "Volvo", "BMW"]; // 数组 var x = {firstName:"Bill", lastName:"Gates"}; // 带两个属性的对象
通过JS可以定义元素的事件处理程序,HTML元素的事件包括元素被点击、元素内容被修改、网页完成加载等, HTML 事件列表可以参见: W3School JavaScript 参考手册 HTML DOM 事件。
除了for循环,JS中也可以使用while循环,switch选择,位运算等。ECMAScript 2015(JS的规范,也称 ES6,相当于是JS根据ES进行了实现,但其也包含ES标准规范未定义的一些其它内容,所以有的JS并不是所有浏览器都支持)引入了 JavaScript 类,使用class来声明一个类,使用new来定义一个类对象。JS中除了数组,还有Set、Map。
如下为通过JSON.parse()将JSON转换为对象,同时,对象的属性也可以进行增删操作:
JS中回调函数的使用:
clearTimeout()和clearInterval()用来停止上面的定时器,其参数为setTimeout()和setInterval()的返回值。
如下所示,getFile()方法中下载mycar.html完成后会调用传入的回调方法myCallback,在回调方法中对mycar.html中的内容进行展示:
RegExp是JS中的正则表达式对象,如下所示使用正则表达式将str中"Microsoft"全部替换为"Runoob",效果与使用replaceAll()一样:
3、AJAX
AJAX(Asynchronous JavaScript And XML)可以在不重载整个页面的情况下,实现了对部分网页的更新,即不刷新页面来更新网页。AJAX可以在页面加载后从服务器请求和接收数据,以及在后台向服务器发送数据。
AJAX是一项技术,它通过浏览器内建的 XMLHttpRequest 对象来从 web 服务器请求数据,然后通过JavaScript 和 HTML DOM来显示或使用数据,如下所示。Ajax 可使用 XML 来传输数据,但将数据作为JSON 文本或纯文本传输也很常见。
如下使用了AJAX技术,按钮在点击的时候会通过XMLHttpRequest来请求数据,然后通过JS来显示回应的数据:
4、HTML DOM
HTML DOM就是页面的文档对象模型(Document Object Model),如下所示,HTML DOM 模型被结构化为对象树,它是关于如何获取、更改、添加、删除 HTML 元素(及其属性和样式)以及HTML事件的标准。HTML DOM 能够通过 JavaScript 进行访问。
在 DOM 中,所有 HTML 元素都被定义为对象,document 文档对象代表整个网页,可以通过其访问 HTML 页面中的任何元素,如document.head获得<head>元素,document.title获得<title>元素,document.URL获得文档的URL。前面我们知道可以通过document.getElementById(id)来获得指定元素,也可以通过document.getElementsByClassName(className)来获得拥有指定class的所有元素(如下所示),document.querySelectorAll("p.intro")用来获得匹配指定 CSS 选择器(id、类名、类型、属性、属性值等等)的所有元素,比如var aryP = document.querySelectorAll("p.intro") 获得了所有类名为intro的<p>标签(querySelector()是仅获得一个元素)。
如下所示,可以通过表单的onsubmit属性来指定一个表单提交前的判断方法,该方法返回false的话就不会执行提交动作,在该方法中可以通过document.forms来获得所有的表单input元素:
如下所示为节点树之间的关系,其中<head>还可以有<title>等子节点,<body>可以有<h>、<p>等子节点。通过 JavaScript,您可以使用以下节点属性在节点之间导航:
- parentNode
- childNodes[nodenumber]
- firstChild
- lastChild
- nextSibling
- previousSibling
向网页添加和删除元素的方法如下所示:
如下为获得类型相同元素集合的两种方法:
除了在定义元素的时候同时设置事件处理程序,还可以通过JS向指定的元素添加事件处理程序,如下所示。当用户进入后及离开页面时,会触发 onload 和 onunload 事件,在onload 事件中可以检测访问者的浏览器类型和浏览器版本,然后基于该信息加载网页的恰当版本,也可以用来处理cookie。onmouseover、onmouseout、onmousedown、onmouseup为 HTML元素上的鼠标事件:
也可以使用元素的addEventListener()方法向元素添加指定事件的处理程序,如document.getElementById("myBtn").addEventListener("click", func) 。使用addEventListener()的特色是其会向元素额外添加事件处理程序,它不会覆盖原来添加的事件处理程序,比如可以向元素添加两个"click" 事件。可以向任何 DOM 对象添加事件处理程序而非仅仅 HTML 元素,例如HTML 对象、window 对象,以及其他支持事件的对象,比如 xmlHttpRequest 对象。removeEventListener() 用来删除事件监听器。addEventListener()的第三个参数为布尔类型,默认为false, 其指定事件传播的顺序,比如 <div> 元素内有一个 <p>,然后用户点击了这个 <p> 元素,false的话表示消息从内到外处理,即首先处理 <p> 元素的点击事件,然后是 <div> 元素的点击事件,true的话表示消息从外到内处理。使用 addEventListener()添加事件处理程序的另一个好处是使JavaScript 与 HTML 标记分离,即使在不控制 HTML 标记时也允许您添加事件监听器。
5、BOM
BOM(Browser Object Model)即浏览器对象模型,DOM规定了JS与HTML文档的对话,BOM规定了JS与浏览器之间的对话。在DOM中document代表了当前网页,BOM中的window对象代表了浏览器窗口,所有全局 JavaScript 对象,函数和变量自动成为 window 对象的成员(全局变量是 window 对象的属性,全局函数是 window 对象的方法),如document.getElementById("id")其实就是window.document.getElementById("id") 。
window.open()/window.close()为打开新窗口和关闭窗口。
window.screen包含当前屏幕的分辨率等信息;
window.location 对象可用于获取当前页面地址(URL)和把浏览器重定向到新页面;
window.navigator可以获得浏览器相关信息(名称、代码、版本、是否已设置关闭cookie、引擎、浏览器平台(操作系统)等);
window.innerWidth、innerHeight为浏览器窗口的宽高,也可以通过文档获得窗口的宽度和高度;
window.alert()用来弹出警告框(也可以省略window),window.confirm弹出确认框(带一个确认和取消按钮),window.prompt()弹出一个带输入栏的确认框;
window.document.cookie为浏览器cookie。
如下所示的setCookie()方法用来设置cookie,getCookie()用来获得cookie,当用户打开页面会调用checkCookie()方法,在其中通过cookie判断用户是否首次访问,首次访问会提示输入姓名并将其记录cookie,用户下次访问会弹出"欢迎再次光临,name"的弹窗。删除cookie与添加cookie类似,不过cookie值不用填,只需将过期时间expires设置为一个过去的时间即可,如document.cookie = "cookieName=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"。
HTML 页面中执行脚本时,页面在脚本完成之前是无响应的,使用Worker 可以在后台运行JavaScript。如下所示,在startWorker()方法中先判断浏览器是否支持Worker,然后Worker没有开启的话就使用指定的JS文件来启动Worker,该JS文件中为Worker后台执行的代码,其中postMessage()用来向HTML 页面发送消息,可以通过Worker的onmessage来设置消息响应程序:
5、jQuery
jQuery 是一个 JavaScript 函数库,它包含HTML 元素选取、元素操作、事件函数,CSS操作,JS特效和动画,HTML DOM遍历和修改,AJAX等功能。同时JQuery对于不同浏览器有很好的兼容性,比如不同浏览器对 AJAX 的实现并不相同,如果你不想编写额外的测试代码的话,就可以使用jQuery中的AJAX功能。使用JQuery会极大地简化 JavaScript 编程。
jQuery 库位于一个 JavaScript 文件中,可以像引入Bootstrap JS一样引入它。如下使用了 jQuery 的 hide() 函数:当点击button后会隐藏了 HTML 文档中所有的 <p> 元素:
可以看到,上面引入js文件的时候添加了type类型,而在上面引入Bootstrap的时候并没有指定type,这是因为上面BootStrap中使用的是HTML5,JavaScript 已经是 HTML5 以及所有现代浏览器中的默认脚本语言。如果不想自己托管jQuery库,那么可以从 Google 或 Microsoft 加载 CDN jQuery 核心文件。
使用Google的CDN:
<head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs /jquery/1.4.0/jquery.min.js"></script> </head>
使用Miscrsoft的CDN:
<head> <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery /jquery-1.4.min.js"></script> </head>
使用谷歌或微软的 jQuery,有一个很大的优势:许多用户在访问其他站点时,已经从谷歌或微软加载过 jQuery,所以JQuery已经被缓存,而且大多数 CDN 都可以确保当用户向其请求文件时,会从离用户最近的缓存服务器上返回响应。
随着HTML5的到来,jQuery现在已经不流行了,因为HTML5中已经完善了浏览器的兼容问题,jQuery 实现的很多功能现在通过几行新标准的JavaScript也能实现。而后面出现的Angular(1.0版本称为AngularJS)、React、vue这些前端框架进一步简化了JS操作,比如它们使用MVVM结构(Model数据模型、View视图UI组件、ViewModel同步View和Model的对象即二者使用ViewModel进行交互)使得数据与视图分离,通过数据来驱动视图,封装了DOM操作,进而使DOM操作从业务代码中移除, 这样使得jQuery的DOM操作便没有了用武之地。
6、node.js
node.js(简称Node)是一个可以让Javascript代码离开浏览器来执行的运行环境,它使用了Google的V8解析引擎和以及IO库libev。由于脱离了浏览器,所以使用JS可以直接开发桌面、手机、甚至嵌入式应用了,又因为node.js中的事件驱动+非阻塞模型非常适合高性能服务器开发,所以使用JS也可以像Java一样用来开发后端服务,也就是说通过JS+node.js,前端开发人员就相当于前后端通吃了。
使用node.js做后端的话一般适合中小型项目,而且解释型脚本语言本身并不适合执行计算型任务(node.js提供JS与C/C++交互的接口,所以面对计算密集型任务时可以选择启动脚本来调用C/C++完成计算密集型任务)。Node.js使用了一个事件驱动、非阻塞式IO的模型,“非阻塞”只是对于IO来说的,进行很耗CPU计算的操作会阻塞住线程,这个时候Node.js的单线程模式的不足就会暴露出来,所以如果有耗时的方法,都要做成异步调用。
V8引擎是谷歌浏览器内的一个JavaScript解释和运行引擎, 负责接收 JavaScript 代码,优化代码,然后在计算机上执行。Node.js 使用V8 引擎来理解和执行JavaScript 代码,当Node.js中的V8 引擎遇到 I/O 操作,它会将该操作传递给 Libuv,由Libuv 执行 I/O 操作,比如JavaScript本身并没有read这么一个function。通过V8,我们可以将其绑定到一个用c++写的read callback上来完成操作。
系统安装了 Node.js 之后,就会配套安装一个命令,叫做 npm(Node Package Manager,Node 的包管理系统)。由于 JS 开发者众多,我们要实现各种功能几乎都能在npm中找到别人写好的包,直接拿来用就好了,很多 npm 包都对应一个 Github 项目。比如执行npm install moment命令就可以把 moment 这个包从 npm 的软件包仓库中下载这个包和安装到本地。
使用node.js进行服务端开发的话需要使用很多框架和中间件,比如web服务框架Express、koa、nest.js、egg.js,数据库ORM框架Sequelize、ORM2,测试框架Mocha、Expresso、Unit.js,模板引擎Jade、EJS、Swig,构建工具/打包工具Grunt,Gulp,Webpack等。Express是最早出现的一款web框架,几行代码就可以启动一个 HTTP 服务器,基于ES5。koa相当于是Express的升级版,基于ES6(Koa 2基于ES8)。nest.js是一个企业级全功能后端框架,默认基于Express,支持TypeScript(JavaScript的超集),社区活跃度高,学习和维护成本低。Egg.js是阿里基于 Koa 开发的企业级后端应用框架。
编译型语言是代码在运行前编译器将人类可以理解的语言(编程语言)转换成机器可以理解的语言,比如C/C++。解释型语言也是人类可以理解的语言(编程语言),也需要转换成机器可以理解的语言才能执行,但是是在运行时转换的,所以解释型语言在执行前需要环境中安装了解释器,比如JavaScript在Chrome浏览器中运行的话需要V8解释引擎。由于Java需要解释运行在JVM上,所以认为Java是一种解释型语言,但Java代码运行前是需要编译的(编译成字节码),所以也可以认为Java是一种混合型语言。