这将是一个系列的文章。javascript
正如文章标题所讲,从新认识JavaScript,我将把JavaScript从概念到用法总体梳理一遍,中间或许还会夹杂一些我我的的使用经验以及工具整理。俗话说“温故而知新”,对基础知识的扎实掌握必是为前端大牛不可或缺的条件,共勉之。css
JavaScript(JS)是一种具备函数优先的轻量级,解释型或即时编译型的编程语言。最初是做为开发Web页面的脚本语言而闻名的,可是如今也被用到了不少非浏览器环境中,例如Node.js等。JavaScript是一种基于原型 (注1) 编程、多范式 (注2) 的动态脚本语言,并支持面向对象、命令式和声明式(如函数式编程)风格。前端
JavaScript的标准是ECMAScript。截止2012年,全部的现代浏览器 (注3) 都完整的支持ECMAScript5.1,旧版本的浏览器至少支持ECMAScript3标准。2015年6月17日,ECMA国际组织发布了ECMAScript的第六版,该版本的正式名称为ECMAScript2015,但一般被称为ECMASctipt6或ES6。自此,ECMAScript每一年发布一次新标准。java
每一个浏览器标签页就是其自身用来运行代码的独立容器(这些容器用专业术语称为“运行环境”)。大多数状况下,每一个标签页中的代码彻底独立运行,并且一个标签页中的代码不能影响另外一个标签页(或者另外一个网站)中的代码。这是一个好的安全措施,若是不这样,黑客就能够从其余网站盗取信息。jquery
能够用安全的方式在不一样网站/标签页中传送代码和数据,这些技术后面再讲。web
当浏览器执行到一段JavaScript代码时,一般会按照从上往下的顺序执行这段代码。这意味着须要注意代码的顺序。例如:编程
console.log('第一个被执行');
console.log('第二个被执行');
console.log('第三个被执行');
复制代码
在解释型语言中,代码自上而下运行,且实时返回运行结果。在代码执行前,不转化为其余形式。浏览器
编译型语言在代码运行前须要先转化(或编译)成另一种形式。好比C/C++先被编译成汇编语言,而后才能由计算机运行。安全
JavaScript是轻量级解释型语言。服务器
在web开发中,还有服务器端和客户端代码这两个术语。客户端代码是在用户电脑上运行的代码,在浏览一个网页时,它的客户端代码就会被下载,而后由浏览器运行并展现。
而服务器端代码在服务器上运行,浏览器将结果下载并展现出来。流行的服务器端web语言包括:PHP、Python、Ruby以及JavaScript。JavaScript也能够用做服务器端语言,好比如今流行的Node.js环境。
“动态”一词既能描述客户端JavaScript,又能描述服务端语言。是指经过按需生成新内容来更新 web页面/应用,使得不一样环境下显示不一样内容。
没有动态更新内容的网页叫作“静态”页面,所显示的内容不会改变。
只须要一个元素<script>
,就能够将JavaScript添加到HTML页面中。
</body>
标签前插入如下代码:<script> // 在此编写JavaScript代码 </script>
复制代码
<script>
元素替换为:<script src='script.js'></script>
复制代码
有时候会在HTML中存在着一丝真实的JavaScript代码。或许看起来像下面这样:
<button onclick='sayHello()'>点我</button>
<script> function sayHello () { console.log('Hello'); } </script>
复制代码
然而请不要这么作,这将使JavaScript污染到HTML,并且效率低下。对于每一个须要应用JavaScript的按钮,都得手动添加onclick='sayHello()'
属性。
能够用纯JavaScript结构来经过一个指令选取全部按钮。以下:
const buttons = document.querySelectAll('button');
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', sayHello);
}
复制代码
这样乍看上去比click
属性要长一些,可是这样写会对页面上全部按钮生效,不管多少个,添加或删除,彻底无需修改JavaScript代码。
要让脚本调用的时机符合预期,须要解决一系列问题。最多见的问题就是:HTML元素是按其在页面中出现的次序调用的,若是用JavaScript来管理页面上的元素,若是JavaScript加载于欲操做的HTML元素以前,则代码将出错。
解决此问题的旧方法:把脚本元素放在文档体的底部(标签以前,与之相邻),这样脚本就能够在HTML解析完毕后加载了。此方案的问题是:只有全部的HTML元素加载完成后才开始脚本的加载/解析过程。对于有大量JavaScript代码的大型网站,可能会带来显著的性能损耗。
上述的脚本阻塞问题实际有两种解决方案:async
和defer
。
先来看async
和defer
的定义。async
:规定异步执行脚本(只限外部脚本);defer
:规定是否对脚本进行延迟,知道页面加载为止。
浏览器遇到async
脚本时不会阻塞页面渲染,而是直接下载后运行。这样脚本的运行次序就没法控制,只是脚本不会阻止剩余页面的显示。当页面中脚本之间彼此独立,且不依赖于本页面的其余任何脚本时,async
是最理想的选择。
好比页面要加载如下三个脚本:
<script src='js/verdor/jquery.js' async></script>
<script src='js/script1.js' async></script>
<script src='js/script2.js' async></script>
复制代码
三者调用顺序是不肯定的,jquery可能在script1和script2以前或者以后嗲用,若是这样,这两个脚本中依赖jauery的函数将产生错误。
解决这一问题可用defer属性,脚本将按照页面中出现的顺序加载和运行:
<script src='js/verdor/jquery.js' defer></script>
<script src='js/script1.js' defer></script>
<script src='js/script2.js' defer></script>
复制代码
脚本调用策略小结:
async
。defer
,将关联的脚本按所需顺序置于HTML中。像其余语言同样,JavaScript也能够添加注释。注释只为本身或同事提供代码如何工做的指引。注释很是有用,并且应该常用,尤为是在大型项目中。
注释分两类:
// 这是一条注释
复制代码
/*
和*/
之间添加多行注释/* 我也是 一条注释 */
复制代码
这一篇文章从理论开始,介绍了为何要使用JavaScript,以及它能作什么事情。下一篇将按部就班,继续深刻JavaScript。
当开发一个大型项目时,会常常遇到在外部脚本中按需加载外部脚本的状况。若是每次加载时,都写一遍类似的加载脚本的代码,会增长很多开发与维护的成本。当有这样的需求时,若是直接将这一类功能相似的代码封装成一个脚本,将会成倍的提升开发效率。
像下面这样:
/* * @Author: 伊丽莎不白 * @Date: 2019-07-23 14:46:44 * @Last Modified by: 伊丽莎不白 * @Last Modified time: 2019-07-23 15:12:24 */
class ResLoader {
constructor () {
this.loaded = false;
}
_createElement (type, url) {
let element = document.createElement(type);
switch (type) {
case 'link':
element.setAttribute('type', 'text/css');
// 指明被连接文档对于当前文档的关系
element.setAttribute('rel', 'stylesheet');
element.setAttribute('href', url);
break;
case 'script':
// 定义script元素包含或src引用的脚本语言
element.setAttribute('type', 'text/javascript');
element.setAttribute('src', url);
break;
}
return element;
}
_addCallback (target, callback) {
let thisScope = this;
target.onload = target.onreadystatechange = function () {
// readyState属性返回当前文档的状态
if (!thisScope.loaded && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) {
thisScope.loaded = true;
// 防止内存泄漏
this.onload = this.onreadystatechange = null;
if (callback && typeof callback === 'function') {
callback();
}
}
};
}
load (url, type, callback) {
if (type === 'link' || type === 'script') {
let head = document.getElementsByTagName('head')[0] || document.documentElement;
let res = this._createElement(type, url);
if (res) {
this._addCallback(res, callback);
head.appendChild(res);
this.loaded = true;
return res;
}
}
}
}
复制代码
注1:基于原型:基于原型的语言具备所谓原型对象的概念。原型对象能够做为一个模版,新对象能够从中得到原始的属性。任何对象均可以制定其自身的属性,既能够是建立时也能够是运行时建立。并且,任何对象均可以做为另外一个对象的原型,从而容许后者共享前者的属性。
注2:范式:编程范式是一类典型的编程风格,例如函数式编程、面向对象编程等为不一样的编程范式。在面向对象编程中,认为程序是一系列互相做用的对象,而在函数式编程中一个程序会被看做是一个无状态的函数计算的序列。
注3:现代浏览器:现代浏览器是指该浏览器可以理解和支持HTML和XHTML,CSS,ECMAScript及W3C DOM标准。