JavaScript基础知识总结

1.前提

Html是一种标记语言,用来结构化我们的网页内容并赋予内容含义,例如定义段落、标题和数据表,或在页面中嵌入图片和视频

Css是一种样式规则语言,可将样式应用于 HTML 内容,例如设置背景颜色和字体,在多个列中布局内容

JavaScript 是一种脚本语言,可以用来创建动态更新的内容,控制多媒体,制作图像动画,还有很多

2.简介

JavaScript 是一种轻量级的编程语言。

JavaScript 是可插入 HTML 页面的编程代码

JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行

3.JavaScript 用法

HTML 中的 Javascript 脚本代码必须位于 <script> 与 </script> 标签之间

Javascript 脚本代码可被放置在 HTML 页面的 <body> 和 <head> 部分中

3.1<script><script/> 标签

如需在 HTML 页面中插入 JavaScript,请使用 <script> 标签

<script> 和 </script> 会告诉 JavaScript 在何处开始和结束

<script> 和 </script> 之间的代码行包含了 JavaScript
<script>

alert("我的第一个 JavaScript");

</script>

您无需理解上面的代码。只需明白,浏览器会解释并执行位于 <script> 和 </script>之间的 JavaScript 代码

那些老旧的实例可能会在 <script> 标签中使用 type="text/javascript"。现在已经不必这样做了。JavaScript 是所有现代浏览器以及 HTML5 中的默认脚本语言

3.2 <body> 中的 JavaScript

JavaScript 会在页面加载时向 HTML 的 <body> 写文本

<!DOCTYPE html>

<html>

<body>

.

.

<script>

document.write("<h1>这是一个标题</h1>");

document.write("<p>这是一个段落</p>");

</script>

.

.

</body>

</html>

3.3<head> 中的 JavaScript 函数

该函数会在点击按钮时被调用

<!DOCTYPE html>

<html>

<head>

<script>

function myFunction()

{

document.getElementById("demo").innerHTML="我的第一个 JavaScript 函数";

}

</script>

</head>

<body>

<h1>我的 Web 页面</h1>

<p id="demo">一个段落</p>

<button type="button" οnclick="myFunction()">尝试一下</button>

</body>

</html>

3.4外部的 JavaScript

可以把脚本保存到外部文件中。外部文件通常包含被多个网页使用的代码

如需使用外部文件,请在 <script> 标签的 "src" 属性中设置该 .js 文件:

<!DOCTYPE html>

<html>

<body>

<script src="myScript.js"></script>

</body>

</html>

myScript.js 文件代码如下

function myFunction()

{

document.getElementById("demo").innerHTML="我的第一个 JavaScript 函数";

}

4.Chrome 浏览器中执行 JavaScript

如何在 Chrome 浏览器上进行 JavaScript 代码的运行与调试

我们在 Chrome 浏览器中可以通过按下 F12 按钮或者右击页面,选择**"检查"**来开启开发者工具

也可以在右上角菜单栏选择 "更多工具"=》"开发者工具" 来开启

4.1Console 窗口调试 JavaScript 代码

打开开发者工具后,我们可以在 Console 窗口调试 JavaScript代码,如下图

上图中我们在 > 符号后输入我们要执行的代码 console.log("runoob"),按回车后执行。

我们也可以在其他地方复制一段代码过来执行,比如复制以下代码到 Console 窗口,按回车执行

4.2清空 Console 窗口到内容可以按以下按钮

4.3Chrome snippets 小脚本

我们也可以在 Chrome 浏览器中创建一个脚本来执行,在开发者工具中点击 Sources 面板,选择 Snippets 选项卡,在导航器中右击鼠标,然后选择 Create new snippet 来新建一个脚本文件

如果你没看到 Snippets ,可以点下面板上到 >> 就能看到了

点击 Create new snippet 后,会自动创建一个文件,你只需在右侧窗口输入以下代码,然后按 Command+S(Mac)或 Ctrl+S(Windows 和 Linux)保存更改即可

5.JavaScript 输出

JavaScript 可以通过不同的方式来输出数据:

  • 使用 window.alert() 弹出警告框。
  • 使用 document.write() 方法将内容写到 HTML 文档中。
  • 使用 innerHTML 写入到 HTML 元素。
  • 使用 console.log() 写入到浏览器的控制台

<p id="demo">我的第一个段落</p>

<script>

document.getElementById("demo").innerHTML = "段落已修改。";

</script>
<script> document.write(Date());</script>
<button οnclick="myFunction()">点我</button>

<script>

function myFunction() {

document.write(Date());

}

</script>
<script>

a = 5;

b = 6;

c = a + b;

console.log(c);

</script>

6.JavaScript 语法

JavaScript 代码

document.getElementById("demo").innerHTML="你好 Dolly";

JavaScript 代码块

function myFunction()

{

document.getElementById("demo").innerHTML="你好Dolly";

}

JavaScript 语句标识符

空格

JavaScript 会忽略多余的空格 您可以向脚本添加空格,来提高其可读性

7.JavaScript 注释

单行注释以 // 开头

多行注释以 /* 开始,以 */ 结尾

8.JavaScript 变量

  • 变量必须以字母开头
  • 变量也能以 $ 和 _ 符号开头(不过我们不推荐这么做)
  • 变量名称对大小写敏感(y 和 Y 是不同的变量)

声明(创建) JavaScript 变量

在 JavaScript 中创建变量通常称为"声明"变量

我们使用 var 关键词来声明变量

var carname;

变量声明之后,该变量是空的(它没有值)

如需向变量赋值,请使用等号:

carname="Volvo";

不过,您也可以在声明变量时对其赋值:

var carname="Volvo";

在下面的例子中,我们创建了名为 carname 的变量,并向其赋值 "Volvo",然后把它放入 id="demo" 的 HTML 段落中:

var carname="Volvo";

document.getElementById("demo").innerHTML=carname;

一条语句,多个变量

您可以在一条语句中声明很多变量。该语句以 var 开头,并使用逗号分隔变量即可:

var lastname="Doe", age=30, job="carpenter";

声明也可横跨多行:

var lastname="Doe",

age=30,

job="carpenter";

一条语句中声明的多个变量不可以同时赋同一个值:

var x,y,z=1;

x,y 为 undefined, z 为 1

9.JavaScript 数据类型

值类型(基本类型)

字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol

**注:**Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值

引用数据类型(对象类型)

对象(Object)、数组(Array)、函数(Function),两个特殊的对象:正则(RegExp)和日期(Date)

JavaScript 拥有动态类型

JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型:

var x; // x 为 undefinedvar

x = 5; // 现在 x 为数字

var x = "John"; // 现在 x 为字符串

变量的数据类型可以使用 typeof 操作符来查看

typeof "John" // 返回 string

typeof 3.14 // 返回 number

typeof false // 返回 boolean

typeof [1,2,3,4] // 返回 object

typeof {name:'John', age:34} // 返回 object

JavaScript 数字

JavaScript 只有一种数字类型。数字可以带小数点,也可以不带

var x1=34.00; //使用小数点来写

var x2=34; //不使用小数点来写

JavaScript 布尔

布尔(逻辑)只能有两个值:true 或 false

var x=true;

var y=false;

JavaScript 数组

下面的代码创建名为 cars 的数组

var cars=new Array();

cars[0]="Saab";

cars[1]="Volvo";

cars[2]="BMW";
var cars=new Array("Saab","Volvo","BMW");

var cars=["Saab","Volvo","BMW"];

JavaScript 对象

对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔

var person={firstname:"John", lastname:"Doe", id:5566};
name=person.lastname;

name=person["lastname"];

undefined 和 Null

Undefined 这个值表示变量不含有值。

可以通过将变量的值设置为 null 来清空变量

cars=null;

person=null;
var person={firstname:"John", lastname:"Doe", id:5566};

// name=person.lastname;

// name=person["lastname"];

var cars=["Saab","Volvo","BMW"];

cars=null;

person=null;

console.info(cars)

声明变量类型

当您声明新变量时,可以使用关键词 "new" 来声明其类型

var carname=new String;

var x= new Number;

var y= new Boolean;

var cars= new Array;

var person= new Object;

对象方法

<p id="demo"></p>

<script>

var person = {

firstName: "John",

lastName : "Doe",

id : 5566,

fullName : function()

{

return this.firstName + " " + this.lastName;

}

};

document.getElementById("demo").innerHTML = person.fullName(); //调用对象方法

</script>

JavaScript 函数

函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块

<script> function myFunction() {

alert("Hello World!");

} </script>

<button οnclick="myFunction()">点我</button>

JavaScript 函数语法

函数就是包裹在花括号中的代码块,前面使用了关键词 function

function functionname ()

{

// 执行代码

}

调用带参数的函数

在调用函数时,您可以向其传递值,这些值被称为参数。

这些参数可以在函数中使用。

您可以发送任意多的参数,由逗号 (,) 分隔:

<p>点击这个按钮,来调用带参数的函数。</p>

<button οnclick="myFunction('Harry Potter','Wizard')">点击这里</button>

<script>

function myFunction(name,job){

alert("Welcome " + name + ", the " + job);

}

</script>

带有返回值的函数

有时,我们会希望函数将值返回调用它的地方。

通过使用 return 语句就可以实现。

在使用 return 语句时,函数会停止执行,并返回指定的值

function myFunction()

{

var x=5;

return x;

}

var myVar=myFunction();
function myFunction(a,b) { return a*b; } document.getElementById("demo").innerHTML=myFunction(4,3);

10.JavaScript 作用域

11.JavaScript 事件

HTML 事件是发生在 HTML 元素上的事情

当在 HTML 页面中使用 JavaScript 时, JavaScript 可以触发这些事件

HTML 事件可以是浏览器行为,也可以是用户行为。

以下是 HTML 事件的实例:

  • HTML 页面完成加载
  • HTML input 字段改变时
  • HTML 按钮被点击

通常,当事件发生时,你可以做些事情。

在事件触发时 JavaScript 可以执行一些代码。

HTML 元素中可以添加事件属性,使用 JavaScript 代码来添加 HTML 元素

在以下实例中,按钮元素中添加了 onclick 属性 (并加上代码)

<button οnclick="getElementById('demo').innerHTML=Date()">现在的时间是?</button>

或者

<p>点击按钮执行 <em>displayDate()</em> 函数.</p>

<button οnclick="displayDate()">点这里</button>

<script>

function displayDate(){

document.getElementById("demo").innerHTML=Date();

}

</script>

<p id="demo"></p>

</body>

其它事件

12.JavaScript 字符串

JavaScript 字符串用于存储和处理文本

var carname = "Volvo XC60";

var character = carname[7];
const name = "RUNOOB";

let letter = name[2];

document.getElementById("demo").innerHTML = letter;

字符串长度

可以使用内置属性 length 来计算字符串的长度

var txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

var sln = txt.length;

13.JavaScript 运算符

比较和逻辑运算符用于测试 true 或者 false

比较运算符

逻辑运算符

14.JavaScript if...Else 语句

通常在写代码时,您总是需要为不同的决定来执行不同的动作。您可以在代码中使用条件语句来完成该任务。

在 JavaScript 中,我们可使用以下条件语句:

  • if 语句 - 只有当指定条件为 true 时,使用该语句来执行代码
  • if...else 语句 - 当条件为 true 时执行代码,当条件为 false 时执行其他代码
  • if...else if....else 语句- 使用该语句来选择多个代码块之一来执行
  • switch 语句 - 使用该语句来选择多个代码块之一来执行

15.JavaScript switch 语句

switch(n)

{

case 1:

执行代码块 1

break;

case 2:

执行代码块 2

break;

default:

与 case 1 和 case 2 不同时执行的代码

}

16.JavaScript for 循环

for 循环

for (var i=0; i<5; i++)

{

x=x + "该数字为 "

}

For/In 循环

JavaScript for/in 语句循环遍历对象的属性

var person={fname:"Bill",lname:"Gates",age:56};

for (x in person) // x 为属性名

{

txt=txt + person[x];

}

while 循环

while (i<5)

{

x=x + "The number is " + i + "<br>";

i++;

}

17.JavaScript break 和 continue 语句

break 语句用于跳出循环

continue 用于跳过循环中的一个迭代

for (i=0;i<10;i++){

if (i==3){

break;

}

x=x + "The number is " + i + "<br>";

}
for (i=0;i<=10;i++){

if (i==3) continue;

console.info(i)

}

18.JavaScript typeof, null, 和 undefined

typeof 操作符来检测变量的数据类型

typeof "John" // 返回 string

typeof 3.14 // 返回 number

typeof false // 返回 boolean

typeof [1,2,3,4] // 返回 object

typeof {name:'John', age:34} // 返回 object

null

在 JavaScript 中 null 表示 "什么都没有"。

null是一个只有一个值的特殊类型。表示一个空对象引用

var person = null; // 值为 null(空), 但类型为对象
var person = undefined; // 值为 undefined, 类型为 undefined

undefined

在 JavaScript 中, undefined 是一个没有设置值的变量

var person; // 值为 undefined(空), 类型是undefined

19.JavaScript 正则表达式

20.JavaScript 表单验证

HTML 表单验证可以通过 JavaScript 来完成

以下实例代码用于判断表单字段(fname)值是否存在, 如果不存在,就弹出信息,阻止表单提交

function validateForm() {

var x = document.forms["myForm"]["fname"].value;

if (x == null || x == "") {

alert("需要输入名字。");

return false;

}

}
<form name="myForm" action="demo_form.php" οnsubmit="return validateForm()" method="post">

名字: <input type="text" name="fname">

<input type="submit" value="提交">

</form>

HTML 表单自动验证

HTML 表单验证也可以通过浏览器来自动完成

如果表单字段 (fname) 的值为空, required 属性会阻止表单提交

<form action="demo_form.php" method="post">

<input type="text" name="fname" required="required">

<input type="submit" value="提交">

</form>

21.JavaScript this 关键字

面向对象语言中 this 表示当前对象的一个引用

但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变

  • 在方法中,this 表示该方法所属的对象
  • 如果单独使用,this 表示全局对象
  • 在函数中,this 表示全局对象
  • 在函数中,在严格模式下,this 是未定义的(undefined)
  • 在事件中,this 表示接收事件的元素
  • 类似 call() 和 apply() 方法可以将 this 引用到任何对象

方法中的 this

在对象方法中, this 指向调用它所在方法的对象

在上面一个实例中,this 表示 person 对象

fullName 方法所属的对象就是 person

<script>

// 创建一个对象

var person = {

firstName: "John",

lastName : "Doe",

id : 5566,

fullName : function() {

return this.firstName + " " + this.lastName;

}

};

// 显示对象的数据

document.getElementById("demo").innerHTML = person.fullName();

</script>

事件中的 this

在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素

<button οnclick="this.style.display='none'">点我后我就消失了</button>

对象方法中绑定

下面实例中,this 是 person 对象,person 对象是函数的所有者

<script>

// 创建一个对象

var person = {

firstName : "John",

lastName : "Doe",

id : 5566,

myFunction : function() {

return this;

}

};

// 显示表单数据

document.getElementById("demo").innerHTML = person.myFunction();

</script>

显式函数绑定

在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。

在下面实例中,当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法:

<script>

var person1 = {

fullName: function() {

return this.firstName + " " + this.lastName;

}

}

var person2 = {

firstName:"John",

lastName: "Doe",

}

var x = person1.fullName.call(person2);

document.getElementById("demo").innerHTML = x;

</script>

22. let 和 const区别

ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: letconst

let 声明的变量只在 let 命令所在的代码块内有效。

const 声明一个只读的常量,一旦声明,常量的值就不能改变。

在 ES6 之前,JavaScript 只有两种作用域: 全局变量函数内的局部变量

全局变量

在函数外声明的变量作用域是全局的:

var carName = "Volvo";

// 这里可以使用 carName 变量

function myFunction() {

// 这里也可以使用 carName 变量

}

全局变量在 JavaScript 程序的任何地方都可以访问。

局部变量

在函数内声明的变量作用域是局部的(函数内):

// 这里不能使用 carName 变量

function myFunction() {

var carName = "Volvo";

// 这里可以使用 carName 变量

}

// 这里不能使用 carName 变量

函数内使用 var 声明的变量只能在函数内访问,如果不使用 var 则是全局变量。

块级作用域(Block Scope)

使用 var 关键字声明的变量不具备块级作用域的特性,它在 {} 外依然能被访问到。

复制代码
{ 
    var x = 2; 
}
// 这里可以使用 x 变量

在 ES6 之前,是没有块级作用域的概念的。

ES6 可以使用 let 关键字来实现块级作用域。

let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。

{

let x = 2;

}

// 这里不能使用 x 变量

重新定义变量

使用 var 关键字重新声明变量可能会带来问题。

在块中重新声明变量也会重新声明块外的变量:

var x = 10;

// 这里输出 x 为 10

{

var x = 2;

// 这里输出 x 为 2

}

// 这里输出 x 为 2

let 关键字就可以解决这个问题,因为它只在 let 命令所在的代码块 {} 内有效。

var x = 10;

// 这里输出 x 为 10

{

let x = 2;

// 这里输出 x 为 2

}

// 这里输出 x 为 10

循环作用域

使用 var 关键字:

var i = 5;

for (var i = 0; i < 10; i++) {

// 一些代码...

}

// 这里输出 i 为 10

使用 let 关键字:

var i = 5;

for (let i = 0; i < 10; i++) {

// 一些代码...

}

// 这里输出 i 为 5

在第一个实例中,使用了 var 关键字,它声明的变量是全局的,包括循环体内与循环体外。

在第二个实例中,使用 let 关键字, 它声明的变量作用域只在循环体内,循环体外的变量不受影响。

变量提升

JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。

JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明

x = 5; // 变量 x 设置为 5

elem = document.getElementById("demo"); // 查找元素

elem.innerHTML = x;

// 在元素中显示 xvar x; // 声明 x
var x = 5; // 初始化 x

var y; // 声明 y

elem = document.getElementById("demo"); // 查找元素

elem.innerHTML = x + " " + y; // 显示 x 和 y

y = 7; // 设置 y 为 7

const 关键字

const 用于声明一个或多个常量,声明时必须进行初始化,且初始化后值不可再修改

const PI = 3.141592653589793;

PI = 3.14; // 报错

PI = PI + 10; // 报错

  • const声明的常量必须初始化,而let声明的变量不用
  • const 定义常量的值不能通过再赋值修改,也不能再次声明。而 let 定义的变量值可以修改

const 的本质: const 定义的变量并非常量,并非不可变,它定义了一个常量引用一个值。

使用 const 定义的对象或者数组,其实是可变的。下面的代码并不会报错:

// 创建常量对象

const car = {type:"Fiat", model:"500", color:"white"};

// 修改属性:

car.color = "red";

// 添加属性

car.owner = "Johnson";
// 创建常量数组

const cars = ["Saab", "Volvo", "BMW"];

// 修改元素

cars[0] = "Toyota";

// 添加元素

cars.push("Audi");

23.JavaScript JSON

JSON 是用于存储和传输数据的格式。

JSON 通常用于服务端向网页传递数据 。

什么是 JSON

JSON 是一种轻量级的数据交换格式

JSON 语法规则

  • 数据为 键/值 对。
  • 数据由逗号分隔。
  • 大括号保存对象
  • 方括号保存数组

JSON 数据 - 一个名称对应一个值

JSON 数据格式为 键/值 对,就像 JavaScript 对象属性。

键/值对包括字段名称(在双引号中),后面一个冒号,然后是值

"name":"Runoob"

JSON 对象

JSON 对象保存在大括号内。

就像在 JavaScript 中, 对象可以保存多个 键/值 对:

{"name":"Runoob", "url":"www.runoob.com"}

JSON 数组

JSON 数组保存在中括号内。

就像在 JavaScript 中, 数组可以包含对象

"sites":[

{"name":"Runoob", "url":"www.runoob.com"},

{"name":"Google", "url":"www.google.com"},

{"name":"Taobao", "url":"www.taobao.com"}

]

JSON 字符串转换为 JavaScript 对象

通常我们从服务器中读取 JSON 数据,并在网页中显示数据

var text = '{ "sites" : [' +

'{ "name":"Runoob" , "url":"www.runoob.com" },' +

'{ "name":"Google" , "url":"www.google.com" },' +

'{ "name":"Taobao" , "url":"www.taobao.com" } ]}';

然后,使用 JavaScript 内置函数 JSON.parse() 将字符串转换为 JavaScript 对象:

var obj = JSON.parse(text);

最后,在你的页面中使用新的 JavaScript 对象:

var text = '{ "sites" : [' +

'{ "name":"Runoob" , "url":"www.runoob.com" },' +

'{ "name":"Google" , "url":"www.google.com" },' +

'{ "name":"Taobao" , "url":"www.taobao.com" } ]}';

obj = JSON.parse(text);

document.getElementById("demo").innerHTML = obj.sites[1].name + " " + obj.sites[1].url;

函数 描述
JSON.parse() 用于将一个 JSON 字符串转换为 JavaScript 对象。
JSON.stringify() 用于将 JavaScript 值转换为 JSON 字符串。

例子

要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法

复制代码
 //结果是 {a: 'Hello', b: 'World'} 一个对象
var obj = JSON.parse('{"a": "Hello", "b": "World"}');

要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法

//结果是 '{"a": "Hello", "b": "World"}' 一个JSON格式的字符串

复制代码
var json = JSON.stringify({a: 'Hello', b: 'World'}); 

javascript:void(0)

创建了一个超级链接,当用户点击以后不会发生任何事

<a href="javascript:void(0)">单击此处什么也不会发生</a>

24.异步编程

异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念

程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系

回调函数

回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终

setTimeout(function () {

document.getElementById("demo").innerHTML="RUNOOB!";

}, 3000);

25.JavaScript Promise

Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务

由于 Promise 是 ES6 新增加的,所以一些旧的浏览器并不支持

构造 Promise

现在我们新建一个 Promise 对象

new Promise(function (resolve, reject) {

// 要做的事情...

});

通过新建一个 Promise 对象好像并没有看出它怎样 "更加优雅地书写复杂的异步任务"。我们之前遇到的异步任务都是一次异步,如果需要多次调用异步函数呢?例如,如果我想分三次输出字符串,第一次间隔 1 秒,第二次间隔 4 秒,第三次间隔 3 秒

setTimeout(function () {

console.log("First");

setTimeout(function () {

console.log("Second");

setTimeout(function () {

console.log("Third");

}, 3000);

}, 4000);

}, 1000);

这段程序实现了这个功能,但是它是用 "函数瀑布" 来实现的。可想而知,在一个复杂的程序当中,用 "函数瀑布" 实现的程序无论是维护还是异常处理都是一件特别繁琐的事情,而且会让缩进格式变得非常冗赘。

现在我们用 Promise 来实现同样的功能:

new Promise(function (resolve, reject) {

setTimeout(function () {

console.log("First");

resolve();

}, 1000);

}).then(function () {

return new Promise(function (resolve, reject) {

setTimeout(function () {

console.log("Second");

resolve();

}, 4000);

});

}).then(function () {

setTimeout(function () {

console.log("Third");

}, 3000);

});

Promise 的构造函数

Promise 构造函数是 JavaScript 中用于创建 Promise 对象的内置构造函数。

Promise 构造函数接受一个函数作为参数,该函数是同步的并且会被立即执行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject,分别表示 Promise 成功和失败的状态。

起始函数执行成功时,它应该调用 resolve 函数并传递成功的结果。当起始函数执行失败时,它应该调用 reject 函数并传递失败的原因。

Promise 构造函数返回一个 Promise 对象,该对象具有以下几个方法:

  • then:用于处理 Promise 成功状态的回调函数。
  • catch:用于处理 Promise 失败状态的回调函数。
  • finally:无论 Promise 是成功还是失败,都会执行的回调函数。

下面是一个使用 Promise 构造函数创建 Promise 对象的例子

const promise = new Promise((resolve, reject) => {

// 异步操作

setTimeout(() => {

if (Math.random() < 0.5) {

resolve('success');

} else {

reject('error');

}

}, 1000);

});

promise.then(result => {

console.log(result);

}).catch(error => {

console.log(error);

});

在上面的例子中,我们使用 Promise 构造函数创建了一个 Promise 对象,并使用 setTimeout 模拟了一个异步操作。如果异步操作成功,则调用 resolve 函数并传递成功的结果;如果异步操作失败,则调用 reject 函数并传递失败的原因。然后我们使用 then 方法处理 Promise 成功状态的回调函数,使用 catch 方法处理 Promise 失败状态的回调函数。

这段程序会直接输出 errorsuccess

resolve 和 reject 都是函数,其中调用 resolve 代表一切正常,reject 是出现异常时所调用的

new Promise(function (resolve, reject) {

var a = 0;

var b = 1;

if (b == 0) reject("Divide zero");

else resolve(a / b);

}).then(function (value) {

console.log("a / b = " + value);

}).catch(function (err) {

console.log(err);

}).finally(function () {

console.log("End");

});

Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列

new Promise(function (resolve, reject) {

console.log(1111);

resolve(2222);

}).then(function (value) {

console.log(value);

return 3333;

}).then(function (value) {

console.log(value);

throw "An error";

}).catch(function (err) {

console.log(err);

});

但是请注意以下两点:

  • resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
  • resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。

Promise 函数

上述的 "计时器" 程序看上去比函数瀑布还要长,所以我们可以将它的核心部分写成一个 Promise 函数

function print(delay, message) {

return new Promise(function (resolve, reject) {

setTimeout(function () {

console.log(message);

resolve();

}, delay);

});

}
print(1000, "First").then(function () {

return print(4000, "Second");

}).then(function () {

print(3000, "Third");

});

异步函数

异步函数(async function)是 ECMAScript 2017 (ECMA-262) 标准的规范,几乎被所有浏览器所支持,除了 Internet Explorer。

在 Promise 中我们编写过一个 Promise 函数

function print(delay, message) {

return new Promise(function (resolve, reject) {

setTimeout(function () {

console.log(message);

resolve();

}, delay);

});

}

然后用不同的时间间隔输出了三行文本

print(1000, "First").then(function () {

return print(4000, "Second");

}).then(function () {

print(3000, "Third");

});

我们可以将这段代码变得更好看

async function asyncFunc() {

await print(1000, "First");

await print(4000, "Second");

await print(3000, "Third");

}

asyncFunc();

异步函数 async function 中可以使用 await 指令,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行

处理异常的机制将用 try-catch 块实现

async function asyncFunc() {

try {

await new Promise(function (resolve, reject) {

throw "Some error"; // 或者 reject("Some error")

});

} catch (err) {

console.log(err);

// 会输出 Some error

}

}

asyncFunc();

如果 Promise 有一个正常的返回值,await 语句也会返回它

async function asyncFunc() {

let value = await new Promise(

function (resolve, reject) {

resolve("Return value");

}

);

console.log(value);

}

asyncFunc();

总结

  • 1、Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)
  • 2、Promise构造函数接收一个函数作为参数,该函数的两个参数分别是 resolve 和 reject
  • 3、一个promise对象只能改变一次状态,成功或者失败后都会返回结果数据。
  • 4、then 方法可以接收两个回调函数作为参数,第一个回调函数是Promise对象的状态改变为 resoved 是调用,第二个回调函数是 Promise 对象的状态变为 rejected 时调用。其中第二个参数可以省略。
  • 5、catch 方法,该方法相当于最近的 then 方法的第二个参数,指向 reject 的回调函数,另一个作用是,在执行resolve回调函数时,如果出错,抛出异常,不会停止运行,而是进入catch 方法中。

注意:catch 只捕获最近的 then 的回调函数,前面的then的执行不成功的结果,有后面 then 的 reject 回调函数执行,如果没有后续 then 回调函数执行,则会被 catch 捕获执行

var promise =new Promise(function(resolve,reject){

//To Do 要异步执行的事情,这个异步执行的事情有可能成功执行完毕,那么Promise将是 fulfilled状态,如果执行失败则是rejected;

//下面测试代码,人为设置为rejected状态;

reject("将当前构建的Promise对象的状态由pending(进行中)设置为rejected(已拒绝)"); //当然此处也可以设置为fulfilled(已完成)状态

})

promise.then(//调用第一个then()

success=>{

console.log("异步执行成功,状态为:fulfilled,成功后返回的结果是:"+success);

return(" 当前 success ");

},

error=>{

console.log("异步执行失败,状态为rejected,失败后返回的结果是:"+error);

return(" 当前 error ");

}

).then(

//调用第二个then() 因为调用第一个then()方法返回的是一个新的promise对象,此对象的状态由上面的success或者error两个回调函数的执行情况决定的:

//如果回调函数能正常执行完毕,则新的promise对象的状态为fulfilled,下面执行success2,如果回调函数无法正常执行,则promise状态为rejected;下面执行error2

success2=>{

console.log("第一个then的回调函数执行成功 成功返回结果:"+success2);

throw(" 当前 success2 ");//自定义异常抛出

},

error2=>{

console.log("第一个then的回调函数执行失败 失败返回结果:"+error2);

return(" 当前 error2 ");

}

).catch(err=>{

//当success2或者error2执行报错时,catch会捕获异常;

console.log("捕获异常:"+err);

});

26.JavaScript 函数

JavaScript 函数定义

JavaScript 使用关键字 function 定义函数。

函数可以通过声明定义,也可以是一个表达式

函数声明

函数声明后不会立即执行,会在我们需要的时候调用到

function myFunction(a, b) { return a * b;}

函数表达式

var x = function (a, b) {return a * b};

var z = x(4, 3);

Function() 构造函数

在以上实例中,我们了解到函数通过关键字 function 定义。

函数同样可以通过内置的 JavaScript 函数构造器(Function())定义

var myFunction = new Function("a", "b", "return a * b");

var x = myFunction(4, 3);

实际上,你不必使用构造函数。上面实例可以写成

var myFunction = function (a, b) {return a * b};

var x = myFunction(4, 3);

箭头函数

ES6 新增了箭头函数。

箭头函数表达式的语法比普通函数表达式更简洁

(参数1, 参数2, ..., 参数N) => { 函数声明 }

(参数1, 参数2, ..., 参数N) => 表达式(单一)

// 相当于:(参数1, 参数2, ..., 参数N) =>{ return 表达式; }

当只有一个参数时,圆括号是可选的

(单一参数) => {函数声明}

单一参数 => {函数声明}

没有参数的函数应该写成一对圆括号

() => {函数声明}
// ES5

var x = function(x, y) {

return x * y;

}

// ES6

const x = (x, y) => x * y;

有的箭头函数都没有自己的 this 。 不适合定义一个 对象的方法

当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的。

箭头函数是不能提升的,所以需要在使用之前定义。

使用 const 比使用 var 更安全,因为函数表达式始终是一个常量。

如果函数部分只是一个语句,则可以省略 return 关键字和大括号 {},这样做是一个比较好的习惯

const x = (x, y) => { return x * y };

总结

(参数) => { 函数体 }

// 普通函数

let sum = function(a, b) {

return a + b;

}

// 箭头函数

let sum1 = (a, b) => {

return a + b;

}

省略包含参数的小括号

// 有效

let sum = (x) => {

return x;

};

// 有效

let sum1 = x => {

return x;

};

// 没有参数需要括号

let sum2 = () => {

return 1;

};

// 有多个参数需要括号

let sum3 = (a, b) => {

return a + b;

};

省略包含函数体的大括号

// 有效

let sum = (a, b) => {

return a + b;

};

// 有效

let sum1 = (a, b) => a + b; // 相当于 return a + b;

// 无效的写法

let sum2 = (a, b) => return a + b;

嵌入函数

let arr = [1, 2, 3, 4, 5];

arr.map(val => val * 2); // [2, 4, 6, 8, 10]

箭头函数不能使用arguments

// 普通函数

let sum = function() {

return arguments.length;

}

sum(1, 2, 3); // 3

// 箭头函数

let sum1 = () => {

return arguments.length;

}

sum1(1, 2); // Uncaught ReferenceError: arguments is not defined

虽然箭头函数中没有 arguments 对象,但可以在包装函数中把它提供给箭头函数:

function foo() {

let bar = () => {

console.log(arguments.length);

}

bar();

}

foo(5, 5, 5); // 3

箭头函数中this 指向

let num = 11;

const obj1 = {

num: 22,

fn1: function() {

let num = 33;

const obj2 = {

num: 44,

fn2: () => {

console.log(this.num);

}

}

obj2.fn2();

}

}

obj1.fn1(); // 22

fn2中得到的结果为:22

原因箭头函数没有this,箭头函数的this是继承父执行上下文里面的this ,这里箭头函数的执行上下文是函数fn1(),所以它就继承了fn1()的this,obj1调用的fn1,所以fn1的this指向obj1, 所以obj1.num 为 22。

注意:简单对象(非函数)是没有执行上下文的!

如果fn1也是个箭头函数呢?

let num = 11;

const obj1 = {

num: 22,

fn1: () => {

let num = 33;

const obj2 = {

num: 44,

fn2: () => {

console.log(this.num);

}

}

obj2.fn2();

}

}

obj1.fn1();

上述结果为undefined,因为fn1也是一个箭头函数,所以它就只能继续向上找也就是window了。

那为什么是undefined而不是11呢?

这里涉及到var和let声明变量的一个区别:使用 let 在全局作用域中声明的变量不会成为 window 对象的属性,var 声明的变量则会(不过,let 声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续,所以使用window访问会为undefined):

var a = 1;

window.a; // 1

let b = 1;

window.b; // undefined

将let改成var后:

var num = 11; //

const obj1 = {

num: 22,

fn1: () => {

let num = 33;

const obj2 = {

num: 44,

fn2: () => {

console.log(this.num);

}

}

obj2.fn2();

}

}

obj1.fn1();

此时结果为window.num => 11

JavaScript 函数参数

参数传递

function foo(a, b) {

console.log([a, b]);

}

foo(1, 2); // 输出 [1, 2]

这个例子中,ab 属于函数中的局部变量,只能在函数中访问。调用函数时,传递的数据会根据位置来匹配对应,分别赋值给 ab

创建函数时,function 函数名 后面括号中设定的参数被称为形参 ;调用函数时,函数名后面括号中传入的参数被称为实参

因为形参是已声明的变量,所以不能再用 letconst 重复声明

function foo(a, b) {

let a = 1; // 报错,a 已声明

const b = 1; // 报错,b 已声明

}

从一个变量赋值到另一个变量

function add(num) {

return num + 1;

}

let count = 5;

let result = add(count); // 此处参数传递的过程可以看作是 num = count

console.log(count); // 5

console.log(result); // 6

引用值:

function setName(obj) {

obj.name = "小明";

}

let person = {};

setName(person); // 此处参数传递的过程可以看作是 obj = person;

console.log(person); // {name: "小明"}

理解参数

JavaScript 中的函数既不会检测参数的类型,也不会检测传入参数的个数。定义函数时设置两个形参,不意味着调用时必须传入两个参数。实际调用时不管是传了一个还是三个,甚至不传参数也不会报错。

所有函数(非箭头)中都有一个名为 arguments 的特殊的类数组对象(不是 Array 的实例),它保存着所有实参的副本,我们可以通过它按照数组的索引访问方式获取所有实参的值,也可以访问它的 arguments.length 属性来确定函数实际调用时传入的参数个数。

function foo(a, b) {

console.log(arguments[0]);

console.log(arguments[1]);

console.log(arguments.length);

}

foo(10, 20); // 依次输出 10、20、2

将对象属性用作实参

当一个函数包含的形参有多个时,调用函数就成了一种麻烦,因为你总是要保证传入的参数放在正确的位置上,有没有办法解决传参顺序的限制呢?

由于对象属性是无序的,通过属性名来确定对应的值。因此可以通过传入对象的方式,以对象中的属性作为真正的实参,这样参数的顺序就无关紧要了。

function foo(obj) {

console.log(obj.name, obj.sex, obj.age);

}

foo({ sex: '男', age: 18, name: '小明' }); // 小明 男 18

参数默认值

如果调用函数时缺少提供实参,那么形参默认值为 undefined

有时候我们想要设置特定的默认值,在 ES6 之前还不支持显式地设置默认值的时候,只能采用变通的方式

function sayHi(name) {

name = name || 'everyone';

console.log( 'Hello ' + name + '!');

}

sayHi(); // 输出 'Hello everyone!'
// if 语句判断

function sayHi(name) {

if (name === undefined) {

name = 'everyone';

}

console.log( 'Hello ' + name + '!');

}

// 三元表达式判断

function sayHi(name) {

name = (name !== undefined) ? name : 'everyone';

console.log( 'Hello ' + name + '!');

}

ES6 就方便了许多,因为它支持了显式的设置默认值的方式

function sayHi(name = 'everyone') { // 定义函数时,直接给形参赋值

console.log( 'Hello ' + name + '!');

}

sayHi(); // 输出 'Hello everyone!'

sayHi('Tony'); // 输出 'Hello Tony!'

sayHi(undefined); // 输出 'Hello everyone!'

参数默认值的位置

function fn(x, y = 2) {

console.log([x, y]);

}

fn(); // 输出 [undefined, 2]

fn(1); // 输出 [1, 2]

fn(1, 1) // 输出 [1, 1]

参数的收集与展开

ES6 提供了**剩余参数(rest)**的语法(...变量名),它可以收集函数多余的实参(即没有对应形参的实参),这样就不再需要使用 arguments 对象来获取了。形参使用了 ... 操作符会变成一个数组,多余的实参都会被放进这个数组中。

剩余参数基本用法:

function sum(a, ...values) {

for (let val of values) {

a += val;

}

return a;

}

sum(0, 1, 2, 3); // 6

参数位置

// 报错

function fn1(a, ...rest, b) {

console.log([a, b, rest]);

}

// 正确写法

function fn2(a, b, ...rest) {

console.log([a, b, rest]);

}

fn2(1, 2, 3, 4) // 输出 [1, 2, [3, 4]]

function sum(...values) {

let sum = 0;

for (let val of values) {

sum += val;

}

return sum;

}

let arr = [1, 2, 3, 4];

sum(arr); // "01,2,3,4"

把所有传进来的数值累加,如果直接传入一个数组,就得到我们想要的结果

sum.apply(null, arr); // 10
sum(...arr); // 10 // 相当于 sum(1,2,3,4);
sum(-1, ...arr); // 9

sum(...arr, 5); // 15

sum(-1, ...arr, 5); // 14

sum(-1, ...arr, ...[5, 6, 7]); // 27

JavaScript 对象

对象只是一种特殊的数据。对象拥有属性方法

创建了对象的一个新实例,并向其添加了四个属性

JavaScript 对象就是一个 name:value 集合

person=new Object();

person.firstname="John";

person.lastname="Doe";

person.age=50;

person.eyecolor="blue";
{ name1 : value1, name2 : value2,...nameN : valueN }

相关推荐
远望清一色9 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
何曾参静谧17 分钟前
「Py」Python基础篇 之 Python都可以做哪些自动化?
开发语言·python·自动化
Prejudices21 分钟前
C++如何调用Python脚本
开发语言·c++·python
我狠狠地刷刷刷刷刷34 分钟前
中文分词模拟器
开发语言·python·算法
wyh要好好学习38 分钟前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf
AitTech38 分钟前
C#实现:电脑系统信息的全面获取与监控
开发语言·c#
qing_04060340 分钟前
C++——多态
开发语言·c++·多态
孙同学_40 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
还是大剑师兰特41 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
froginwe1141 分钟前
XML 编辑器:功能、选择与使用技巧
开发语言