第二章 JavaScript 入门教程(1)

往期文章

目录

1 JS书写位置

1.1 script标签

1.2 三种书写位置

1.2.1 行内JS

1.2.2 内嵌JS

1.2.3 外部JS

1.3 script标签的位置

1.3.1 页面的加载、解析、渲染(简单理解)

1.3.2 script标签的位置问题

1.3.3 async defer

1.3.4 总结

2 JavaScript语法

2.1 标识符

2.2 区分大小写

2.3 严格模式

2.4 关键字和保留字

2.5 分号问题

2.6 注释

3 JavaScript 输入输出语句

4 变量

4.1 变量的基础知识

4.2 变量的定义

4.3 变量的赋值

4.4 其它关键字

4.4.1 let关键字

4.4.2 const关键字

5 数据类型

5.1 typeof操作符

5.2 Undefined类型

5.3 Null类型

5.4 Boolean类型

5.5 Number类型

5.5.1 介绍

5.5.2 整数

5.5.3 浮点数值

5.5.4 数值范围和三个特殊值

5.5.5 IsNaN 函数

5.5.6 数值转换

1 Number函数

2 parseInt函数(常用)

3 parseFloat函数

5.6 String类型

5.6.1 String的基本使用

5.6.2 字符串转义符

5.6.3 字符串拼接

5.6.4 转换为字符串

5.7 Object 类型

6 操作符

6.1 算术运算符

6.2 递增递减运算符

6.3 比较运算符

6.4 逻辑运算符

6.5 赋值运算符

6.7 运算符优先级

7 流程控制

7.1 流程控制介绍

7.2 分支流程控制

7.2.1 if语句

7.2.2 三元表达式

7.2.3 switch语句

7.2.4 if与switch比较

7.3 循环流程控制

7.3.1 for循环

7.3.2 双重for循环

7.3.3 while循环

7.4 do while 循环

7.5 continue break

8 数组(基础)

8.1 数组概念

8.2 创建数组

8.3 获取数组元素

8.4 遍历数组和数组长度

8.5 数组新增元素​​

 9 函数(基础)

9.1 函数概念

9.2 声明函数和调用函数

9.3 函数的参数

9.3.1 形参和实参

9.3.2 形参和实参个数不匹配问题

9.4 函数返回值

9.5 arguments的使用

9.6 匿名函数

10 作用域

10.1 作用于概念

10.2 变量作用域

10.3 作用域链

11 预解析

11.1 基本概念

11.2 分析方法(用来做题)

12 对象(基础)

12.1 对象的概念

12.2 创建对象的三种方式

12.3 访问修改删除对象属性

12.4 遍历对象


1 JS书写位置

1.1 script标签

script标签作用

使用<script>标签将 JavaScript程序插入到 HTML 文档的任何位置。

<script>属性

<script type=…>:通常情况下,我们会将<script>标签的type属性设置为"text/javascript",表示该脚本内容是JavaScript代码。该属性如今变得可选了。如果省略了type属性,浏览器会默认将其解析为 JavaScript 代码

<script src="...">:src属性用于指定外部 JavaScript 文件的 URL 地址,从而将该文件引入到当前的 HTML 页面中。这样做的作用是可以将 JavaScript 代码与 HTML 内容分离,使代码更加模块化和可维护。

1.2 三种书写位置

1.2.1 行内JS

可以将单行或少量 JS 代码写在HTML标签的事件属性中( 以 on 开头的属性)

例子

注意单双引号的使用:在HTML中我们推荐使用双引号, JS 中我们推荐使用单引号

onsubmit事件属性:form表单事件,当用户点击提交按钮时触发

 <!-- onsubmit属性 -->
    <form onsubmit="alert('Hello, World!');">
        <input type="text" name="username">
        <input type="submit" value="提交">
    </form>

onclick事件属性:当用户点击时触发

<!-- onclick属性 -->
    <input type="button" value="点我试试" onclick="alert('Hello World')" />

onload事件属性:在对象已加载时触发

<img src="image.jpg" onload="alert('Hello World'">

1.2.2 内嵌JS

将多行JS代码写到 <script> 标签中,例如:

<script>
        alert('Hello World~!');
</script>

1.2.3 外部JS

利于HTML页面代码结构化,把大段 JS代码独立到 HTML 页面之外, 既美观,也方便文件级别的复用(适合于JS 代码量比较大的情况)

例子

同一文件夹下有两个文件

my.js内容如下:

alert('Hello World~!')

在js.html引入my.js,如下代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <!-- 引入my.js -->
    <script src="my.js"></script>
</head>
<body>
</body>
</html>

1.3 script标签的位置

1.3.1 页面的加载、解析、渲染(简单理解)

一个页面(HTML文档)的加载顺序是从上到下顺序加载的,在这过程中进行解析和渲染

页面加载

页面加载是指从服务器下载网页资源的过程。过程如下:

  1. 浏览器接收到用户输入的网址,并向服务器发送请求。
  2. 服务器接收到请求后,将网页的 HTML、CSS、JavaScript 等资源发送回浏览器。
  3. 浏览器开始下载这些资源。

页面解析

  1. 浏览器接收到 HTML 文件后,开始对其进行解析。
  2. 根据 HTML 的结构构建 DOM(文档对象模型)树,表示网页的结构。
  3. 当遇到外部资源的引用(如 CSS 和 JavaScript),会暂停 HTML 的解析,转而下载这些资源。

页面渲染

  1. 浏览器解析到 CSS 资源时,会开始构建 CSSOM(CSS 对象模型)树,表示网页的样式信息(页面解析)。
  2. 浏览器将 DOM 树和 CSSOM 树合并,生成渲染树(Render Tree)。 渲染树包含了所有需要显示的内容和样式信息。 浏览器根据渲染树开始布局(Layout),确定每个元素在页面中的位置和大小。 最后,浏览器根据布局信息对渲染树进行绘制(Paint),将页面内容显示在屏幕上。 (页面渲染)
  3. 简单理解:页面内容可视化过程

1.3.2 script标签的位置问题

head标签内部

<!DOCTYPE html>
<html lang="en">
<head>
    <script>
        var myElement = document.getElementById("helloTag");
        // 输出结果为空
        console.log(myElement);
    </script>
</head>
<body>
    <div id="helloTag">
        <p>Hello World</p>
    </div>
</body>
</html>

页面解析时遇到JS,会暂停页面的解析,要在JS解析完毕并执行后才能继续解析页面,因此console.log(myElement)的结果为null。因此,把script标签放在head标签里,可能会出现问题

当JS脚本通常不会直接操作页面中的 DOM 元素(例如引入外部JS库)时,才可放在head标签

body标签内部

<!DOCTYPE html>
<html lang="en">
<head>
    
</head>
<body>
    <div id="helloTag">
        <p>Hello World</p>
    </div>
    <script>
        var myElement = document.getElementById("helloTag");
        console.log(myElement);
    </script>
</body>
</html>

将script标签放在body尾部,浏览器会先解析完DOM,再下载并执行JS脚本,此时console.log(myElement)能正常输出,但是对于那些高度依赖于js的网页,效率会很慢(因为自上而下的顺序加载)

当JS脚本需要等待 DOM 的加载完成才能执行时(例如操作DOM元素),需要放在body标签末尾,以保证能够正确操作已加载的 DOM 元素

1.3.3 async defer

async

格式如下:

<script src="my.js" async></script>

多个async脚本的加载顺序是随机的, 一旦加载完async脚本,解析渲染就会中断,执行完成后才会继续解析渲染

当JS脚本并不关心页面中的DOM元素,并且也不会产生其他脚本需要的数据,则考虑用async

defer

格式如下:

<script src="my.js" defer></script>

多个defer脚本的加载顺序从上到下, 不会阻止页面解析渲染,等到页面解析完成后再按顺序执行脚本

当JS脚本需要等待 DOM 的加载完成才能执行时(例如操作DOM元素),或者被其他脚本文件依赖,则考虑defer

图解普通script async defer

如下所示,有两个JS脚本

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="my01.js" defer></script>
    <script src="my02.js" defer></script>
</head>
<body>
</body>
</html>

如图三种颜色,代表不同含义

普通script

文档解析过程中,遇到JS脚本就会停止解析,转而下载JS脚本

my01.js和my02.js可以同时加载,但是my01.js在my02.js的前面,因此必须my01.js执行完后才能执行my02.js

defer

文档解析时,遇到defer脚本,会进行下载,但是并不会阻止文档的渲染,当页面解析&渲染完毕后按顺序执行

async

async脚本异步加载,加载完成后立即执行并中断解析渲染文档,脚本执行完成后,继续解析渲染文档。

由于是异步加载,这里只给其中一种情况

1.3.4 总结

问题1:srcipt标签放head标签还是放body标签内部

  1. 当JS脚本通常不会直接操作页面中的 DOM 元素(例如引入外部JS库)时,放在head标签内部
  2. 当JS脚本需要等待 DOM 的加载完成才能执行时(例如操作DOM元素),需要放在body标签末尾,以保证能够正确操作已加载的 DOM 元素
  3. 感觉放body比较稳定

问题2:async和derfer的应用场景

  1. 当JS脚本并不关心页面中的DOM元素,并且也不会产生其他脚本需要的数据,则考虑用async
  2. 当JS脚本需要等待 DOM 的加载完成才能执行时(例如操作DOM元素),或者被其他脚本文件依赖,则考虑defer
  3. defer会比较稳定

2 JavaScript语法

2.1 标识符

所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。标识符可以是按照下列格式规则组合起来的一或多个字符:

  1. 第一个字符必须是字母、下划线(_)或美元符号($)
  2. 其它字符可以是字母、下划线、美元符号或数字

标识符中的字母也可以包含扩展的 ASCII 或 Unicode 字母字符,并不推荐

对于多个英文单词,ECMAScript标识符采用驼峰大小写格式——除首个单词外,后面单词的首字母大写

例子

myCar,doSomethingImportant都是标识符

2.2 区分大小写

JavaScript 严格区分大小写,例如 Test 和 test 是两个不同的标识符。

为了避免输入混乱和语法错误,建议采用小写字符编写代码,以下特殊情况下可以使用大写形式:

  1. 如果标识符由多个单词组成,考虑使用骆驼命名法——除首个单词外,后面单词的首字母大写。例如:typeOf
  2. 构造函数的首字母建议大写。构造函数不同于普通函数。(后面会学到)

2.3 严格模式

ECMAScript 5 引入了严格模式(strict mode)的概念,在该模式下,ECMAScript 3 的一些不正确行为将得到处理,也对某些不安全的操作抛出错误

  1. 在整个脚本中启用严格模式方法:在顶部添加代码:“ust strict”
  2. 指定函数在严格模式下执行方法:function doSomething(){"use strict"; },即在函数内部的顶部加上代码 “ust strict”

2.4 关键字和保留字

关键字

关键字是指被JavaScript语言保留并用于特定目的的单词。这些关键字在代码中具有特定的含义,不能被用作标识符或变量名

ECMAscript的全部关键字(带*号代表第五版新增的关键字):

保留字

保留字是指目前未被使用,但在将来可能被JavaScript语言保留作为关键字使用的单词。开发者应当避免使用保留字作为标识符或变量名,以免日后这些单词被JavaScript引入为新的关键字而导致代码出现错误。

ECMA-262 第3版定义的全部保留字:

第五版进行了修改,如下:

  1. 在非严格模式下,仅规定 class、const、enums、export、extends、import、super 为保留字,其它第三版保留字可以自由使用;
  2. 在严格模式下,严格限制 implements、interface、let、package、private、protected、public、static、yield、eval(非保留字)、arguments(非保留字)的使用。

2.5 分号问题

JS会将换行符当成一个隐式的分号,因此当存在换行符时(即你换行时),绝大多数情况下可以省略分号。如下例子:

alert('Hello World~!')
alert('Hello World~!')

但是有特殊情况,例如:

s = a + b
(x + y).doSomething()

结果会被解析成如下所示:这里的b是一个函数了

s = a + b(x + y).doSomething()

还有很多其它例子,这里不一一列出了

综上所述:如果不想因为分号产生错误,最好还是加上分号

2.6 注释

单行注释

快捷键:ctrl+/

// 注释用来提高代码的可读性
alert('Hello World~!');
alert('Hello World~!');

多行注释

默认快捷键:alt+shift+a

// 注释用来提高代码的可读性
alert('Hello World~!');
alert('Hello World~!');
/* 
这是多行注释
你好
 */

如果使用vscode,修改快捷键为ctrl+shift+/,步骤如下:

1、打开vscode,点击左上角的"文件"选项。

2、选择下方选项列表中的"首选项"。

3、点击其中的"键盘快捷方式"选项。

4、进入新界面后,选择搜索alt+shift+a

5、点击右键选择更改键绑定

6、进入新界面,直接按ctrl+shift+/(不要加号),再按Enter键,修改成功

3 JavaScript 输入输出语句

方法说明归属
alert(msg)浏览器弹出警示框浏览器
console.log(msg)浏览器控制台打印输出信息浏览器
prompt(info)浏览器弹出输入框浏览器

alert(msg)

alert("hello world");

console.log(msg)

console.log("hello world");

prompt(info)

let result = prompt(message, default);
参数说明:

  • message(可选):要显示给用户的文本消息,通常是一条提示信息。
  • default(可选):用户输入框中的默认值。

返回值:

  • 如果用户点击了确定按钮并提供了输入内容,则返回该内容(字符串)。
  • 如果用户点击了取消按钮或者直接关闭了对话框,则返回 null。
let age = prompt('How old are you?', 20);

alert(`You are ${age} years old!`); 

按确定后,如图所示:

4 变量

4.1 变量的基础知识

变量的概念

变量是用于存储数据的命名存储器。它们被用来存储各种类型的数据,如数字、字符串、对象、函数等

变量的命名规则

变量的命名规则和标识符的命名规则一致

  • 注意:做项目的时候,变量名应该要有意义,简单明了

4.2 变量的定义

定义变量需要使用 var 操作符(var是一个关键字),后跟变量名(即标识符)如下所示:

var 标识符;
  • 注意:变量没有赋值,初始值为:undefined

例子如下:

var message;//定义变量
var message_1,message_2,message_3,message_4;//同时定义多个变量

4.3 变量的赋值

方式一

var message;//定义变量
message = 10;

方式二

var message = 10;//定义变量并赋值
var message_1 = 1, message_2 = 2;//定义多个变量并赋值

注意一个细节问题:可以在修改变量值的同时修改值的类型,但不推荐

var message = "hi";//定义变量并赋值
message = 10;//不推荐

4.4 其它关键字

4.4.1 let关键字

let关键字用于声明块级作用域的变量,使用let关键字声明变量,其作用域限定在最近的块(一对花括号)内

例子1

if (true) {
     let x = 10; // 块级作用域内的变量
     console.log(x); // 10
 }
 console.log(x); // x is not defined

效果为:

if (true) {
     var x = 10;
     console.log(x); // 10
 }
 console.log(x); // 10

效果为:

4.4.2 const关键字

const关键字和let关键字一样,不同点是:其值在声明后不能被修改。例子

const PI = 3.14159; // 常量

5 数据类型

5.1 typeof操作符

typeof:检测给定变量的数据类型

例子

var message = "string";
console.log(typeof message);//string
console.log(typeof(message));//string

5.2 Undefined类型

Undefined 类型只有一个值,即 undefined。在使用 var 声明变量但未对其初始化时,这时变量的值就是 undefined

var message;
console.log(message);  // undefined

使用 typeof 操作符查看未赋值的变量类型时,它们的类型是 undefined,并且未声明变量的类型也是 undefined

var message;
console.log(typeof message);  // undefined
console.log(typeof age);  // undefined

5.3 Null类型

Null 类型只有一个值,即 null。从逻辑角度看,null 值表示一个空对象指针,因此typeof操作符检测 null 值会返回 “object”

var message = null;
console.log(typeof message);  // object

5.4 Boolean类型

Boolean(布尔)类型只有两个值,即 true 或者 false ,ture 和 false 是区分大小写的。

为变量赋布尔类型值的例子

var message = true;
var message_1 = 3 > 1; //通过表达式赋值,表达式为真,则布尔值为true

转型函数Boolean()

var message = "Hello";
var message_1 = Boolean(message);// 结果为true

转换规则如下:

n/a代表不存在

如果遇到流控制语句(如 if 语句),则自动转换为布尔值(遵循上述规则),例如

var message = "Hello";
if(message){//判断为true
     console.log("true");
}

5.5 Number类型

5.5.1 介绍

Number类型用 IEEE754格式 表示整数和浮点数(也称双精度数值)

5.5.2 整数

十进制

var intNum = 10; // 整数

八进制

八进制第一位必须是0

var intNum1 = 070; // 八进制56
var intNum2 = 079; // 八进制没有9,无效八进制,视为十进制,为79
var intNum3 = 08; // 八进制没有8,无效八进制,视为十进制,为8

十六进制

十六进制的前两位必须是0x,后跟十六进制数字( 0-9 以及 A-F ),字母 A-F 可小写

var intNum1 = 0xA; // 十进制10

5.5.3 浮点数值

浮点数值必须有小数点且小数点后必须至少有一位数字

var floatNum1 = 1.1; 
var floatNum2 = 0.1; 
var floatNum3 = .1; // 结果为0.1,但不推荐这么写

保存浮点数值所需内存空间比保存整数值所需内存空间大,因此 ECMAScript 会在合适时候将浮点数值转换为整数值

var floatNum1 = 1.;  //解析为1
var floatNum2 = 10.0; //整数,解析为10

"e" 表示法是一种用于表示科学计数法的语法格式。它允许使用指数来表示非常大或非常小的数值。"e" 表示法的语法格式如下:

number e exponent

  • 其中,number 是一个数值,exponent 是一个整数指数。
  • 表示number × 10的 exponent 次方
var floatNum1 = 3.125e7; // 等于3125000 
var floatNum2 = 3e-7; // 等于0.0000003

浮点数进行算术运算时精度远远不如整数,例如 0.1 + 0.2 的结果不是 0.3,而是0.3000...,会存在一点误差,但是 0.05 + 0.25 的结果就是0.3,这是因为IEEE754使用二进制表示浮点数,0.1+0.2 存在舍入误差,而 0.05+0.25 则恰好没有舍入误差。因此无法测试特定的浮点数值(后续会在计算机组成学习IEEE754)

例子

不能这样测试特定的浮点数值

if(a + b == 0.3)

5.5.4 数值范围和三个特殊值

最大和最小值

  • 最大值: Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
  • 最小值: Number.MIN_VALUE,这个值为: 5e-324
alert(Number.MAX_VALUE); // 1.7976931348623157e+308
alert(Number.MIN_VALUE); // 5e-324

三个特殊值

  • Infinity ,代表无穷大,大于任何数值
  • -Infinity ,代表无穷小,小于任何数值
  • NaN , Not a number,代表一个非数值
alert(Infinity); // Infinity
alert(-Infinity); // -Infinity
alert(NaN); // NaN

5.5.5 IsNaN 函数

语法格式

isNaN(value)

  • 判断value是否 “不是数值”,如果不是数值或者无法转换为数字,返回true,否则返回false

5.5.6 数值转换

1 Number函数

语法格式:

Number(value)

  • value是要转换为数字的值,可以是任何数据类型。

转换规则如下:

例子

2 parseInt函数(常用)

语法格式:

parseInt(string, radix)

  • string 是要解析的字符串,radix 是一个可选参数,表示要解析的数字的基数(进制),默认为 10。
  • praselnt以 radix 进制解析数字,返回结果是十进制数字

对字符串解析规则:

  • 遇到空字符串,返回NaN
  • 遇到非空字符串,忽略前面的空格。如果第一个非空格字符不是数字字符或者正负号,返回NaN;如果是,则解析到非数字字符为止或解析完整个字符串
  • 如果字符串以 0x 开头且后面跟数字字符,则当作十六进制,如果字符串以 0 开头且后面跟数字字符,则当作八进制(对于八进制,ECMAScript 5 已不再支持,建议由第二个参数写明)
  • 简单理解:从第一个有效的非空格字符(数字字符或者正负号)开始,解析出有效的数字
var num1 = parseInt("1123blue"); // 1123
var num2 = parseInt(""); // NAN
var num3 = parseInt("22.5"); // 22
var num4 = parseInt("0xA"); // 十进制10
var num5 = parseInt("070"); // 十进制56,不推荐写法(八进制)
var num6 = parseInt('10') // 10
var num7 = parseInt('10',2) // 2
var num8 = parseInt('10',16) // 16
var num9 = parseInt('-10',8) // -8,推荐写法(八进制)

3 parseFloat函数

语法格式:

parseFloat(string)

  • string是要转换为浮点数的字符串
  • 只解析十进制数字

对字符串解析规则:

  • 简单理解:从第一个有效的非空格字符(数字字符或者正负号)开始,解析出有效的数字,对于没有小数点的有效数,解析为整数

5.6 String类型

5.6.1 String的基本使用

字符串类型是一段以 '' 或 “” 包裹起来的文本,JS推荐使用单引号。例如

var str1 = "hello";
var str2 = 'world';//推荐

JS 可以用单引号嵌套双引号 , 或者用双引号嵌套单引号 (外双内单,外单内双)

var strMsg = '我是"高帅富"程序猿'; // 可以用''包含""
var strMsg2 = "我是'高帅富'程序猿"; // 也可以用"" 包含''
// 常见错误
var badQuotes = 'What on earth?"; // 报错, 不能 单双引号搭配

5.6.2 字符串转义符

字符串中有特殊的字符字面量,称之为转义符,如下所示

例子

想在单引号包裹起来的文本这种再用单引号,则需要转移符

var str = '\'hello\''; //结果为:'hello'

5.6.3 字符串拼接

多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串

//1.1 字符串 "相加"
alert('hello' + ' ' + 'world'); // hello world
//1.2 数值字符串 "相加"
alert('100' + '100'); // 100100
//1.3 数值字符串 + 数值
alert('11' + 12); // 1112
var age = 18;
console.log('pink老师' + age); // pink老师18
console.log('pink老师' + age + '岁啦'); // pink老师18岁啦

5.6.4 转换为字符串

toString函数

numObj.toString([radix])

  • numObj表示需要转换为字符串的对象(数值,布尔值,对象和字符串值)。radix是一个可选参数,用于指定转换时使用的进制数。如果省略该参数,则默认使用十进制。
  • 返回一个副本,不改变原来的
var num = 42;
console.log(num.toString());       // 输出字符串 "42"
console.log(num.toString(2));      // 输出二进制字符串 "101010"
console.log(num.toString(16));     // 输出十六进制字符串 "2a"

var bool = true;
console.log(bool.toString());      // 输出字符串 "true"

String函数

转换规则如下:

例子:

5.7 Object 类型

Object类型(对象)是一组由键、值组成的无序集合,对象类型的键都是字符串类型的,值则可以是任意数据类型,通过 对象.键 的方式获取值

例子

const person = {
     name: 'John',
     age: 30,
     gender: 'male'
};// 对象
console.log(person.name); //John

6 操作符

6.1 算术运算符

var x = 5,y = 2;
console.log(x + y);  // 输出:7
console.log(x - y);  // 输出:3
console.log(x * y);  // 输出:10
console.log(x / y);  // 输出:2.5
console.log(x % y);  // 输出:1

6.2 递增递减运算符

运算符名称结果
++x递增运算符将x加1,返回x的值
x++递增运算符返回x的值,将x加1
--x递减运算符将x减1,返回x的值
x--递减运算符返回x的值,将x减1
var x = 1;
console.log(++x);  // 输出:2
console.log(x);    // 输出:2
x = 1;
console.log(x++);  // 输出:1
console.log(x);    // 输出:2
x = 1;
console.log(--x);  // 输出:0
console.log(x);    // 输出:0
x = 1;
console.log(x--);  // 输出:1
console.log(x);    // 输出:0

6.3 比较运算符

比较运算符( 关系运算符) 是两个数据进行比较时所使用的运算符, 比较运算后, 会返回一个布尔值( true / false)作为比较运算的结果。

var x = 1;
var y = 2;
var z = "1";
console.log(x == z);  // 输出: true
console.log(x === z); // 输出: false
console.log(x != y);  // 输出: true
console.log(x !== z); // 输出: true
console.log(x < y);   // 输出: true
console.log(x > y);   // 输出: false
console.log(x <= y);  // 输出: true
console.log(x >= y);  // 输出: false

6.4 逻辑运算符

逻辑运算符是用来进行布尔值运算的运算符, 其返回值也是布尔值。 后面开发中经常用于多个条件的判断

逻辑与

如图所示

逻辑与存在短路运算:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值,语法格式如下

表达式1 && 表达式2

  • 如果第一个表达式的值为真,则返回表达式2
  • 如果第一个表达式的值为假,则返回表达式1
console.log( 123 && 456 ); // 456
console.log( 0 && 456 ); // 0
console.log( 123 && 456&& 789 ); // 789
console.log(1 > 3 && 2 > 1); // false

逻辑或

如图所示

逻辑或也存在短路运算:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值,语法格式如下

表达式1 || 表达式2

  • 如果第一个表达式的值为真,则返回表达式1
  • 如果第一个表达式的值为假,则返回表达式2
console.log( 123 || 456 ); // 123
console.log( 0 || 456 ); // 456
console.log( 123 || 456 || 789 ); // 123
console.log(2 > 1 || 1 > 3); // true

逻辑非( !)

也叫作取反符, 用来取一个布尔值相反的值,如 true 的相反值是 false

var isOk = !true;
console.log(isOk); // false

6.5 赋值运算符

概念: 用来把数据赋值给变量的运算符。

var age = 10;
age += 5; // 相当于 age = age + 5;
age -= 5; // 相当于 age = age - 5;
age *= 10; // 相当于 age = age * 10;/= %=同理

6.7 运算符优先级

一元运算符的概念

只能操作一个值的运算符

优先级

7 流程控制

7.1 流程控制介绍

流程控制就是来控制我们的代码按照什么结构顺序来执行,流程控制主要有三种结构,分别是顺序结构、 分支结构和循环结构, 这三种结构代表三种代码执行的顺序。
 

7.2 分支流程控制

7.2.1 if语句

if 语句
语法结构

// 条件成立执行代码, 否则什么也不做
if (条件表达式) {
   // 条件成立执行的代码语句
}

执行流程

例子

var usrAge = prompt('请输入您的年龄: ');
if(usrAge >= 18){
   alert('您的年龄合法,欢迎来天际网吧享受学习的乐趣! ');
}

if else语句
语法结构

// 条件成立 执行 if 里面代码,否则执行else 里面的代码
if (条件表达式) {
  // [如果] 条件成立执行的代码
} else {
  // [否则] 执行的代码
}

执行流程

例子

if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
   alert("这个年份是闰年");
} else { // 剩下的是平年
   alert("这个年份是平年");
}

if else if 语句
语法结构

// 适合于检查多重条件。
if (条件表达式1) {
  语句1;
} else if (条件表达式2) {
  语句2;
} else if (条件表达式3) {
  语句3;
....
} else {
  // 上述条件都不成立执行此处代码
}

执行流程

例子

var score = prompt('请您输入分数:');
if (score >= 90) {
alert('宝贝,你是我的骄傲');
} else if (score >= 80) {
alert('宝贝,你已经很出色了');
} else if (score >= 70) {
alert('你要继续加油喽');
} else if (score >= 60) {
alert('孩子,你很危险');
} else {
alert('熊孩子,我不想和你说话,我只想用鞭子和你说话');

7.2.2 三元表达式

三元表达式能做一些简单的条件选择。 有三元运算符组成的式子称为三元表达式,其语法结构如下:

表达式1 ? 表达式2 : 表达式3;

  • 如果表达式1为 true ,则返回表达式2的值, 如果表达式1为 false,则返回表达式3的值
  • 简单理解: 就类似于 if else (双分支) 的简写

例子

var time = prompt('请您输入一个 0 ~ 59 之间的一个数字');
// 三元表达式 表达式 ? 表达式1 :表达式2
var result = time < 10 ? '0' + time : time; // 把返回值赋值给一个变量
alert(result);

7.2.3 switch语句

语法结构

  • witch 表达式的值会与结构中的 case 的值做比较,如果存在匹配全等(===) , 则与该 case 关联的代码块会被执行,并在遇到 break 时停止,整个 switch 语句代码,执行结束
  •  如果所有的 case 的值都和表达式的值不匹配, 则执行 default 里的代码

例子

var fruit = prompt('请您输入查询的水果:');
switch (fruit) {
case '苹果':
alert('苹果的价格是 3.5/斤');
break;
case '榴莲':
alert('榴莲的价格是 35/斤');
break;
default:
alert('没有此水果');
}

7.2.4 if与switch比较

① 一般情况下,它们两个语句可以相互替换

② switch...case 语句通常处理 case为比较确定值的情况, 而 if…else…语句更加灵活,常用于范围判断(大于、等于某个范围)

③ switch 语句进行条件判断后直接执行到程序的条件语句,效率更高。 而if…else 语句有几种条件,就得判断多少次。

④ 当分支比较少时, if… else语句的执行效率比 switch语句高。

⑤ 当分支比较多时, switch语句的执行效率比较高, 而且结构更清晰

7.3 循环流程控制

7.3.1 for循环

语法结构

for(初始化变量; 条件表达式; 操作表达式 ){
  //循环体
}
  1. 初始化变量, 初始化操作在整个 for 循环只会执行一次。
  2. 执行条件表达式,如果为true,则执行循环体语句,否则退出循环,循环结束。
  3. 执行操作表达式,此时第一轮结束。
  4. 第二轮开始,直接去执行条件表达式(不再初始化变量),如果为 true ,则去执行循环体语句,否则退出循环。
  5. 继续执行操作表达式,第二轮结束。
  6. 后续跟第二轮一致,直至条件表达式为假, 结束整个 for 循环。

例子

// 基本写法
for(var i = 1; i <= 10; i++){
console.log('媳妇我错了~');
}
// 用户输入次数
var num = prompt('请输入次数:');
for ( var i = 1 ; i <= num; i++) {
console.log('媳妇我错了~');
}

7.3.2 双重for循环

语法结构

for (外循环的初始; 外循环的条件; 外循环的操作表达式) {
   for (内循环的初始; 内循环的条件; 内循环的操作表达式) {
    需执行的代码;
 }
}
  • 外层循环执行一次,内层循环要执行全部次数
     

例子

打印n行n列星星

var row = prompt('请输入您打印几行星星:');
var col = prompt('请输入您打印几列星星:');
var str = '';
for (var i = 1; i <= row; i++) {
   for (j = 1; j <= col; j++) {
     str += '☆';
   }
   str += '\n';//打满一行星星就换行
}
console.log(str);

7.3.3 while循环

语法结构

while (条件表达式) {
  // 循环体代码
}
  • 使用 while 循环时一定要注意,它必须要有退出条件,否则会成为死循环
     

例子

var i = 1;
while (i <= 10) {
  console.log(i);
  i++;
}

7.4 do while 循环

语法结构

do {
// 循环体代码,条件表达式为 true 时重复执行循环体代码
} while(条件表达式);
  1. 先执行一次循环体代码
  2. 再执行条件表达式, 如果结果为 true, 则继续执行循环体代码, 如果为 false, 则退出循环, 继续执行后面 代码

注意: 先再执行循环体,再判断,我们会发现 do…while 循环语句至少会执行一次循环体代码(和while循环不同的地方)

例子

var i = 1;
do {
  console.log(i);
  i++;
} while (i <= 5);

7.5 continue break

continue 关键字
continue 关键字用于立即跳出本次循环, 继续下一次循环(本次循环体中 continue 之后的代码就会少执行一次)

for (var i = 1; i <= 5; i++) {
    if (i == 3) {
      console.log('这个包子有虫子,扔掉');
      continue; // 跳出本次循环, 跳出的是第3次循环
    }
    console.log('我正在吃第' + i + '个包子呢');
}

break 关键字
break 关键字用于立即跳出整个循环(循环结束)

for (var i = 1; i <= 5; i++) {
    if (i == 3) {
      break; // 直接退出整个for 循环, 跳到整个for下面的语句
    }
    console.log('我正在吃第' + i + '个包子呢');
}

8 数组(基础)

8.1 数组概念

数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式

数组元素的类型

数组中可以存放任意类型的数据,例如字符串,数字,布尔值等。
 

var arrStus = ['小白',12,true,28.9];


8.2 创建数组

new 创建数组

var 数组名 = new Array() ;
var arr = new Array(); // 创建一个新的空数组

学完对象后会细说

数组字面量创建数组(常用)

//1. 使用数组字面量方式创建空的数组
var 数组名 = [];
//2. 使用数组字面量方式创建带初始值的数组
var 数组名 = ['小白','小黑','大黄','瑞奇'];

8.3 获取数组元素

索引 (下标) : 用来访问数组元素的序号(数组下标从 0 开始) 。

可以通过“数组名[索引]” 的形式来获取数组中的元素
 

// 定义数组
var arrStus = [1,2,3];
// 获取数组中的第2个元素
alert(arrStus[1]);

8.4 遍历数组和数组长度

数组的长度
使用“数组名.length”可以访问数组元素的数量(数组长度)

var arrStus = [1,2,3];
alert(arrStus.length); // 3

遍历数组

遍历: 就是把数组中的每个元素从头到尾都访问一次

var arr = ['red','green', 'blue'];
for(var i = 0; i < arr.length; i++){
    console.log(arrStus[i]);
}

8.5 数组新增元素​​​​​​​​​

修改数组索引新增数组元素(常用)

var arr = ['red', 'green', 'blue', 'pink'];
arr[4] = 'hotpink';
console.log(arr)

​​​​​​​修改 length 长度新增数组元素

var arr = ['red', 'green', 'blue', 'pink'];
arr.length = 7;
console.log(arr);
console.log(arr[4]);
console.log(arr[5]);
console.log(arr[6]);

其中索引号是 4, 5, 6 的空间没有给值,就是声明变量未给值, 默认值就是 undefined。
 

 9 函数(基础)

9.1 函数概念

函数: 封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。

9.2 声明函数和调用函数

声明函数

// 声明函数
function 函数名() {
 //函数体代码
}

例子

function sayHello(name){
    console.log("Hello " + name);
}

调用函数

// 调用函数
函数名(); // 通过调用函数名来执行函数体代码
  • 注意: 声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码。
     
function sayHello(name){
    console.log("Hello " + name);
}

sayHello("John");

9.3 函数的参数

9.3.1 形参和实参

  • 在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参
  • 在调用该函数时,同样也需要传递相应的参数,这些参数被称为实参
// 带参数的函数声明
function 函数名(形参1, 形参2 , 形参3...) { // 可以定义任意多的参数,用逗号分隔
// 函数体
}
// 带参数的函数调用
函数名(实参1, 实参2, 实参3...);

例子

function getSum(num1, num2) {
 //num1,num2是形参
 console.log(num1 + num2);
}
//1,3;6,5是实参
getSum(1, 3); // 4
getSum(6, 5); // 11

9.3.2 形参和实参个数不匹配问题

例子

function sum(num1, num2) {
   console.log(num1 + num2);
}
sum(100, 200); // 形参和实参个数相等, 输出正确结果
sum(100, 400, 500, 700); // 实参个数多于形参,只取到形参的个数
sum(200); // 实参个数少于形参,多的形参定义为undefined,结果为NaN

9.4 函数返回值

语法格式

// 声明函数
function 函数名() {
  ...
  return 需要返回的值;
}
// 调用函数
函数名(); // 此时调用函数就可以得到函数体内return 后面的值
  • 注意:return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准
  • 如果有return 则返回 return 后面的值
  • 如果没有return 则返回 undefined
     

例子1

function getArray() {
  // 创建一个包含一些元素的数组
  var array = [1, 2, 3, 4, 5];

  // 返回数组
  return array;
}

// 调用函数并接收返回值
var result = getArray();

例子2

function add(num1, num2){
  //函数体
  return num1, num2;
}
var resNum = add(21,6); // 调用函数, 传入两个实参,并通过 resNum 接收函数返回值
alert(resNum); // 6

9.5 arguments的使用

当我们不确定有多少个参数传递的时候, 可以用 arguments 来获取。arguments 中存储了传递的所有实参
arguments展示形式是一个伪数组,因此可以进行遍历。 伪数组具有以下特点:

  • 具有 length 属性
  • 按索引方式储存数据
  • 不具有数组的 push , pop 等方法

例子

function maxValue() {
    var max = arguments[0];
    for (var i = 0; i < arguments.length; i++) {
        if (max < arguments[i]) {
          max = arguments[i];
        }
    }
    return max;
}
console.log(maxValue(2, 4, 5, 9));
console.log(maxValue(12, 4, 9));

9.6 匿名函数

// 这是函数表达式写法, 匿名函数后面跟分号结束
var fn = function(){...};
// 调用的方式, 函数调用必须写到函数体下面
fn();
  • 因为函数没有名字, 所以也被称为匿名函数
  • 这个fn 里面存储的是一个函数
  • 函数表达式方式原理跟声明变量方式是一致的
  • 函数调用的代码必须写到函数体后面

10 作用域

10.1 作用于概念

一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域
JavaScript(ES6前) 中的作用域有两种:

  • 全局作用域:作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
  • 局部作用域(函数作用域):作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系, 所以也称为函数作用域。

JS 没有块级作用域
块作用域由 { } 包括,但JS没有块级作用域(在ES6之前)

if(true){
  var num = 123;
  console.log(123); //123
}
console.log(123); //123

10.2 变量作用域

全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。

  • 全局变量在代码的任何位置都可以使用
  • 在全局作用域下 var 声明的变量 是全局变量
  • 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)

在任何一个地方都可以使用, 只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量

在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)

  • 局部变量只能在该函数内部使用
  • 在函数内部 var 声明的变量是局部变量
  • 函数的形参实际上就是局部变量

只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后, 就会被销毁,因此更节省内存空间

10.3 作用域链

  • 只要是代码,就至少有一个作用域
  • 写在函数内部的局部作用域
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问, 就称作作用域链

例子

function f1() {//外部函数
    var num = 123;
    function f2() {//内部函数
      console.log( num );
    }
    f2();
}
var num = 456;
f1();

最外层的0级链:f1 和 num=456

1级链:num=123 和 f2

2级链:console.log(num);

console.log(num)从本级依次往上找,二级链没有,因此到一级链,找到 num=123 ,输出

11 预解析

11.1 基本概念

JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。 JavaScript 解析器在运行 JavaScript 代码的时候分为两步: 预解析和代码执行。

  • 预解析: 在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。
  • 代码执行: 从上到下执行JS语句。

预解析只会发生在通过 var 定义的变量和 function 上。

变量提升

变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升

例子1:结果为undefined

console.log(message);
var message = "hi";//定义变量并赋值

例子2:结果为hi

var message = "hi";//定义变量并赋值
console.log(message);

函数提升

函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。

fn();// 输出打印
function fn() {
    console.log('打印');
}

注意匿名函数的坑

fn();//此时fn还是undefined,因为fn是变量
var fn = function() {
  console.log('想不到吧');
}

11.2 分析方法(用来做题)

例题

num结果是多少

var num = 10;
fun();
function fun() {
  console.log(num);
  var num = 20;
}

第一步:写出等价代码

把带有 var 和 function 声明的变量在内存中进行提前声明或者定义(当前作用域)

//把带有 var 和 function 声明的变量在内存中进行提前声明或者定义(当前作用域)
var num
function fun() {
     var num
     console.log(num);
     num = 20;
}
num = 10;
fun();

第二步:分析作用域链

根据作用域链原则,fun()里的 var num 和 console.log(num) 在同一链内,因此输出结果为:undefined

12 对象(基础)

12.1 对象的概念

在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。

对象是由属性方法组成的。

  • 属性:事物的特征, 在对象中用属性来表示(常用名词)
  • 方法:事物的行为, 在对象中用方法来表示(常用动词)

12.2 创建对象的三种方式

字面量创建对象

对象字面量: 就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法。{ } 里面采取键值对的形式表示

  • 键:相当于属性名
  • 值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
var star = {
  name : 'pink',
  age : 18,
  sex : '男',
  sayHi : function(){
    alert('大家好啊~');
  }
};

new Object创建对象

使用的格式: 对象.属性 = 值;(属性自定义)

var andy = new Obect();
andy.name = 'pink';
andy.age = 18;
andy.sex = '男';
andy.sayHi = function(){
  alert('大家好啊~');
}

构造函数

构造函数 : 主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。
在 js 中,使用构造函数要时要注意以下问题:

  1. 构造函数用于创建某一类对象,其首字母要大写
  2. 构造函数要和 new 一起使用才有意义
  3. 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
  4. 当我们创建对象的时候, 必须用 new 来调用构造函数
function Person(name, age, sex) {
   this.name = name;
   this.age = age;
   this.sex = sex;
   this.sayHi = function() {
     alert('我的名字叫: ' + this.name + ', 年龄: ' + this.age + ', 性别: ' + this.sex);
   }
}
var bigbai = new Person('大白', 100, '男');
var smallbai = new Person('小白', 21, '男');
console.log(bigbai.name);
console.log(smallbai.name);

12.3 访问修改删除对象属性

访问对象属性

要访问或获取属性的值,可使用 对象名.属性名 或者 对象名["属性名"] 的形式,例子如下

  • 注意:如果属性名中包含空格或者特殊字符
var person = {
  name: "Alice",
  age: 25,
  "favorite color": "blue"//不能使用对象名.属性名
};

console.log(person.name);  // 输出 "Alice"
console.log(person["age"]);  // 输出 25
console.log(person["favorite color"]);  // 输出 "blue"

修改对象属性

使用 对象名.属性名 或者 对象名["属性名"] 的形式修改属性值

var person = {
  name: "Alice",
  age: 25,
};

person.name = "Bob";
console.log(person.name);  // 输出 "Bob"

person["age"] = 30;
console.log(person["age"]);  // 输出 30

删除对象属性

使用 对象名.属性名 或者 对象名["属性名"] 的形式删除属性值

var person = {
  name: "Alice",
  age: 25,
};

// 使用对象名.属性名 的方式删除属性
delete person.age;
console.log(person.age);  // 输出 undefined

// 使用对象名["属性名"] 的方式删除属性
delete person["name"];
console.log(person.name);  // 输出 undefined

12.4 遍历对象

for (var k in obj) {
  console.log(k); // 这里的 k 是属性名
  console.log(obj[k]); // 这里的 obj[k] 是属性值
}
  • 46
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值