S03-01 JS-基础-基础语法
[TOC]
概述
前端的三大核心
前端开发最主要需要掌握的是三个知识点:HTML、CSS、JavaScript
计算机语言
前面我们已经学习了HTML和CSS很多相关的知识:
- 在之前我们提到过, HTML是一种标记语言, CSS也是一种样式语言;
他们本身都是属于计算机语言, 因为都在和计算机沟通交流;
- 在生活中两个人想要沟通, 必然是通过某一种语言(中文/英语/粤语/东北话)
- 计算机语言就是我们人和计算机进行交流要学习的语言;
网页的三大组成部分的另外一个核心就是JavaScript:JavaScript必然也是一种计算机语言;
编程语言
事实上, JavaScript我们可以对其有更加精准的说法:一种编程语言.
我们先搞清楚计算机语言和编程语言的关系和区别:
- 计算机语言:计算机语言(computer language)指用于人与计算机之间通讯的语言,是人与计算机之间传递信息的介质。但 是其概念比通用的编程语言要更广泛。例如,HTML是标记语言,也是计算机语言,但并不是编程语言。
- 编程语言:编程语言(英语:programming language),是用来定义计算机程序的形式语言。它是一种被标准化的交流技巧, 用来向计算机发出指令,一种能够让程序员准确地定义计算机所需要使用数据的计算机语言,并精确地定义在不同情况下所 应当采取的行动。
很抽象, 我们来说明一下编程语言的特点:
- 数据和数据结构
- 指令及流程控制
- 引用机制和重用机制
- 设计哲学
这样的区分是否有意义呢?我们这里不讨论,我这里只把最专业的定义来告诉大家。
常见的编程语言
编程语言的发展历史 – 机器语言
阶段一: 机器语言
- 计算机的存储单元只有0和1两种状态,因此一串代码要让计算机“读懂”,这串代码只能由数字0和1组成。
- 像这种由数字0和1按照一定的规律组成的代码就叫机器码,也叫二进制编码。
- 一定长度的机器码组成了机器指令,用这些机器指令所编写的程序就称为机器语言。
优点:
- 代码能被计算机直接识别,不需要经过编译解析;
- 直接对硬件产生作用,程序的执行效率非常高;
缺点:
- 程序全是些0和1的指令代码,可读性差,还容易出错;
- 不易编写(目前没有人这样开发);
编程语言的发展历史 – 汇编语言
阶段二: 汇编语言
- 为了解决机器语言的缺陷,人们发明了另外一种语言——汇编语言。
- 这种语言用符号来代替冗长的、难以记忆的0、1代码。(mov/push指令,经过汇编器,汇编代码再进一步转成0101)
优点:
- 像机器语言一样,可以直接访问、控制计算机的各种硬件设备;
- 占用内存少,执行速度快;
缺点:
- 第一,不同的机器有不同的汇编语言语法和编译器,代码缺乏可移植性 ✓ 也就是说,一个程序只能在一种机器上运行,换到其他机器上可能就不能运行;
- 第二,符号非常多、难记 ✓ 即使是完成简单的功能也需要大量的汇编语言代码,很容易产生BUG,难于调试;
应用场景
- 操作系统内核、驱动程序、单片机程序;
编程语言的发展历史 – 高级语言
阶段三: 高级语言
- 最好的编程语言应该是什么? 自然语言;
- 而高级语言, 就是接近自然语言, 更符合人类的思维方式
- 跟和人交流的方式很相似, 但是大多数编程语言都是国外发明的, 因为都是接近于英文的交流方式
优点:
- 简单、易用、易于理解,语法和结构类似于普通英文;
- 远离对硬件的直接操作,使得一般人经过学习之后都可以编程,而不用熟悉硬件知识;
- 一个程序还可以在不同的机器上运行,具有可移植性;
缺点:
- 程序不能直接被计算机识别,需要经编译器翻译成二进制指令后,才能运行到计算机上;
- 种类繁多:JavaScript 、 C语言、C++、C#、Java、Objective-C 、Python等;
机器语言和高级语言
在前端,我们需要学好的只有一门高级语言:JavaScript。
认识JavaScript
维基百科对JavaScript的定义:
- JavaScript(通常缩写为JS)是一种高级的、解释型的编程语言;
- JavaScript是一门基于原型、头等函数的语言,是一门多范式的语言,它支持面向对象程序设计,指令式编程,以及函数式编 程;
从上面的定义中, 我们会发现很多关键词:
- 解释型语言? 原型? 头等函数? 多范式? 面向对象程序设计? 指令式编程? 函数式编程?
- 这些改变往往会让人不知所云,需要我们完全掌握JavaScript再来回头看,每一个词语描述的都非常准确;
现在只需要知道,通俗的说法:
- JavaScript是一门高级编程语言, 是前端开发的重要组成部分!
HTML和CSS也是前端开发的重要组成部分, 而JavaScript是前端开发的灵魂;
JavaScript的历史(一)
1994年,网景公司(Netscape)发布了Navigator浏览器0.9版。
- 这是历史上第一个比较成熟的网络浏览器,轰动一时。
- 但是,这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。
- 网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。
JavaScript的历史(二)
网景公司当时想要选择一种语言来嵌入到浏览器中:
- 采用现有的语言,比如Perl、Python、Tcl、Scheme等等, 允许它们直接嵌入网页;
- 1995年网景公司招募了程序员Brendan Eich,希望将Scheme语言作为网页脚本语言的可能性;
就在这时,发生了另外一件大事:1995年Sun公司将Oak语言改名为Java,正式向市场推出;
- Java推出之后立马在市场上引起了轰动,Java当初有一个口号:“write once run anywhere”;
- 网景公司动了心,决定与Sun公司结成联盟,希望将Java嵌入到网页中来运行;
- Brendan Eich本人非常热衷于Scheme,但是管理层那个时候有点倾向于Java,希望可以简化Java来适应网页脚本的需求;
JavaScript的历史(三)
但是Brendan Eich对此并不感兴趣,他用10天时间设计出来了JavaScript;
- 最初这门语言的名字是Mocha(摩卡);
- 在Navigator2.0 beta版本更名为LiveScript;
- 在Navigator2.0 beta 3版本正式重命名为JavaScript,当时是为了给这门语言搭上Java这个热词;
当然10天设计出来语言足够说明Brendan Eich是天才,但是这门语言当时更像是一个多种语言的大杂烩;
- 借鉴C语言的基本语法;
- 借鉴Java语言的数据类型和内存管理;
- 借鉴Scheme语言,将函数提升到"第一等公民"(first class)的地位;
- 借鉴Self语言,使用基于原型(prototype)的继承机制。
Brendan Eich曾经这样描述过JavaScript:
- 与其说我爱Javascript,不如说我恨它,它是C语言和Self语言一夜情的产物;
- 十八世纪英国文学家约翰逊博士说得好:'它的优秀之处并非原创,它的原创之处并不优秀。’
- (the part that is good is not original, and the part that is original is not good.)
JavaScript的历史(四)
微软公司于1995年首次推出Internet Explorer,从而引发了与Netscape的浏览器大战。
- 微软对Netscape Navigator解释器进行了逆向工程,创建了JScript,以与处于市场领导地位的网景产品同台竞争;
- 这个时候对于开发者来说是一场噩耗,因为需要针对不同的浏览器进行不同的适配;
1996年11月,网景正式向ECMA(欧洲计算机制造商协会)提交语言标准。
- 1997年6月,ECMA以JavaScript语言为基础制定了ECMAScript标准规范ECMA-262;
- ECMA-262是一份标准,定义了ECMAScript;
- JavaScript成为了ECMAScript最著名的实现之一;
- 除此之外,ActionScript和JScript也都是ECMAScript规范的实现语言;
所以说,ECMAScript是一种规范,而JavaScript是这种规范的一种实现。
JavaScript的组成
ECMAScript是JavaScript的标准,描述了该语言的语法和基本对象。
- JavaScript是ECMAScript的语言层面的实现;
- 因为除了语言规范之外,JavaScript还需要对页面和浏览器进行各种操作;
- 除了基本实现之外,还包括DOM操作和BOM操作;
目前我们会针对性的学习ECMAScript,也就是语言层面的内容,特别是ES5之前的语法。
JavaScript由谁来运行
我们经常会说:不同的浏览器有不同的内核组成
- Gecko:早期被Netscape和Mozilla Firefox浏览器浏览器使用;
- Trident:微软开发,被IE4~IE11浏览器使用,但是Edge浏览器已经转向Blink;
- Webkit:苹果基于KHTML开发、开源的,用于Safari,Google Chrome之前也在使用;
- Blink:是Webkit的一个分支,Google开发,目前应用于Google Chrome、Edge、Opera等;
- 等等...
事实上,我们经常说的浏览器内核指的是浏览器的排版引擎:
- 排版引擎(layout engine),也称为浏览器引擎(browser engine)、页面渲染引擎(rendering engine)或样版引擎。
那么,JavaScript代码由谁来执行呢?
- JavaScript引擎
认识JavaScript引擎
为什么需要JavaScript引擎呢?
- 我们前面说过,高级的编程语言都是需要转成最终的机器指令来执行的;
- 事实上我们编写的JavaScript无论你交给浏览器或者Node执行,最后都是需要被CPU执行的;
- 但是CPU只认识自己的指令集,实际上是机器语言,才能被CPU所执行;
- 所以我们需要JavaScript引擎帮助我们将JavaScript代码翻译成CPU指令来执行;
比较常见的JavaScript引擎有哪些呢?
- SpiderMonkey:第一款JavaScript引擎,由Brendan Eich开发(也就是JavaScript作者);
- Chakra:微软开发,用于IT浏览器;
- JavaScriptCore:WebKit中的JavaScript引擎,Apple公司开发;
- V8:Google开发的强大JavaScript引擎,也帮助Chrome从众多浏览器中脱颖而出;
- 等等…
浏览器内核和JS引擎的关系
这里我们先以WebKit为例,WebKit事实上由两部分组成的:
- WebCore:负责HTML解析、布局、渲染等等相关的工作;
- JavaScriptCore:解析、执行JavaScript代码;
小程序中也是这样的划分:
- 在小程序中编写的JavaScript代码就是被JSCore执行的;
著名的Atwood定律
Stack Overflow的创立者之一的 Jeff Atwood 在2007年提出了著名的 Atwood定律:
- Any application that can be written in JavaScript, will eventually be written in JavaScript.
- 任何可以使用JavaScript来实现的应用都最终都会使用JavaScript实现。
JavaScript应用越来越广泛
编写方式
编写方式:
位置一:HTML代码行内(不推荐)
位置二:script标签中
位置三:外部的script文件
需要通过script元素的src属性来引入JavaScript文件
注意事项:
注意一: script元素不能写成单标签
- 在外联式引用js文件时,script标签中不可以写JavaScript代码,并且script标签不能写成单标签;
- 即不能写成<script src=“index.js”/>;
注意二: 省略type属性
- 在以前的代码中,<script>标签中会使用 type=“text/javascript”;
- 现在可不写这个代码了,因为JavaScript 是所有现代浏览器以及 HTML5 中的默认脚本语言;
注意三: 加载顺序
- 作为HTML文档内容的一部分,JavaScript默认遵循HTML文档的加载顺序,即自上而下的加载顺序;
- 推荐将JavaScript代码和编写位置放在body子元素的最后一行;
注意四: JavaScript代码严格区分大小写
- HTML元素和CSS属性不区分大小写,但是在JavaScript中严格区分大小写;
后续补充:script元素还有defer、async属性,我们后续再详细讲解。
<noscript>
如果运行的浏览器不支持JavaScript, 那么我们如何给用户更好的提示呢?
- 针对早期浏览器不支持 JavaScript 的问题,需要一个页面优雅降级的处理方案;
- 最终,<noscript> 元素出现,被用于给不支持 JavaScript 的浏览器提供替代内容;
下面的情况下, 浏览器将显示包含在<noscript>中的内容:
- 浏览器不支持脚本;
- 浏览器对脚本的支持被关闭。
交互方式
JavaScript有如下和用户交互的手段:
- 最常见的是通过console.log, 目前大家掌握这个即可;
Chrome调试
Console
在前面我们利用Chrome的调试工具来调试了HTML、CSS,它也可以帮助我们来调试JavaScript。
当我们在JavaScript中通过console函数显示一些内容时,也可以使用Chrome浏览器来查看:
另外补充几点:
- 1.如果在代码中出现了错误,那么可以在console中显示错误;
- 2.console中有个 > 标志,它表示控制台的命令行 ✓ 在命令行中我们可以直接编写JavaScript代码,按下enter会执行代码; ✓ 如果希望编写多行代码,可以按下shift+enter来进行换行编写;
- 3.在后续我们还会学习如何通过debug方式来调试、查看代码的执行流程;
语句和分号
语句是向浏览器发出的指令,通常表达一个操作或者行为(Action)。
- 语句英文是Statements;
- 比如我们前面编写的每一行代码都是一个语句,用于告知浏览器一条执行的命令;
通常每条语句的后面我们会添加一个分号,表示语句的结束:
- 分号的英文是semicolon
- 当存在换行符(line break)时,在大多数情况下可以省略分号;
- JavaScript 将换行符理解成“隐式”的分号;
- 这也被称之为自动插入分号(an automatic semicolon);
推荐:
- 前期在对JavaScript语法不熟悉的情况推荐添加分号;
- 后期对JavaScript语法熟练的情况下,任意!
注释
在HTML、CSS中我们都添加过注释,JavaScript也可以添加注释。
JavaScript的注释主要分为三种:
- 单行注释
- 多行注释
- 文档注释(VSCode中需要在单独的JavaScript文件中编写才有效)
详情见代码
注意:JavaScript也不支持注释的嵌套
VSCode插件
推荐一个VSCode的插件:(个人经常使用的)
- ES7+ React/Redux/React-Native snippets
- 这个插件是在react开发中会使用到的,但是我经常用到它里面的打印语句;
另外再推荐一个插件:
Bracket Pair Colorizer 2,但是该插件已经不再推荐使用了;
因为VSCode已经内置了该功能,我们可以直接通过VSCode的配置来达到插件的效果;
如何配置呢? VSCode插件和配置
json"editor.bracketPairColorization.enabled": true, "editor.guides.bracketPairs":"active"
变量
程序中变量的数据
在我们平时开发中,使用最多的并不是固定的数据, 而是会变换的数据:
- 比如购物车商品的数量、价格的计算等等;
- 比如一首歌曲播放的时间、进度条、歌词的展示等等;
- 比如微信聊天中消息条数、时间、语音的长度、头像、名称等等;
- 比如游戏中技能的冷却时间、血量、蓝量、buff时间、金币的数量等等;
变化数据的记录 – 变量
如果我们希望记录某一个之后会变量的数据,在JavaScript中我们可以定义一个 变量:
- 一个变量,就是一个用于存放数值的容器;
- 这个数值可能是一个用于计算的数字,或者是一个句子中的字符串,或者其他任意的数据;
- 变量的独特之处在于它存放的数值是可以改变的;
我们可以把变量想象成一个盒子,盒子里面装着我们的数据,我们需要给盒子进行一个特性的名称。
- 例如,变量 message 可以被想象成一个标有 “message” 的盒子,盒子里面的值为 “Hello!”;
- 并且,这个盒子的值,我们想改变多少次,就可以改变多少次;
变量的命名格式
在JavaScript中如何命名一个变量呢?包含两部分:
- 变量的声明:在JavaScript中声明一个变量使用var关键字(variable单词的缩写)(后续学习ES6还有let、const声明方式)
- 变量的赋值:使用 = 给变量进行赋值;
这个过程也可以分开操作:
同时声明多个变量:
变量的命名规范
变量命名规则:必须遵守
- 1.第一个字符必须是一个字母、下划线( _ )或一个美元符号( $ )
- 2.其他字符可以是字母、下划线、美元符号或数字
- 3.不能使用关键字和保留字命名: ✓ 什么是关键字,什么是保留字? ✓ https://developer.mozilla.org/zh-CN/docs/web/javascript/reference/lexical_grammar
- 4.变量严格区分大小写
变量命名规范:建议遵守
- 多个单词使用驼峰标识;
- 赋值 = 两边都加上一个空格;
- 一条语句结束后加上分号; 也有很多人的习惯是不加;
- 变量应该做到见名知意;
变量的练习
练习一:定义一些变量,保存自己的个人信息:
- 比如姓名、年龄、身高、体重、爱好等等
练习二:定义一个变量name,赋值成coderwhy。定义一个变量admin,将name赋值给admin
练习三:定义变量,保存两个数字,并且对两个变量的数字进行交换
- 方式一:使用临时变量
- 方式二:不使用临时变量(了解即可)
练习四:让用户在浏览器中输入一个值,在JavaScript程序中使用变量接收
作业:你平时在使用一些应用程序时,哪些内容可以定义成变量?
- 比如玩游戏、听歌、购物的应用程序中;
变量的使用注意
注意一:如果一个变量未声明(declaration)就直接使用,那么会报错;
注意二:如果一个变量有声明,但是没有赋值,那么默认值是undefined
注意三:如果没有使用var声明变量也可以,但是不推荐(事实上会被添加到window对象上)
数据类型
JavaScript的数据类型
JavaScript 中的值都具有特定的类型。
- 例如,字符串或数字。
- 我们可以将值赋值给一个变量,那么这个变量就具备了特定的类型;
- 一个变量可以在前一刻是个字符串,下一刻就存储一个数字;
- 允许这种操作的编程语言,例如 JavaScript,被称为“动态类型”(dynamically typed)的编程语言;
在 JavaScript 中有 8 种基本的数据类型(7 种原始类型和 1 种复杂类型)
- Number
- String
- Boolean
- Undefined
- Null
- Object
- BigInt(后续了解)
- Symbol(后续了解)
typeof
因为 ECMAScript 的类型系统是松散的,所以需要一种手段来确定任意变量的数据类型。
- typeof 操作符就是为此而生的。
对一个值使用 typeof 操作符会返回下列字符串之一:
- "undefined"表示值未定义;
- "boolean"表示值为布尔值;
- "string"表示值为字符串;
- "number"表示值为数值;
- "object"表示值为对象(而不是函数)或 null;
- "function"表示值为函数;
- “symbol”表示值为符号;
typeof()的用法:
- 你可能还会遇到另一种语法:typeof(x),它与 typeof x 相同;
- typeof是一个操作符,并非是一个函数,()只是将后续的内容当做一个整体而已;
Number
number 类型代表整数和浮点数。
数字number可以有很多操作,比如,乘法 *、除法 /、加法 +、减法 - 等等。
- 常见的运算符后续会专门讲解
除了常规的数字,还包括所谓的“特殊数值(“special numeric values”)”也属于Number类型(了解)
- Infinity:代表数学概念中的 无穷大 ∞,也可以表示-Infinity; ✓ 比如 1/0 得到的就是无穷大;
- NaN:NaN 代表一个计算错误,它是一个错误的操作所得到的结果; ✓ 比如 字符串和一个数字相乘;
在之前我们学习过进制的概念,数字类型也有其他的进制表示方法:
- 十进制(掌握)、十六进制、二进制、八进制(了解)
数字表示的范围:
- 最小正数值:Number.MIN_VALUE,这个值为: 5e-324,小于这个的数字会被转化为0
- 最大正数值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
isNaN
- 用于判断是否不是一个数字。不是数字返回true,是数字返回false。
后续我们会对Number类型进行更加详细的学习;
String
在开发中我们经常会有一些文本需要表示,这个时候我们会使用字符串String:
- 比如人的姓名:coderwhy。地址:广州市。简介:认真是一种可怕的力量;
JavaScript 中的字符串必须被括在引号里,有三种包含字符串的方式。
- 双引号:"Hello"
- 单引号:'Hello’
- 反引号:
Hello
(ES6之后学习)
前后的引号类型必须一致:
- 如果在字符串里面本身包括单引号,可以使用双引号;
- 如果在字符串里面本身包括双引号,可以使用单引号;
字符串中的转义字符
除了普通的可打印字符以外,一些有特殊功能的字符可以通过转义字符的形式放入字符串中:
转义字符串开发中只有特殊场景才会用到,暂时掌握 \’\” \t \n四个的用法即可。
字符串的属性和方法
字符串还有很多细节和操作方法,在后续学习了面向对象后,我们再详细学习;
这里我们先掌握几个基本的字符串使用操作:
操作一:字符串拼接,通过+运算符(后续还会详细讲解)
操作二:获取字符串长度
Boolean
Boolean(布尔)类型用于表示真假:
- 比如是否毕业. 是否有身份证. 是否购买车票. 是否成年人;
- 比如开发中,我们会判断一个账号是否登录、是否是管理员、是否具备某个权限、是否拥有某个英雄、皮肤等;
布尔(英语:Boolean)是计算机科学中的逻辑数据类型,以发明布尔代数的数学家乔治·布尔为名。
Boolean 类型仅包含两个值:true 和 false。
在后续 逻辑运算符 中我们还会详细学习和使用Boolean类型;
Undefined
Undefined 类型只有一个值,就是特殊值 undefined。
- 如果我们声明一个变量,但是没有对其进行初始化时,它默认就是undefined;
下面的代码是一样的
这里有两个注意事项:
- 注意一:最好在变量定义的时候进行初始化,而不只是声明一个变量;
- 注意二:不要显示的将一个变量赋值为undefined ✓ 如果变量刚开始什么都没有,我们可以初始化为0、空字符串、null等值;
Object类型
Object 类型是一个特殊的类型,我们通常把它称为引用类型或者复杂类型;
- 其他的数据类型我们通常称之为 “原始类型”,因为它们的值质保函一个单独的内容(字符串、数字或者其他);
- Object往往可以表示一组数据,是其他数据的一个集合;
- 在JavaScript中我们可以使用 花括号{} 的方式来表示一个对象;
Object是对象的意思,后续我们会专门讲解面向对象的概念等;
Object相关的内容我们会在后续详细讲解。
Null
Null 类型同样只有一个值,即特殊值 null。
- null类型通常用来表示一个对象为空,所以通常我们在给一个对象进行初始化时,会赋值为null;
null和undefined的关系:
- undefined通常只有在一个变量声明但是未初始化时,它的默认值是undefined才会用到;
- 并且我们不推荐直接给一个变量赋值为undefined,所以很少主动来使用;
- null值非常常用,当一个变量准备保存一个对象,但是这个对象不确定时,我们可以先赋值为null;
总结
JavaScript 中有八种基本的数据类型(前七种为基本数据类型,也称为原始类型,而 object 为复杂数据类型,也称为引用类 型)。
- number 用于任何类型的数字:整数或浮点数。
- string 用于字符串:一个字符串可以包含 0 个或多个字符,所以没有单独的单字符类型。
- boolean 用于 true 和 false。
- undefined 用于未定义的值 —— 只有一个 undefined 值的独立类型。
- object 用于更复杂的数据结构。
- null 用于未知的值 —— 只有一个 null 值的独立类型。
后续学习的类型:
- symbol 用于唯一的标识符。
- bigint 用于任意长度的整数。
数据类型转换
在开发中,我们可能会在不同的数据类型之间进行某些操作
- 比如把一个String类型的数字和另外一个Number类型的数字进行运算;
- 比如把一个String类型的文本和另外一个Number类型的数字进行相加;
- 比如把一个String类型或者Number类型的内容,当做一个Boolean类型来进行判断;
- 等等
也就是在开发中,我们会经常需要对数据类型进行转换:
- 大多数情况下,运算符和函数会自动将赋予它们的值转换为正确的类型,这是一种隐式转换;
- 我们也可以,通过显示的方式来对数据类型进行转换;
接下来我们来看一下数据类型之间的转换:
- String、Number、Boolean类型;
字符串String的转换
其他类型经常需要转换成字符串类型,比如和字符串拼接在一起或者使用字符串中的方法。
转换方式一:隐式转换
- 一个字符串和另一个字符串进行+操作; ✓ 如果+运算符左右两边有一个是字符串,那么另一边会自动转换成字符串类型进行拼接;
- 某些函数的执行也会自动将参数转为字符串类型; ✓ 比如console.log函数;
转换方式二:显式转换
- 调用String()函数;
- 调用toString()方法(后续面向对象再学习);
方法和函数的区别,我们后续在讲解面向对象时会讲到;
数字类型Number的转换
其他类型也可能会转成数字类型。
转换方式一:隐式转换
- 在算数运算中,通常会将其他类型转换成数字类型来进行运算; ✓ 比如 "6" / "2"; ✓ 但是如果是+运算,并且其中一边有字符串,那么还是按照字符串来连接的;
转换方式二:显式转换
- 我们也可以使用Number()函数来进行显式的转换;
其他类型转换数字的规则:
布尔类型Boolean的转换
布尔(boolean)类型转换是最简单的。
它发生在逻辑运算中,但是也可以通过调用 Boolean(value) 显式地进行转换。
转换规则如下:
- 直观上为“空”的值(如 0、空字符串、null、undefined 和 NaN)将变为 false。
- 其他值变成 true。
注意:包含 0 的字符串 "0" 是 true
- 一些编程语言(比如 PHP)视 "0" 为 false。但在 JavaScript 中,非空的字符串总是 true。
运算符
认识运算符
在小学的时候我们就学习了各种运算符,比如加号 +、乘号 *、减号 - 、除号/
几乎所有的编程语言都有各种各样的运算符(也被称之为操作符,operators)
- 初次接触这些运算符, 你会感觉种类繁多, 难以记忆.
- 但是并不需要特别担心, 因为很多的运算符我们在以后的开发中, 每天都会使用;
- 多练习, 不需要刻意去记忆;
- 而且常见的高级语言运算符都是相似的,学了JavaScript运算符很容易掌握C/C++/OC/Python等语言的运算符;
计算机最基本的操作就是执行运算,执行运算时就需要使用运算符来操作:
- 比如 console.log(20 + 30);
+
号就是一个运算符. - 比如 console.log(20 * 30);
*
号也是一个运算符.
JavaScript按照使用场景的不同将运算符分成了很多种类型:
- 算术运算符/赋值运算符/关系(比较)运算符/逻辑运算符
认识运算元
在正式开始运算之前,我们先学习一下常见的术语:
- 运算元 —— 运算符应用的对象。 ✓ 比如说乘法运算 5 * 2,有两个运算元; ✓ 左运算元 5 和右运算元 2; ✓ 有时候人们也称其为“参数”;
- 如果一个运算符对应的只有一个运算元,那么它是 一元运算符。 ✓ 比如说一元负号运算符(unary negation)-,它的作用是对数字进行正负转换;
- 如果一个运算符拥有两个运算元,那么它是 二元运算符。 ✓ 比如 2 + 3
一元运算符通常我们是使用 – 和 +,-号使用的会较多一些;
JavaScript中的运算
算术运算符
- 算术运算符用在数学表达式中, 它的使用方式和数学中也是一直的;
- 算术运算符是对数据进行计算的符号;
取余 % 和 求幂
取余运算符是 %,尽管它看起来很像百分数,但实际并无关联
- a % b 的结果是 a 整除 b 的 余数
求幂运算 a ** b 将 a 提升至 a 的 b 次幂。(ES7中的语法,也叫做ES2016)
- 在数学中我们将其表示为 a的b次方。
赋值运算符
前面我们使用的 = 其实也是一个运算符,被称之为 赋值( assignments )运算符。
= 是一个运算符,而不是一个有着“魔法”作用的语言结构。
- 语句 x = value 将值 value 写入 x 然后返回 x。
链式赋值(Chaining assignments)
- 链式赋值从右到左进行计算;
- 首先,对最右边的表达式 2 + 2 求值,然后将其赋给左边的变量:c、b 和 a。
- 最后,所有的变量共享一个值。
但是从代码的可读性的角度来说,不推荐这种写法。
原地修改(Modify-in-place)
什么是原地修改呢?
- 我们经常需要对一个变量做运算,并将新的结果存储在同一个变量中。
可以使用运算符 += 和 *= 来缩写这种表示。
所有算术和位运算符都有简短的“修改并赋值”运算符:/= 和 -= 等。
自增、自减
对一个数进行加一、减一是最常见的数学运算符之一。
所以,对此有一些专门的运算符:
- 自增 ++ 将变量加1;
- 自减 -- 将变量减1;
自增/自减只能应用于变量。
- 将其应用于数值(比如 5++)则会报错。
++和—的位置
运算符 ++ 和 -- 可以置于变量前,也可以置于变量后。
- 当运算符置于变量后,被称为“后置形式”(postfix form):counter++。
- 当运算符置于变量前,被称为“前置形式”(prefix form):++counter。
- 两者都做同一件事:将变量 counter 与 1 相加。
他们有什么区别吗?
- 有,但只有当我们使用 ++/-- 的返回值时才能看到区别;
- 如果自增/自减的值不会被使用,那么两者形式没有区别;
- 如果我们想要对变量进行自增操作,并且 需要立刻使用自增后的值,那么我们需要使用前置形式;
- 前置形式返回一个新的值,但后置返回原来的值;
运算符的优先级
运算符放到一起使用时会有一定的优先级:
在MDN上给出了所有运算符的优先级(不用去记)
比较运算符
我们知道,在数学中有很多用于比较大小的运算符,在JavaScript中也有相似的比较:
- 大于 / 小于:a > b,a < b。
- 大于等于 / 小于等于:a >= b,a <= b。
- 检查两个值的相等:a == b,请注意双等号 == 表示相等性检查,而单等号 a = b 表示赋值。
- 检查两个值不相等:不相等在数学中的符号是 ≠,但在 JavaScript 中写成 a != b。
比较运算符的结果都是Boolean类型的
=== 和 == 的区别
普通的相等性检查 == 存在一个问题,它不能区分出 0 和 false,或者空字符串和 false这类运算:
- 这是因为在比较不同类型的值时,处于判断符号 == 两侧的值会先被转化为数字;
- 空字符串和 false 也是如此,转化后它们都为数字 0;
如果我们需要区分 0 和 false,该怎么办?
- 严格相等运算符 === 在进行比较时不会做任何的类型转换;
- 换句话说,如果 a 和 b 属于不同的数据类型,那么 a === b 不会做任何的类型转换而立刻返回 false;
同样的,“不相等”符号 != 类似,“严格不相等”表示为 !==。
严格相等的运算符虽然写起来稍微长一些,但是它能够很清楚地显示代码意图,降低你犯错的可能性。
分支语句
程序的执行顺序
在程序开发中,程序有三种不同的执行方式:
- 顺序 —— 从上向下,顺序执行代码
- 分支 —— 根据条件判断,决定执行代码的 分支
- 循环 —— 让 特定代码 重复 执行
代码块的理解
代码块是多行执行代码的集合,通过一个花括号{}放到了一起。
- 在开发中,一行代码很难完成某一个特定的功能,我们就会将这些代码放到一个代码块中
在JavaScript中,我们可以通过流程控制语句来决定如何执行一个代码块:
- 通常会通过一些关键字来告知js引擎代码要如何被执行;
- 比如分支语句、循环语句对应的关键字等;
生活中的条件判断
现实生活中有很多情况, 我们要根据条件来做一些决定:
- 小明妈妈说: 如果小明考试了100分, 就去游乐场(判断分数等于100分)
- 网吧禁止未成年人入内(判断年龄大于等于18岁,是否带身份证,是否带钱)
- 开发中,登录成功:账号和密码正确 或 扫描二维码成功
什么是分支结构
程序是生活的一种抽象, 只是我们用代码表示了出来
- 在开发中, 我们经常需要根据一定的条件, 来决定代码的执行方向
- 如果 条件满足,才能做某件事情
- 如果 条件不满足,就做另外一件事情
分支结构
- 分支结构的代码就是让我们根据条件来决定代码的执行
- 分支结构的语句被称为判断结构或者选择结构.
- 几乎所有的编程语言都有分支结构(C、C++、OC、JavaScript等等)
JavaScript中常见的分支结构有:
- if分支结构
- switch分支结构
if分支语句
if分支结构有三种:
单分支结构
- if..
多分支结构
- if..else..
- if..else if..else..
单分支结构
单分支语句:if
- if(...) 语句计算括号里的条件表达式,如果计算结果是 true,就会执行对应的代码块。
案例一: 如果小明考试超过90分, 就去游乐场
- “如果”相当于JavaScript中的关键字if
- 分数超过90分是一个条件(可以使用 > 符号)
案例二:单位5元/斤的苹果,如果购买超过5斤,那么立减8元
- 注意:这里我们让用户输入购买的重量,计算出最后的价格并且弹出结果
if语句的细节补充
补充一:如果代码块中只有一行代码,那么{}可以省略:
补充二:if (…) 语句会计算圆括号内的表达式,并将计算结果转换为布尔型(Boolean)。
- 转换规则和Boolean函数的规则一致;
- 数字 0、空字符串 “”、null、undefined 和 NaN 都会被转换成 false。 ✓ 因为它们被称为“假值(falsy)”;
- 其他值被转换为 true,所以它们被称为“真值(truthy)”;
多分支语句:if else
多分支语句一: if.. else..
- if 语句有时会包含一个可选的 “else” 块。
- 如果判断条件不成立,就会执行它内部的代码。
案例一:如果分数超过90分去游乐场,否则去上补习班
- 满足条件时,做某些事情
- 不满足(else),去做另外一些事情
案例二:m=20,n=30,比较两个数字的大小,获取较大的那个数字
多分支结构: if else if else
多分支结构: if.. else if.. else..
- 有时我们需要判断多个条件;
- 我们可以通过使用 else if 子句实现;
案例: 分数评级:
- 考试分数大于90:优秀
- 大于80小于等于90:良好
- 大于60小于等于80:合格
- 小于60分:不及格
三元运算符
有时我们需要根据一个条件去赋值一个变量。
- 比如比较数字大小的时候,获取较大的数字;
- 这个时候if else语句就会显得过于臃肿,有没有更加简介的方法呢?
条件运算符:’?’
- 这个运算符通过问号 ? 表示;
- 有时它被称为三元运算符,被称为“三元”是因为该运算符中有三个操作数(运算元);
- 实际上它是 JavaScript 中唯一一个有这么多操作数的运算符;
使用格式如下:
var result = condition ? value1 : value2;
- 计算条件结果,如果结果为真,则返回 value1,否则返回 value2。
案例一: m=20,n=30,比较两个数字的大小,获取较大的那个数字
案例二:判断一个人是否是成年人了
认识逻辑运算符
逻辑运算符,主要是由三个:
- ||(或),&&(与),!(非)
- 它可以将多个表达式或者值放到一起来获取到一个最终的结果;
有了逻辑运算符,我们就可以在判断语句中编写多个条件。
逻辑或的本质
||(或)两个竖线符号表示“或”运算符(也称为短路或):
- 从左到右依次计算操作数。
- 处理每一个操作数时,都将其转化为布尔值(Boolean);
- 如果结果是 true,就停止计算,返回这个操作数的初始值。
- 如果所有的操作数都被计算过(也就是,转换结果都是 false),则返回最后一个操作数。
注意:返回的值是操作数的初始形式,不会转换为Boolean类型。
换句话说,一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。
逻辑与的本质
&&(或)两个竖线符号表示“与”运算符(也称为短路与):
- 从左到右依次计算操作数。
- 在处理每一个操作数时,都将其转化为布尔值(Boolean);
- 如果结果是 false,就停止计算,并返回这个操作数的初始值(一般不需要获取到初始值);
- 如果所有的操作数都被计算过(例如都是真值),则返回最后一个操作数。
换句话说,与运算 返回第一个假值,如果没有假值就返回最后一个值。
!(非)
逻辑非运算符接受一个参数,并按如下运算:
- 步骤一:将操作数转化为布尔类型:true/false;
- 步骤二:返回相反的值;
两个非运算 !! 有时候用来将某个值转化为布尔类型:
- 也就是,第一个非运算将该值转化为布尔类型并取反,第二个非运算再次取反。
- 最后我们就得到了一个任意值到布尔值的转化。
switch语句
switch是分支结构的一种语句:
- 它是通过判断表达式的结果(或者变量)是否等于case语句的常量,来执行相应的分支体的;
与if语句不同的是,switch语句只能做值的相等判断(使用全等运算符 ===),而if语句可以做值的范围判断;
switch的语法:
- switch 语句有至少一个 case 代码块和一个可选的 default 代码块。
switch语句的补充
case穿透问题:
- 一条case语句结束后,会自动执行下一个case的语句;
- 这种现象被称之为case穿透;
break关键字
- 通过在每个case的代码块后添加break关键字来解决这个问题;
注意事项:这里的相等是严格相等。
- 被比较的值必须是相同的类型才能进行匹配。
案例练习:播放模式(单曲循环、循环播放、随机播放)
循环语句
认识循环
在开发中我们经常需要做各种各样的循环操作:
- 比如把一个列表中的商品、歌曲、视频依次输出进行展示;
- 比如对一个列表进行累加计算;
- 比如运行相同的代码将数字 1 到 10 逐个输出;
循环 是一种重复运行同一代码的方法。
- 如果是对某一个列表进行循环操作,我们通常也会称之为 遍历(traversal)或者迭代(iteration);
在JavaScript中支持三种循环方式:
- while循环;
- do..while循环;
- for循环;
while循环
while循环的语法如下:
- 当条件成立时,执行代码块;
- 当条件不成立时,跳出代码块;
如果条件一直成立(为true),那么会产生死循环。
- 这个时候必须通过关闭页面来停止死循环;
- 开发中一定要避免死循环的产生;
while循环的练习
while循环的练习题目:
- 练习一:打印10次Hello World
- 练习二:打印0~99的数字
- 练习三:计算0~99的数字和
- 练习四:计算0~99所有奇数的和
- 练习五:计算0~99所有偶数的和
do..while循环
do..while循环和while循环非常像,二者经常可以相互替代(不常用)
- 但是do..while的特点是不管条件成不成立,do循环体都会先执行一次;
通常我们更倾向于使用while循环。
for循环
for 循环更加复杂,但它是最常使用的循环形式。
begin 执行一次,然后进行迭代:每次检查 condition 后,执行 body 和 step
for循环的练习
利用for循环实现之前的案例:
- 练习一:打印10次Hello World
- 练习二:打印0~99的数字
- 练习三:计算0~99的数字和
- 练习四:计算0~99所有奇数的和
- 练习五:计算0~99所有偶数的和
for循环的嵌套
什么是循环的嵌套呢?(日常开发使用不算多,在一些算法中比较常见)
- 在开发中,某些情况下一次循环是无法达到目的的,我们需要循环中嵌套循环;
我们通过for循环的嵌套来完成一些案例:
案例一:在屏幕上显示包含很多❤的矩形
案例二:在屏幕上显示一个三角的❤图像
案例三:在屏幕上显示一个九九乘法表
循环控制
循环的跳转(控制):
- 在执行循环过程中, 遇到某一个条件时, 我们可能想要做一些事情;
- 比如循环体不再执行(即使没有执行完), 跳出循环;
- 比如本次循环体不再执行, 执行下一次的循环体;
循环的跳转控制
break: 直接跳出循环, 循环结束
- break 某一条件满足时,退出循环,不再执行后续重复的代码
continue: 跳过本次循环次, 执行下一次循环体
- continue 指令是 break 的“轻量版”。
- continue 某一条件满足时,不执行后续重复的代码
猜数字游戏
猜数字游戏规则:
- 电脑随机生成一个0~99之间的数字;
- 玩家有7次猜测的机会;
- 玩家猜测一个数字, 输入到程序中;
- 电脑根据输入的数字打印: 猜大了/猜小了/猜对了的情况;
- 猜对了, 那么游戏结束,显示恭喜您;
- 7次机会用完打印: 您的次数用完了, 您失败了;
循环的总结
我们学习了三种循环:
- while —— 每次迭代之前都要检查条件;
- do..while —— 每次迭代后都要检查条件;
- for (;😉 —— 每次迭代之前都要检查条件,可以使用其他设置;
break/continue 可以对循环进行控制。