JavaScript 最初被称为 LiveScript,由 Netscape(Netscape Communications Corporation,网景通信公司)公司的布兰登·艾奇(Brendan Eich)在 1995 年开发。在 Netscape 与 Sun(一家互联网公司,全称为“Sun Microsystems”,现已被甲骨文公司收购)合作之后将其更名为了 JavaScript。
之所以将 LiveScript 更名为 JavaScript,是因为 JavaScript 是受 Java 的启发而设计的,因此在语法上它们有很多相似之处 ,JavaScript 中的许多命名规范也都借鉴自 Java,还有一个原因就是为了营销,蹭 Java 的热度。
同一时期,微软和 Nombas(一家名为 Nombas 的公司)也分别开发了 JScript 和 ScriptEase 两种脚本语言,与 JavaScript 形成了三足鼎立之势。它们之间没有统一的标准,不能互用。为了解决这一问题,1997 年,在 ECMA(欧洲计算机制造商协会)的协调下,Netscape、Sun、微软、Borland(一家软件公司)组成了工作组,并以 JavaScript 为基础制定了 ECMA-262 标准(ECMAScript)。
ECMAScript(简称“ES”)是根据 ECMA-262 标准实现的通用脚本语言,ECMA-262 标准主要规定了这门语言的语法、类型、语句、关键字、保留字、操作符、对象等几个部分,目前 ECMAScript 的最新版是 ECMAScript6(简称“ES6”)。
至于 JavaScript,有时人们会将 JavaScript 与 ECMAScript 看作是相同的,其实不然,JavaScript 中所包含的内容远比 ECMA-262 中规定的多得多,完整的 JavaScript 是由以下三个部分组成:
JavaScript 具有以下特点:
JavaScript 是一种解释型脚本语言,与 C、C++ 等语言需要先编译再运行不同,使用 JavaScript 编写的代码不需要编译,可以直接运行。
JavaScript是一种面向对象语言,使用 JavaScript 不仅可以创建对象,也能操作使用已有的对象。
JavaScript是一种弱类型的编程语言,对使用的数据类型没有严格的要求,例如您可以将一个变量初始化为任意类型,也可以随时改变这个变量的类型。
JavaScript 是一种采用事件驱动的脚本语言,它不需要借助 Web 服务器就可以对用户的输入做出响应,例如我们在访问一个网页时,通过鼠标在网页中进行点击或滚动窗口时,通过 JavaScript 可以直接对这些事件做出响应。
JavaScript不依赖操作系统,在浏览器中就可以运行。因此一个 JavaScript 脚本在编写完成后可以在任意系统上运行,只需要系统上的浏览器支持 JavaScript 即可。
DOM 全称是 Document Object Model,也就是文档对象模型。
什么是DOM参考:DOM解释
首先将HTML代码转化,通过HTML解析器解析构建为一颗DOM树
再将CSS代码通过CSS解释器将构建规则放到对应的树节点上,得到一颗带有样式属性的DOM树。
浏览器按照层次结构遍历(从上到下,从左到右),将DOM树上的内容放置到传送带上,传送带就是文档流。
如果节点下还有节点,就把他按父节点的顺序摆放。
如果节点下还有节点,就一直套娃。
文档排序完成之后,开始获取计算节点的坐标和大小等CSS属性,作为盒子的说明,然后把盒子放到页面之中,完成布局,此时还不可见。
行内元素一般是内容的容器,而块级元素一般是其他容器的容器。一般情况下,行内元素只能包含内容或者其它行内元素,宽度和长度依据内容而定,不可以设置,可以和其它元素和平共处于一行;而块级元素可以包含行内元素和其它块级元素,且占据父元素的整个空间,可以设置 width 和 height 属性,浏览器通常会在块级元素前后另起一个新行。
详细见原文:原文链接。
文档流与页面是一维与二位之间的映射关系。
Node.js 不是一门新的编程语言,也不是一个 JavaScript 框架,它是一套 JavaScript 运行环境,用来支持 JavaScript 代码的执行。用编程术语来讲,Node.js 是一个 JavaScript 运行时(Runtime)。
所谓运行时,就是程序在运行期间需要依赖的一系列组件或者工具;把这些工具和组件打包在一起提供给程序员,程序员就能运行自己编写的代码了。
对于 JavaScript 来说,它在运行期间需要依赖以下组件:
JavaScript 是一种脚本语言,需要一边解释一边运行,用到哪些源代码就编译哪些源代码,整个过程由解释器完成。没有解释器的话,JavaScript 只是一堆纯文本文件,不能被计算机识别。
我们在 JavaScript 代码中会调用一些内置函数,这些函数不是我们自己编写的,而是标准库自带的。
所谓本地模块,就是已经被提前编译好的模块,它们是二进制文件,和可执行文件在内部结构上没有什么区别,只是不能单独运行而已。这些本地模块其实就是动态链接库(在 Windows 下是 .dll 文件),如果你使用过C语言、C++ 等编译型语言,那你应该能够更好地理解它。
JavaScript 的很多功能都需要本地模块的支持,比如:
JavaScript 解释器需要本地模块的支持,标准库在编写时也会调用本地模块的接口,而我们编写的 JavaScript 代码一般不会直接使用本地模块,所以 Web 前端程序员触及不到它们。
JavaScript 的一生伴随着浏览器大战。JavaScript 由 Netscape(网景)浏览器发布,但是 Netscape 在和 IE 的竞争中落败,早已不复存在;后来谷歌公司的 Chrome 浏览器异军突起,凭借强悍的性能把 IE 按在地上摩擦。
谷歌公司在 Chrome 浏览器中集成了一种名为“V8”的 JavaScript 引擎(也即 JavaScript 解释器),它能够非常快速地解析和执行 JavaScript 代码。
V8 引擎使用 C++ 语言编写,可以独立运行,也可以嵌入到任何其它 C++ 程序中。谷歌公司将 V8 引擎甚至整个 Chrome 浏览器都开源了,任何人都可以免费地将 V8 应用到自己的项目中。
Node.js 是针对 V8 引擎构建的。通过与此引擎的最新版本保持同步,确保及时向 Node.js 开发人员提供 JavaScript ECMA-262 specification 中的新功能,以及持续的性能和稳定性改进。
所有的 ECMAScript 2015 (ES6) 功能将被分为三个部分 shipping,staged 和 in progress:
--harmony
标记。node.green 提供了非常完整、几乎涵盖了不同版本的 Node.js 中所支持的 ECMAScript 特性。它基于 kangax 的兼容性对照表构建。
新特性源源不断地被加入 V8 引擎。一般说来,虽然具体的时间未知,但我们总希望他们将来在 Node.js 中有所体现。
在每个 Node.js 发布版中,你可以通过 greeping 配上 --v8-options
参数罗列出全部处于 in progress 状态的特性功能。请注意:他们尚未完成,可能因为 V8 引擎自带的功能而夭折。所以使用这些特性时会冒风险。
node --v8-options | grep "in progress"
JavaScript 程序不仅可以直接放在 HTML 文档中,也可以放在 JavaScript 脚本文件中。JavaScript 脚本文件是文本文件,扩展名为.js
,使用任何文本编辑器都可以编辑。
常用的文本编辑器有 Windows 系统中的记事本、Linux 系统中的 Vim、Sublime Text、Notepad++ 等。对于初学者来说,建议先使用文本编辑器来编写 JavaScript 代码,这样有助于我们对 JavaScript 语法、关键字、函数等内容的记忆。等到了实际开发阶段,则可以选择一些更加专业的代码编辑器,例如 Visual Studio Code(简称“VS Code”)、WebStorm(收费)、Atom 等,这样可以提高开发效率。
第1步,新建文本文件,保存为 new.js。注意,扩展名为.js
,它表示该文本文件是 JavaScript 类型的文件。
第2步,打开 test.js 文件,在其中编写如下 JavaScript 代码。
在上面代码中,alert() 表示 Window 对象的方法,调用该方法将弹出一个提示对话框,显示参数字符串 “ZZY 's First Js Code”。
第3步,保存 JavaScript 文件。在此建议把 JavaScript 文件和网页文件放在同一个目录下。
JavaScript 文件不能够独立运行,需要导入到网页中,通过浏览器来执行。使用 < script> 标签可以导入 JavaScript 文件。
第4步,新建 HTML 文档,保存为 test.html。
第5步,在 < head > 标签内插入一个 < script > 标签。定义 src 属性,设置属性值为指向外部 JavaScript 文件的 URL 字符串。代码如下:
注意:使用<script>标签包含外部 JavaScript 文件时,默认文件类型为 Javascript。因此,不管加载的文件扩展名是不是 .js,浏览器都会按 JavaScript 脚本来解析。
效果如下:
浏览器在解析 HTML 文档时,将根据文档流从上到下逐行解析和显示。JavaScript 代码也是 HTML 文档的组成部分,因此 JavaScript 脚本的执行顺序也是根据 < script> 标签的位置来确定的。
使用浏览器测试下面示例,会看到 JavaScript 代码从上到下逐步被解析的过程。
DOCTYPE html>
<script>
alert("顶部脚本");
script>
<html>
<head>
<meta charset="UTF-8">
<title>testtitle>
<script>
alert("头部脚本");
script>
head>
<body>
<h1>网页标题h1>
<script>
alert("页面脚本");
script>
<p>正文内容p>
body>
<script>
alert("底部脚本");
script>
html>
效果如下:
在浏览器中浏览上面示例网页,首先弹出提示文本“顶部脚本”,然后显示网页标题“test”,接着弹出提示文本“头部脚本”,下面才显示一级标题文本“网页标题”,继续弹出提示文本“页面脚本”, 接着显示段落文本“正文内容”,最后弹出提示文本“底部脚本”。
值得注意的是,所有JS执行完成以后才有以下内容被渲染出来,也就是说解析完成整个文档以后才会进行渲染,html解析是其中的一部分:
对于导入的 JavaScript 文件,也将按照 <script> 标签在文档中出现的顺序来执行,而且执行过程是文档解析的一部分,不会单独解析或者延期执行。
如果你熟悉C、C++、Java、Python等语言,你就很好上手JS,这里就直接说明一些不同点,方便你快速入门。
关键字(Keyword)就是 JavaScript 语言内部使用的一组名字(或称为命令)。这些名字具有特定的用途,用户不能自定义同名的标识符,具体内容如表所示。
关键字 | 关键字 | 关键字 | 关键字 | 关键字 |
---|---|---|---|---|
break | delete | if | this | while |
case | do | in | throw | with |
catch | else | instanceof | try | |
continue | finally | new | typeof | |
debugger(ECMAScript 5 新增) | for | return | var | |
default | function | switch | void |
保留字就是 JavaScript 语言内部预备使用的一组名字(或称为命令)。这些名字目前还没有具体的用途,是为 JavaScript 升级版本预留备用的,建议用户不要使用。具体说明如表所示。
abstract | double | goto | native | static |
---|---|---|---|---|
boolean | enum | implements | package | super |
byte | export | import | private | synchronized |
char | extends | int | protected | throws |
class | final | interface | public | transient |
const | float | long | short | volatile |
ECMAScript 3 将 Java 所有关键字都列为保留字,而 ECMAScript 5 规定较为灵活,例如:
JavaScript 预定义了很多全局变量和函数,用户也应该避免使用它们,具体说明如表所示。
arguments | encodeURL | Infinity | Number | RegExp |
---|---|---|---|---|
Array | encodeURLComponent | isFinite | Object | String |
Boolean | Error | isNaN | parseFloat | SyntaxError |
Date | eval | JSON | parseInt | TypeError |
decodeURL | EvalError | Math | RangeError | undefined |
decodeURLComponent | Function | NaN | ReferenceError | URLError |
无论是在严格模式下还是在非严格模式下,都不要在定义变量名、函数名或者属性名时使用上面列举出的保留字,以免同学们入坑。
下面示例分别定义不同类型的直接量:字符串、数值、布尔值、正则表达式、特殊值、对象、数组和函数。
1. //空字符串直接量
2. 1 //数值直接量
3. true //布尔值直接量
4. /a/g //正则表达式直接量
5. null //特殊值直接量
6. {} //空对象直接量
7. [] //空数组直接量
8. function(){} //空函数直接量,也就是函数表达式。
对于常用的就不再介绍,这里说些比较特殊的细节。
数值(Number)类型用来定义数值,JavaScript 中不区分整数和小数(浮点数),统一使用 Number 类型表示,如下例所示:
var num1 = 123; // 整数
var num2 = 3.14; // 浮点数
注意:Number 类型所能定义的数值并不是无限的,JavaScript 中的 Number 类型只能表示 − ( 2 53 − 1 ) -(2^{53} - 1) −(253−1) 到 ( 2 53 − 1 ) (2^{53} - 1) (253−1)之间的数值。
对于一些极大或者极小的数,也可以通过科学(指数)计数法来表示,如下例所示:
var y=123e5; // 123 乘以 10 的 5 次方,即 12300000
var z=123e-5; // 123 乘以 10 的 -5 次方,即 0.00123
另外,Number 类型中还有一些比较特殊的值,分别为 Infinity、-Infinity 和 NaN,其中
提示:如果某次计算的结果超出了 JavaScript 中 Number 类型的取值范围,那么这个数就会自动转化为无穷大,正数为 Infinity,负数为 -Infinity。
参考如下:
//Example0
var num_Infinity =Infinity
var num_Science = 123e5
console.log(num_Infinity);
console.log(num_Science);
布尔(Boolean)类型只有两个值,true(真)或者 false(假),在做条件判断时使用的比较多,除了可以直接使用 true 或 false 来定义布尔类型的变量外,还可以通过一些表达式来得到布尔类型的值,例如:
var c = 2 > 1; // 表达式 2 > 1 成立,其结果为“真(true)”,所以 c 的值为布尔类型的 true
var d = 2 < 1; // 表达式 2 < 1 不成立,其结果为“假(false)”,所以 c 的值为布尔类型的 false
Symbol 是 ECMAScript6 中引入的一种新的数据类型,表示独一无二的值,Symbol 类型的值需要使用 Symbol() 函数来生成,如下例所示:
var str = "Jszszzy";
var sym1 = Symbol(str);
var sym2 = Symbol(str);
console.log(sym1); // 输出 Symbol(Jszszzy)
console.log(sym2); // 输出 Symbol(Jszszzy)
console.log(sym1 == sym2); // 输出 false :虽然 sym1 与 sym2 看起来是相同的,但实际上它们并不一样,根据 Symbol 类型的特点,sym1 和 sym2 都是独一无二的
虽然 sym1 与 sym2 看起来是相同的,但实际上它们并不一样,根据 Symbol 类型的特点,sym1 和 sym2 都是独一无二的。
输出结果:
Null 是一个只有一个值的特殊数据类型,表示一个“空”值,即不存在任何值,什么都没有,用来定义空对象指针。使用 typeof 操作符来查看 Null 的类型,会发现 Null 的类型为 Object,说明 Null 其实使用属于 Object(对象)的一个特殊值。因此通过将变量赋值为 Null 我们可以创建一个空的对象。
JavaScript 中的对象(Object)类型是一组由键、值组成的无序集合,定义对象类型需要使用花括号{ }
,语法格式如下:
{name1: value1, name2: value2, name3: value3, ..., nameN: valueN}
其中 name1、name2、name3、…、nameN 为对象中的键,value1、value2、value3、…、valueN 为对应的值。
在 JavaScript 中,对象类型的键都是字符串类型的,值则可以是任意数据类型。要获取对象中的某个值,可以使用对象名.键
的形式,如下例所示:
var person = {
name:"Jszszzy",
age : "21",
city: "Hainan"
}
console.log(person.name)
结果如下:
数组(Array)是一组按顺序排列的数据的集合,数组中的每个值都称为元素,而且数组中可以包含任意类型的数据。在 JavaScript 中定义数组需要使用方括号[ ]
,数组中的每个元素使用逗号进行分隔,例如:
var array=[1000,2000,3000,"Jszszzy"]
console.log(array[0]);
结果如下:
比较运算符用来比较运算符左右两侧的表达式,比较运算符的运算结果是一个布尔值,结果只有两种,不是 true 就是 false。下表中列举了 JavaScript 中支持的比较运算符,这里只说明比较特殊的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQ7ucHSr-1654231826032)(前端入门.assets/13.png)]
在相等运算中,应注意以下几个问题:
console.log("1" == 1); //返回true。字符串被转换为数字
console.log(true == 1); //返回true。true被转换为1
console.log(false == 0); //返回true。false被转换为0
console.log(null == 0); //返回false
console.log(undefined == 0); //返回false
console.log(undefined == null); //返回true
console.log(NaN == "NaN"); //返回false
测试结果:
在全等运算中,应注意以下几个问题:
console.log(null === undefined); //返回false
console.log(0 === "0"); //返回false
console.log(0 === false); //返回false
对于简单的值,只要类型相同、值相等,它们就是全等,不考虑表达式运算的过程变化,也不用考虑变量的引用地址。
var a = "1" + 1;
var b = "11";
console.log(a ===b); //返回true
对于复合型对象,主要比较引用的地址,不比较对象的值。
var x = {}
var y = {}
console.log(x=== y); //返回false
console.log(x == y); //返回false
在上面示例中,两个对象的值相等,但是引用地址不同,所以它们既不想等,也不全等。因此,对于复合型对象来说,相等==
和全等===
运算的结果是相同的。
表达式(a>b || a==b)与表达式(a>=b)并不完全相等。
var x = null;
var y = undefined;
console.log((a > b || a == b) == (a >= b)); //返回false,表达式的值并非相等