0x01 JavaScript是什么?JavaScript简介
JavaScript 与 HTML 和 CSS 共同构成了我们所看到的网页,其中:
-
JavaScript 用来实时更新网页中的内容,例如从服务器获取数据并更新到网页中,修改某些标签的样式或其中的内容等,可以让网页更加生动。
JavaScript 的特点
JavaScript 具有以下特点:
1) 解释型脚本语言
JavaScript 是一种解释型脚本语言,与 C、C++ 等语言需要先编译再运行不同,使用 JavaScript 编写的代码不需要编译,可以直接运行。
2) 面向对象
JavaScript 是一种面向对象语言,使用 JavaScript 不仅可以创建对象,也能操作使用已有的对象。
3) 弱类型
JavaScript 是一种弱类型的编程语言,对使用的数据类型没有严格的要求,例如您可以将一个变量初始化为任意类型,也可以随时改变这个变量的类型。
4) 动态性
JavaScript 是一种采用事件驱动的脚本语言,它不需要借助 Web 服务器就可以对用户的输入做出响应,例如我们在访问一个网页时,通过鼠标在网页中进行点击或滚动窗口时,通过 JavaScript 可以直接对这些事件做出响应。
5) 跨平台
JavaScript 不依赖操作系统,在浏览器中就可以运行。因此一个 JavaScript 脚本在编写完成后可以在任意系统上运行,只需要系统上的浏览器支持 JavaScript 即可。
0x02 Node.js是什么?Node.js简介
对于 JavaScript 来说,它在运行期间需要依赖以下组件:
1) 解释器
JavaScript 是一种脚本语言,需要一边解释一边运行,用到哪些源代码就编译哪些源代码,整个过程由解释器完成。没有解释器的话,JavaScript 只是一堆纯文本文件,不能被计算机识别。
2) 标准库
我们在 JavaScript 代码中会调用一些内置函数,这些函数不是我们自己编写的,而是标准库自带的。
3) 本地模块
所谓本地模块,就是已经被提前编译好的模块,它们是二进制文件,和可执行文件在内部结构上没有什么区别,只是不能单独运行而已。这些本地模块其实就是动态链接库(在 Windows 下是 .dll 文件),如果你使用过C语言、C++ 等编译型语言,那你应该能够更好地理解它。
Node.js 的组成
Node.js 运行时主要由 V8 引擎、标准库和本地模块组成,尤其是本地模块的多少,从底层决定了 Node.js 功能的强弱。
1) V8 引擎
V8 引擎就是 JavaScript 解释器,它负责解析和执行 JavaScript 代码。
V8 引擎借鉴了 Java 虚拟机和 C++ 编译器的众多技术,它将 JavaScript 代码直接编译成原生机器码,并且使用了缓存机制来提高性能,这使得 JavaScript 的运行速度可以媲美二进制程序。
2) 本地模块
Node.js 集成了众多高性能的开源库,它们使用 C/C++ 语言实现,比如:
模块 | 说明 |
---|---|
libuv | 一个跨平台的、基于事件驱动的异步 I/O 库。但是 libuv 不仅限于 I/O,它还提供了进程管理、线程池、信号处理、定时器等其它功能。Linux 中一切皆文件,这里的 I/O 不仅仅包括文件读写,还包括数据库读写、网络通信(socket)等。 |
nmp | Node.js 包管理器,可以下载包、安装包、卸载包、更新包、上传包等。 |
http_parser | 一款由C语言编写的轻量级 HTTP 解析器,用以支持 Web 应用开发。 |
zlib | 工业级的数据压缩/解压模块,Nodejs 借助 zlib 来创建同步、异步或者流式的压缩/解压接口。 |
OpenSSL | 该模块提供了经过严密测试的许多加密/解密功能,现代 Web 依赖这些功能来实现安全性,比如 SSL 协议和 https 协议。 |
c-ares | 异步 DNS 查询和解析库。 |
Node.js 直接在计算机上运行 JavaScript 代码,并且要赋予 JavaScript 强大的能力,所以它的本地模块和浏览器中的运行时有很多大区别,甚至说几乎没有什么关联。Node.js 几乎完全抛弃了浏览器,自己从头构建了一套全新的 JavaScript 运行时。
3) 标准库
本地模块使用 C/C++ 编写,而 Node.js 面向 JavaScript 开发人员,所以必须要封装本地模块的 C/C++ 接口,提供一套优雅的 JavaScript 接口给开发人员,并且要保持接口在不同平台(操作系统)上的一致性。
这套 JavaScript 接口,就是 Node.js 标准库。标准库是否优雅和强大,决定了 Node.js 的易用性,直接影响 Node.js 的市场表现。
最后我们来汇总一下 JavaScript 和 Node.js 的历史:
-
Netscape 浏览器衍生出了 JavaScript 脚本,赋予网页编程能力;
-
Chrome 浏览器衍生了 V8 引擎,提高了 JavaScript 性能;
-
V8 引擎构建了 Node.js,拓展了 JavaScript 的编程能力;
-
Node.js 衍生了 Libuv 库,给网络开发增加了一款优秀的工具。
3、第一个JavaScript程序
在 HTML 文档中嵌入 JavaScript 代码
在 <script> 标签内输入 JavaScript 代码document.write("船山院士网络安全团队");
。
type="text/javascript"是将<script>标签的脚本类型设置为javascript
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>第一个JavaScript程序</title>
<script type="text/javascript">
document.write("<h1>船山院士网络安全团队</h1>");
</script>
</head>
<body></body>
</html>
在 JavaScript 脚本中,document 表示网页文档对象;document.write() 表示调用 Document 对象的 write() 方法,在当前网页源代码中写入 HTML 字符串"船山院士网络安全团队"
。
在脚本文件中编写 JavaScript 代码
打开 test.js 文件,在其中编写如下 JavaScript 代码。
alert("船山院士网络安全团队");
在上面代码中,alert() 表示 Window 对象的方法,调用该方法将弹出一个提示对话框,显示参数字符串 "Hi, JavaScript!"。
js不能独立运行需要导入到网页中通过浏览器来运行所以通过<script>来实现
<script type="text/javascript" src="test.js"></script>
src来指向外部属性
JavaScript 代码执行顺序
浏览器在解析 HTML 文档时,将根据文档流从上到下逐行解析和显示。JavaScript 代码也是 HTML 文档的组成部分,因此 JavaScript 脚本的执行顺序也是根据 <script> 标签的位置来确定的。
如果想改变 JavaScript 文件的执行顺序,可以给 <script> 标签增加 defer 或者 async 属性
<script async src="example.js"></script>
script添加async属性,表示后续文档的加载和渲染与js脚本的加载和执行是并行进行的,即异步执行。执行会阻塞HTML解析。ps:和js脚本的执行是并行进行,我不太理解。
<script defer src="example.js"></script>
script添加defer属性,加载后续文档的过程和js脚本的加载是并行进行的,此时的js脚本仅加载不执行,js脚本的执行需要等到文档所有元素解析完成之后,DOMContentLoaded事件触发执行之前。
4、JavaScript中的几个重要概念
1. 标识符
所谓标识符(Identifier),就是名字。JavaScript 中的标识符包括变量名、函数名、参数名、属性名、类名等。
合法的标识符应该注意以下强制规则:
-
第一个字符必须是字母、下划线(_)或美元符号($)。
-
除了第一个字符外,其他位置可以使用 Unicode 字符。一般建议仅使用 ASCII 编码的字母,不建议使用双字节的字符。
-
不能与 JavaScript 关键字、保留字重名。
-
可以使用 Unicode 转义序列。例如,字符 a 可以使用“u0061”表示。
示例
在下面示例中,str 就是变量的名字:。
var str = "船山院士网络安全团队";
document.write(str);
第1行代码定义了一个变量,名字为 str,第2行通过 str 这个名字使用了变量。
2. 关键字
关键字(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 |
3. 保留字
保留字就是 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 规定较为灵活,例如:
-
在非严格模式下,仅规定 class、const、enums、export、extends、import、super 为保留字,其他 ECMAScript 3 保留字可以自由使用;
-
在严格模式下,ECMAScript 5 变得更加谨慎,严格限制 implements、interface、let、package、private、protected、public、static、yield、eval(非保留字)、arguments(非保留字)的使用。
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 |
不同的 JavaScript 运行环境都会预定义一些全局变量和函数,上表列出的仅针对 Web 浏览器运行环境。
无论是在严格模式下还是在非严格模式下,都不要在定义变量名、函数名或者属性名时使用上面列举出的保留字,以免大家入坑。
4. 区分大小写
JavaScript 严格区分大小写,所以 Hello 和 hello 是两个不同的标识符。
为了避免输入混乱和语法错误,建议采用小写字符编写代码,在以下特殊情况下可以使用大写形式:
1) 构造函数的首字母建议大写。构造函数不同于普通函数。
示例
下面示例调用预定义的构造函数 Date(),创建一个时间对象,然后把时间对象转换为字符串显示出来。
d = new Date(); //获取当前日期和时间
document.write(d.toString()); // 显示日期
2) 如果标识符由多个单词组成,可以考虑使用骆驼命名法——除首个单词外,后面单词的首字母大写。例如:
typeOf();
printEmployeePaychecks();
提示:
上述都是约定俗成的一般习惯,不构成强制性要求,用户可以根据个人习惯进行命名。
5. 直接量
字面量(Literal)也叫直接量,就是具体的值,即能够直接参与运算或显示的值,如字符串、数值、布尔值、正则表达式、对象直接量、数组直接量、函数直接量等。
示例
下面示例分别定义不同类型的直接量:字符串、数值、布尔值、正则表达式、特殊值、对象、数组和函数。
//空字符串直接量
1 //数值直接量
true //布尔值直接量
/a/g //正则表达式直接量
null //特殊值直接量
{} //空对象直接量
[] //空数组直接量
function(){} //空函数直接量,也就是函数表达式
5、JS注释(多行注释+单行注释)
单行注释://
多行注释:/* */
HTML注释:<!-- -->
6、JS变量定义和赋值
1、定义变量
在 JavaScript 中,定义变量需要使用var
关键字,语法格式如下:
var 变量名;
举几个例子:
var str; //用来存储字符串
var age; //用来存储年龄
var prePage; //用来存储上一页
定义变量时,可以一次定义一个或多个变量,若定义多个变量,则需要在变量名之间使用逗号,
分隔开,如下例所示:
var a, b, c; // 同时声明多个变量
变量定义后,如果没有为变量赋值,那么这些变量会被赋予一个初始值——undefined(未定义)。
2、 为变量赋值
变量定义后,可以使用等于号=
来为变量赋值,等号左边的为变量的名称,等号右边为要赋予变量的值,如下例所示:
var num; // 定义一个变量 num
num = 1; // 将变量 num 赋值为 1
此外,也可以在定义变量的同时为变量赋值,如下例所示:
var num = 1; // 定义一个变量 num 并将其赋值为 1
var a = 2, b = 3, c = 4; // 同时定义 a、b、c 三个变量并分别赋值为 2、3、4
// var a = 2, // 为了让代码看起来更工整,上一行代码也可以写成这样
// b = 3,
// c = 4;
3、 变量提升
JavaScript 在预编译期会先预处理声明的变量,但是变量的赋值操作发生在 JavaScript 执行期,而不是预编译期。
document.write(str); //显示undefined
str = http://c.biancheng.net/js/;
document.write(str); //显示 http://c.biancheng.net/js/
var str;
在上面示例中,声明变量放在最后,赋值操作放在前面。由于 JavaScript 在预编译期已经对变量声明语句进行了预解析,所以第1行代码读取变量值时不会抛出异常,而是返回未初始化的值 undefined。第3行代码是在赋值操作之后读取,故显示为数字 1。
JavaScript 引擎的解析方式是:先解析代码,获取所有被声明的变量,然后再一行一行地运行。这样,所有声明的变量都会被提升到代码的头部,这就叫作变量提升(Hoisting)。
4、 let 和 const 关键字
2015 年以前,JavaScript 只能通过 var 关键字来声明变量,在 ECMAScript6(ES6)发布之后,新增了 let 和 const 两个关键字来声明变量,其中:
-
使用 let 关键字声明的变量只在其所在的代码块中有效(类似于局部变量),并且在这个代码块中,同名的变量不能重复声明;
-
const 关键字的功能和 let 相同,但使用 const 关键字声明的变量还具备另外一个特点,那就是 const 关键字定义的变量,一旦定义,就不能修改(即使用 const 关键字定义的为常量)。
注意:IE10 及以下的版本不支持 let 和 const 关键字。
示例代码如下:
let name = "小明"; // 声明一个变量 name 并赋值为“小明”
let age = 11; // 声明一个变量 age
let age = 13; // 报错:变量 age 不能重复定义
const PI = 3.1415 // 声明一个常量 PI,并赋值为 3.1415
console.log(PI) // 在控制台打印 PI
7、JS数据类型(基本数据类型+引用类型)
JavaScript 中的数据类型可以分为两种类型:
-
基本数据类型(值类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol;
-
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
提示:Symbol 是 ECMAScript6 中引入的一种新的数据类型,表示独一无二的值。
typeof 操作符
在开始介绍各种数据类型之前,先来了解一下 typeof 操作符,使用 typeof 操作符可以返回变量的数据类型。
typeof 操作符有带括号和不带括号两种用法,如下例所示:
typeof x; // 获取变量 x 的数据类型typeof(x); // 获取变量 x 的数据类型
1. JS 基本数据类型
1) String 类型
字符串(String)类型是一段以单引号''
或双引号""
包裹起来的文本,例如 '123'、"abc"。需要注意的是,单引号和双引号是定义字符串的不同方式,并不是字符串的一部分。
定义字符串时,如果字符串中包含引号,可以使用反斜杠来转义字符串中的引号,或者选择与字符串中不同的引号来定义字符串,如下例所示:
var str = "Let's have a cup of coffee."; // 双引号中包含单引号
var str = 'He said "Hello" and left.'; // 单引号中包含双引号
var str = 'We'll never give up.'; // 使用反斜杠转义字符串中的单引号
2) Number 类型
数值(Number)类型用来定义数值,JavaScript 中不区分整数和小数(浮点数),统一使用 Number 类型表示,如下例所示:
var num1 = 123; // 整数var
num2 = 3.14; // 浮点数
注意:Number 类型所能定义的数值并不是无限的,JavaScript 中的 Number 类型只能表示 -(253 - 1) 到 (253 -1) 之间的数值。
对于一些极大或者极小的数,也可以通过科学(指数)计数法来表示,如下例所示:
var y=123e5; // 123 乘以 10 的 5 次方,即 12300000
var z=123e-5; // 123 乘以 10 的 -5 次方,即 0.00123
另外,Number 类型中还有一些比较特殊的值,分别为 Infinity、-Infinity 和 NaN,其中
-
Infinity:用来表示正无穷大的数值,一般指大于 1.7976931348623157e+308 的数;
-
-Infinity:用来表示负无穷大的数值,一般指小于 5e-324 的数;
-
NaN:即非数值(Not a Number 的缩写),用来表示无效或未定义的数学运算结构,例如 0 除以 0。
提示:如果某次计算的结果超出了 JavaScript 中 Number 类型的取值范围,那么这个数就会自动转化为无穷大,正数为 Infinity,负数为 -Infinity。
3) Boolean 类型
布尔(Boolean)类型只有两个值,true(真)或者 false(假),在做条件判断时使用的比较多,您除了可以直接使用 true 或 false 来定义布尔类型的变量外,还可以通过一些表达式来得到布尔类型的值,例如:
var a = true; // 定义一个布尔值 true
var b = false; // 定义一个布尔值 false
var c = 2 > 1; // 表达式 2 > 1 成立,其结果为“真(true)”,所以 c 的值为布尔类型的 true
var d = 2 < 1; // 表达式 2 < 1 不成立,其结果为“假(false)”,所以 c 的值为布尔类型的 false
4) Null 类型
Null 是一个只有一个值的特殊数据类型,表示一个“空”值,即不存在任何值,什么都没有,用来定义空对象指针。
使用 typeof 操作符来查看 Null 的类型,会发现 Null 的类型为 Object,说明 Null 其实使用属于 Object(对象)的一个特殊值。因此通过将变量赋值为 Null 我们可以创建一个空的对象。
5) Undefined 类型
Undefined 也是一个只有一个值的特殊数据类型,表示未定义。当我们声明一个变量但未给变量赋值时,这个变量的默认值就是 Undefined。例如:
var num;
console.log(num); // 输出 undefined
在使用 typeof 操作符查看未赋值的变量类型时,会发现它们的类型也是 undefined。对于未声明的变量,使用 typeof 操作符查看其类型会发现,未声明的变量也是 undefined,示例代码如下:
var message;
console.log(typeof message); // 输出 undefined
console.log(typeof name); // 输出 undefined
6) Symbol 类型
Symbol 是 ECMAScript6 中引入的一种新的数据类型,表示独一无二的值,Symbol 类型的值需要使用 Symbol() 函数来生成,如下例所示:
var str = "123";
var sym1 = Symbol(str);
var sym2 = Symbol(str);
console.log(sym1); // 输出 Symbol(123)
console.log(sym2); // 输出 Symbol(123)
console.log(sym1 == sym2); // 输出 false :虽然 sym1 与 sym2 看起来是相同的,但实际上它们并不一样,根据 Symbol 类型的特点,sym1 和 sym2 都是独一无二的
2. JS 引用数据类型
1) Object 类型
JavaScript 中的对象(Object)类型是一组由键、值组成的无序集合,定义对象类型需要使用花括号{ }
,语法格式如下:
{name1: value1, name2: value2, name3: value3, ..., nameN: valueN}
其中 name1、name2、name3、...、nameN 为对象中的键,value1、value2、value3、...、valueN 为对应的值。
在 JavaScript 中,对象类型的键都是字符串类型的,值则可以是任意数据类型。要获取对象中的某个值,可以使用对象名.键
的形式,如下例所示:
var person = {
name: 'Bob',
age: 20,
tags: ['js', 'web', 'mobile'],
city: 'Beijing',
hasCar: true,
zipcode: null
};
console.log(person.name); // 输出 Bob
console.log(person.age); // 输出 20
2) Array 类型
数组(Array)是一组按顺序排列的数据的集合,数组中的每个值都称为元素,而且数组中可以包含任意类型的数据。在 JavaScript 中定义数组需要使用方括号[ ]
,数组中的每个元素使用逗号进行分隔,例如:
[1, 2, 3, 'hello', true, null]
另外,也可以使用 Array() 函数来创建数组,如下例所示:
var arr = new Array(1, 2, 3, 4);
console.log(arr); // 输出 [1, 2, 3, 4]
数组中的元素可以通过索引来访问。数组中的索引从 0 开始,并依次递增,也就是说数组第一个元素的索引为 0,第二个元素的索引为 1,第三个元素的索引为 2,以此类推。如下例所示:
var arr = [1, 2, 3.14, 'Hello', null, true];
console.log(arr[0]); // 输出索引为 0 的元素,即 1
console.log(arr[6]); // 输出索引为 5 的元素,即 true
console.log(arr[7]); // 索引超出了范围,返回 undefined
3) Function 类型
函数(Function)是一段具有特定功能的代码块,函数并不会自动运行,需要通过函数名调用才能运行,如下例所示:
function sayHello(name){
return "Hello, " + name;
}
var res = sayHello("Peter");
console.log(res); // 输出 Hello, Peter
此外,函数还可以存储在变量、对象、数组中,而且函数还可以作为参数传递给其它函数,或则从其它函数返回,如下例所示:
var fun = function(){
console.log("http://c.biancheng.net/js/");
}
function createGreeting(name){
return "Hello, " + name;
}
function displayGreeting(greetingFunction, userName){
return greetingFunction(userName);
}
var result = displayGreeting(createGreeting, "Peter");
console.log(result); // 输出 Hello, Peter
小结
在学习JavaScript过程中记录的一些小笔记,不足之处还望指正。在之后的日子里大家一起进步吧!
web渗透师徒班:昕之所嚮学习分享!
原文始发于微信公众号(衡阳信安):JavaScript学习笔记分享 (1)
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论