javascript初级部分
前言
JavaScript之父 Brendan Eich(布兰登·艾奇)
在JavaScript诞生的前几年,有人说:
JavaScript是一门四不像的语言;JavaScript是一门没有规范的语言;JavaScript是一门兼容糟糕的语言;JavaScript是一门不精准的语言;JavaScript是一个半成品语言;JavaScript是一门糟糕的语言;JavaScript只是一个玩具胶水语言;
这些声音从JavaScript面世之初就一直伴随着她,声音的主人不乏已掌握多门语言的coding老兵,每一条负面都事实支撑。就连JavaScript之父也曾经说过:
1 | "与其说我爱Javascript,不如说我恨它。它是C语言和Self语言一夜情的产物。十八世纪英国文学家约翰逊博士说得好:'它的优秀之处并非原创,它的原创之处并不优秀。'(the part that is good is not original, and the part that is original is not good.)" |
Ruby的设计者——松本行弘为此感叹:
“这样的出身,得到这样的成功,还真让人出乎意料,……”,“但由于开发周期短,确实也存在着不足……”。
Douglas Crockford写了一本《JavaScript:The Good Parts》,在书中他这样写到:
JavaScript建立在一些非常好的想法和少数非常坏的想法之上。
那些非常好的想法包括函数、弱类型、动态对象和一个富有表现力的对象字面量表示法,而那些坏的想法包括基于全局变量的编程模型、缺乏块作用域、“保留”了一堆根本没用到的保留字,不支持真正的数组(它所提供的类数组对象性能不好)等等。
还有一些是“鸡肋”,比如with语句,原始类型的包装对象,new,void等等
但如今,JavaScript已经成为大部分全球开发者与编程爱好者最常用/最喜欢的语言之一。
[github Octoverse 调查报告][ https://octoverse.github.com/] 合作开发中应用最多的语言排行
[stackoverflow 2019年度调查报告][https://insights.stackoverflow.com/survey/2019#developer-profile-developer-roles-all-respondent ] 最受欢迎的语言排行
这中间到底发生了什么,为什么会导致如此大的变化,让我们一起与JavaScript相关的历史年表;
时间 | 事件 |
---|---|
1990年 | 万维网诞生 |
1992年 | 第一个浏览器诞生 |
1994年 | Netscape(网景)成立开发第一代Netscape Navigator浏览器 |
1995年 | Mocha诞生,之后改为LiveScript,最后与sun公司达成协议改为javascript |
1996年 | 微软开发JScript,Netscape公司将JavaScript提交给国际标准化组织ECMA |
1997年 | ECMAscript1.0版发布 JavaScript进入标准化时代 ECMA-262发布 |
1998年 | ECMAScript 2.0版发布。 |
1999年 | ECMAScript 3.0版发布,成为JavaScript的通行标准,得到了广泛支持。 |
2004年 | Gmail发布 Dojo诞生 |
2005年 | Ajax 即“ Asynchronous Javascript And XML” AJAX 推广 CouchDB基于json格式的数据库 |
2006年 | XMLHttpRequest被w3c纳入正式标准 同年 jQuery发布 |
2008年 | V8引擎发布 |
2009年 | ECMAScript 5.0发布 & node.js诞生 |
2010年 | Express 发布 & angular发布 NPM、BackboneJS和RequireJS 诞生 |
2011年 | React原型成立 |
2012年 | Webpack诞生 |
2013年 | mongodb 2.4* 开始支持JavaScript ELECTRON诞生 HTML5.1 发布 |
2014年 | Vue.js 发布 |
2015年 | ECMAScript 6正式发布,并且更名为 ECMAScript 2015 ,iotjs 发布 |
2016年 | ECMAScript 2016发布 |
2017 | ECMAScript 2017发布 主流浏览器全面支持 WebAssembly |
1 | 个人观点: 真香 |
JavaScript 的基本语法和对象体系,是模仿 Java 而设计的。但是,JavaScript 没有采用 Java 的静态类型。正是因为 JavaScript 与 Java 有很大的相似性,所以这门语言才从一开始的 LiveScript 改名为 JavaScript。基本上,JavaScript 这个名字的原意是“很像Java的脚本语言”。
JavaScript 语言的函数是一种独立的数据类型,以及采用基于原型对象(prototype)的继承链。这是它与 Java 语法最大的两点区别。JavaScript 语法要比 Java 自由得多。
另外,Java 语言需要编译,而 JavaScript 语言则是运行时由解释器直接执行。
总之,JavaScript 的原始设计目标是一种小型的、简单的动态语言,与 Java 有足够的相似性,使得使用者(尤其是 Java 程序员)可以快速上手。
什么是JavaScript?
JavaScript 是一门弱类型的动态脚本语言,支持多种编程范式,包括面向对象和函数式编程,被广泛用于 Web 开发。
JavaScript是一门基于原型的动态解释性脚本语言
一般来说,前端领域完整的JavaScript包括以下几个部分:
- ECMAScript,描述了该语言的语法和基本对象
- 文档对象模型(DOM),描述处理网页内容的方法和接口
- 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口
它的基本特点如下:
- 是一种解释性脚本语言(代码不进行预编译)。
- 主要用来向HTML页面添加交互行为。
- 可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。
JavaScript常用来完成以下任务:
- 嵌入动态文本于HTML页面
- 对浏览器事件作出响应
- 读写HTML元素
- 在数据被提交到服务器之前验证数据
- 检测访客的浏览器信息
BOM - 浏览器对象模型
一套操作浏览器功能的API
通过BOM可以操作浏览器窗口,比如:弹出框、控制浏览器跳转、获取分辨率等
DOM - 文档对象模型
一套操作页面元素的API
DOM可以把HTML看做是文档树,通过DOM提供的API可以对树上的节点进行操作
JavaScript 与 Java 的关系
本质上讲 JavaScript和 Java没有关系,只是JavaScript诞生之初 网景与sun合作想要推出 web端的脚本语言。JavaScript 的基本语法和对象体系,是模仿 Java 而设计的。但是,JavaScript 没有采用 Java 的静态类型。除此之外JavaScript和Java在语言层面上可以说是大相径庭。处于某种商业意图,这门语言才从一开始的LiveScript 改名为 JavaScript。
JavaScript与ECMAScript的关系
ECMAScript 只用来标准化 JavaScript 这种语言的基本语法结构,与部署环境相关的标准都由其他标准规定,比如 DOM 的标准就是由 W3C组织(World Wide Web Consortium)制定的。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。在日常场合,这两个词是可以互换的。
JavaScript能做什么?
任何能够用JavaScript实现的应用系统,最终都必将用JavaScript实现 —Atwood定律
前端领域
ajax出现之后 JavaScript有了在WEB领域立足的土壤和根基,时至今日。JavaScript已经是WEB前端领域最重要的基石,一切现代化的WEB项目都离不开JavaScript。
- 数据交互
- UI管理
- 用户行为交互
- 数据校验
- 工程化/模块化
- MVVM
后端领域
V8 JIT NodeJS 让JavaScript可以在服务端崭露头角 打破了JavaScript只能寄生在浏览器上的魔咒
CouchDB mongodb等基于JSON格式的NoSQL类型的数据库诞生 让JavaScript也可以在DB操作上大展身手
- WEB服务框架: express/KOA
- NoSQL 数据库: mongodb CouchDB
- 博客系统 : Ghost/hexo
- 自动化构建领域: Gulp/Grunt
APP
目前来说主流的App开发方式有三种:Native App 、Web App、Hybird App,而3种方式下又分别有众多的框架可供选择。JavaScript 可以介入开发的有下面三种:
- Web App HTML5 APP 框架开发模式
- Hybrid App 混合模式移动应用
- PWA Progressive Web App 渐进式网页应用
桌面应用
JavaScript还可以介入的桌面应用开发,主流有 electron Node-webkit hex React Navite
**electron代表作: **
- vscode
- atom
**Node-webkit代表作: **
- teambition
hex代表作
- 有道词典
图形/游戏
世界上最流行的 2D 游戏引擎之一 Cocos2d 和最流行的 3D 游戏引擎之一 Unity3D 均支持 JS 开发游戏。
以及 Cocos2d-js 轻量型跨平台Web游戏引擎
嵌入式与IOT开发
JavaScript 不只是 Web 时代的通用语言,如今还延伸到了使人难以置信的其它地方: 物联网;
为什么要学JavaScript?
JavaScript 的上手方便 表达灵活 社区支持度高 应用广泛,是当今最受欢迎 应用最广泛的语言之一….
现实点说,在现代互联网环境下,你很难找到不需要JavaScript开发岗位的企业。
学习JavaScript所需要的的环境与设备
- 一台可以运行浏览器的电脑
- 浏览器
- 开发工具 (推荐 vscode)
学习JavaScript所需要做的心里准备
不论你之前是否学习接触过其他编程语言,学习JavaScript你需要做好以下几点心里准备
- 不要用常规认知去理解JavaScript世界的规则 3<2<1 0.2 + 0.7
- 一切以事实为准,一切认知建立在实践基础上
- 多练 多练 多练 多练 多练 多练 多练 多练…….
JavaScript基础
在HTML中嵌入JavaScript代码
1 | <html> |
第一段JavaScript代码
1 | var str = 'hello world!'; |
JavaScript基础名词概念
1 | var num = 1 + 1; |
语句
JavaScript语句为由上至下 单行执行; 每一行都是一条语句, 每一条语句执行完成之后会进入下一行 语句由于 ; 结尾
表达式
上述代码中
1 + 1
就是一个表达式(expression) 指一个为了得到返回值的计算式。
语句可以理解为一条命令,并不一定需要的到一个具体的期望值。表达式的目的是为了得到一个值,方便后面利用值去做什么事情,在上述例子中 表达式 1+1
得到的值 赋值 给了 变量 num;
变量
上述例子中 num 为我们 声明 的 变量 , 变量可以理解为一个容器,用于存放各种各样的值。由于需要存放各种不同的值 所以我们要为 变量命名
num
就是 上述例子中 的变量名
变量声明
上述例子中 我们通过表达式
1 + 1
得到的值, 赋值给了 我们通过 var关键字 声明的 变量str
; 后续 num 所指向的内存地址中存储的值就是1 + 1
的结果。 在这个过程中我们其实做了两件事情:
我们声明变量 是通过 关键字var 创建了变量 num
我们将 表达式
1 + 1
的值 赋值给了 变量 num
1 | // 声明变量 变量名为 num 没有赋值 默认值为 undefined undefined也是一个 JavaScript 关键字,表示“无定义”。 |
变量赋值
我们可以通过
var
关键字 创建一个变量 , 创建出现的变量默认值为undefined
未定义, 我们可以通过赋值 表达式=
来给变量存储值 格式如下
1 | 变量名称 = 值; |
变量引用
我们学会了如何创建变量 以及如何给变量赋值, 那赋值后的变量我们如何使用呢?
1 | //使用console.log方法 在控制台中 打印 num变量的值 |
标识符 ( 变量名称 )
标识符(identifier)指的是用来识别各种值的合法名称。最常见的标识符就是变量名,以及后面要提到的函数名。JavaScript 语言的标识符对大小写敏感,所以
a
和A
是两个不同的标识符。
命名规则
必须遵守的命名规则 如果不遵守 就会报错
1 | - 由字母、数字、下划线、$符号组成,不能以数字以及其他符号开头 |
保留关键字:
arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield。
*合法标识符 中文为合法标识符任意 Unicode 字母(包括英文字母和其他语言的字母)
1 | num |
*非法标识符
1 | 1x |
命名规范
遵守规范能够给自己和他人带来更好的开发体验,不遵守并不会导致报错
- 具有语义性的 英文单词 ;
- 多个单词使用驼峰命名法
- 变量名称 为名词 可以使用形容词为前缀
*良好的命名
1 | maxCount |
*不好的命名
1 | max-count |
变量规则
未声明变量直接使用
1 | console.log(x); |
上面代码直接使用变量x
,系统就报错,告诉你变量x
没有声明。
省略 var 关键字
1 | a = 30; |
在javascript中 变量可以省略 var关键字 直接调用或者赋值,解释器会帮我们 隐式声明 变量
但是,不写
var
的做法,不利于表达意图,而且容易不知不觉地创建全局变量,所以建议总是使用var
命令声明变量。
重复赋值
1 | var x = 10; |
x
一开始声明并且赋值为10
后面如果想要修改x
的值 不需要重新声明 直接再次赋值20
覆盖之前x
的值内容即可
重复声明
1 | var x = 1; |
对同一个变量进行二次声明 第二次声明是无效的操作 因为同一个 环境中 变量名是唯一的;
重复声明赋值
1 | var x = 1; |
结合上一个重复声明, 当重复声明且赋值的时候, 第二行的声明无效 但 赋值操作有效 所以 变量
x
的值 由1 覆盖为 2
批量声明
1 | var a,b,c,d = 10; |
在上面的代码中 我们可以通过
,
隔开多个变量, 通过一个var
关键字进行批量声明 , 最后一个 变量d
赋值为10;
变量提升
1 | console.log(num); //undefined |
上面的这个代码中 我们书写语句的顺序是
- 调用了 num 进行打印
- 声明了变量 num 并且 赋值 10
实际在javascript引擎解释后 顺序为
1 | var num; |
- 先声明 num 这一步称为 变量提升
- 调用console.log() 打印 num的值 这时因为没有给num赋值 num的值还是 初始默认值 undefined
- 给num 赋值 为 10
注释
在javascript也会频繁用到注释 注释形式有 两种
1 | // 这是单行注释 ctrl+/ |
数据类型
JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有七种。
- 数值(number):整数和小数(比如
1
和3.14
) - 字符串(string):文本(比如
'Hello World'
)。 - 布尔值(boolean):表示真伪的两个特殊值,即
true
(真)和false
(假) undefined
:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值null
:表示空值,即此处的值为空 。- 对象(object):各种值组成的集合。
- symbol (symbol ) : 唯一标识符 //es6学习前不做讨论
1 | 通常,数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefined和null,一般将它们看成两个特殊值。 |
类型分类
传统分类通过存储位置 把数据类型分为 基础类型 和 引用类型
1 | 基础类型 存储在 栈内存 中 |
Number 类型
数值字面量:数值的固定值的表示法
110 1024 60.5
进制
1 | 十进制 |
浮点数
- 浮点数的精度问题
1 | 浮点数 |
- 数值范围
1 | 最小值:Number.MIN_VALUE,这个值为: 5e-324 |
数值判断
- NaN:not a number 表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
- NaN 与任何值都不相等,包括他本身
- isNaN: is not a number
- NaN进行任何数学运算 结果也是 NaN
- NaN:not a number 表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
数值精度问题
根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。
- 第1位:符号位,
0
表示正数,1
表示负数 - 第2位到第12位(共11位):指数部分
- 第13位到第64位(共52位):小数部分(即有效数字)
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。
指数部分一共有11个二进制位,因此大小范围就是0到2047。IEEE 754 规定,如果指数部分的值在0到2047之间(不含两个端点),那么有效数字的第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字这时总是1.xx...xx
的形式,其中xx..xx
的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript 提供的有效数字最长为53个二进制位。
1 | (-1)^符号位 * 1.xx...xx * 2^指数部分 |
上面公式是正常情况下(指数部分在0到2047之间),一个数在 JavaScript 内部实际的表示形式。
精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-2^53到2^53,都可以精确表示。
数值范围
根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。
如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity
。
String类型
‘joker’ “kyogre”
字符串字面量
‘海牙老师 真的帅’
转义符
字符串长度 (只读)
length属性用来获取字符串的长度
1
2var str = '海牙 Hello World';
console.log(str.length);字符串拼接
字符串拼接使用 + 连接
1
2
3
4
5console.log(11 + 11);
console.log('hello' + ' world');
console.log('100' + '100');
console.log('11' + 32);
console.log('male:' + true);- 两边只要有一个是字符串,那么+就是字符串拼接功能
- 两边如果都是数字,那么就是算术功能。
字符串换行
1
2
3
4
5
6
7
8
9
10
11
12var longString = '第一行 '
+ '第二行 '
+ '第三行 '
+ '文本内容';
var longString = '第一行 \
第二行 \
第三行 \
文本内容';
longString按位取值(只读)
1
2
3var str = 'hello world!';
console.log(str[1]); //e
str[1] = 'x'; //无法改写
Boolean类型
布尔值代表“真”和“假”两个状态。“真”用关键字
true
表示,“假”用关键字false
表示。布尔值只有这两个值。
- Boolean字面量: true和false,区分大小写
- 计算机内部存储:true为1,false为0
Undefined和Null
null
与undefined
都可以表示“没有”,含义非常相似。将一个变量赋值为undefined
或null
,老实说,语法效果几乎没区别。
- undefined表示一个声明了没有赋值的变量,变量只声明的时候值默认是undefined
- null表示一个空,变量的值如果想为null,必须手动设置
在javascript设计初期 null
就像在 Java 里一样,被当成一个对象。初像 Java 一样,只设置了null
表示”无”。根据 C 语言的传统,null
可以自动转为0
。 但是javascript并没有完整的ERROR机制 null
可以转换为0 对于javascript这种弱类型的语言来说 不利于发现bug 所以设计了 undefined
变量默认值也就成为了 undefined
所以在学习javascript的过程中 不能用java等编程语言的null
来理解javascript中的null
在javascript中 null是 对象的延伸 是一个 ‘空’ 对象。var str = '';
中 ''
不能用null判断 他是有值的 内存中分配了空间来存储 ''
一个空字符串值。null
在javascript中常见于释放内存空间 var str = null;
类型判断
JavaScript 有三种方法,可以确定一个值到底是什么类型。
typeof
运算符instanceof
运算符Object.prototype.toString
方法
typeof
数值、字符串、布尔值分别返回
number
、string
、boolean
, undefined返回
undefined null返回
object
1 | typeof 123 // "number" |
typeof 针对未声明的变量
1 | if (typeof v === "undefined" ) { |
isNaN
isNaN
方法可以用来判断一个值是否为NaN
。
1 | isNaN(NaN) // true |
但是,isNaN
只对数值有效,如果传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成NaN
,所以最后返回true
,这一点要特别引起注意。也就是说,isNaN
为true
的值,有可能不是NaN
,而是一个字符串。
1 | isNaN('Hello') // true |
出于同样的原因,对于对象和数组,isNaN
也返回true
。
1 | isNaN({}) // true |
但是,对于空数组和只有一个数值成员的数组,isNaN
返回false
。
1 | isNaN([]) // false |
上面代码之所以返回false
,原因是这些数组能被Number
函数转成数值
因此,使用isNaN
之前,最好判断一下数据类型。
1 | function myIsNaN(value) { |
判断NaN
更可靠的方法是,利用NaN
为唯一不等于自身的值的这个特点,进行判断。
1 | function myIsNaN(value) { |
isFinite
isFinite
方法返回一个布尔值,表示某个值是否为正常的数值。
1 | isFinite(Infinity) // false |
除了Infinity
、-Infinity
、NaN
和undefined
这几个值会返回false
,isFinite
对于其他的数值都会返回true
。
操作符
运算符 operator
5 + 6
表达式 组成 操作数和操作符,会有一个结果
算术运算符
- 加法运算符:
x + y
- 减法运算符:
x - y
- 乘法运算符:
x * y
- 除法运算符:
x / y
- 指数运算符:
x ** y
- 余数运算符:
x % y
- 自增运算符:
++x
或者x++
- 自减运算符:
--x
或者x--
- 数值运算符:
+x
- 负数值运算符:
-x
一元运算符
一元运算符:只有一个操作数的运算符
1 + 2 两个操作数的运算符 二元运算符
++ 自身加1
– 自身减1
前置++
1
2
3
4
5var num1 = 5;
++ num1;
var num2 = 6;
console.log(num1 + ++ num2);后置++
1
2
3
4var num1 = 5;
num1 ++;
var num2 = 6
console.log(num1 + num2 ++);猜猜看
1
2
3
4var a = 1; var b = ++a + ++a; console.log(b);
var a = 1; var b = a++ + ++a; console.log(b);
var a = 1; var b = a++ + a++; console.log(b);
var a = 1; var b = ++a + a++; console.log(b);总结
前置++:先加1,后参与运算
后置++:先参与运算,后加1
上面两个理解后,下面两个自通
前置– :先减1,后参与运算
后置– :先参与运算,后减1
逻辑运算符(布尔运算符)
&& 与 两个操作数同时为true,结果为true,否则都是false
|| 或 两个操作数有一个为true,结果为true,否则为false
! 非 取反
关系运算符(比较运算符)
< > >= <= == != === !==
1 | ==与===的区别:==只进行值得比较,===类型和值同时相等,则相等 |
赋值运算符
= += -= *= /= %=
1 | 例如: |
二进制运算符 (了解)
javascript 支持二进制运算 ~ | & >> << >>> ^
1 | 异或运算 ^ |
1 | 否运算符 ~ |
运算符的优先级
优先级从高到底
1. () 优先级最高
2. 一元运算符 ++ -- !
3. 算数运算符 先* / % 后 + -
4. 关系运算符 > >= < <=
5. 相等运算符 == != === !==
6. 逻辑运算符 先&& 后||
7. 赋值运算符
8. 默认从左至右 除了 赋值运算 = 三目运算 ?: 指数运算 **
1 | // 练习1: |
注: Unicode 码表查询地址 https://www.ltool.net/characters-to-unicode-charts-in-simplified-chinese.php
数据类型转换
chrome浏览器中 不同类型的值 打印颜色不同
字符串的颜色是黑色的,数值类型是蓝色的,布尔类型也是蓝色的,undefined和null是灰色的
转换成字符串类型
toString()
1
2var num = 5;
console.log(num.toString());String()
1
String()函数存在的意义:有些值没有toString(),这个时候可以使用String()。比如:undefined和null
拼接字符串方式
num + “”,当 + 两边一个操作符是字符串类型,一个操作符是其它类型的时候,会先把其它类型转换成字符串再进行字符串拼接,返回字符串
转换成数值类型
Number(Obj)
1
Number()可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaN
parseInt(string,radix)
1
2var num1 = parseInt("12.3abc"); // 返回12,如果第一个字符是数字会解析知道遇到非数字结束
var num2 = parseInt("abc123"); // 返回NaN,如果第一个字符不是数字或者符号就返回NaNparseFloat(string)
1
2
3
4parseFloat()把字符串转换成浮点数
parseFloat()和parseInt非常相似,不同之处在与
parseFloat会解析第一个. 遇到第二个.或者非数字结束
如果解析的内容里只有整数,解析成整数+,-0等运算
1
2
3
4var str = '500';
console.log(+str); // 取正
console.log(-str); // 取负
console.log(str - 0);
转换成布尔类型
Boolean()
!!
''(空字符串) null undefined NaN 0 会转换成false 其它都会转换成true
隐式转换
递增递减运算符(前置、后置)
如果包含的是有效数字字符串或者是有效浮点数字符串,则会将字符串转换(Number())为数值,再进行加减操作,返回值的类型是:number类型。
如果不包含有效数字字符串,则会将字符串的值转换为NaN,返回值的类型是:number类型。
如果是boolean类型,则先会把true或者false转换为1或者0,再进行加减操作,返回值的类型是:number类型。
如果是null类型,则先会把null转换为0,在进行加减操作,返回值的类型是:number类型。
如果是undefined,则先会把undefined转换为NaN,再进行加减操作,返回值的类型是:number类型。
如果是对象,则先会通过对象的valueOf()方法,进行转换,如果返回的是NaN,调用toString()方法,在进行前面的操作,返回值的类型是:number类型。(注:空数组[]会返回0,在进行加减操作,空对象则会返回NaN)。
逻辑操作符中的隐式转换规律
注:只有undefined、null、NaN、0、空字符串会被转换为false,其余都为true
逻辑操作符一般用于语句判断中。通过判断结果返回的值进行后面的语句操作。
- 逻辑非(!)操作符:首先会通过Boolean()函数将其操作值转换为布尔值,然后求反。
- 逻辑与(&&)操作符:如果第一个值经过Boolean()函数转换后为true,则返回第二个操作值,否则返回第一个操作值。如果有一个操作值为null这返回null,如果有一个操作值为undefined,则返回undefined,如果有一个值为NaN,则返回NaN。
- 逻辑或(||)操作符:如果第一个值经过Boolean()函数转换为false,则返回第二个操作值,否则返回第一个操作值。
(注:逻辑操作符的运算为短路逻辑运算:前一个条件已经能够得出结果后续条件不再执行!)
关系操作符的隐式转换规律
(关系操作符的操作值也可以是任意类型):
- 如果两个操作值都是数值,则直接比较大小。
- 如果两个操作值都是字符串,则字符串进行其Unicode编码进行比较。
- 如果一个操作值是数值,则另一个值转换为数值进行比较。
- 如果一个操作值是对象,则调用对象的valueOf()和toString()方法,然后再进行上述比较。
- 如果一个操作值是布尔值,则将布尔值转换为数值再进行比较。
(注:NaN和任何值都不相等,包括自己,同时它与任何类型比较都会返回false。)
相等操作符==和===的隐式转换规律:
- 布尔值、字符串和数值进行比较,会先将其转换为数值再进行比较。
- null和undefined比较是相等的,但不是全等的。
- NaN与任何值都不相等,都会返回false。
布尔类型的隐式转换
流程控制语句会把后面的值隐式转换成布尔类型
转换为true 非空字符串 非0数字 true 任何对象
转换成false 空字符串 0 false null undefined NaN
1 | // 结果是什么? |
转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
- 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而true 转换为 1;
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较;
这两个操作符在进行比较时则要遵循下列规则。
null 和 undefined 是相等的。
要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。 重要提示:即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则, NaN 不等于 NaN。
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,
则相等操作符返回 true;否则,返回 false。表达式 值 null==undefined true “NaN”==NaN false 5==NaN false NaN==NaN false false==0 true true==1 true true==2 false undefined==0 false null==0 false
null == undefined 会返回 true,因为它们是类似的值;但 null === undefined 会返回 false,因为它们是不同类型的值。
=== 转换
值 | 字符串操作环境 | 数字运算环境 | 逻辑运算环境 | 对象操作环境 |
---|---|---|---|---|
undefined | “undefined” | NaN | false | Error |
null | “null” | 0 | false | Error |
非空字符串 | 不转换 | 字符串对应的数字值 | True | |
空字符串 | 不转换 | 0 | false | String |
0 | “0” | 不转换 | false | Number |
NaN | “NaN” | 不转换 | false | Number |
Infinity | “Infinity” | 不转换 | true | Number |
Number.POSITIVE_INFINITY | “Infinity” | 不转换 | true | Number |
Number.NEGATIVE_INFINITY | “-Infinity” | 不转换 | true | Number |
Number.MAX_VALUE | “1.7976931348623157e+308” | 不转换 | true | Number |
Number.MIN_VALUE | “5e-324” | 不转换 | true | Number |
其他所有数字 | “数字的字符串值” | 不转换 | true | Number |
true | “true” | 1 | 不转换 | Boolean |
false | “false” | 0 | 不转换 | Boolean |
对象 | toString() | value()或toString()或NaN | true | 不转换 |
测试:
1 | 1 + true; |
关于 null 在关系运算和相等运算中的坑:
1 | null > 0 // null 尝试转型为number , 则为0 . 所以结果为 false, |
参考 : http://bclary.com/log/2004/11/07/#a-11.9.3
- 关系运算符 和 相等运算符 并不是一个类别的.
- 关系运算符,在设计上,总是需要运算元尝试转为一个number . 而相等运算符在设计上,则没有这方面的考虑.
- 最重要的一点, 不要把 拿 a > b , a == b 的结果 想当然的去和 a >= b 建立联系. 正确的符合最初设计思想的关系是 a > b 与 a >= b是一组 . a == b 和其他相等运算符才是一组. 比如 a === b , a != b, a !== b .
控制流程
编程的三种基本结构
顺序结构
从上到下执行的代码就是顺序结构
程序默认就是由上到下顺序执行的
分支结构
根据不同的情况,执行对应代码
循环结构
循环结构:重复做一件事情
分支结构
f语句
语法结构
1 | if (/* 条件表达式 */) { |
案例:
求两个数的最大数
判断一个数是偶数还是奇数
分数转换,把百分制转换成ABCDE <60 E 60-70 D 70-80 C 80-90 B 90 - 100 A
判断四季 3-5 春 6-8夏 9-11 秋 12-2 冬
作业:
判断一个年份是闰年还是平年
判断一个人的年龄是否满18岁(是否成年)
挑战:
闰年:能被4整除,但不能被100整除的年份 或者 能被400整除的年份
三元运算符
表达式1 ? 表达式2 : 表达式3
是对if……else语句的一种简化写法
案例:
是否年满18岁
从两个数中找最大值
1 | i = i ? i < 0 ? Math.max(0, len + i) : i : 0; |
switch语句
语法格式:
1 | switch (expression) { |
break可以省略,如果省略,代码会继续执行下一个case
switch 语句在比较值时使用的是全等操作符, 因此不会发生类型转换(例如,字符串'10' 不等于数值 10)
作业: switch 打印星期几 0为星期日 1-6分别对应星期一到星期六
交互与写入:alert、prompt 和 confirm / write
由于我们将使用浏览器作为我们的演示环境,让我们看几个与用户交互的函数:alert
,prompt
和confirm
。
alert
这个我们前面已经看到过了。它会显示一条信息,并等待用户按下 “OK”。
例如:
1 | alert("Hello"); |
弹出的这个带有信息的小窗口被称为 模态窗。“modal” 意味着用户不能与页面的其他部分(例如点击其他按钮等)进行交互,直到他们处理完窗口。在上面示例这种情况下 —— 直到用户点击“确定”按钮。
prompt
pormpt有文本消息的模态窗口,还有 input 框和确定/取消按钮。
1 | result = prompt(title, [default]); |
浏览器会显示一个带有文本消息的模态窗口,还有 input 框和确定/取消按钮。
title
显示给用户的文本
default
可选的第二个参数,指定 input 框的初始值。
语法中的方括号 [...]
上述语法中 default
周围的方括号表示该参数是可选的,不是必需的。
访问者可以在提示输入栏中输入一些内容,然后按“确定”键。然后我们在 result
中获取该文本。或者他们可以按取消键或按 Esc 键取消输入,然后我们得到 null
作为 result
。
prompt
将返回用户在 input
框内输入的文本,如果用户取消了输入,则返回 null
。
举个例子:
1 | var age = prompt('How old are you?', 100); |
IE 浏览器会提供默认值
第二个参数是可选的。但是如果我们不提供的话,Internet Explorer 会把 "undefined"
插入到 prompt。
我们可以在 Internet Explorer 中运行下面这行代码来看看效果:
1 | var test = prompt("Test"); |
所以,为了 prompt 在 IE 中有好的效果,我们建议始终提供第二个参数:
1 | var test = prompt("Test", ''); // <-- 用于 IE 浏览器 |
confirm
confirm取消两个按钮的模态窗口。
1 | result = confirm(question); |
confirm
函数显示一个带有 question
以及确定和取消两个按钮的模态窗口。
点击确定返回 true
,点击取消返回 false
。
例如:
1 | var isBoss = confirm("Are you the boss?"); |
document.write
在JavaScript中document.write()函数可以向文档写入HTML表达式或JavaScript代码,用法“document.write(exp1,exp2,exp3,….)”,该函数可接受任何多个参数,并将其写入文档中。
1 | document.write('我被写入了BODY中','还有我'); |
循环结构
在javascript中,循环语句有三种,while、do..while、for循环。
我们经常需要重复执行一些操作。
例如,我们需要将列表中的商品逐个输出,或者运行相同的代码将数字 1 到 10 逐个输出。
循环 是一种重复运行同一代码的方法。
while语句
基本语法:
1 | // 当循环条件为true时,执行循环体, |
当 condition
(条件) 为 true
时,执行循环体的代码。
例如,以下将循环输出当 i < 3
时的 i
值:
1 | var i = 0; |
案例:
打印100以内 7的倍数
打印100以内所有偶数
打印100以内所有偶数的和
作业:
打印100以内的奇数
打印100以内的奇数的和
do…while语句
do..while循环和while循环非常像,二者经常可以相互替代,但是do..while的特点是不管条件成不成立,都会执行一次。
基础语法:
1 | do { |
代码示例:
1 | // 初始化变量 |
案例:
1 | 求100以内所有3的倍数的和 |
for语句
while和do…while一般用来解决无法确认次数的循环。for循环一般在循环次数确定的时候比较方便
for循环语法:
1 | // for循环的表达式之间用的是;号分隔的,千万不要写成, |
执行顺序:1243 —- 243 —–243(直到循环条件变成false)
- 初始化表达式
- 判断表达式
- 自增表达式
- 循环体
案例:
1 | 打印1-100之间所有数 |
作业:
1 | 打印9 9 乘法表 |
continue和break
break:立即跳出整个循环,即循环结束,开始执行循环后面的内容(直接跳到大括号)
continue:立即跳出当前循环,继续下一次循环(跳到i++的地方)
案例:
1 | 求整数1~100的累加值,但要求碰到个位为3的数则停止累加 |
作业:
求1-100之间不能被7整除的整数的和(用continue)
求200-300之间所有的奇数的和(用continue)
求200-300之间第一个能被7整数的数(break)
调试
- 过去调试JavaScript的方式
- alert()
- console.log()
- 断点调试
断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。
- 调试步骤
1 | 浏览器中按F12-->sources-->找到需要调试的文件-->在程序的某一行设置断点 |
- 调试中的相关操作
1 | Watch: 监视,通过watch可以监视变量的值的变化,非常的常用。 |
tips: 监视变量,不要监视表达式,因为监视了表达式,那么这个表达式也会执行。
- 代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug的能力。初学者不要觉得调试代码麻烦就不去调试,知识点花点功夫肯定学的会,但是代码调试这个东西,自己不去练,永远都学不会。
- 今天学的代码调试非常的简单,只要求同学们记住代码调试的这几个按钮的作用即可,后面还会学到很多的代码调试技巧。
数组
为什么要学习数组
之前学习的数据类型,只能存储一个值 比如:Number/String。我们想存储班级中所有学生的姓名,此时该如何存储?
数组的概念
所谓数组,就是将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。
数组的定义
数组是一个有序的列表,可以在数组中存放任意的数据,并且数组的长度可以动态的调整。
创建方式
通过实例化创建
1 | var arr = new Array(3); //只写一个参数,创建一个长度为3的数组 , 数组中每一项都为 空置empty [empty,empty,empty] |
通过数组字面量创建数组
1 | // 创建一个空数组 |
数组的属性
1 | var arr = [1,2,3,4]; |
获取数组元素
数组的取值
1 | // 格式:数组名[下标] 下标又称索引 |
遍历数组
遍历:遍及所有,对数组的每一个元素都访问一次就叫遍历。
数组遍历的基本语法:
1 | for(var i = 0; i < arr.length; i++) { |
for in 遍历(不推荐)
1 | for(var key in arr){ |
for of 遍历
1 | for(var key of arr){ |
数组元素赋值
数组的赋值
1 | var arr = ['red', 'green', 'blue']; |
多维数组
数组中包含数组的话称之为多维数组。 您可以通过将两组方括号链接在一起来访问数组内的另一个数组
使用最多的是二维数组
1 | var arr = [[1,2,3],[4,5,6],[7,8,9]]; |
数组类型判定与隐式转换
1 | var arr = [1,2,3]; |
数组基础方法
数组的方法有很多,在我们学习完函数 作用域 对象之前我们先了解一些数组的基础方法
isArray(obj)
用于确定传递的值是否是一个 Array。
1 | Array.isArray([1, 2, 3]); |
参数
1 | obj 需要检测的值 |
返回值
1 | 如果值是Array 则为true; 否则为false。 |
join(separator)
方法将一个数组的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。
1 | const elements = ['火', '空气', '水']; |
参数
1 | separator 可选 指定分隔符号 该参数默认值为"," |
返回值
1 | 一个所有数组元素连接的字符串。如果 arr.length 为0,则返回空字符串。 |
注意
如果一个元素为 undefined
或 null
,它会被转换为空字符串’’。
push(element1,…,elementN)
方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
1 | var animals = ['猪', '狗', '牛']; |
参数
1 | elementN 可选多个参数 |
返回值
1 | 当调用该方法时,新的 length 属性值将被返回。 |
unshift(element1,…,elementN)
方法将一个或多个元素添加到数组的前端,并返回该数组的新长度。
1 | var animals = ['猪', '狗', '牛']; |
参数
1 | elementN 可选多个参数 |
返回值
1 | 当调用该方法时,新的 length 属性值将被返回。 |
pop()
方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
1 | var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆']; |
参数
1 | 无 |
返回值
1 | 从数组中删除的元素(当数组为空时返回undefined)。 |
shift()
方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
1 | var array = [1, 2, 3]; |
参数
1 | 无 |
返回值
1 | 从数组中删除的元素; 如果数组为空则返回undefined 。 |
slice()
切割方法返回一个新的数组对象,这一对象是一个由
begin
和end
决定的原数组的浅拷贝(包括begin
(起始下标),不包括end
(结束下标))。原始数组不会被改变。
1 | var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆']; |
参数
1 | arr.slice([begin[, end]]) //begin 和end都是可选参数 |
返回值
1 | 一个含有被提取元素的新数组。 |
concat()
合并方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
1 | var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆']; |
参数
1 | var newArray = oldArray.concat(value1[, value2[, ...[, valueN]]]); |
返回值
1 | 一个合并后的新数组。 |
indexOf()
方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
1 | var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆','黄瓜']; |
参数
1 | arr.indexOf(searchElement[, fromIndex]) |
返回值
1 | 首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1 |
排序
冒泡排序
冒泡排序是一种比较简单的排序算法,这种算法是让越小或者越大的元素经由交换慢慢“浮”到数列的顶端,就像水里面的泡泡向上浮动一样,所以叫“冒泡排序”。 冒泡排序算法的原理如下:
1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个.
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码表现
1 | var arr = [4,6,3,2,7,9,11,1]; |
选择排序
选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
代码表现
1 | var arr = [4,6,3,2,7,9,11,1]; |
插入排序
插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
代码表现
1 | var arr = [4,6,3,2,7,9,11,1]; |
数组引用
数组属于对象object的一种,从数据类型上隶属于 引用类型
1 | 非引用关系的基础类型 在进行直接赋值的时候 会对赋值变量(右边)对应栈内存中空间所存储的值 赋值 给 被赋值变量(左边) |
1 | 引用类型进行直接变量赋值操作时 因为数组为引用类型 内容存储于堆内存中 栈内存只存储了数组的指针 所以数组变量直接作为赋值值时是将栈内存的指针赋值给了 接收变量 |
为了切断引用关系 我们可以选择进行 按顺序给新数组push或者赋值 或者使用slice()进行浅拷贝 后续会学习深拷贝
1 | var arr = [1,2,3]; |
案例
1 | 求一组数中的所有数的和和平均值 |
作业
1 | 一、看数组 观察变化找规律 |
字符串基础方法
charAt()
方法从一个字符串中返回指定的字符。
1 | var str ='你好,我是海牙老师'; |
参数
1 | index |
返回值
1 | 指定字符串 |
indexOf()
方法返回在字符串中可以找到一个给定字符的第一个首字对应索引,如果不存在,则返回-1。
1 | var plants = '西红柿,黄瓜,芹菜,豆角,土豆,黄瓜'; //length 18 |
参数
1 | str.indexOf(searchValue[, fromIndex]) |
返回值
1 | 查找的字符串 searchValue 的第一次出现的索引,如果没有找到,则返回 -1。 |
split()
方法使用指定的分隔符字符串将一个String对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。
1 | var str ='你好,我是海牙老师'; |
参数
1 | str.split([separator[, limit]]) |
返回值
1 | 返回源字符串以分隔符出现位置分隔而成的一个 数组(Array) |
slice()
方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。
1 | var str = 'The quick brown fox jumps over the lazy dog.'; |
参数
1 | str.slice(beginIndex[, endIndex]) |
返回值
1 | 返回一个从原字符串中提取出来的新字符串 |
trim()
方法会从一个字符串的两端删除空白字符。在这个上下文中的空白字符是所有的空白字符 (space, tab, no-break space 等) 以及所有行终止符字符(如 LF,CR等)。
1 | var greeting = ' Hello world! '; |
返回值
1 | 一个依据调用字符串两端去掉空白的新字符串。 |
JavaScript 函数
函数是程序的主要“构建模块”。函数使该段代码可以被调用很多次,而不需要写重复的代码。
我们已经看到了内置函数的示例,如
alert(message)
、prompt(message, default)
和confirm(question)
。但我们也可以创建自己的函数。函数在javascript中是
一等公民
函数定义
JavaScript 函数是被设计为执行特定任务的代码块。
JavaScript 函数会在某代码调用它时被执行。
什么是函数?
把一段相对独立的具有特定功能的代码块封装起来,形成一个独立实体,就是函数,起个名字(函数名),在后续开发中可以反复调用
函数的基础作用就是封装一段代码,将来可以重复使用。我们称之为 封装
函数示例
1 | function padLeft(num) { |
分解图

函数的类型
函数拥有自己的数据类型 在某些老版本浏览器中会辨识为 object 需要用 Object.prototype.toString.call()来进行判断
1 | function fn() {} |
函数的定义
函数的定义 有 函数表达式 和 函数声明 两种, 函数声明的时候,函数体并不会执行,只要当函数被调用的时候才会执行。
JavaScript 函数通过 function 关键词进行定义,其后是函数名和括号 ()。
函数名可包含字母、数字、下划线和美元符号(规则与变量名相同)。
- 函数声明
1 | function 函数名(){ |
- 函数表达式
1 | var 变量名 = function() { |
函数名:
函数一般都用来干一件事情,需用使用动词+名词 的驼峰结构命名,例如: setValue
clearInterval
等。
函数调用
函数有声明就有调用,函数内代码只有在调用时才会执行。函数可以多次调用。
1 | 函数名(); //主动调用 |
1 | //从指定数组中查询目标值 |
函数的参数
函数的参数分为 形参(parameter) 和 实参(argument) , 当函数需求根据不同的值做出不同反馈时, 就需要通过使用参数。 形参为声明函数时预设的形势参数,我们可以自定义命名。 实参为调用函数时对应 形参所传递的实际参数,为所需要的原始值。
为什么要有参数
1 | function getSum() { |
语法:
1 | // 函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部 |
对比:
- 形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。
- 实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。
1 | var x = 5, y = 6; |
注意:
如果函数调用时 没有传入实参 对应形参默认值为 undefined
JavaScript 参数通过值传递:函数只知道值,而不是参数的位置。
如果函数改变了参数的值,它不会改变参数的原始值。
参数的改变在函数之外是不可见的。
函数返回值
当 JavaScript 到达 return 语句,函数将停止执行。
如果函数被某条语句调用,JavaScript 将在调用语句之后“返回”执行代码。
返回值语法:
1 | //声明一个带返回值的函数 |
函数的调用结果就是返回值,因此我们可以直接对函数调用结果进行操作。
返回值详解:
如果函数没有显示的使用 return语句 ,那么函数有默认的返回值:undefined
如果函数使用 return语句,那么跟再return后面的值,就成了函数的返回值
如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined
函数使用return语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说return后面的所有其他代码都不会再执行。
arguments
JavaScript 函数有一个名为 arguments 对象的内置对象。
arguments 对象包含函数调用时使用的参数数组。
arguments为 (类数组)
这样,您就可以简单地使用函数来查找(例如)数字列表中的最高值:
实例
1 | jsx = findMax(1, 123, 500, 115, 44, 88); |
或创建一个函数来总和所有输入值:
实例
1 | jsx = sumAll(1, 123, 500, 115, 44, 88); |
函数分类
javascript非常适合函数式编程,这里简单介绍下几种基础函数方式的基础应用
纯函数
纯函数(Pure Function)
- 如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。
- 该函数不会产生任何可观察的副作用
1 | function padLeft(num) { |
非纯函数(函数副作用)
所谓”副作用”(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
1 | var str = '海牙'; |
匿名函数
匿名函数:没有名字的函数
匿名函数如何使用:
将匿名函数赋值给一个变量,这样就可以通过变量进行调用
匿名函数自调用
关于自执行函数(匿名函数自调用)的作用:防止全局变量污染。
自调用函数
匿名函数(IIFE)不能通过直接调用来执行,因此可以通过匿名函数的自调用的方式来执行
1 | (function () { |
柯理化函数
柯理化(currying)
函数可以用来作为返回值
函数柯里化允许和鼓励你分隔复杂功能变成更小更容易分析的部分。这些小的逻辑单元显然是更容易理解和测试的,然后你的应用就会变成干净而整洁的组合,由一些小单元组成的组合。
1 | //纯函数 |
回调函数
偏函数
递归函数
深度柯理化函数
通道函数
闭包
高阶函数
等函数式编程技巧会在后续学习中慢慢展开
作用域
作用域:变量可以起作用的范围
全局变量和局部变量
全局变量
在任何地方都可以访问到的变量就是全局变量,对应全局作用域
局部变量
只在固定的代码片段内可访问到的变量,最常见的例如函数内部。对应局部作用域(函数作用域)
1 | 不使用var声明的变量是全局变量,不推荐使用。 |
块级作用域
任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
在es5之前没有块级作用域的的概念,只有函数作用域,现阶段可以认为JavaScript没有块级作用域
词法作用域
变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。
在 js 中词法作用域规则:
- 函数允许访问函数外的数据.
- 整个代码结构中只有函数可以限定作用域.
- 作用域规则首先使用提升规则分析
- 如果当前作用规则中有名字了, 就不考虑外面的名字
1 | var num = 123; |
1 | if ( false ) { |
作用域链
只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。
1 | // 案例1: |
1 | // 案例2 |
预解析
JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
- 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
- 先提升var,在提升function
JavaScript的执行过程
1 | var a = 25; |
全局解析规则
函数内部解析规则
变量提升
变量提升
定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。
函数提升
JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面
1 | // 1、----------------------------------- |
对象 Object
什么是对象? 咱们要说的对象可不是
女朋友
, 在这个世界上 任何具体事物都可以看做对象
因为他们都有自己的特征、行为。
1 | 车子 手机 猫 是对象吗? |
JavaScript是一门基于对象的语言。
javascript中 我们称Object为 对象 对象的概念也分广义和狭义:广义上javascript中处处是对象,狭义指的是我们通过{}字面量创建的对象。
1 | JavaScript的对象是无序属性的集合。 |
字面量
字面量(literal)是用于表达源代码中一个固定值的表示法(notation).
几乎所有计算机编程语言都具有对基本值的字面量表示, 诸如: 整数, 浮点数以及字符串; 而有很多也对布尔类型和字符类型的值也支持字面量表示; 还有一些甚至对枚举类型的元素以及像数组, 记录和对象等复合类型的值也支持字面量表示法.
字面量(literal),在高级语言中 我们可以通过更直观更高效的方式直接赋予变量 具体
值
, 当需要使用值得时候 才会去根据值得类型和内容进行包装解析; 先存储 后解释 。
javascript中字面量包括
1. 字符串字面量(String Literal)
1 | var str = '张晓华'; //张晓华 就是字符串字面量 |
2.数组字面量(array literal)
1 | var arr = [1,2,3,4,5]; //[1,2,3,4,5] 就是数组字面量 |
3.对象字面量(object literal)
1 | var obj = { |
4.函数字面量(function literal)
1 | var fn = function(){ |
javascript中的内置对象
JavaScript中的对象分为3种:内置对象、浏览器对象、自定义对象
javascript是基于对象的语言, javascript不可以自己创建一个原生对象,只能访问内置对象属性和调用已有的内置对象方法。但是可以通过基于Object创建狭义概念上的
对象
。

1 | Number //数字 |
创建对象方式(自定义)
创建对象有三种基础方式: 对象字面量 原生对象实例化 自定义构造函数
- 字面量对象
1 | var myCat = { |
- 原生对象实例化 new Object()
1 | var myCat = new Object(); |
- 工厂函数创建对象
1 | function createCat(name,age,color){ |
- 自定义构造函数
1 | function Cat(name,age,color,favorite){ |
属性 方法
1 | 如果一个变量属于一个对象所有,那么该变量就可以称之为该对象的一个属性,属性一般是名词,用来描述事物的特征 |
instanceof
在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如:
1 | var oStringObject = new String("hello world"); |
构造函数
面向对象编程’的第一步,就是要生成对象。而js中面向对象编程是基于构造函数(constructor)和原型链(prototype)的。
前面说过,“对象”是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后“对象”根据这个模板生成。
js语言中使用构造函数(constructor)作为对象的模板。所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。
1 | function Person(name,age,sex){ //Person就是构造函数 |
1 | a:构造函数的函数名的第一个字母通常大写。 |
new关键字
构造函数 ,是一种特殊的函数。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
- 构造函数用于创建一类对象,首字母要大写。
- 构造函数要和new一起使用才有意义。
new在执行时会做四件事情
1 | 1 创建一个空对象,作为将要返回的对象实例。 |
this详解
JavaScript中的this指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解
现在我们需要掌握函数内部的this几个特点
1. 函数在定义的时候this是不确定的,只有在调用的时候才可以确定
2. 一般函数直接执行,内部this指向全局window
3. 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
4. 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到了这个隐式对象身上,后续通过new关键字来调用,从而实现实例化
对象的使用
遍历对象的属性
通过for..in语法可以遍历一个对象
1 |
|
删除对象的属性
1 | function fun() { |
JSON格式对象
JSON即Javascript对象表示方法 (Javascript Object Notation) ,也就是通过字面量来表示一个对象:
1 | JSON 英文全称 JavaScript Object Notation |
JSON 语法:
1 | 数据使用键名/值对表示,键名是字符串,值没有限定; |
JSON 示例:
1 | var nodeDate = { |
1 | var studentList = [ |
1 | var chinaMap = [ |
JSON方法API:
JSON.parse() 反序列化
将JSON数据解析为Javascript对象
方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的 reviver 函数用以在返回之前对所得到的对象执行变换(操作)。
1 | var json = '{"result":true, "count":42}'; |
参数
1 | JSON.parse(text[, reviver]) |
返回值
1 | Object 类型, 对应给定 JSON 文本的对象/值。 |
异常
1 | 若传入的字符串不符合 JSON 规范,则会抛出 SyntaxError 异常 |
JSON.stringify() 序列化
方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。
1 | console.log(JSON.stringify({ x: 5, y: 6 })); |
参数
1 | JSON.stringify(value[, replacer [, space]]) |
返回值
1 | 一个表示给定值的JSON字符串。 |
异常
1 | 当发现循环引用时,抛出类型错误TypeError(“循环对象值”)异常。 |
执行上下文
1. 什么是执行上下文
简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行
2. 执行上下文的类型
执行上下文总共有三种类型:
- 全局执行上下文: 这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。它做了两件事:1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。2. 将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。
- 函数执行上下文: 每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤,具体过程将在本文后面讨论。
- Eval 函数执行上下文: 运行在 eval 函数中的代码也获得了自己的执行上下文,但由于eval是魔鬼 我们一般不通过eval进行开发操作。
执行上下文的生命周期
执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段,本文重点介绍创建阶段。
1. 创建阶段
当函数被调用,但未执行任何其内部代码之前,会做以下三件事:
- 创建变量对象:首先初始化函数的参数 arguments,提升函数声明和变量声明。下文会详细说明。
- 创建作用域链(Scope Chain):在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。作用域链本身包含变量对象。作用域链用于解析变量。当被要求解析变量时,JavaScript 始终从代码嵌套的最内层开始,如果最内层没有找到变量,就会跳转到上一层父作用域中查找,直到找到该变量。
- 确定 this 指向:包括多种情况,下文会详细说明
在一段 JS 脚本执行之前,要先解析代码(所以说 JS 是解释执行的脚本语言),解析的时候会先创建一个全局执行上下文环境,先把代码中即将执行的变量、函数声明都拿出来。变量先暂时赋值为 undefined,函数则先声明好可使用。这一步做完了,然后再开始正式执行程序。
另外,一个函数在执行之前,也会创建一个函数执行上下文环境,跟全局上下文差不多,不过 函数执行上下文中会多出 this arguments 和函数的参数。
2. 执行阶段
执行变量赋值、代码执行
3. 回收阶段
执行上下文出栈等待虚拟机回收执行上下文
变量提升和 this 指向的细节
1. 变量声明提升
大部分编程语言都是先声明变量再使用,但在 JS 中,事情有些不一样:
1 | console.log(a); // undefined |
上述代码正常输出undefined
而不是报错Uncaught ReferenceError: a is not defined
,这是因为声明提升(hoisting),相当于如下代码:
1 | var a; //声明 默认值是undefined “准备工作” |
2. 函数声明提升
我们都知道,创建一个函数的方法有两种,一种是通过函数声明function foo(){}
另一种是通过函数表达式var foo = function(){}
,那这两种在函数提升有什么区别呢?
1 | console.log(f1); // function f1(){} |
接下来我们通过一个例子来说明这个问题:
1 | function test() { |
在上面的例子中,foo()调用的时候报错了,而 bar 能够正常调用。
我们前面说过变量和函数都会上升,遇到函数表达式 var foo = function(){}
时,首先会将var foo
上升到函数体顶部,然而此时的 foo 的值为 undefined,所以执行foo()
报错。
而对于函数bar()
, 则是提升了整个函数,所以bar()
才能够顺利执行。
有个细节必须注意:当遇到函数和变量同名且都会被提升的情况,函数声明优先级比较高,因此变量声明会被函数声明所覆盖,但是可以重新赋值。
1 | alert(a); //输出:function a(){ alert('我是函数') } |
function 声明的优先级比 var 声明高,也就意味着当两个同名变量同时被 function 和 var 声明时,function 声明会覆盖 var 声明
这代码等效于:
1 | function a() { |
最后我们看个复杂点的例子:
1 | function test(arg) { |
这是因为当函数执行的时候,首先会形成一个新的私有的作用域,然后依次按照如下的步骤执行:
- 如果有形参,先给形参赋值
- 进行私有作用域中的预解释,函数声明优先级比变量声明高,最后后者会被前者所覆盖,但是可以重新赋值
- 私有作用域中的代码从上到下执行
3. 确定 this 的指向
先搞明白一个很重要的概念 —— this 的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 —— 因为 this 是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子:
1 | // 情况1 |
接下来我们逐一解释上面几种情况
- 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window
- 对于 obj.foo() 来说,我们只需要记住,谁调用了函数, this指向谁,所以在这个场景下 foo 函数中的 this 就是 obj 对象
- 在构造函数模式中,类中(函数体中)出现的 this.xxx=xxx 中的 this 是当前类的一个实例
- IIFE匿名函数自调用时 因为没有明确调用主体 this指向 window。
执行上下文栈(Execution Context Stack)
函数多了,就有多个函数执行上下文,每次调用函数创建一个新的执行上下文,那如何管理创建的那么多执行上下文呢?
JavaScript 引擎创建了执行上下文栈来管理执行上下文。可以把执行上下文栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。
从上面的流程图,我们需要记住几个关键点:
- JavaScript 执行在单线程上,所有的代码都是排队执行。
- 一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。
- 每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收。
- 浏览器的 JS 执行引擎总是访问栈顶的执行上下文。
- 全局上下文只有唯一的一个,它在浏览器关闭时出栈。
我们再来看个例子:
1 | var color = "blue"; |
上述代码运行按照如下步骤:
- 当上述代码在浏览器中加载时,JavaScript 引擎会创建一个全局执行上下文并且将它推入当前的执行栈
- 调用 changeColor 函数时,此时 changeColor 函数内部代码还未执行,js 执行引擎立即创建一个 changeColor 的执行上下文(简称 EC),然后把这执行上下文压入到执行栈(简称 ECStack)中。
- 执行 changeColor 函数过程中,调用 swapColors 函数,同样地,swapColors 函数执行之前也创建了一个 swapColors 的执行上下文,并压入到执行栈中。
- swapColors 函数执行完成,swapColors 函数的执行上下文出栈,并且被销毁。
- changeColor 函数执行完成,changeColor 函数的执行上下文出栈,并且被销毁。
#包装对象
基础类型undefined、null、boolean、number、string和symbol 都是非引用类型(非对象)
之前我们学习了对象 了解到 对象具有属性和方法 也学习了字面量值 我们一起来看一个案例
1 | var str = '你好'; |
问题:
一个以string基础类型的字面量为值的变量str 是如何能够通过 . 操作执行方法的呢? str到底是对象 还是 字符串呢?
1 | var str = '你好'; |
#常用内置对象方法
javascript内置对象都提供了基本方法, 学习方法需要注意 参数 返回值 是否改变原对象 三个点。
MDN 官方文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects
Object方法
Object.is()
方法判断两个值是否为同一个值
1 | Object.is() 方法判断两个值是否为同一个值。如果满足以下条件则两个值相等: |
参数
1 | Object.is(value1, value2); |
返回值
1 | 一个 Boolean 类型标示两个参数是否是同一个值。 true or false |
Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。
freeze()
返回和传入的参数相同的对象。
1 | var obj = { |
参数
1 | Object.freeze(obj) |
返回值
1 | 被冻结的对象。 |
Object.assign()
方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
1 | var target = { a: 1, b: 2 }; |
参数
1 | Object.assign(target, ...sources) |
返回值
1 | 目标对象。 |
Object.keys()
方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
1 | Object.keys({a:1,b:2,c:3,d:5}); |
参数
1 | Object.keys(obj) |
返回值
1 | 一个表示给定对象的所有可枚举属性的字符串数组。 |
Array方法
forEach()
方法对数组的每个元素执行一次给定的函数。
1 | var items = ['item1', 'item2', 'item3']; |
参数
1 | arr.forEach(callback(currentValue [, index [, array]])[, thisArg]) |
返回值
1 | undefined |
sort()
方法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
1 | const months = ['March', 'Jan', 'Feb', 'Dec']; |
参数
1 | arr.sort( [,compareFunction(firstEl,secondEl)]) |
返回值
1 | 排序后的数组。请注意,数组已原地排序,不会产生新数组。 |
map()
方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
1 | var originArr = [1,2,3,4,5]; |
参数
1 | var new_array = arr.map(function callback(currentValue[, index[, array]]) { |
返回值
1 | 一个由原数组每个元素执行回调函数的结果组成的新数组。 |
filter()
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
1 | var arr = [ |
参数
1 | var newArray = arr.filter(callback(element[, index[, array]])[, thisArg]) |
返回值
1 | 一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。 |
reduce()
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
1 | var originArr = [3,4,5,6,7,8]; |
参数
1 | var newArray = arr.filter(callback(element[, index[, array]])[, thisArg]) |
返回值
1 | 函数累计处理的结果 |
lastIndexOf()
方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从
fromIndex
处开始。
1 | var array = [2, 5, 9, 2]; |
参数
1 | arr.lastIndexOf(searchElement[, fromIndex]) |
返回值
1 | 数组中该元素最后一次出现的索引,如未找到返回-1。 |
reverse()
方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。
1 | var array1 = ['one', 'two', 'three']; |
参数
1 | arr.reverse() |
返回值
1 | 颠倒后的数组。 |
splice()
方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
1 | var months = ['Jan', 'March', 'April', 'June']; |
参数
1 | array.splice(start[, deleteCount[, item1[, item2[, ...]]]]) |
返回值
1 | 由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。 |
includes()
方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
1 | var array1 = [1, 2, 3]; |
参数
1 | valueToFind |
返回值
1 | 返回一个布尔值 Boolean ,如果在数组中找到了(如果传入了 fromIndex ,表示在 fromIndex 指定的索引范围中找到了)则返回 true 。 |
flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
1 | var arr1 = [1, 2, [3, 4]]; |
参数
1 | var newArray = arr.flat([depth]) |
返回值
1 | 一个包含将数组与子数组中所有元素的新数组。 |
方法汇总
1 |
|
String方法
charCodeAt()
方法返回
0
到65535
之间的整数,表示给定索引处的 UTF-16 代码单元
1 | var str = '如果'; |
参数
1 | str.charCodeAt(index) |
返回值
1 | 指定 index 处字符的 UTF-16 代码单元值的一个数字;如果 index 超出范围,charCodeAt() 返回 NaN。 |
replace()
方法返回一个由替换值(
replacement
)替换部分或所有的模式(pattern
)匹配项后的新字符串。模式可以是一个字符串或者一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。如果pattern
是字符串,则仅替换第一个匹配项。
1 | var str = '如果你是春天,就请融化冰雪,让小草破土而出。如果你是夏天,就请用用各种各样的风,谱写快乐的乐章如果你是秋天,就让枫叶似火,洋溢丰收的喜悦;,如果你是冬天,就请做一位时装设计师,为大地披上雪白霓裳。'; |
参数
1 | str.replace(regexp|substr, newSubStr|function) |
返回值
1 | 一个部分或全部匹配由替代模式所取代的新的字符串。 |
slice()
方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。
1 | const str = 'The quick brown fox jumps over the lazy dog.'; |
参数
1 | str.slice(beginIndex[, endIndex]) |
返回值
1 | 返回一个从原字符串中提取出来的新字符串 |
方法汇总
1 | // 1 字符方法 |
案例
- 截取字符串”我爱中华人民共和国”,中的”中华”
1 | var s = "我爱中华人民共和国"; |
- “abcoefoxyozzopp”查找字符串中所有o出现的位置
1 | var s = 'abcoefoxyozzopp'; |
- 把字符串中所有的o替换成!
1 | var s = 'abcoefoxyozzopp'; |
- 判断一个字符串中出现次数最多的字符,统计这个次数
1 | var s = 'abcoefoxyozzopp'; |
Math对象方法
Math对象不是构造函数,它具有数学常数和函数的属性和方法,都是以静态成员的方式提供
跟数学相关的运算来找Math中的成员(求绝对值,取整)
Math静态属性
1 | Math.E //属性表示自然对数的底数(或称为基数),e,约等于 2.718。 |
Math.abs()
函数返回指定数字 “x“ 的绝对值。如下:
$$
{\mathtt{\operatorname{Math.abs}(x)}} = {|x|} = \begin{cases} x & \text{if} \quad x \geq 0 \ -x & \text{if} \quad x < 0 \end{cases}
$$
1 | Math.abs(x); //x为数值参数 |
Math.cos()
函数返回一个数值的余弦值。
1 | x |
Math.sin()
函数返回一个数值的正弦值。
1 | x |
Math.tan()
方法返回一个数值的正切值。
1 | Math.tan(x); |
Math.max()
函数返回一组数中的最大值。
1 | console.log(Math.max(1, 3, 2)); |
返回值
1 | 返回给定的一组数字中的最大值。如果给定的参数中至少有一个参数无法被转换成数字,则会返回 NaN。 |
Math.min()
函数返回一组数中的最大值。
1 | console.log(Math.min(1, 3, 2)); |
返回值
1 | 给定数值中最小的数。如果任一参数不能转换为数值,则返回NaN。 |
Math.pow()
函数返回基数(
base
)的指数(exponent
)次幂,即baseexponent
。
1 | console.log(Math.pow(7, 3)); |
返回值
1 | 返回base的exponent次幂结果 |
Math.random()
函数返回一个浮点, 伪随机数在范围从0到小于1,也就是说,从0(包括0)往上,但是不包括1(排除1),然后您可以缩放到所需的范围。实现将初始种子选择到随机数生成算法;它不能被用户选择或重置。
1 | function getRandomInt(max) { |
返回值
1 | 一个浮点型伪随机数字,在0(包括0)和1(不包括)之间。 |
Math.round()
函数返回一个数字四舍五入后最接近的整数
1 | Math.round(20.49) //20 |
返回值
1 | 四舍五入后的值 |
Math.floor()
返回小于或等于一个给定数字的最大整数 : 向下取整
1 | Math.floor(x); |
返回值
1 | 一个表示小于或等于指定数字的最大整数的数字。 |
Math.ceil()
函数返回大于或等于一个给定数字的最小整数
1 | Math.ceil(x); |
返回值
1 | 大于或等于给定数字的最小整数。 |
方法汇总
1 | Math.PI // 圆周率 |
Date对象方法
创建
Date
实例用来处理日期和时间。Date 对象基于1970年1月1日(世界标准时间)起的毫秒数。
1 | // 获取当前时间,UTC世界时间,距1970年1月1日(世界标准时间)起的毫秒数 |
- 获取日期的毫秒形式
1 | var now = new Date(); |
- 日期格式化方法
1 | toString() // 转换成字符串 |
- 获取日期指定部分
1 | getTime() // 返回毫秒数和valueOf()结果一样,valueOf()内部调用的getTime() |
案例
- 写一个函数,格式化日期对象,返回yyyy-MM-dd HH:mm:ss的形式
1 | function formatDate(d) { |
- 计算时间差,返回相差的天/时/分/秒
1 | function getInterval(start, end) { |