update: refactor
This commit is contained in:
325
04-JavaScript基础/01-JS简介.md
Normal file
325
04-JavaScript基础/01-JS简介.md
Normal file
@@ -0,0 +1,325 @@
|
||||
|
||||
|
||||
> 本文最初发表于[博客园](https://www.cnblogs.com/smyhvae/p/8303507.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
|
||||
## JavaScript背景
|
||||
|
||||
Web前端有三层:
|
||||
|
||||
- HTML:从语义的角度,描述页面**结构**
|
||||
|
||||
- CSS:从审美的角度,描述**样式**(美化页面)
|
||||
|
||||
- JavaScript:从交互的角度,描述**行为**(提升用户体验)
|
||||
|
||||
JavaScript是世界上用的最多的**脚本语言**。
|
||||
|
||||
### 发展历史
|
||||
|
||||
JavaScript诞生于**1995年**。布兰登 • 艾奇(Brendan Eich,1961年~),1995年在网景公司,发明的JavaScript。
|
||||
|
||||
JavaScript是由**网景**公司发明,起初命名为LiveScript,后来由于SUN公司的介入更名为了JavaScript。
|
||||
|
||||
> 备注:由于当时Java这个语言特别火,所以为了傍大牌,就改名为JavaScript。如同“北大”和“北大青鸟”的关系。“北大青鸟”就是傍“北大”大牌。
|
||||
|
||||
同时期还有其他的网页语言,比如VBScript、JScript等等,但是后来都被JavaScript打败了,所以现在的浏览器中,只运行一种脚本语言就是JavaScript。
|
||||
|
||||
### JavaScript和ECMAScript的关系
|
||||
|
||||
ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)制定和发布的脚本语言规范。
|
||||
|
||||
JavaScript是由公司开发而成的,问题是不便于其他的公司拓展和使用。所以欧洲的这个ECMA的组织,牵头制定JavaScript的标准,取名为ECMAScript。
|
||||
|
||||
简单来说,**ECMAScript不是一门语言,而是一个标准**。
|
||||
|
||||
ECMAScript在2015年6月,发布了ECMAScript 6版本(ES6),语言的能力更强(也包含了很多新特性)。但是,浏览器的厂商不会那么快去追上这个标准,需要时间。
|
||||
|
||||
### JavaScript的发展:蒸蒸日上
|
||||
|
||||
2003年之前,JavaScript被认为“牛皮鲜”,用来制作页面上的广告,弹窗、漂浮的广告。什么东西让人烦,什么东西就是JavaScript开发的。所以很多浏览器就推出了屏蔽广告功能。
|
||||
|
||||
2004年,JavaScript命运开始改变。那一年,**谷歌公司开始带头使用Ajax技术**,Ajax技术就是JavaScript的一个应用。并且,那时候人们逐渐开始提升用户体验了。Ajax有一些应用场景。比如,当我们在百度搜索框搜文字时,输入框下方的智能提示,可以通过Ajax实现。比如,当我们注册网易邮箱时,能够及时发现用户名是否被占用,而不用调到另外一个页面。
|
||||
|
||||
2007年乔布斯发布了第一款iPhone,这一年开始,用户就多了上网的途径,就是用移动设备上网。
|
||||
**JavaScript在移动页面中,也是不可或缺的**。并且这一年,互联网开始标准化,按照W3C规则三层分离,JavaScript越来越被重视。
|
||||
|
||||
2010年,人们更加了解**HTML5技术**,**HTML5推出了一个东西叫做Canvas**(画布),工程师可以在Canvas上进行游戏制作,利用的就是JavaScript。
|
||||
|
||||
2011年,**Node.js诞生**,使JavaScript能够开发服务器程序了。
|
||||
|
||||
如今,**WebApp**已经非常流行,就是用**网页技术开发手机应用**。手机系统有iOS、安卓。比如公司要开发一个“携程网”App,就需要招聘三队人马,比如iOS工程师10人,安卓工程师10人,前端工程师10人。共30人,开发成本大;而且如果要改版,要改3个版本。现在,假设公司都用web技术,用html+css+javascript技术就可以开发App。也易于迭代(网页一改变,所有的终端都变了)。
|
||||
|
||||
虽然目前WebApp在功能和性能上的体验远不如Native App,但是“WebApp慢慢取代Native App”很有可能是未来的趋势。
|
||||
|
||||
|
||||
## JavaScript介绍
|
||||
|
||||
### JavaScript入门易学性
|
||||
|
||||
- JavaScript对初学者比较友好。
|
||||
|
||||
- JavaScript是有界面效果的(比如C语言却只有白底黑字)。
|
||||
|
||||
- JavaScript是**弱变量类型**的语言,变量只需要用var来声明。而Java中变量的声明,要根据变量的类型来定义。
|
||||
|
||||
比如Java中需要定义如下变量:
|
||||
|
||||
```java
|
||||
int a;
|
||||
float a;
|
||||
double a;
|
||||
String a;
|
||||
boolean a;
|
||||
```
|
||||
|
||||
而JavaScript中,只需要用一种方式来定义:
|
||||
|
||||
```JavaScript
|
||||
var a;
|
||||
```
|
||||
|
||||
- JavaScript不用关心其他的一些事情(比如内存的释放、指针等),更关心自己的业务。
|
||||
|
||||
### 浏览器工作原理
|
||||
|
||||

|
||||
|
||||
1、User Interface 用户界面,我们所看到的浏览器
|
||||
|
||||
2、Browser engine 浏览器引擎,用来查询和操作渲染引擎
|
||||
|
||||
3、Rendering engine 用来显示请求的内容,负责解析HTML、CSS
|
||||
|
||||
4、Networking 网络,负责发送网络请求
|
||||
|
||||
5、JavaScript Interpreter(解析者) JavaScript解析器,负责执行JavaScript的代码
|
||||
|
||||
6、UI Backend UI后端,用来绘制类似组合框和弹出窗口
|
||||
|
||||
7、Data Persistence(持久化) 数据持久化,数据存储 cookie、HTML5中的sessionStorage
|
||||
|
||||
参考链接:<https://www.2cto.com/kf/201202/118111.html>
|
||||
|
||||
### JavaScript是前台语言
|
||||
|
||||
JavaScript是前台语言,而不是后台语言。
|
||||
|
||||
JavaScript运行在用户的终端网页上,而不是服务器上,所以我们称为“**前台语言**”。就是服务于页面的交互效果、美化,不能操作数据库。
|
||||
|
||||
**后台语言**是运行在服务器上的,比如PHP、ASP、JSP等等,这些语言都能够操作数据库,都能够对数据库进行“增删改查”操作。Node.js除外。
|
||||
|
||||
### JavaScript的组成
|
||||
|
||||
JavaScript基础分为三个部分:
|
||||
|
||||
- ECMAScript:JavaScript的语法标准。包括变量、表达式、运算符、函数、if语句、for语句等。
|
||||
|
||||
- **DOM**:文档对象模型,操作**网页上的元素**的API。比如让盒子移动、变色、轮播图等。
|
||||
|
||||
- **BOM**:浏览器对象模型,操作**浏览器部分功能**的API。比如让浏览器自动滚动。
|
||||
|
||||
PS:JS机械重复性的劳动几乎为0,基本都是创造性的劳动。而不像HTML、CSS中margin、padding都是机械重复劳动。
|
||||
|
||||
### JavaScript的特点
|
||||
|
||||
(1)简单易用:可以使用任何文本编辑工具编写,只需要浏览器就可以执行程序。
|
||||
|
||||
(2)**解释型语言**:事先不需要被编译为机器码再执行,逐行执行、无需进行严格的变量声明。
|
||||
|
||||
> 由于少了编译这一步骤,所以解释型语言开发起来尤为轻松,但是解释型语言运行较慢也是它的劣势。不过解释型语言中使用了JIT技术,使得运行速度得以改善。
|
||||
|
||||
(3)基于对象:内置大量现成对象,编写少量程序可以完成目标
|
||||
|
||||
### 编程语言的分类
|
||||
|
||||
- 解释型语言:**边解析边执行**,不需要事先编译。例如:JavaScript、php。
|
||||
|
||||
- 编译型语言:事先把所有的代码翻译成计算机能够执行的指令,然后整体执行。例如:c、c++。
|
||||
|
||||
## 开始写第一行JavaScript代码
|
||||
|
||||
### JavaScript代码的书写位置
|
||||
|
||||
(1)内嵌的方式:
|
||||
|
||||
页面中,我们可以在`<body>`标签里放入`<script type=”text/javascript”></script>`标签对儿,并在`<script>`里书写JavaScript程序:
|
||||
|
||||
```
|
||||
<script type="text/javascript">
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
text表示纯文本,因为JavaScript也是一个纯文本的语言。
|
||||
|
||||
PS:在Sublime Text里,输入`<sc`后,按tab键,可以自动补齐。
|
||||
|
||||
(2)外链式:引入外部JavaScript文件(放到body标签里,可以和内嵌的js代码并列)
|
||||
|
||||
```
|
||||
<script src="tool.js"></script>
|
||||
```
|
||||
|
||||
### alert语句
|
||||
|
||||
我们要学习的第一个语句,就是alert语句。
|
||||
|
||||
```
|
||||
<script type="text/javascript">
|
||||
alert("生命壹号");
|
||||
</script>
|
||||
```
|
||||
|
||||
**alert**(英文翻译为“警报”)的用途:**弹出“警告框”**。
|
||||
|
||||
`alert("")`警告框的效果如下:
|
||||
|
||||

|
||||
|
||||
这个警告框,在IE浏览器中长这样:
|
||||
|
||||

|
||||
|
||||
上面的代码中,如果写了两个alert()语句的话,网页的效果是:弹出第一个警告框,点击确定后,继续弹出第二个警告框。
|
||||
|
||||
### 语法规则
|
||||
|
||||
学习程序,是有规律可循的,就是程序是有相同的部分,这些部分就是一种规定,不能更改,我们成为:语法。
|
||||
|
||||
(1)JavaScript对换行、缩进、空格不敏感。每一条语句以分号结尾。
|
||||
|
||||
也就是说:
|
||||
|
||||
代码一:
|
||||
|
||||
```
|
||||
<script type="text/javascript">
|
||||
alert("今天蓝天白云");
|
||||
alert("我很高兴");
|
||||
</script>
|
||||
```
|
||||
|
||||
等价于代码二:
|
||||
|
||||
```
|
||||
<script type="text/javascript">
|
||||
alert("今天蓝天白云");alert("我很高兴");
|
||||
</script>
|
||||
```
|
||||
|
||||
备注:每一条语句末尾要加上分号,虽然分号不是必须加的,如果不写分号,浏览器会自动添加,但是会消耗一些系统资源。
|
||||
|
||||
(2)所有的符号,都是英语的。比如**括号**、引号、分号。
|
||||
|
||||
如果你用的是搜狗拼音,**建议不要用shift切换中英文**(可以在搜狗软件里进行设置),不然很容易输入中文的分号;建议用ctrl+space切换中英文输入法。
|
||||
|
||||
(3)严格区分大小写
|
||||
|
||||
### 注释
|
||||
|
||||
我们不要把html、CSS、JavaScript三者的注释格式搞混淆了。
|
||||
|
||||
(1)**html的注释:**
|
||||
|
||||
```html
|
||||
<!-- 我是注释 -->
|
||||
```
|
||||
|
||||
(2)**CSS的注释:**
|
||||
|
||||
```html
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
我是注释
|
||||
*/
|
||||
|
||||
p{
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
color: red;
|
||||
}
|
||||
|
||||
</style>
|
||||
```
|
||||
|
||||
注意:CSS只有`/* */`这种注释,没有`//`这种注释。而且注释要写在`<style>`标签里面才算生效哦。
|
||||
|
||||
(3)**JavaScript的注释:**
|
||||
|
||||
单行注释:
|
||||
|
||||
```
|
||||
// 我是注释
|
||||
```
|
||||
|
||||
多行注释:
|
||||
|
||||
```
|
||||
/*
|
||||
多行注释1
|
||||
多行注释2
|
||||
*/
|
||||
```
|
||||
|
||||
备注:sublime中,单行注释的快捷键是`ctrl+/`,多行注释的快捷键是`ctrl+shift+/`。
|
||||
|
||||
## Javascript 网页中输出信息的写法
|
||||
|
||||
### 弹出警告框:alert("")
|
||||
|
||||
我们在上一段讲到了alert语句,这里不再赘述。
|
||||
|
||||
### 控制台输出:console.log("")
|
||||
|
||||
`console.log("")`表示在控制台中输出。console表示“控制台”,log表示“输出”。
|
||||
|
||||
控制台在Chrome浏览器的F12中。控制台是工程师、程序员调试程序的地方。程序员经常使用这条语句输出一些东西,来测试程序是否正确。
|
||||
|
||||
`console.log("")`效果如下:
|
||||
|
||||

|
||||
|
||||
普通人是不会在意控制台的,但是有些网站另藏玄机。有个很有意思的地方是,百度首页的控制台,悄悄地放了一段招聘信息:
|
||||
|
||||

|
||||
|
||||
毕竟做前端的人是经常使用控制台的。
|
||||
|
||||
接下来,我们开始学习JavaScript语法。
|
||||
|
||||
### 用户输入:prompt()语句
|
||||
|
||||
`prompt()`就是专门用来弹出能够让用户输入的对话框。用得少,测试的时候可能会用。
|
||||
|
||||
JS代码如下:
|
||||
|
||||
```javascript
|
||||
var a = prompt("请随便输入点什么东西吧");
|
||||
console.log(a);
|
||||
```
|
||||
|
||||
上方代码中,用户输入的内容,将被传递到变量 a 里面。
|
||||
|
||||
效果如下:
|
||||
|
||||

|
||||
|
||||
**prompt()语句中,用户不管输入什么内容,都是字符串。**
|
||||
|
||||
**alert和prompt的区别:**
|
||||
|
||||
```javascript
|
||||
alert("从前有座山"); //直接使用,不需要变量
|
||||
var a = prompt("请输入一个数字"); // 必须用一个变量,来接收用户输入的值
|
||||
```
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
587
04-JavaScript基础/02-变量.md
Normal file
587
04-JavaScript基础/02-变量.md
Normal file
@@ -0,0 +1,587 @@
|
||||
|
||||
## 字面量:数字和字符串
|
||||
|
||||
“字面量”即**常量**,是固定值,不可改变。看见什么,它就是什么。
|
||||
|
||||
简单的字面量有2种:数字、字符串。
|
||||
|
||||
(1)数值的字面量非常简单,写上去就行了,不需要任何的符号。例如:
|
||||
|
||||
```javascript
|
||||
1 alert(886); //886是数字,所以不需要加引号。
|
||||
```
|
||||
|
||||
(2)字符串的字面量也很简单,但一定要加上引号。可以是单词、句子等。
|
||||
|
||||
温馨提示:100是数字,"100"是字符串。
|
||||
|
||||
### 总结
|
||||
|
||||
字面量都可以直接使用,但是我们一般不会直接使用字面量。
|
||||
|
||||
如果直接使用字面量的话,非常麻烦。比如说,多个地方要用到同一个字面量,还不如事先定义一个变量,用来保存字面量。
|
||||
|
||||
变量更加方便我们使用,所以在开发中都是通过变量去保存一个字面量,而不会直接使用字面量。
|
||||
|
||||
## 变量
|
||||
|
||||
|
||||
### 变量的概念
|
||||
|
||||
**变量**:变量可以用来保存字面量,而且变量的值可以任意改变。
|
||||
|
||||
|
||||
### 变量的定义和赋值
|
||||
|
||||
在js中使用`var`关键字来声明一个变量。
|
||||
|
||||
变量举例如下:
|
||||
|
||||
```javascript
|
||||
var a = 100;
|
||||
```
|
||||
|
||||
如下图所示:
|
||||
|
||||

|
||||
|
||||
var是英语“variant”变量的缩写。后面要加一个空格,空格后面的东西就是“变量名”:
|
||||
|
||||
- 定义变量:var就是一个**关键字**,用来定义变量。所谓关键字,就是有特殊功能的小词语。关键字后面一定要有空格隔开。
|
||||
|
||||
- 变量的赋值:等号表示**赋值**,将等号右边的值,赋给左边的变量。
|
||||
|
||||
- 变量名:我们可以给变量任意的取名字。
|
||||
|
||||
PS:**在JavaScript中,永远都是用var来定义变量**(在ES6 之前),这和C、Java等语言不同。
|
||||
|
||||
变量要先定义,才能使用。比如,我们不设置变量,直接输出:
|
||||
|
||||
```html
|
||||
<script type="text/javascript">
|
||||
console.log(a);
|
||||
</script>
|
||||
```
|
||||
|
||||
控制台将会报错:
|
||||
|
||||

|
||||
|
||||
正确写法:
|
||||
|
||||
```javascript
|
||||
var a; // 定义
|
||||
a = 100; //赋值
|
||||
console.log(a); //输出100
|
||||
```
|
||||
|
||||
有经验的程序员,会把定义和赋值写在一起:
|
||||
|
||||
```javascript
|
||||
var a = 100; //定义,并且赋值100
|
||||
console.log(a); //输出100
|
||||
```
|
||||
|
||||
### 变量的命名规范
|
||||
|
||||
变量名有命名规范:只能由英语字母、数字、下划线、美元符号$构成,且不能以数字开头,并且不能是JavaScript保留字。
|
||||
|
||||
下列的单词,叫做保留字,就是说不允许当做变量名,不用记:
|
||||
|
||||
```
|
||||
abstract、boolean、byte、char、class、const、debugger、double、enum、export、extends、final、float、goto
|
||||
implements、import、int、interface、long、native、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile
|
||||
```
|
||||
|
||||
大写字母是可以使用的,并且大小写敏感。也就是说A和a是两个变量。
|
||||
|
||||
```javascript
|
||||
var A = 250; //变量1
|
||||
var a = 888; //变量2
|
||||
```
|
||||
|
||||
我们来整理一下**变量的命名规则**:
|
||||
|
||||
1.建议用驼峰命名规则:getElementById/matherAndFather/aaaOrBbbAndCcc
|
||||
|
||||
2.变量命名必须以字母或是下标符号”_”或者”$”为开头。
|
||||
|
||||
3.变量名长度不能超过255个字符。
|
||||
|
||||
4.变量名中不允许使用空格,首个字不能为数字。
|
||||
|
||||
5.不用使用脚本语言中保留的**关键字**及**保留字**作为变量名。
|
||||
|
||||
6.变量名区分大小写(javascript是区分大小写的语言)。
|
||||
|
||||
7.汉语可以作为变量名。但是不建议使用,因为 low。
|
||||
|
||||
|
||||
## 标识符
|
||||
|
||||
**标识符**:在JS中所有的可以由我们**自主命名**的都可以称之为标识符。
|
||||
|
||||
例如:变量名、函数名、属性名都是属于标识符。
|
||||
|
||||
**标识符的命名规则**和变量的命令规则是一样的。看上面一段就可以了。
|
||||
|
||||
重点要注意的是:标识符不能使用脚本语言中保留的**关键字**及**保留字**。如下。
|
||||
|
||||
**关键字**:
|
||||
|
||||

|
||||
|
||||
**保留字**:
|
||||
|
||||

|
||||
|
||||
|
||||
**其他不建议使用的标识符**:
|
||||
|
||||

|
||||
|
||||
|
||||
## 变量的数据类型
|
||||
|
||||
变量里面能够存储数字、字符串等。变量会自动的根据存储内容的类型不同,来决定自己的类型。
|
||||
|
||||
**在JS中一共有六种数据类型**:
|
||||
|
||||
|
||||
- **基本数据类型(值类型)**:String 字符串、Number 数值、Boolean 布尔值、Null 空值、Undefined 未定义。
|
||||
|
||||
- **引用数据类型(引用类型)**:Object 对象。
|
||||
|
||||
注意:内置对象function、Array、Date、RegExp、Error等都是属于Object类型。也就是说,除了那五种基本数据类型之外,其他的,都称之为 Object类型。
|
||||
|
||||
> 面试问:引用数据类型有几种?
|
||||
|
||||
> 面试答:只有一种,即 Object 类型。
|
||||
|
||||
**数据类型之间最大的区别**:
|
||||
|
||||
- 基本数据类型:参数赋值的时候,传数值。
|
||||
|
||||
- 引用数据类型:参数赋值的时候,传地址(修改的同一片内存空间)。
|
||||
|
||||
接下来,我们详细讲一下基本数据类型。
|
||||
|
||||
## String 字符串
|
||||
|
||||
来看个示例。现有如下代码:
|
||||
|
||||
```javascript
|
||||
var a = "abcde";
|
||||
var b = "生命壹号";
|
||||
var c = "123123";
|
||||
var d = "哈哈哈哈哈";
|
||||
var e = ""; //空字符串
|
||||
|
||||
console.log(typeof a);
|
||||
console.log(typeof b);
|
||||
console.log(typeof c);
|
||||
console.log(typeof d);
|
||||
console.log(typeof e);
|
||||
```
|
||||
|
||||
控制台输出如下:
|
||||
|
||||
```
|
||||
string
|
||||
string
|
||||
string
|
||||
string
|
||||
string
|
||||
```
|
||||
|
||||
注意事项:
|
||||
|
||||
(1)在JS中,字符串需要使用引号引起来。使用双引号或单引号都可以,但是不要混着用。比如下面这样写是不可以的:
|
||||
|
||||
```
|
||||
var str = `hello";
|
||||
```
|
||||
|
||||
(2)引号不能嵌套:双引号里不能再放双引号,单引号里不能再放单引号。但是单引号里可以嵌套双引号。
|
||||
|
||||
(3)**转义字符**:在字符串中我们可以使用`\`作为转义字符,当表示一些特殊符号时可以使用`\`进行转义。
|
||||
|
||||
|
||||
- `\"` 表示 `"`
|
||||
|
||||
- `\'` 表示 `'`
|
||||
|
||||
- `\n` 表示换行
|
||||
|
||||
- `\r` 表示回车
|
||||
|
||||
- `\t` 表示制表符
|
||||
|
||||
- `\b` 表示空格
|
||||
|
||||
- `\\` 表示`\`
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var str1 = "我说:\"今天\t天气真不错!\"";
|
||||
var str2 = "\\\\\\";
|
||||
|
||||
console.log(str1);
|
||||
console.log(str2);
|
||||
```
|
||||
|
||||
|
||||
上方代码的打印结果:
|
||||
|
||||
```
|
||||
我说:"今天 天气真不错!"
|
||||
\\\
|
||||
```
|
||||
|
||||
将其他数值转换为字符串有三种方式:
|
||||
|
||||
- 拼串
|
||||
|
||||
- toString()
|
||||
|
||||
- String()
|
||||
|
||||
|
||||
### 补充知识:typeof 运算符
|
||||
|
||||
`typeof()`表示“**获取变量的类型**”,返回的是小写,语法为:
|
||||
|
||||
```
|
||||
typeof 变量
|
||||
```
|
||||
|
||||
**返回结果**:
|
||||
|
||||
- `typeof 数值`的返回结果:number
|
||||
|
||||
- `typeof 字符串`的返回结果:string
|
||||
|
||||
- `typeof 布尔型`的返回结果:boolean
|
||||
|
||||
- `typeof undefined`的返回结果:undefined
|
||||
|
||||
- `typeof null`的返回结果:object
|
||||
|
||||
在JavaScript中,只要是数,就是 number 数值型的。无论整浮、浮点数(即小数)、无论大小、无论正负,都是 number 类型的。
|
||||
|
||||
|
||||
## 数值型:Number
|
||||
|
||||
在JS中所有的数值都是Number类型,包括整数和浮点数(小数)。
|
||||
|
||||
```javascript
|
||||
var a = 100; //定义了一个变量a,并且赋值100
|
||||
console.log(typeof a); //输出a变量的类型
|
||||
```
|
||||
|
||||
上方代码的输出结果为:
|
||||
|
||||
```
|
||||
number
|
||||
```
|
||||
|
||||
|
||||
**数值范围:**
|
||||
|
||||
由于内存的限制,ECMAScript 并不能保存世界上所有的数值。
|
||||
|
||||
- 最大值:`Number.MAX_VALUE`,这个值为: 1.7976931348623157e+308
|
||||
|
||||
- 最小值:`Number.MIN_VALUE`,这个值为: 5e-324
|
||||
|
||||
如果使用Number表示的变量超过了最大值,则会返回Infinity。
|
||||
|
||||
- 无穷大(正无穷):Infinity
|
||||
|
||||
- 无穷小(负无穷):-Infinity
|
||||
|
||||
注意:`typeof Infinity`的返回结果是number。
|
||||
|
||||
|
||||
**NaN和isNaN()函数:**
|
||||
|
||||
(1)NaN:是一个特殊的数字,表示Not a Number,非数值。比如:
|
||||
|
||||
```javascript
|
||||
console.log("abc" / 18); //结果是NaN
|
||||
|
||||
console.log("abc" * "abcd"); //按理说,字符串相乘是没有结果的,但如果你非要让JS去算,它就一定会给你一个结果。结果是NaN
|
||||
```
|
||||
|
||||
注意:`typeof NaN`的返回结果是number。
|
||||
|
||||
Undefined和任何数值计算的结果为NaN。NaN 与任何值都不相等,包括 NaN 本身。
|
||||
|
||||
(2)isNaN() :任何不能被转换为数值的值,都会让这个函数返回 true。
|
||||
|
||||
```javascript
|
||||
isNaN(NaN);// true
|
||||
isNaN("blue"); // true
|
||||
isNaN(123); // false
|
||||
|
||||
```
|
||||
|
||||
**浮点数的运算**:
|
||||
|
||||
在JS中,整数的运算**基本**可以保证精确;但是**小数的运算,可能会得到一个不精确的结果**。所以,千万不要使用JS进行对精确度要求比较高的运算。
|
||||
|
||||
如下:
|
||||
|
||||
```javascript
|
||||
var a = 0.1 + 0.2;
|
||||
console.log(a); //打印结果:0.30000000000000004
|
||||
```
|
||||
|
||||
上方代码中,打印结果并不是0.3,而是0.30000000000000004。
|
||||
|
||||
我们知道,所有的运算都要转换成二进制去计算,然而,二进制是无法精确表示1/10的。因此存在小数的计算不精确的问题。
|
||||
|
||||
### 连字符和加号的区别
|
||||
|
||||
键盘上的`+`可能是连字符,也可能是数字的加号。如下:
|
||||
|
||||
```
|
||||
console.log("我" + "爱" + "你"); //连字符,把三个独立的汉字,连接在一起了
|
||||
console.log("我+爱+你"); //原样输出
|
||||
console.log(1+2+3); //输出6
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```
|
||||
我爱你
|
||||
我+爱+你
|
||||
6
|
||||
```
|
||||
|
||||
**总结**:如果加号两边**都是**数值,此时是加。否则,就是连字符(用来连接字符串)。
|
||||
|
||||
举例1:
|
||||
|
||||
```javascript
|
||||
var a = "1";
|
||||
var b = 2;
|
||||
console.log(a + b);
|
||||
```
|
||||
|
||||
控制台输出:
|
||||
|
||||
```
|
||||
12
|
||||
```
|
||||
|
||||
举例2:
|
||||
|
||||
```
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
console.log("a" + b); //"a"就不是变量了!所以就是"a"+2 输出a2
|
||||
|
||||
```
|
||||
|
||||
控制台输出:
|
||||
|
||||
```
|
||||
a2
|
||||
```
|
||||
|
||||
于是我们明白了,在变量中加入字符串进行拼接,可以被同化为字符串。【重要】
|
||||
|
||||
|
||||
### 隐式转换
|
||||
|
||||
我们知道,`"2"+1`得到的结果其实是字符串,但是`"2"-1`得到的结果却是数值1,这是因为计算机自动帮我们进行了“**隐式转换**”。
|
||||
|
||||
也就是说,`-`、`*`、`/`、`%``这几个符号会自动进行隐式转换。例如:
|
||||
|
||||
```javascript
|
||||
var a = "4" + 3 - 6;
|
||||
console.log(a);
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
```javascript
|
||||
37
|
||||
```
|
||||
|
||||
虽然程序可以对`-`、`*`、`/`、`%``这几个符号自动进行“隐式转换”;但作为程序员,我们最好自己完成转换,方便程序的可读性。
|
||||
|
||||
|
||||
## 布尔值:Boolean
|
||||
|
||||
true 和 false。主要用来做逻辑判断。
|
||||
|
||||
布尔值直接使用就可以了,千万不要加上引号。
|
||||
|
||||
代码:
|
||||
|
||||
```javascript
|
||||
var a = true;
|
||||
console.log(typeof a);
|
||||
```
|
||||
|
||||
控制台输出结果:
|
||||
|
||||
```
|
||||
boolean
|
||||
```
|
||||
|
||||
|
||||
## null和undefined
|
||||
|
||||
### `null`:空值
|
||||
|
||||
专门用来表示一个为空的**对象**(例如:`var a = null`)。注意,专门用来表示**空对象**。
|
||||
|
||||
|
||||
- Null类型的值只有一个,就是null。比如:`var a = null`。
|
||||
|
||||
|
||||
- 使用 typeof 检查一个null值时,会返回object。
|
||||
|
||||
### `undefined`:未定义
|
||||
|
||||
**声明**了一个变量,但是没有**赋值**(例如:`var a;`),此时它的值就是undefined。
|
||||
|
||||
- Undefined类型的值只有一个,就是undefind
|
||||
|
||||
- 使用 type of 检查一个undefined时,会返回undefined。
|
||||
|
||||
null和undefined有最大的相似性。看看null == undefined的结果(true)也就更加能说明这点。
|
||||
|
||||
但是null === undefined的结果(false)。它们虽然相似,但还是有区别的,其中一个区别是:和数字运算时,10 + null结果为:10;10 + undefined结果为:NaN。
|
||||
|
||||
- 任何数据类型和undefined运算都是NaN;
|
||||
|
||||
- 任何值和null运算,null可看做0运算。
|
||||
|
||||
## 变量值的传递(赋值)
|
||||
|
||||
语句:
|
||||
|
||||
```
|
||||
a = b;
|
||||
```
|
||||
|
||||
把b的值赋给a,b不变。
|
||||
|
||||
将等号右边的值,赋给左边的变量;等号右边的变量,值不变。
|
||||
|
||||
来做几个题目。
|
||||
|
||||
举例1:
|
||||
|
||||
```
|
||||
//a b c
|
||||
var a = 1; //1
|
||||
var b = 2; //1 2
|
||||
var c = 3; //1 2 3
|
||||
a = b + c; //5 2 3
|
||||
b = c - a; //5 -2 3
|
||||
c = a * b; //5 -2 -10
|
||||
console.log(a);
|
||||
console.log(b);
|
||||
console.log(c);
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```
|
||||
5
|
||||
-2
|
||||
-10
|
||||
```
|
||||
|
||||
举例2:
|
||||
|
||||
```
|
||||
//a b c
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var c = 3; //1 2 3
|
||||
a = a + b; //3 2 3
|
||||
b = b + a; //3 5 3
|
||||
c = c + b; //3 5 8
|
||||
console.log(a); //3
|
||||
console.log(b); //5
|
||||
console.log(c); //8
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```
|
||||
3
|
||||
5
|
||||
8
|
||||
```
|
||||
|
||||
举例3:
|
||||
|
||||
```
|
||||
//a b
|
||||
var a = "1";
|
||||
var b = 2; //"1" 2
|
||||
a = a + b; //"12" 2
|
||||
b = b + a; //"12" "212"
|
||||
console.log(a); //输出12
|
||||
console.log(b); //输出212
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```
|
||||
12
|
||||
212
|
||||
```
|
||||
|
||||
举例4:
|
||||
|
||||
```
|
||||
//a b
|
||||
var a = "1";
|
||||
var b = 2;
|
||||
a = b + a; //"21" 2
|
||||
b = b + a; //"21" "221"
|
||||
console.log(a); //21
|
||||
console.log(b) //221
|
||||
```
|
||||
|
||||
|
||||
效果:
|
||||
|
||||
```
|
||||
21
|
||||
221
|
||||
```
|
||||
|
||||
举例5:(这个例子比较特殊,字符串减去数字)
|
||||
|
||||
```
|
||||
var a = "3";
|
||||
var b = 2;
|
||||
console.log(a-b);
|
||||
```
|
||||
|
||||
|
||||
效果:(注意,字符串 - 数值 = 数值)
|
||||
|
||||
```
|
||||
1
|
||||
```
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
219
04-JavaScript基础/03-变量的强制类型转换.md
Normal file
219
04-JavaScript基础/03-变量的强制类型转换.md
Normal file
@@ -0,0 +1,219 @@
|
||||
## 前言
|
||||
|
||||
强制类型转换:将一个数据类型强制转换为其他的数据类型。
|
||||
|
||||
类型转换主要指,将其他的数据类型,转换为:String、Number、Boolean。你会把某个数据类型转换成 null 或者 undefined 吗?不会,因为这样做,没有意义。
|
||||
|
||||
## 其他的简单类型 --> String
|
||||
|
||||
### 方法一:变量+"" 或者 变量+"abc"
|
||||
|
||||
举例如下:
|
||||
|
||||
```javascript
|
||||
var a = 123; // Number 类型
|
||||
console.log(a + ''); // 转换成 String 类型
|
||||
console.log(a + 'haha'); // 转换成 String 类型
|
||||
```
|
||||
|
||||
上面的例子中,打印的结果,都是字符串类型的数据。
|
||||
|
||||
### 方法二:调用toString()方法
|
||||
|
||||
举例如下:
|
||||
|
||||
```
|
||||
变量.toString()
|
||||
```
|
||||
|
||||
【重要】该方法**不会影响到原变量**,它会将转换的结果返回。当然我们还可以直接写成`a = a.toString()`,这样的话,就是直接修改原变量。
|
||||
|
||||
注意:null和undefined这两个值没有toString()方法,所以它们不能用方法二。如果调用,会报错。
|
||||
|
||||
另外,Number类型的变量,在调用toString()时,可以在方法中传递一个整数作为参数。此时它将会把数字转换为指定的进制,如果不指定则默认转换为10进制。例如:
|
||||
|
||||
```javascript
|
||||
var a = 255;
|
||||
|
||||
//对于Number调用toString()时可以在方法中传递一个整数作为参数
|
||||
//此时它将会把数字转换为指定的进制,如果不指定则默认转换为10进制
|
||||
a = a.toString(2);
|
||||
|
||||
console.log(a); // 11111111
|
||||
console.log(typeof a); // string
|
||||
```
|
||||
|
||||
### 方法三:使用String()函数
|
||||
|
||||
格式如下:
|
||||
|
||||
```
|
||||
String(变量)
|
||||
```
|
||||
|
||||
使用String()函数做强制类型转换时:
|
||||
|
||||
- 对于Number和Boolean而言,实际上就是调用toString()方法。
|
||||
|
||||
- 但是对于null和undefined,就不会调用toString()方法。它会将 null 直接转换为 "null"。将 undefined 直接转换为 "undefined"。
|
||||
|
||||
### prompt():用户的输入
|
||||
|
||||
我们在JS基础的第一篇里,就讲过,`prompt()`就是专门用来弹出能够让用户输入的对话框。重要的是:用户不管输入什么,都是字符串。
|
||||
|
||||
## 其他的数据类型 --> Number
|
||||
|
||||
### 方式一:使用Number()函数
|
||||
|
||||
**情况一:字符串 --> 数字**
|
||||
|
||||
- 1.如果字符串中是纯数字,则直接将其转换为数字。
|
||||
|
||||
- 2.如果字符串中有非数字的内容,则转换为NaN。(此处可以看到Number()函数的局限性)
|
||||
|
||||
- 3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为0。
|
||||
|
||||
**情况二:布尔 --> 数字**
|
||||
|
||||
- true 转成 1
|
||||
|
||||
- false 转成 0
|
||||
|
||||
**情况三:null --> 数字**
|
||||
|
||||
- 结果为:0
|
||||
|
||||
**情况四:undefined --> 数字**
|
||||
|
||||
- 结果为:NaN
|
||||
|
||||
### 方式二:`parseInt()`:字符串 -> 整数【重要】
|
||||
|
||||
> `parseInt()`是专门用来对付字符串的。
|
||||
|
||||
**parseInt()的作用是将字符串中的有效的整数内容转为数字**。parse表示“转换”,Int表示“整数”(注意`Int`的拼写)。例如:
|
||||
|
||||
```
|
||||
parseInt("5");
|
||||
```
|
||||
|
||||
得到的结果是数字5。
|
||||
|
||||
**parseInt()还具有以下特性**:
|
||||
|
||||
(1)**只保留字符串最开头的数字**,后面的中文自动消失。例如:
|
||||
|
||||
```
|
||||
console.log(parseInt("2017在公众号上写了6篇文章")); //打印结果:2017
|
||||
|
||||
console.log(parseInt("2017.01在公众号上写了6篇文章")); //打印结果仍是:2017 (说明只会取整数)
|
||||
|
||||
console.log(parseInt("aaa2017.01在公众号上写了6篇文章")); //打印结果:NaN
|
||||
```
|
||||
|
||||
(2)自动带有截断小数的功能:**取整,不四舍五入**。
|
||||
|
||||
例1:
|
||||
|
||||
```javascript
|
||||
var a = parseInt(5.8) + parseInt(4.7);
|
||||
console.log(a);
|
||||
```
|
||||
|
||||
控制台输出:
|
||||
|
||||
```
|
||||
9
|
||||
```
|
||||
|
||||
例2:
|
||||
|
||||
```javascript
|
||||
var a = parseInt(5.8 + 4.7);
|
||||
console.log(a);
|
||||
```
|
||||
|
||||
控制台输出:
|
||||
|
||||
```javascript
|
||||
10
|
||||
```
|
||||
|
||||
(3)如果对**非String**使用parseInt()或parseFloat(),它会**先将其转换为String**然后再操作。
|
||||
|
||||
比如:
|
||||
|
||||
```javascript
|
||||
var a = true;
|
||||
console.log(parseInt(a)); //打印结果:NaN (因为是先将a转为字符串"true",然后然后再操作)
|
||||
|
||||
var b = null;
|
||||
console.log(parseInt(b)); //打印结果:NaN (因为是先将b转为字符串"null",然后然后再操作)
|
||||
|
||||
var c = undefined;
|
||||
console.log(parseInt(c)); //打印结果:NaN (因为是先将b转为字符串"undefined",然后然后再操作)
|
||||
|
||||
var d = 168.23;
|
||||
console.log(parseInt(d)); //打印结果:168 (因为是先将c转为字符串"168.23",然后然后再操作)
|
||||
|
||||
```
|
||||
|
||||
(4)带两个参数时,表示进制转换。
|
||||
|
||||
### `parseFloat()`:字符串 --> 浮点数(小数)
|
||||
|
||||
> `parseFloat()`是专门用来对付字符串的。
|
||||
|
||||
parseFloat()的作用是:将字符串转换为**浮点数**。
|
||||
|
||||
parseFloat()和parseInt()的作用类似,不同的是,parseFloat()可以获得有效的小数部分。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var a = '123.456.789px';
|
||||
console.log(parseFloat(a)); // 打印结果:123.456
|
||||
```
|
||||
|
||||
## 转换为 Boolean
|
||||
|
||||
将其他的数据类型转换为Boolean,可以使用Boolean()函数。
|
||||
|
||||
- 情况一:数字 --> 布尔。除了0和NaN,其余的都是true。
|
||||
|
||||
- 情况二:字符串 ---> 布尔。除了空串,其余的都是true。
|
||||
|
||||
- 情况三:null和undefined都会转换为false。
|
||||
|
||||
- 情况四:对象也会转换为true。
|
||||
|
||||
PS:转换为 Boolean 的这几种情况,很重要,开发中会经常用到。
|
||||
|
||||
## 其他进制的数字
|
||||
|
||||
- 16进制的数字,以`0x`开头
|
||||
|
||||
- 8进制的数字,以`0`开头
|
||||
|
||||
- 2进制的数字,`0b`开头(不是所有的浏览器都支持:chrome和火狐支持,IE不支持)
|
||||
|
||||
比如`070`这个字符串,如果我调用parseInt()转成数字时,有些浏览器会当成8进制解析,有些会当成10进制解析。
|
||||
|
||||
所以,比较建议的做法是:可以在parseInt()中传递第二个参数,来指定数字的进制。例如:
|
||||
|
||||
```javascript
|
||||
a = "070";
|
||||
|
||||
a = parseInt(a,10); //转换成十进制
|
||||
```
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
621
04-JavaScript基础/04-运算符.md
Normal file
621
04-JavaScript基础/04-运算符.md
Normal file
@@ -0,0 +1,621 @@
|
||||
|
||||
> 本文首发于[博客园](https://www.cnblogs.com/smyhvae/p/8306146.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
|
||||
我们在本文件夹的[第二篇](https://github.com/smyhvae/Web/blob/master/03-JavaScript%E5%9F%BA%E7%A1%80/02-%E5%8F%98%E9%87%8F.md)里讲到了JS中**变量**的概念,本篇文章讲一下**运算符**和表达式。
|
||||
|
||||
## 前言
|
||||
|
||||
比如说`+`、`*`、`/`、`(` 都是**运算符**,而`(3+5)/2`则是**表达式**。
|
||||
|
||||
### 运算符的定义和分类
|
||||
|
||||
运算符也叫操作符。通过运算符可以对一个或多个值进行运算,并获取运算结果。
|
||||
|
||||
比如:typeof 就是运算符,可以来获得一个值的类型。它会将该值的类型以**字符串**的形式返回:number string boolean undefined object。
|
||||
|
||||
注:运算符都是会返回结果的,而typeof这个运算符返回的结果就是变量的类型。那返回的结果的类型是什么呢?是字符串。
|
||||
|
||||
运算符有很多分类,比如:
|
||||
|
||||
- 算数运算符
|
||||
|
||||
- 自增运算符
|
||||
|
||||
- 逻辑运算符
|
||||
|
||||
- 赋值运算符
|
||||
|
||||
- 关系运算符
|
||||
|
||||
- 三元运算符(条件运算符)
|
||||
|
||||
## 算数运算符
|
||||
|
||||
常见的算数运算符有以下几种:
|
||||
|
||||

|
||||
|
||||
**求余的举例**:
|
||||
|
||||
假设用户输入345,怎么分别得到3、4、5这三个数呢?
|
||||
|
||||
**答案**:
|
||||
|
||||
```
|
||||
得到3的方法:345 除以100,得到3.45然后取整,得到3。即:parseInt(345/100)
|
||||
|
||||
得到4的方法:345 除以100,余数是45,除以10,得到4.5,取整。即:parseInt(345 % 100 / 10)
|
||||
|
||||
得到5的方法:345 除以10,余数就是5。即:345 % 10
|
||||
```
|
||||
|
||||
### 算数运算符的运算规则
|
||||
|
||||
(1)先算乘除、后算加减。
|
||||
|
||||
(2)小括号:能够影响计算顺序,且可以嵌套。没有中括号、没有大括号,只有小括号。
|
||||
|
||||
(3)百分号:取余。只关心余数。
|
||||
|
||||
举例1:(取余)
|
||||
|
||||
```
|
||||
console.log(3 % 5);
|
||||
```
|
||||
|
||||
输出结果为3。
|
||||
|
||||
举例2:(注意运算符优先级)
|
||||
|
||||
```
|
||||
var a = 1 + 2 * 3 % 4 / 3;
|
||||
```
|
||||
|
||||
结果分析:
|
||||
|
||||
原式 = 1 + 6 % 4 / 3 = 1 + 2 / 3 = 1.66666666666666
|
||||
|
||||
### 算数运算符的注意事项
|
||||
|
||||
(1)当对非Number类型的值进行运算(包括`+`、`-`、`*`、`/`)时,会将这些值转换为Number然后再运算。(注:`字符串 + Number`、`字符串 + 字符串`是特例,稍后再讲)
|
||||
|
||||
比如:
|
||||
|
||||
```javascript
|
||||
result1 = true + 1; // 2 = 1+ 1
|
||||
|
||||
result2 = true + false; // 1 = 1+ 0
|
||||
|
||||
result3 = 1 + null; // 1 = 1+ 0
|
||||
|
||||
result4 = 100 - '1' // 99
|
||||
```
|
||||
|
||||
|
||||
(2)任何值和NaN做运算的结果都是NaN。
|
||||
|
||||
(3)任何的值和字符串做加法运算,都会先转换为字符串,然后再做拼串操作。
|
||||
|
||||
比如:
|
||||
|
||||
```javascript
|
||||
result1 = 1 + 2 + '3' // 33
|
||||
|
||||
result2 = '1' + 2 + 3; // 123
|
||||
```
|
||||
|
||||
我们可以利用这一特点,来将一个任意的数据类型转换为String:我们只需要为任意的数据类型 + 一个 "" 即可将其转换为String。这是一种**隐式**的类型转换,由浏览器自动完成,实际上它也是调用String()函数。也就是说,`c = c + ""` 等价于 `c = String(c)`。
|
||||
|
||||
|
||||
|
||||
(4)任何值做`-`、`*`、`/`运算时都会自动转换为Number。
|
||||
|
||||
我们可以利用这一特点,为一个值`-0`、`*1`、`/1`来将其转换为Number。原理和Number()函数一样,使用起来更加简单。
|
||||
|
||||
### 乘方
|
||||
|
||||
如果想计算 `a 的 b 次方`,可以使用如下函数:
|
||||
|
||||
```
|
||||
Math.pow(a, b);
|
||||
```
|
||||
|
||||
Math的中文是“数学”,pow是“power 幂”。
|
||||
|
||||
**举例1:**
|
||||
|
||||

|
||||
|
||||
代码实现:
|
||||
|
||||
```
|
||||
var a = Math.pow(3, Math.pow(2, 2));
|
||||
console.log(a);
|
||||
```
|
||||
|
||||
**举例2:**
|
||||
|
||||

|
||||
|
||||
代码实现:
|
||||
|
||||
```
|
||||
var a = Math.pow(Math.pow(3, 2), 4);
|
||||
console.log(a);
|
||||
```
|
||||
|
||||
### 开方
|
||||
|
||||
如果想计算数值a的开二次方,可以使用如下函数:
|
||||
|
||||
```
|
||||
Math.sqrt(a);
|
||||
```
|
||||
|
||||
sqrt即“square 开方”。比如:
|
||||
|
||||
```
|
||||
var a = Math.sqrt(36);
|
||||
```
|
||||
|
||||
## 一元运算符
|
||||
|
||||
一元运算符,只需要一个操作数。
|
||||
|
||||
常见的一元运算符如下。
|
||||
|
||||
### typeof
|
||||
|
||||
typeof就是典型的一元运算符,因为后面只跟一个操作数。
|
||||
|
||||
举例如下:
|
||||
|
||||
```javascript
|
||||
var a = '123';
|
||||
console.log(typeof a); // 打印结果:string
|
||||
```
|
||||
|
||||
|
||||
### 正号 `+`
|
||||
|
||||
(1)正号不会对数字产生任何影响。比如说,`2`和`+2`是一样的。
|
||||
|
||||
(2)我们可以对一个其他的数据类型使用`+`,来将其转换为number【小技巧】。比如:
|
||||
|
||||
```javascript
|
||||
var a = true;
|
||||
a = +a; // 注意这行代码的一元运算符操作
|
||||
console.log('a:' + a);
|
||||
console.log(typeof a);
|
||||
|
||||
console.log('-----------------');
|
||||
|
||||
var b = '18';
|
||||
b = +b; // 注意这行代码的一元运算符操作
|
||||
console.log('b:' + b);
|
||||
console.log(typeof b);
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
### 负号 `-`
|
||||
|
||||
负号可以对数字进行取反。
|
||||
|
||||
## 自增和自减
|
||||
|
||||
### 自增 `++`
|
||||
|
||||
自增分成两种:`a++`和`++a`。
|
||||
|
||||
(1)对于一个变量自增以后,原变量的值会**立即**自增1。也就是说,无论是 `a++` 还是`++a`,都会立即使原变量的值自增1。
|
||||
|
||||
(2)**我们要注意的是**:`a`是变量,而`a++`和`++a`是**表达式**。
|
||||
|
||||
那这两种自增,有啥区别呢?区别是:`a++` 和 `++a`的值不同:(也就是说,表达式的值不同)
|
||||
|
||||
- `a++`的值等于原变量的值(a自增前的值)
|
||||
|
||||
- `++a`的值等于新值 (a自增后的值)
|
||||
|
||||
### 自减 `-- `
|
||||
|
||||
原理同上。
|
||||
|
||||
### 代码举例
|
||||
|
||||
```javascript
|
||||
var n1=10;
|
||||
var n2=20;
|
||||
|
||||
var n = n1++; //n1 = 11 n1++ = 10
|
||||
|
||||
console.log('n='+n); // 10
|
||||
console.log('n1='+n1); //11
|
||||
|
||||
n = ++n1 //n1 = 12 ++n1 =12
|
||||
console.log('n='+n); //12
|
||||
console.log('n1='+n1); //12
|
||||
|
||||
n = n2--;// n2=19 n2--=20
|
||||
console.log('n='+n); //20
|
||||
console.log('n2='+n2); //19
|
||||
|
||||
n = --n2; //n2=18 --n2 = 18
|
||||
console.log('n='+n); //18
|
||||
console.log('n2='+n2); //18
|
||||
|
||||
```
|
||||
|
||||
## 逻辑运算符
|
||||
|
||||
逻辑运算符有三个:
|
||||
|
||||
- `&&` 与(且):两个都为真,结果才为真。
|
||||
|
||||
- `||` 或:只要有一个是真,结果就是真。
|
||||
|
||||
- `!` 非:对一个布尔值进行取反。
|
||||
|
||||
**连比的写法:**
|
||||
|
||||
来看看逻辑运算符连比的写法。
|
||||
|
||||
举例1:
|
||||
|
||||
```javascript
|
||||
console.log(3 < 2 && 2 < 4);
|
||||
```
|
||||
|
||||
输出结果为false。
|
||||
|
||||
举例2:(判断一个人的年龄是否在18~60岁之间)
|
||||
|
||||
```javascript
|
||||
var a = prompt("请输入您的年龄");
|
||||
alert(a>=18 && a<= 65);
|
||||
```
|
||||
|
||||
|
||||
PS:上面的这个`a>=18 && a<= 65`千万别想当然的写成` 18<= a <= 65`,没有这种语法。
|
||||
|
||||
### 注意事项
|
||||
|
||||
(1)能参与逻辑运算的,都是布尔值。
|
||||
|
||||
(2)JS中的`&&`属于**短路**的与,如果第一个值为false,则不会看第二个值。举例:
|
||||
|
||||
```javascript
|
||||
//第一个值为true,会检查第二个值
|
||||
true && alert("看我出不出来!!"); // 可以弹出 alert 框
|
||||
|
||||
//第一个值为false,不会检查第二个值
|
||||
false && alert("看我出不出来!!"); // 不会弹出 alert 框
|
||||
```
|
||||
|
||||
(3)JS中的`||`属于**短路**的或,如果第一个值为true,则不会看第二个值。举例:
|
||||
|
||||
(4)如果对**非布尔值**进行逻辑运算,则会**先将其转换为布尔值**,然后再操作。举例:
|
||||
|
||||
```javascript
|
||||
var a = 10;
|
||||
a = !a;
|
||||
|
||||
console.log(a); // false
|
||||
console.log(typeof a); // boolean
|
||||
```
|
||||
|
||||
上面的例子,我们可以看到,对非布尔值进行`!`操作之后,返回结果为布尔值。
|
||||
|
||||
### 非布尔值的与或运算【重要】
|
||||
|
||||
> 之所以重要,是因为在实际开发中,我们经常用这种代码做容错处理。
|
||||
|
||||
非布尔值进行**与或运算**时,会先将其转换为布尔值,然后再运算,但返回结果是**原值**。比如说:
|
||||
|
||||
```javascript
|
||||
var result = 5 && 6; // 运算过程:true && true;
|
||||
console.log('result:' + result); // 打印结果:6(也就是说最后面的那个值。)
|
||||
```
|
||||
|
||||
上方代码可以看到,虽然运算过程为布尔值的运算,但返回结果是原值。
|
||||
|
||||
那么,返回结果是哪个原值呢?我们来看一下。
|
||||
|
||||
**与运算**的返回结果:(以两个非布尔值的运算为例)
|
||||
|
||||
- 如果第一个值为true,则必然返回第二个值(所以说,如果所有的值都为true,则返回的是最后一个值)
|
||||
|
||||
- 如果第一个值为false,则直接返回第一个值
|
||||
|
||||
**或运算**的返回结果:(以两个非布尔值的运算为例)
|
||||
|
||||
- 如果第一个值为true,则直接返回第一个值
|
||||
|
||||
- 如果第一个值为false,则返回第二个值
|
||||
|
||||
|
||||
实际开发中,我们经常是这样来处理容错的:
|
||||
|
||||
当成功调用一个接口后,返回的数据为 result 对象。这个时候,我们用变量 a 来接收 result 里的图片资源。通常的写法是这样的:(这里我只是举个例子)
|
||||
|
||||
|
||||
```javascript
|
||||
if (result.resultCode == 0) {
|
||||
var a = result && result.data && result.data.imgUrl || 'http://img.smyhvae.com/20160401_01.jpg';
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
上方代码的意思是,获取返回结果中的`result.data.imgUrl`这个图片资源;如果返回结果中没有 `result.data.imgUrl` 这个字段,就用 `http://img.smyhvae.com/20160401_01.jpg` 作为**兜底**图片。这种写法,在实际开发中经常用到。
|
||||
|
||||
## 赋值运算符
|
||||
|
||||
可以将符号右侧的值赋值给符号左侧的变量。
|
||||
|
||||
举例:
|
||||
|
||||
- `+=`。a += 5 等价于 a = a + 5
|
||||
|
||||
- `-=`。a -= 5 等价于 a = a - 5
|
||||
|
||||
- `*=`。a *= 5 等价于 a = a * 5
|
||||
|
||||
- `/=`。a /= 5 等价于 a = a / 5
|
||||
|
||||
- `%=`。a %= 5 等价于 a = a % 5
|
||||
|
||||
## 关系运算符
|
||||
|
||||
通过关系运算符可以比较两个值之间的大小关系,如果关系成立它会返回true,如果关系不成立则返回false。
|
||||
|
||||
关系运算符有很多种,比如:
|
||||
|
||||
```
|
||||
> 大于号
|
||||
< 小于号
|
||||
>= 大于或等于
|
||||
<= 小于或等于
|
||||
== 等于
|
||||
=== 全等于
|
||||
!= 不等于
|
||||
!== 不全等于
|
||||
```
|
||||
|
||||
**关系运算符,得到的结果都是布尔值:要么是true,要么是false**。
|
||||
|
||||
举例如下:
|
||||
|
||||
```javascript
|
||||
var result = 5 > 10; // false
|
||||
```
|
||||
|
||||
### 非数值的比较
|
||||
|
||||
(1)对于非数值进行比较时,会将其转换为数字然后再比较。
|
||||
|
||||
举例如下:
|
||||
|
||||
```javascript
|
||||
console.log(1 > true); //false
|
||||
console.log(1 >= true); //true
|
||||
console.log(1 > "0"); //true
|
||||
|
||||
//console.log(10 > null); //true
|
||||
|
||||
//任何值和NaN做任何比较都是false
|
||||
|
||||
console.log(10 <= "hello"); //false
|
||||
console.log(true > false); //true
|
||||
|
||||
```
|
||||
|
||||
(2)特殊情况:如果符号两侧的值都是字符串时,**不会**将其转换为数字进行比较。比较两个字符串时,比较的是字符串的**Unicode编码**。【非常重要,这里是个大坑】
|
||||
|
||||
比较字符编码时,是一位一位进行比较。如果两位一样,则比较下一位,所以借用它可以来对英文进行排序。
|
||||
|
||||
PS:所以说,当你尝试去比较`"123"`和`"56"`这两个字符串时,你会发现,字符串"56"竟然比字符串"123"要大。也就是说,下面这样代码的打印结果,其实是true:(这个我们一定要注意,在日常开发中,很容易忽视)
|
||||
|
||||
```javascript
|
||||
// 比较两个字符串时,比较的是字符串的字符编码,所以可能会得到不可预期的结果
|
||||
console.log("56" > "123"); // true
|
||||
```
|
||||
|
||||
**因此**:当我们在比较两个字符串型的数字时,**一定一定要先转型**,比如 `parseInt()`。
|
||||
|
||||
(3)任何值和NaN做任何比较都是false。
|
||||
|
||||
### `==`符号的强调
|
||||
|
||||
注意`==`这个符号,它是**判断是否等于**,而不是赋值。
|
||||
|
||||
(1)`== `这个符号,还可以验证字符串是否相同。例如:
|
||||
|
||||
```
|
||||
console.log("我爱你中国" == "我爱你中国"); //输出结果为true
|
||||
```
|
||||
|
||||
(2)`== `这个符号并不严谨,会将不同类型的东西,**转为相同类型**进行比较(大部分情况下,都是转换为数字)。例如:
|
||||
|
||||
```javascript
|
||||
console.log("6" == 6); // 打印结果:true。这里的字符串"6"会先转换为数字6,然后再进行比较
|
||||
console.log(true == "1"); // 打印结果:true
|
||||
console.log(0 == -0); // 打印结果:true
|
||||
|
||||
console.log(null == 0); // 打印结果:false
|
||||
```
|
||||
|
||||
(3)undefined 衍生自 null,所以这两个值做相等判断时,会返回true。
|
||||
|
||||
```javascript
|
||||
console.log(undefined == null); //打印结果:true。
|
||||
```
|
||||
|
||||
(4)NaN不和任何值相等,包括他本身。
|
||||
|
||||
```javascript
|
||||
console.log(NaN == NaN); //false
|
||||
```
|
||||
|
||||
问题:那如果我想判断 b的值是否为NaN,该怎么办呢?
|
||||
|
||||
答案:可以通过isNaN()函数来判断一个值是否是NaN。举例:
|
||||
|
||||
|
||||
```javascript
|
||||
console.log(isNaN(b)); //false
|
||||
```
|
||||
|
||||
|
||||
如上方代码所示,如果 b 为 NaN,则返回true;否则返回false。
|
||||
|
||||
|
||||
### `===`全等符号的强调
|
||||
|
||||
|
||||
如果要保证**完全等于**,我们就要用三个等号`===`。**全等不会做类型转换**。例如:
|
||||
|
||||
```javascript
|
||||
console.log("6" === 6); //false
|
||||
console.log(6 === 6); //true
|
||||
```
|
||||
|
||||
上述内容分析出:
|
||||
|
||||
- `==`两个等号,不严谨,"6"和6是true。
|
||||
|
||||
- `===`三个等号,严谨,"6"和6是false。
|
||||
|
||||
另外还有:**`==`的反面是`!=`,`===`的反面是`!==`。**。例如:
|
||||
|
||||
```javascript
|
||||
console.log(3 != 8); //true
|
||||
console.log(3 != "3"); //false,因为3=="3"是true,所以反过来就是false。
|
||||
console.log(3 !== "3"); //true,应为3==="3"是false,所以反过来是true。
|
||||
```
|
||||
|
||||
|
||||
## 三元运算符
|
||||
|
||||
三元运算符也叫条件运算符。
|
||||
|
||||
语法:
|
||||
|
||||
```
|
||||
条件表达式?语句1:语句2;
|
||||
```
|
||||
|
||||
**执行的流程**:
|
||||
|
||||
条件运算符在执行时,首先对条件表达式进行求值:
|
||||
|
||||
- 如果该值为true,则执行语句1,并返回执行结果
|
||||
|
||||
- 如果该值为false,则执行语句2,并返回执行结果
|
||||
|
||||
如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后再运算。
|
||||
|
||||
|
||||
## 运算符的优先级
|
||||
|
||||
运算符的优先级如下:(越往上,优先级越高)
|
||||
|
||||
|
||||
- `.`、`[]`、`new`
|
||||
|
||||
|
||||
- ()
|
||||
|
||||
- ++、--
|
||||
|
||||
- `!`、`~`、`+`(单目)、`-`(单目)、`typeof`、`void`、`delete`
|
||||
|
||||
- `%`、`*`、`/`
|
||||
|
||||
- `+`(双目)、`-`(双目)
|
||||
|
||||
- `<<`、`>>`、`>>>`
|
||||
|
||||
- `<`、`<=`、`>`、`>=`
|
||||
|
||||
- `==`、`!==`、`===`
|
||||
|
||||
- `&`
|
||||
|
||||
- `^`
|
||||
|
||||
- `|`
|
||||
|
||||
- `&&`
|
||||
|
||||
- `||`
|
||||
|
||||
- `?:`
|
||||
|
||||
- `=`、`+=`、`-=`、`*=`、`/=`、`%=`、`<<=`、`>>=`、`>>>=`、`&=`、`^=`、`|=`
|
||||
|
||||
- `,`
|
||||
|
||||
|
||||
备注:你在实际写代码的时候,如果不清楚哪个优先级更高,可以把括号运用上。
|
||||
|
||||
|
||||
## Unicode 编码表
|
||||
|
||||
> 这一段中,我们来讲引申的内容:Unicode编码的使用。
|
||||
|
||||
1、在字符串中可以使用转义字符输入Unicode编码。格式如下:
|
||||
|
||||
```
|
||||
\u四位编码
|
||||
```
|
||||
|
||||
|
||||
|
||||
举例如下:
|
||||
|
||||
```javascript
|
||||
console.log("\u2600"); // 这里的 2600 采用的是16进制
|
||||
console.log("\u2602"); // 这里的 2602 采用的是16进制。
|
||||
```
|
||||
|
||||
|
||||
打印结果:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
2、同样,我们可以在网页中使用Unicode编码。格式如下:
|
||||
|
||||
```
|
||||
&#编码;
|
||||
```
|
||||
|
||||
PS:我们知道,Unicode编码采用的是16进制,但是,这里的编码需要使用10进制。
|
||||
|
||||
举例如下:
|
||||
|
||||
```html
|
||||
<h1 style="font-size: 100px;">⚄</h1>
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
354
04-JavaScript基础/05-流程控制语句:选择结构(if和switch).md
Normal file
354
04-JavaScript基础/05-流程控制语句:选择结构(if和switch).md
Normal file
@@ -0,0 +1,354 @@
|
||||
|
||||
|
||||
> 本文首发于[博客园](http://www.cnblogs.com/smyhvae/p/8310295.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
|
||||
## 代码块
|
||||
|
||||
用`{}`包围起来的代码,就是代码块。
|
||||
|
||||
|
||||
JS中的代码块,只具有**分组**的作用,没有其他的用途。
|
||||
|
||||
代码块中的内容,在外部是完全可见的。举例:
|
||||
|
||||
```javascript
|
||||
{
|
||||
var a = 2;
|
||||
alert("smyhvae");
|
||||
console.log("永不止步");
|
||||
}
|
||||
|
||||
console.log("a = " + a);
|
||||
```
|
||||
|
||||
打印结果:(可以看出,虽然变量 a 是定义在代码块中的,但是在外部依然可以访问)
|
||||
|
||||
```
|
||||
永不止步
|
||||
a = 2
|
||||
```
|
||||
|
||||
|
||||
## 流程控制语句
|
||||
|
||||
在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。所以,我们必须清楚每条语句的执行流程。而且,很多时候我们要通过控制语句的执行顺序来实现我们要完成的功能。
|
||||
|
||||
### 流程控制语句分类
|
||||
|
||||
- 顺序结构
|
||||
|
||||
- 选择结构:if语句、switch语句
|
||||
|
||||
- 循环结构:while语句、for语句
|
||||
|
||||
|
||||
## 顺序结构
|
||||
|
||||
按照代码的先后顺序,依次执行。结构图如下:
|
||||
|
||||

|
||||
|
||||
## if语句
|
||||
|
||||
if语句有以下三种。
|
||||
|
||||
### 1、条件判断语句
|
||||
|
||||
> 条件成立才执行。如果条件不成立,那就什么都不做。
|
||||
|
||||
格式:
|
||||
|
||||
```javascript
|
||||
if (条件表达式) {
|
||||
// 条件为真时,做的事情
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 2、条件分支语句
|
||||
|
||||
|
||||
格式1:
|
||||
|
||||
```javascript
|
||||
if (条件表达式) {
|
||||
// 条件为真时,做的事情
|
||||
|
||||
} else {
|
||||
// 条件为假时,做的事情
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
格式:(多分支的if语句)
|
||||
|
||||
```javascript
|
||||
if (条件表达式1) {
|
||||
// 条件1为真时,做的事情
|
||||
|
||||
} else if (条件表达式2) {
|
||||
// 条件1不满足,条件2满足时,做的事情
|
||||
|
||||
} else if (条件表达式3) {
|
||||
// 条件1、2不满足,条件3满足时,做的事情
|
||||
|
||||
} else {
|
||||
// 条件1、2、3都不满足时,做的事情
|
||||
}
|
||||
```
|
||||
|
||||
以上所有的语句体中,只执行其中一个。
|
||||
|
||||
### 做个题目
|
||||
|
||||
```
|
||||
根据BMI(身体质量指数)显示一个人的体型。
|
||||
BMI指数,就是体重、身高的一个计算公式。公式是:
|
||||
BMI =体重÷身高的平方
|
||||
|
||||
比如,老师的体重是81.6公斤,身高是1.71米。
|
||||
那么老师的BMI就是 81.6 ÷ 1.712 等于 27.906022365856163
|
||||
|
||||
过轻:低于18.5
|
||||
正常:18.5-24.99999999
|
||||
过重:25-27.9999999
|
||||
肥胖:28-32
|
||||
非常肥胖, 高于32
|
||||
|
||||
用JavaScript开发一个程序,让用户先输入自己的体重,然后输入自己的身高(弹出两次prompt框)。
|
||||
计算它的BMI,根据上表,弹出用户的身体情况。比如“过轻” 、 “正常” 、“过重” 、 “肥胖” 、“非常肥胖”。
|
||||
```
|
||||
|
||||
**答案**:
|
||||
|
||||
写法1:
|
||||
|
||||
```javascript
|
||||
//第一步,输入身高和体重
|
||||
var height = parseFloat(prompt("请输入身高,单位是米"));
|
||||
var weight = parseFloat(prompt("请输入体重,单位是公斤"));
|
||||
//第二步,计算BMI指数
|
||||
var BMI = weight / Math.pow(height, 2);
|
||||
//第三步,if语句来判断。注意跳楼现象
|
||||
if (BMI < 18.5) {
|
||||
alert("偏瘦");
|
||||
} else if (BMI < 25) {
|
||||
alert("正常");
|
||||
} else if (BMI < 28) {
|
||||
alert("过重");
|
||||
} else if (BMI <= 32) {
|
||||
alert("肥胖");
|
||||
} else {
|
||||
alert("非常肥胖");
|
||||
}
|
||||
```
|
||||
|
||||
写法2:
|
||||
|
||||
```javascript
|
||||
//第一步,输入身高和体重
|
||||
var height = parseFloat(prompt("请输入身高,单位是米"));
|
||||
var weight = parseFloat(prompt("请输入体重,单位是公斤"));
|
||||
//第二步,计算BMI指数
|
||||
var BMI = weight / Math.pow(height, 2);
|
||||
//第三步,if语句来判断。注意跳楼现象
|
||||
if (BMI > 32) {
|
||||
alert("非常肥胖");
|
||||
} else if (BMI >= 28) {
|
||||
alert("肥胖");
|
||||
} else if (BMI >= 25) {
|
||||
alert("过重");
|
||||
} else if (BMI >= 18.5) {
|
||||
alert("正常")
|
||||
} else {
|
||||
alert("偏瘦");
|
||||
}
|
||||
```
|
||||
|
||||
### if语句的嵌套
|
||||
|
||||
我们通过下面这个例子来引出if语句的嵌套。
|
||||
|
||||
```
|
||||
一个加油站为了鼓励车主多加油,所以加的多有优惠。
|
||||
92号汽油,每升6元;如果大于等于20升,那么每升5.9;
|
||||
97号汽油,每升7元;如果大于等于30升,那么每升6.95
|
||||
编写JS程序,用户输入自己的汽油编号,然后输入自己加多少升,弹出价格。
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
代码实现如下:
|
||||
|
||||
```javascript
|
||||
//第一步,输入
|
||||
var bianhao = parseInt(prompt("您想加什么油?填写92或者97"));
|
||||
var sheng = parseFloat(prompt("您想加多少升?"));
|
||||
|
||||
//第二步,判断
|
||||
if (bianhao == 92) {
|
||||
//编号是92的时候做的事情
|
||||
if (sheng >= 20) {
|
||||
var price = sheng * 5.9;
|
||||
} else {
|
||||
var price = sheng * 6;
|
||||
}
|
||||
} else if (bianhao == 97) {
|
||||
//编号是97的时候做的事情
|
||||
if (sheng >= 30) {
|
||||
var price = sheng * 6.95;
|
||||
} else {
|
||||
var price = sheng * 7;
|
||||
}
|
||||
} else {
|
||||
alert("对不起,没有这个编号的汽油!");
|
||||
}
|
||||
|
||||
alert("价格是" + price);
|
||||
```
|
||||
|
||||
|
||||
## switch语句(条件分支语句)
|
||||
|
||||
switch语句也叫条件分支语句。
|
||||
|
||||
格式:
|
||||
|
||||
```
|
||||
switch(表达式) {
|
||||
case 值1:
|
||||
语句体1;
|
||||
break;
|
||||
|
||||
case 值2:
|
||||
语句体2;
|
||||
break;
|
||||
|
||||
...
|
||||
...
|
||||
|
||||
default:
|
||||
语句体 n+1;
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### switch语句的执行流程
|
||||
|
||||
流程图如下:
|
||||
|
||||

|
||||
|
||||
执行流程如下:
|
||||
|
||||
(1)首先,计算出表达式的值,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
|
||||
|
||||
(2)然后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分。
|
||||
|
||||
|
||||
### switch 语句的结束条件【非常重要】
|
||||
|
||||
- 情况a:遇到break就结束,而不是遇到default就结束。(因为break在此处的作用就是退出switch语句)
|
||||
|
||||
- 情况b:执行到程序的末尾就结束。
|
||||
|
||||
我们来看下面的两个例子就明白了。
|
||||
|
||||
### case穿透的问题
|
||||
|
||||
switch 语句中的`break`可以省略,但一般不建议。否则结果可能不是你想要的,会出现一个现象:**case穿透**。
|
||||
|
||||
|
||||
**举例1**:(case穿透的情况)
|
||||
|
||||
```javascript
|
||||
var num = 4;
|
||||
|
||||
//switch判断语句
|
||||
switch (num) {
|
||||
case 1:
|
||||
console.log("星期一");
|
||||
break;
|
||||
case 2:
|
||||
console.log("星期二");
|
||||
break;
|
||||
case 3:
|
||||
console.log("星期三");
|
||||
break;
|
||||
case 4:
|
||||
console.log("星期四");
|
||||
//break;
|
||||
case 5:
|
||||
console.log("星期五");
|
||||
//break;
|
||||
case 6:
|
||||
console.log("星期六");
|
||||
break;
|
||||
case 7:
|
||||
console.log("星期日");
|
||||
break;
|
||||
default:
|
||||
console.log("你输入的数据有误");
|
||||
break;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
上方代码的运行结果,可能会令你感到意外:
|
||||
|
||||
```
|
||||
星期四
|
||||
星期五
|
||||
星期六
|
||||
```
|
||||
|
||||
|
||||
上方代码的解释:因为在case 4和case 5中都没有break,那语句走到case 6的break才会停止。
|
||||
|
||||
**举例2**:
|
||||
|
||||
```javascript
|
||||
//switch判断语句
|
||||
var number = 5;
|
||||
|
||||
switch (number) {
|
||||
default:
|
||||
console.log("我是defaul语句");
|
||||
// break;
|
||||
case (2):
|
||||
console.log("第二个呵呵:" + number);
|
||||
//break;
|
||||
case (3):
|
||||
console.log("第三个呵呵:" + number);
|
||||
break;
|
||||
case (4):
|
||||
console.log("第四个呵呵:" + number);
|
||||
break;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
上方代码的运行结果,你也许会意外:
|
||||
|
||||
```
|
||||
我是defaul语句
|
||||
第二个呵呵:5
|
||||
第三个呵呵:5
|
||||
```
|
||||
|
||||
上方代码的解释:代码走到 default 时,因为没有遇到 break,所以会继续往下走,直到遇见 break 或者走到程序的末尾。 从这个例子可以看出:switch 语句的结束与 default 的顺序无关。
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
511
04-JavaScript基础/06-流程控制语句:循环结构(for和while).md
Normal file
511
04-JavaScript基础/06-流程控制语句:循环结构(for和while).md
Normal file
@@ -0,0 +1,511 @@
|
||||
|
||||
|
||||
|
||||
## 前言
|
||||
|
||||
循环语句:通过循环语句可以反复的执行一段代码多次。
|
||||
|
||||
## for循环
|
||||
|
||||
### for循环的语法
|
||||
|
||||
语法:
|
||||
|
||||
```
|
||||
for(①初始化表达式; ②条件表达式; ④更新表达式){
|
||||
③语句...
|
||||
}
|
||||
```
|
||||
|
||||
执行流程:
|
||||
|
||||
```
|
||||
①执行初始化表达式,初始化变量(初始化表达式只会执行一次)
|
||||
|
||||
②执行条件表达式,判断是否执行循环:
|
||||
如果为true,则执行循环③
|
||||
如果为false,终止循环
|
||||
|
||||
④执行更新表达式,更新表达式执行完毕继续重复②
|
||||
```
|
||||
|
||||
|
||||
|
||||
for循环举例:
|
||||
|
||||
```javascript
|
||||
for (var i = 1; i <= 100; i++) {
|
||||
console.log(i);
|
||||
}
|
||||
```
|
||||
|
||||
上方代码的解释:
|
||||
|
||||

|
||||
|
||||
|
||||
### for循环举例
|
||||
|
||||
|
||||
```javascript
|
||||
for (var i = 1; i < 13; i = i + 4) {
|
||||
console.log(i);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
上方代码的遍历步骤:
|
||||
|
||||
```
|
||||
程序一运行,将执行var i = 1;这条语句, 所以i的值是1。
|
||||
然后程序会验证一下i < 13是否满足,1<13是真,所以执行一次循环体(就是大括号里面的语句)。
|
||||
执行完循环体之后,会执行i=i+4这条语句,所以i的值,是5。
|
||||
|
||||
程序会会验证一下i < 13是否满足,5<13是真,所以执行一次循环体(就是大括号里面的语句)。
|
||||
执行完循环体之后,会执行i=i+4这条语句,所以i的值,是9。
|
||||
|
||||
程序会会验证一下i < 13是否满足,9<13是真,所以执行一次循环体(就是大括号里面的语句)。
|
||||
执行完循环体之后,会执行i=i+4这条语句,所以i的值,是13。
|
||||
|
||||
程序会会验证一下i < 13是否满足,13<13是假,所以不执行循环体了,将退出循环。
|
||||
|
||||
最终输出输出结果为:1、5、9
|
||||
```
|
||||
|
||||
接下来做几个题目。
|
||||
|
||||
**题目1**:
|
||||
|
||||
```javascript
|
||||
for (var i = 1; i < 10; i = i + 3) {
|
||||
i = i + 1;
|
||||
console.log(i);
|
||||
}
|
||||
```
|
||||
|
||||
输出结果:2、6、10
|
||||
|
||||
**题目2**:
|
||||
|
||||
```javascript
|
||||
for (var i = 1; i <= 10; i++) {
|
||||
|
||||
}
|
||||
console.log(i);
|
||||
```
|
||||
|
||||
输出结果:11
|
||||
|
||||
**题目3**:
|
||||
|
||||
```javascript
|
||||
for(var i = 1; i < 7; i = i + 3){
|
||||
|
||||
}
|
||||
console.log(i);
|
||||
```
|
||||
|
||||
输出结果:7
|
||||
|
||||
**题目4**:
|
||||
|
||||
```javascript
|
||||
for (var i = 1; i > 0; i++) {
|
||||
console.log(i);
|
||||
}
|
||||
```
|
||||
|
||||
死循环。
|
||||
|
||||
|
||||
|
||||
## while循环语句
|
||||
|
||||
### while循环
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
while(条件表达式){
|
||||
语句...
|
||||
}
|
||||
```
|
||||
|
||||
执行流程:
|
||||
|
||||
```
|
||||
while语句在执行时,先对条件表达式进行求值判断:
|
||||
|
||||
如果值为true,则执行循环体:
|
||||
循环体执行完毕以后,继续对表达式进行判断
|
||||
如果为true,则继续执行循环体,以此类推
|
||||
|
||||
如果值为false,则终止循环
|
||||
```
|
||||
|
||||
|
||||
**如果有必要的话,我们可以使用 break 来终止循环**。
|
||||
|
||||
|
||||
### do...while循环
|
||||
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
do{
|
||||
语句...
|
||||
}while(条件表达式)
|
||||
|
||||
```
|
||||
|
||||
执行流程:
|
||||
|
||||
```
|
||||
do...while语句在执行时,会先执行循环体:
|
||||
|
||||
循环体执行完毕以后,在对while后的条件表达式进行判断:
|
||||
如果结果为true,则继续执行循环体,执行完毕继续判断以此类推
|
||||
如果结果为false,则终止循环
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
### while循环和 do...while循环的区别
|
||||
|
||||
这两个语句的功能类似,不同的是:
|
||||
|
||||
- while是先判断后执行,而do...while是先执行后判断。
|
||||
|
||||
也就是说,do...while可以保证循环体至少执行一次,而while不能。
|
||||
|
||||
### while循环举例
|
||||
|
||||
|
||||
**题目**:假如投资的年利率为5%,试求从1000块增长到5000块,需要花费多少年?
|
||||
|
||||
**代码实现**:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
|
||||
<head>
|
||||
<meta>
|
||||
<meta>
|
||||
<meta>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
/*
|
||||
* 假如投资的年利率为5%,试求从1000块增长到5000块,需要花费多少年
|
||||
*
|
||||
* 1000 1000*1.05
|
||||
* 1050 1050*1.05
|
||||
*/
|
||||
|
||||
//定义一个变量,表示当前的钱数
|
||||
var money = 1000;
|
||||
|
||||
//定义一个计数器
|
||||
var count = 0;
|
||||
|
||||
//定义一个while循环来计算每年的钱数
|
||||
while (money < 5000) {
|
||||
money *= 1.05;
|
||||
|
||||
//使count自增
|
||||
count++;
|
||||
}
|
||||
|
||||
console.log(money);
|
||||
console.log("一共需要" + count + "年");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
5003.18854203379
|
||||
|
||||
一共需要33年
|
||||
```
|
||||
|
||||
|
||||
另外,你也可以自己算一下,假如投资的年利率为5%,从1000块增长到1万块,需要花费48年:
|
||||
|
||||
```
|
||||
|
||||
10401.269646942128
|
||||
一共需要48年
|
||||
```
|
||||
|
||||
|
||||
## break 和 continue
|
||||
|
||||
> 这个知识点非常重要。
|
||||
|
||||
|
||||
### break
|
||||
|
||||
- break可以用来退出switch语句或**整个**循环语句(循环语句包括for、while。不包括if。if里不能用 break 和 continue,否则会报错)。
|
||||
|
||||
- break会立即终止离它**最近**的那个循环语句。
|
||||
|
||||
- 可以为循环语句创建一个label,来标识当前的循环(格式:label:循环语句)。使用break语句时,可以在break后跟着一个label,这样break将会结束指定的循环,而不是最近的。
|
||||
|
||||
|
||||
**举例1**:通过 break 终止循环语句
|
||||
|
||||
```javascript
|
||||
for (var i = 0; i < 5; i++) {
|
||||
console.log('i的值:' + i);
|
||||
if (i == 2) {
|
||||
break; // 注意,虽然在 if 里 使用了 break,但这里的 break 是服务于外面的 for 循环。
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
i的值:0
|
||||
i的值:1
|
||||
i的值:2
|
||||
```
|
||||
|
||||
|
||||
**举例2**:label的使用
|
||||
|
||||
```javascript
|
||||
outer:
|
||||
for (var i = 0; i < 5; i++) {
|
||||
console.log("外层循环 i 的值:" + i)
|
||||
for (var j = 0; j < 5; j++) {
|
||||
break outer; // 直接跳出outer所在的外层循环(这个outer是我自定义的label)
|
||||
console.log("内层循环 j 的值:" + j);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
外层循环 i 的值:0
|
||||
```
|
||||
|
||||
|
||||
|
||||
### continue
|
||||
|
||||
- continue可以用来跳过**当次**循环。
|
||||
|
||||
- 同样,continue默认只会离他**最近**的循环起作用。
|
||||
|
||||
|
||||
|
||||
## 各种练习
|
||||
|
||||
|
||||
### 练习一:质数相关
|
||||
|
||||
**题目**:在页面中接收一个用户输入的数字,并判断该数是否是质数。
|
||||
|
||||
代码实现:
|
||||
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script type="text/javascript">
|
||||
/*
|
||||
质数:只能被1和它自身整除的数,1不是质数也不是合数,质数必须是大于1的自然数。
|
||||
*/
|
||||
|
||||
var num = prompt("请输入一个大于1的整数:");
|
||||
|
||||
//判断这个值是否合法
|
||||
if (num <= 1) {
|
||||
alert("该值不合法!");
|
||||
} else {
|
||||
|
||||
//先用flag标志位,来保存当前的数的状态
|
||||
//默认当前num是质数
|
||||
var flag = true;
|
||||
|
||||
//判断num是否是质数
|
||||
//获取2-num之间的数
|
||||
for (var i = 2; i < num; i++) {
|
||||
//console.log(i);
|
||||
//判断num是否能被i整除
|
||||
if (num % i == 0) {
|
||||
//如果num能被i整除,则说明num一定不是质数
|
||||
//设置flag为false
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
//如果num是质数则输出
|
||||
if (flag) {
|
||||
alert(num + "是质数!!!");
|
||||
} else {
|
||||
alert("这个不是质数")
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
|
||||
### 练习二:质数相关
|
||||
|
||||
**题目**:打印1~100之间的所有质数
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script type="text/javascript">
|
||||
|
||||
/*
|
||||
* 打印出1-100之间所有的质数
|
||||
*/
|
||||
|
||||
//打印2-100之间所有的数
|
||||
for (var i = 2; i <= 100; i++) {
|
||||
|
||||
//创建一个布尔值,用来保存结果,默认i是质数
|
||||
var flag = true;
|
||||
|
||||
//判断i是否是质数
|
||||
//获取到2-i之间的所有的数
|
||||
for (var j = 2; j < i; j++) {
|
||||
|
||||
//判断i是否能被j整除
|
||||
if (i % j == 0) {
|
||||
//如果进入判断则证明i不是质数,修改flag值为false
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
//如果是质数,则打印i的值
|
||||
if (flag) {
|
||||
console.log(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
### 练习三:99乘法表
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
width: 2000px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
|
||||
/*
|
||||
* 1.打印99乘法表
|
||||
* 1*1=1
|
||||
* 1*2=2 2*2=4
|
||||
* 1*3=3 2*3=6 3*3=9
|
||||
* 1*4=4 2*4=8 3*4=12 4*4=16
|
||||
* ....9*9=81
|
||||
*
|
||||
* 2.打印出1-100之间所有的质数
|
||||
*/
|
||||
|
||||
//创建外层循环,用来控制乘法表的高度
|
||||
for (var i = 1; i <= 9; i++) {
|
||||
//创建一个内层循环来控制图形的宽度
|
||||
for (var j = 1; j <= i; j++) {
|
||||
document.write("<span>" + j + "*" + i + "=" + i * j + "</span>");
|
||||
}
|
||||
|
||||
//输出一个换行
|
||||
document.write("<br />");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
页面效果:
|
||||
|
||||

|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
364
04-JavaScript基础/07-对象简介和对象的基本操作.md
Normal file
364
04-JavaScript基础/07-对象简介和对象的基本操作.md
Normal file
@@ -0,0 +1,364 @@
|
||||
|
||||
|
||||
## 面向对象简介
|
||||
|
||||
**对象的作用是:封装信息**。比如Student类里可以封装学生的姓名、年龄、成绩等。
|
||||
|
||||
对象具有**特征**(属性)和**行为**(方法)。
|
||||
|
||||
面向对象:可以创建自定义的类型,很好的支持继承和多态。
|
||||
|
||||
面向对象的特征:封装、继承、多态。
|
||||
|
||||
|
||||
## 对象简介
|
||||
|
||||
### 基本数据类型和引用数据类型的对比
|
||||
|
||||
- **基本数据类型(值类型)**:String 字符串、Number 数值、Boolean 布尔值、Null 空值、Undefined 未定义。
|
||||
|
||||
- **引用数据类型(引用类型)**:Object 对象。
|
||||
|
||||
**基本数据类型**:
|
||||
|
||||
基本数据类型的值直接保存在**栈内存**中,值与值之间是独立存在,修改一个变量不会影响其他的变量。
|
||||
|
||||
**对象**:
|
||||
|
||||
只要不是那五种基本数据类型,就全都是对象。
|
||||
|
||||
如果使用基本数据类型的数据,我们所创建的变量都是独立,不能成为一个整体。
|
||||
|
||||
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
|
||||
|
||||
对象是保存到**堆内存**中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间。变量保存的是对象的内存地址(对象的引用)。
|
||||
|
||||
换而言之,对象的值是保存在**堆内存**中的,而对象的引用(即变量)是保存在**栈内存**中的。
|
||||
|
||||
**如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响**。
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
var obj = new Object();
|
||||
obj.name = "孙悟空";
|
||||
|
||||
var obj2 = obj;
|
||||
|
||||
//修改obj的name属性
|
||||
obj.name = "猪八戒";
|
||||
```
|
||||
|
||||
上面的代码中,当我修改obj的name属性后,会发现,obj2的name属性也会被修改。因为obj和obj2指向的是堆内存中的同一个地址。
|
||||
|
||||
## 对象的分类
|
||||
|
||||
1.内置对象:
|
||||
|
||||
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
|
||||
|
||||
- 比如:Math、String、Number、Boolean、Function、Object....
|
||||
|
||||
2.宿主对象:
|
||||
|
||||
- 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象。
|
||||
|
||||
- 比如 BOM DOM。比如`console`、`document`。
|
||||
|
||||
3.自定义对象:
|
||||
|
||||
- 由开发人员自己创建的对象
|
||||
|
||||
## 对象的基本操作
|
||||
|
||||
### 创建对象
|
||||
|
||||
使用new关键字调用的函数,是构造函数constructor。**构造函数是专门用来创建对象的函数**。
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
var obj = new Object();
|
||||
```
|
||||
|
||||
另外,使用`typeof`检查一个对象时,会返回`object`。
|
||||
|
||||
### 向对象中添加属性
|
||||
|
||||
在对象中保存的值称为属性。
|
||||
|
||||
向对象添加属性的语法:
|
||||
|
||||
```javascript
|
||||
对象.属性名 = 属性值;
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var obj = new Object();
|
||||
|
||||
//向obj中添加一个name属性
|
||||
obj.name = "孙悟空";
|
||||
|
||||
//向obj中添加一个gender属性
|
||||
obj.gender = "男";
|
||||
|
||||
//向obj中添加一个age属性
|
||||
obj.age = 18;
|
||||
|
||||
console.log(JSON.stringify(obj)); // 将 obj 以字符串的形式打印出来
|
||||
```
|
||||
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
{
|
||||
"name":"孙悟空",
|
||||
"gender":"男",
|
||||
"age":18
|
||||
}
|
||||
```
|
||||
|
||||
**补充1**:对象的属性值可以是任何的数据类型,也可以是个**函数**:(也称之为方法)
|
||||
|
||||
```javascript
|
||||
var obj = new Object();
|
||||
obj.sayName = function () {
|
||||
console.log('smyhvae');
|
||||
};
|
||||
|
||||
console.log(obj.sayName); //没加括号,获取的是对象
|
||||
console.log('-----------');
|
||||
console.log(obj.sayName()); //加了括号,执行函数内容,并执行函数体的内容
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
**补充2**:js中的属性值,也可以是一个**对象**。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
//创建对象 obj1
|
||||
var obj1 = new Object();
|
||||
obj1.test = undefined;
|
||||
|
||||
//创建对象 obj2
|
||||
var obj2 = new Object();
|
||||
obj2.name = "smyhvae";
|
||||
|
||||
//将整个 obj2 对象,设置为 obj1 的属性
|
||||
obj1.test = obj2;
|
||||
|
||||
console.log(obj1.test.name);
|
||||
```
|
||||
|
||||
打印结果为:smyhvae
|
||||
|
||||
### 获取对象中的属性
|
||||
|
||||
**方式1**:
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
对象.属性名
|
||||
```
|
||||
|
||||
如果获取对象中没有的属性,不会报错而是返回`undefined`。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var obj = new Object();
|
||||
|
||||
//向obj中添加一个name属性
|
||||
obj.name = "孙悟空";
|
||||
|
||||
//向obj中添加一个gender属性
|
||||
obj.gender = "男";
|
||||
|
||||
//向obj中添加一个age属性
|
||||
obj.age = 18;
|
||||
|
||||
// 获取对象中的属性,并打印出来
|
||||
console.log(obj.gender); // 打印结果:男
|
||||
console.log(obj.color); // 打印结果:undefined
|
||||
```
|
||||
|
||||
|
||||
**方式2**:可以使用`[]`这种形式去操作属性
|
||||
|
||||
对象的属性名不强制要求遵守标识符的规范,但是我们使用是还是尽量按照标识符的规范去做。
|
||||
|
||||
但如果要使用特殊的属性名,就不能采用`.`的方式来操作对象的属性。比如说,`123`这种属性名,如果我们直接写成`obj.123 = 789`,是会报错的。那怎么办呢?办法如下:
|
||||
|
||||
语法格式如下:(读取时,也是采用这种方式)
|
||||
|
||||
```
|
||||
对象["属性名"] = 属性值
|
||||
|
||||
```
|
||||
|
||||
|
||||
上面这种语法格式,举例如下:
|
||||
|
||||
```javascript
|
||||
obj["123"] = 789;
|
||||
```
|
||||
|
||||
|
||||
**重要**:使用`[]`这种形式去操作属性,更加的灵活,因为,我们可以在`[]`中直接传递一个**变量**,这样变量值是多少就会读取那个属性。
|
||||
|
||||
|
||||
### 修改对象的属性值
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
对象.属性名 = 新值
|
||||
```
|
||||
|
||||
|
||||
```javascript
|
||||
obj.name = "tom";
|
||||
```
|
||||
|
||||
|
||||
### 删除对象的属性
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
delete obj.name;
|
||||
```
|
||||
|
||||
|
||||
### in 运算符
|
||||
|
||||
通过该运算符可以检查一个对象中是否含有指定的属性。如果有则返回true,没有则返回false。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
"属性名" in 对象
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
//检查obj中是否含有name属性
|
||||
console.log("name" in obj);
|
||||
```
|
||||
|
||||
|
||||
我们平时使用的对象不一定是自己创建的,可能是别人提供的,这个时候,in 运算符可以派上用场。
|
||||
|
||||
## 对象字面量
|
||||
|
||||
如果要创建一个对象,我们可以使用下面这种方式:
|
||||
|
||||
```javascript
|
||||
var obj = new Object();
|
||||
```
|
||||
|
||||
|
||||
但是上面的这种方式,比较麻烦,我们还有更简洁的方式来创建一个对象。如下。
|
||||
|
||||
使用对象字面量来创建一个对象:
|
||||
|
||||
```javascript
|
||||
var obj = {};
|
||||
```
|
||||
|
||||
|
||||
使用对象字面量,可以在创建对象时,直接指定对象中的属性。语法:{属性名:属性值,属性名:属性值....}
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
var obj2 = {
|
||||
|
||||
name: "猪八戒",
|
||||
age: 13,
|
||||
gender: "男",
|
||||
test: {
|
||||
name: "沙僧"
|
||||
}
|
||||
//我们还可以在对象中增加一个方法。以后可以通过obj2.sayName()的方式调用这个方法
|
||||
sayName: function(){
|
||||
console.log('smyhvae');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
对象字面量的属性名可以加引号也可以不加,建议不加。如果要使用一些特殊的名字,则必须加引号。
|
||||
|
||||
属性名和属性值是一组一组的键值对结构,键和值之间使用`:`连接,多个值对之间使用`,`隔开。如果一个属性之后没有其他的属性了,就不要写`,`,因为它是对象的最后一个属性。
|
||||
|
||||
|
||||
## 遍历对象中的属性:for in
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
for (var 变量 in 对象) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
解释:对象中有几个属性,循环体就会执行几次。每次执行时,会将对象中的**每个属性的 属性名 赋值给变量**。
|
||||
|
||||
举例:
|
||||
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script type="text/javascript">
|
||||
var obj = {
|
||||
name: "smyhvae",
|
||||
age: 26,
|
||||
gender: "男",
|
||||
address: "shenzhen"
|
||||
};
|
||||
|
||||
//枚举对象中的属性
|
||||
for (var n in obj) {
|
||||
console.log("属性名:" + n);
|
||||
console.log("属性值:" + obj[n]); // 注意,因为这里的属性名 n 是变量,所以,如果想获取属性值,不能写成 obj.n,而是要写成 obj[n]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
82
04-JavaScript基础/08-基本数据类型vs引用数据类型.md
Normal file
82
04-JavaScript基础/08-基本数据类型vs引用数据类型.md
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
## 前言
|
||||
|
||||
|
||||
在之前的**javascript基础**文章中(编号02、编号07),我们介绍过,变量有以下数据类型:
|
||||
|
||||
- **基本数据类型(值类型)**:String 字符串、Number 数值、Boolean 布尔值、Null 空值、Undefined 未定义。
|
||||
|
||||
- **引用数据类型(引用类型)**:Object 对象。
|
||||
|
||||
本文,我们针对这两种类型,做个详细介绍。我们先来看个例子。
|
||||
|
||||
|
||||
**基本数据类型举例**:
|
||||
|
||||
```javascript
|
||||
var a = 23;
|
||||
var b = a;
|
||||
|
||||
a++;
|
||||
|
||||
console.log(a); // 打印结果:24
|
||||
console.log(b); // 打印结果:23
|
||||
```
|
||||
|
||||
上面的代码中:a 和 b 都是基本数据类型,让 b 等于 a,然后**改变 a 的值之后,发现 b 的值并没有被改变**。
|
||||
|
||||
但是在引用数据类型中,就不同了,我们来看一看。
|
||||
|
||||
**引用数据类型举例**:
|
||||
|
||||
```javascript
|
||||
var obj1 = new Object();
|
||||
obj1.name = 'smyh';
|
||||
|
||||
// 让 obj2 等于 obj1
|
||||
var obj2 = obj1;
|
||||
|
||||
// 修改 obj1 的 name 属性
|
||||
obj1.name = 'vae';
|
||||
|
||||
console.log(obj1.name); // 打印结果:vae
|
||||
console.log(obj2.name); // 打印结果:vae
|
||||
```
|
||||
|
||||
|
||||
上面的代码中:obj1 和 obj2 都是引用数据类型,让 obj2 等于 obj1,然后**修改 obj1.name 的值之后,发现 obj2.name 的值也发生了改变**。
|
||||
|
||||
|
||||
从上面的例子中,可以反映出,基本数据类型和引用数据类型是有区别的。
|
||||
|
||||
|
||||
|
||||
## 栈内存和堆内存
|
||||
|
||||
我们首先记住一句话:JS中,所有的**变量**都是保存在**栈内存**中的。
|
||||
|
||||
然后来看看下面的区别。
|
||||
|
||||
**基本数据类型**:
|
||||
|
||||
基本数据类型的值,直接保存在栈内存中。值与值之间是独立存在,修改一个变量不会影响其他的变量。
|
||||
|
||||
**引用数据类型**:
|
||||
|
||||
|
||||
对象是保存到堆内存中的。每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而**变量保存了对象的内存地址**(对象的引用)。如果两个变量保存了同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。
|
||||
|
||||
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
295
04-JavaScript基础/09-函数.md
Normal file
295
04-JavaScript基础/09-函数.md
Normal file
@@ -0,0 +1,295 @@
|
||||
|
||||
|
||||
## 函数的介绍
|
||||
|
||||
函数:就是将一些功能或语句进行**封装**,在需要的时候,通过**调用**的形式,执行这些语句。
|
||||
|
||||
- **函数也是一个对象**
|
||||
|
||||
- 使用`typeof`检查一个函数对象时,会返回function
|
||||
|
||||
**函数的作用**:
|
||||
|
||||
- 将大量重复的语句写在函数里,以后需要这些语句的时候,可以直接调用函数,避免重复劳动。
|
||||
|
||||
- 简化编程,让编程模块化。
|
||||
|
||||
来看个例子:
|
||||
|
||||
```javascript
|
||||
console.log("你好");
|
||||
sayHello(); // 调用函数
|
||||
|
||||
// 定义函数
|
||||
function sayHello(){
|
||||
console.log("欢迎");
|
||||
console.log("welcome");
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 函数的定义和调用
|
||||
|
||||
### 第一步:函数的定义
|
||||
|
||||
**方式一**:使用`函数声明`来创建一个函数。语法:
|
||||
|
||||
|
||||
```javascript
|
||||
function 函数名([形参1,形参2...形参N]){ // 备注:语法中的中括号,表示“可选”
|
||||
语句...
|
||||
}
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
function sum(a, b){
|
||||
return a+b;
|
||||
}
|
||||
```
|
||||
|
||||
解释如下:
|
||||
|
||||
- function:是一个关键字。中文是“函数”、“功能”。
|
||||
|
||||
- 函数名字:命名规定和变量的命名规定一样。只能是字母、数字、下划线、美元符号,不能以数字开头。
|
||||
|
||||
- 参数:可选。
|
||||
|
||||
- 大括号里面,是这个函数的语句。
|
||||
|
||||
PS:在有些编辑器中,方法写完之后,我们在方法的前面输入`/**`,然后回车,会发现,注释的格式会自动补齐。
|
||||
|
||||
**方式二**:使用`函数表达式`来创建一个函数。语法:
|
||||
|
||||
```javascript
|
||||
var 函数名 = function([形参1,形参2...形参N]){
|
||||
语句....
|
||||
}
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var fun3 = function() {
|
||||
console.log("我是匿名函数中封装的代码");
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
从方式二的举例中可以看出:所谓的“函数表达式”,其实就是将匿名函数赋值给一个变量。
|
||||
|
||||
当然,我们还有方式三:使用构造函数来创建一个对象。这种方式,用的少。
|
||||
|
||||
### 第二步:函数的调用
|
||||
|
||||
函数调用的语法:
|
||||
|
||||
```javascript
|
||||
函数名字();
|
||||
```
|
||||
|
||||
## 函数的参数:形参和实参
|
||||
|
||||
函数的参数包括形参和实参。来看下面的图就懂了:
|
||||
|
||||
|
||||

|
||||
|
||||
注意:实际参数和形式参数的个数,要相同。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
sum(3,4);
|
||||
sum("3",4);
|
||||
sum("Hello","World");
|
||||
|
||||
//函数:求和
|
||||
function sum(a, b) {
|
||||
console.log(a + b);
|
||||
}
|
||||
```
|
||||
|
||||
控制台输出结果:
|
||||
|
||||
```
|
||||
7
|
||||
34
|
||||
helloworld
|
||||
```
|
||||
|
||||
|
||||
## 函数的参数:形参和实参
|
||||
|
||||
假设我们定义一个求和的函数。
|
||||
|
||||
**形参:**
|
||||
|
||||
- 可以在函数的`()`中来指定一个或多个形参。
|
||||
|
||||
- 多个形参之间使用`,`隔开,声明形参就相当于在函数内部声明了对应的变量,但是并不赋值。
|
||||
|
||||
|
||||
**实参**:
|
||||
|
||||
- 在调用函数时,可以在 `()`中指定实参。
|
||||
|
||||
- 实参将会赋值给函数中对应的形参。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
// 调用函数
|
||||
sum(3,4);
|
||||
sum("3",4);
|
||||
sum("Hello","World");
|
||||
|
||||
// 定义函数:求和
|
||||
function sum(a, b) {
|
||||
console.log(a + b);
|
||||
}
|
||||
```
|
||||
|
||||
控制台输出结果:
|
||||
|
||||
```
|
||||
7
|
||||
34
|
||||
helloworld
|
||||
```
|
||||
|
||||
**实参的类型:**
|
||||
|
||||
|
||||
函数的实参可以是任意的数据类型。
|
||||
|
||||
调用函数时解析器不会检查实参的类型,所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查。
|
||||
|
||||
|
||||
**实参的数量:**
|
||||
|
||||
调用函数时,解析器也不会检查实参的数量:
|
||||
|
||||
- 多余实参不会被赋值
|
||||
|
||||
- 如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined。例如:
|
||||
|
||||

|
||||
|
||||
## 函数的返回值
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
console.log(sum(3, 4));
|
||||
|
||||
//函数:求和
|
||||
function sum(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
return的作用是结束方法。
|
||||
|
||||
注意:
|
||||
|
||||
- return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果。
|
||||
|
||||
- 在函数中return后的语句都不会执行(函数在执行完 return 语句之后停止并立即退出)
|
||||
|
||||
- 如果return语句后不跟任何值,就相当于返回一个undefined
|
||||
|
||||
- 如果函数中不写return,则也会返回undefined
|
||||
|
||||
- 返回值可以是任意的数据类型,可以是对象,也可以是函数。
|
||||
|
||||
|
||||
## 函数名、函数体和函数加载问题(重要,请记住)
|
||||
|
||||
我们要记住:**函数名 == 整个函数**。举例:
|
||||
|
||||
```javascript
|
||||
console.log(fn) == console.log(function fn(){alert(1)});
|
||||
|
||||
//定义fn方法
|
||||
function fn(){
|
||||
alert(1)
|
||||
};
|
||||
```
|
||||
|
||||
我们知道,当我们在调用一个函数时,通常使用`函数()`这种格式;但此时,我们是直接使用`函数`这种格式,它的作用相当于整个函数。
|
||||
|
||||
**函数的加载问题**:JS加载的时候,只加载函数名,不加载函数体。所以如果想使用内部的成员变量,需要调用函数。
|
||||
|
||||
|
||||
## fn() 和 fn 的区别【重要】
|
||||
|
||||
- `fn()`:调用函数。相当于获取了函数的返回值。
|
||||
|
||||
- `fn`:函数对象。相当于直接获取了函数对象。
|
||||
|
||||
|
||||
## 立即执行函数
|
||||
|
||||
现有匿名函数如下:
|
||||
|
||||
```javascript
|
||||
function(a, b) {
|
||||
console.log("a = " + a);
|
||||
console.log("b = " + b);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
立即执行函数如下:
|
||||
|
||||
```javascript
|
||||
(function(a, b) {
|
||||
console.log("a = " + a);
|
||||
console.log("b = " + b);
|
||||
})(123, 456);
|
||||
```
|
||||
|
||||
|
||||
立即执行函数:函数定义完,立即被调用,这种函数叫做立即执行函数。
|
||||
|
||||
立即执行函数往往只会执行一次。为什么呢?因为没有变量保存它,执行完了之后,就找不到它了。
|
||||
|
||||
|
||||
## 方法
|
||||
|
||||
函数也可以称为对象的属性。**如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法**。
|
||||
|
||||
|
||||
调用这个函数就说调用对象的方法(method)。相比于方法,它只是名称上的区别,并没有其他的区别。
|
||||
|
||||
|
||||
函数举例:
|
||||
|
||||
```javascript
|
||||
// 调用函数
|
||||
fn();
|
||||
```
|
||||
|
||||
方法举例:
|
||||
|
||||
```javascript
|
||||
// 调用方法
|
||||
obj.fn();
|
||||
```
|
||||
|
||||
|
||||
我们可以这样说,如果直接是`fn()`,那就说明是函数调用。如果是发现`XX.fn()`的这种形式,那就说明是**方法**调用。
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
146
04-JavaScript基础/10-作用域.md
Normal file
146
04-JavaScript基础/10-作用域.md
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
|
||||
> 作用域、变量提升的知识点,面试时会经常遇到。
|
||||
|
||||
## 作用域(Scope)的概念
|
||||
|
||||
作用域指一个变量的作用范围。在js中,一共有两种作用域:
|
||||
|
||||
- 全局作用域
|
||||
|
||||
- 函数作用域
|
||||
|
||||
## 全局作用域
|
||||
|
||||
直接编写在script标签中的JS代码,都在全局作用域。
|
||||
|
||||
- 全局作用域在页面打开时创建,在页面关闭时销毁。
|
||||
|
||||
- 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用。
|
||||
|
||||
在全局作用域中:
|
||||
|
||||
- 创建的**变量**都会作为window对象的属性保存。
|
||||
|
||||
- 创建的**函数**都会作为window对象的方法保存。
|
||||
|
||||
全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到。
|
||||
|
||||
### 变量的声明提前(变量提升)
|
||||
|
||||
使用var关键字声明的变量( 比如 `var a = 1`),**会在所有的代码执行之前被声明**(但是不会赋值),但是如果声明变量时不是用var关键字(比如直接写`a = 1`),则变量不会被声明提前。
|
||||
|
||||
举例1:
|
||||
|
||||
```javascript
|
||||
console.log(a);
|
||||
var a = 123;
|
||||
```
|
||||
|
||||
|
||||
打印结果:undefined。(说明变量 a 被 被提前声明了,只是尚未被赋值)
|
||||
|
||||
举例2:
|
||||
|
||||
```javascript
|
||||
console.log(a);
|
||||
a = 123; //此时a相当于window.a
|
||||
```
|
||||
|
||||
程序会报错:
|
||||
|
||||

|
||||
|
||||
### 函数的声明提前
|
||||
|
||||
**函数声明**:
|
||||
|
||||
使用`函数声明`的形式创建的函数`function foo(){}`,**会被声明提前**。
|
||||
|
||||
也就是说,整个函数会在所有的代码执行之前就被**创建完成**,所以我们可以在函数声明之前,调用函数。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
fn1(); // 虽然 函数 fn1 的定义是在后面,但是因为被提前声明了, 所以此处可以调用函数
|
||||
|
||||
function fn1() {
|
||||
console.log('我是函数 fn1');
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**函数表达式**:
|
||||
|
||||
使用`函数表达式`创建的函数`var foo = function(){}`,**不会被声明提前**,所以不能在声明前调用。
|
||||
|
||||
很好理解,因为此时foo被声明了,且为undefined,并没有把 `function(){}` 赋值给 foo。
|
||||
|
||||
所以说,下面的例子,会报错:
|
||||
|
||||

|
||||
|
||||
## 作用域
|
||||
|
||||
**作用域**:变量和函数生效的区域。作用域在**函数定义**时,就已经确定了。
|
||||
|
||||
在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量。
|
||||
|
||||
**执行期上下文**:当**函数执行**时,会创建一个执行期上下文的内部对象。每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立的。当函数执行完毕,它所产生的执行期上下文会被销毁。参考链接:<https://www.cnblogs.com/chenyingjie1207/p/9966036.html>
|
||||
|
||||
|
||||
**作用域的上下级关系:**
|
||||
|
||||
当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用(**就近原则**)。如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报错ReferenceError。
|
||||
|
||||
在函数中要访问全局变量可以使用window对象。(比如说,全局作用域和函数作用域都定义了变量a,如果想访问全局变量,可以使用`window.a`)
|
||||
|
||||
**提醒1:**
|
||||
|
||||
在函数作用域也有声明提前的特性:
|
||||
|
||||
- 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
|
||||
|
||||
- 函数声明也会在函数中所有的代码执行之前执行
|
||||
|
||||
|
||||
因此,在函数中,没有var声明的变量都是**全局变量**,而且并不会提前声明。
|
||||
|
||||
举例1:
|
||||
|
||||
```javascript
|
||||
var a = 1;
|
||||
|
||||
function foo() {
|
||||
console.log(a);
|
||||
a = 2; // 此处的a相当于window.a
|
||||
}
|
||||
|
||||
foo();
|
||||
console.log(a); //打印结果是2
|
||||
|
||||
```
|
||||
|
||||
上方代码中,foo()的打印结果是`1`。如果去掉第一行代码,打印结果是`Uncaught ReferenceError: a is not defined`
|
||||
|
||||
|
||||
**提醒2:**定义形参就相当于在函数作用域中声明了变量。
|
||||
|
||||
```javascript
|
||||
function fun6(e) { // 这个函数中,因为有了形参 e,此时就相当于在函数内部的第一行代码里,写了 var e;
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
fun6(); //打印结果为 undefined
|
||||
fun6(123);//打印结果为123
|
||||
```
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
191
04-JavaScript基础/11-this.md
Normal file
191
04-JavaScript基础/11-this.md
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
|
||||
## this
|
||||
|
||||
解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的 上下文对象。
|
||||
|
||||
根据函数的调用方式的不同,this会指向不同的对象:【重要】
|
||||
|
||||
- 1.以函数的形式调用时,this永远都是window。比如`fun();`相当于`window.fun();`
|
||||
|
||||
- 2.以方法的形式调用时,this是调用方法的那个对象
|
||||
|
||||
- 3.以构造函数的形式调用时,this是新创建的那个对象
|
||||
|
||||
- 4.使用call和apply调用时,this是指定的那个对象
|
||||
|
||||
|
||||
**针对第1条的举例**:
|
||||
|
||||
```javascript
|
||||
function fun() {
|
||||
console.log(this);
|
||||
console.log(this.name);
|
||||
}
|
||||
|
||||
var obj1 = {
|
||||
name: "smyh",
|
||||
sayName: fun
|
||||
};
|
||||
|
||||
var obj2 = {
|
||||
name: "vae",
|
||||
sayName: fun
|
||||
};
|
||||
|
||||
var name = "全局的name属性";
|
||||
|
||||
//以函数形式调用,this是window
|
||||
fun(); //可以理解成 window.fun()
|
||||
```
|
||||
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
Window
|
||||
全局的name属性
|
||||
```
|
||||
|
||||
|
||||
上面的举例可以看出,this指向的是window对象,所以 this.name 指的是全局的name。
|
||||
|
||||
|
||||
**第2条的举例**:
|
||||
|
||||
```javascript
|
||||
function fun() {
|
||||
console.log(this);
|
||||
console.log(this.name);
|
||||
}
|
||||
|
||||
var obj1 = {
|
||||
name: "smyh",
|
||||
sayName: fun
|
||||
};
|
||||
|
||||
var obj2 = {
|
||||
name: "vae",
|
||||
sayName: fun
|
||||
};
|
||||
|
||||
var name = "全局的name属性";
|
||||
|
||||
//以方法的形式调用,this是调用方法的对象
|
||||
obj2.sayName();
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
Object
|
||||
vae
|
||||
```
|
||||
|
||||
上面的举例可以看出,this指向的是 对象 obj2 ,所以 this.name 指的是 obj2.name。
|
||||
|
||||
**箭头函数中this的指向**:
|
||||
|
||||
ES6中的箭头函数并不会使用上面四条标准的绑定规则,而是会继承外层函数调用的this绑定(无论this绑定到什么)。
|
||||
|
||||
## 类数组 arguments
|
||||
|
||||
> 这部分,小白可能看不懂。所以,这一段,暂时可以忽略。
|
||||
|
||||
在调用函数时,浏览器每次都会传递进两个隐含的参数:
|
||||
|
||||
- 1.函数的上下文对象 this
|
||||
|
||||
- 2.**封装实参的对象** arguments
|
||||
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
console.log(arguments);
|
||||
console.log(typeof arguments);
|
||||
}
|
||||
|
||||
foo();
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
arguments是一个类数组对象,它可以通过索引来操作数据,也可以获取长度。
|
||||
|
||||
**arguments代表的是实参**。在调用函数时,我们所传递的实参都会在arguments中保存。有个讲究的地方是:arguments**只在函数中使用**。
|
||||
|
||||
|
||||
|
||||
|
||||
### 1、返回函数**实参**的个数:arguments.length
|
||||
|
||||
|
||||
arguments.length可以用来获取**实参的长度**。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
fn(2,4);
|
||||
fn(2,4,6);
|
||||
fn(2,4,6,8);
|
||||
|
||||
function fn(a,b) {
|
||||
console.log(arguments);
|
||||
console.log(fn.length); //获取形参的个数
|
||||
console.log(arguments.length); //获取实参的个数
|
||||
|
||||
console.log("----------------");
|
||||
}
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
我们即使不定义形参,也可以通过arguments来使用实参(只不过比较麻烦):arguments[0] 表示第一个实参、arguments[1] 表示第二个实参...
|
||||
|
||||
### 2、返回正在执行的函数:arguments.callee
|
||||
|
||||
arguments里边有一个属性叫做callee,这个属性对应一个函数对象,就是当前正在指向的函数对象。
|
||||
|
||||
```javascript
|
||||
function fun() {
|
||||
|
||||
console.log(arguments.callee == fun); //打印结果为true
|
||||
}
|
||||
|
||||
fun("hello");
|
||||
```
|
||||
|
||||
在使用函数**递归**调用时,推荐使用arguments.callee代替函数名本身。
|
||||
|
||||
### 3、arguments可以修改元素
|
||||
|
||||
之所以说arguments是伪数组,是因为:**arguments可以修改元素,但不能改变数组的长短**。举例:
|
||||
|
||||
```javascript
|
||||
fn(2,4);
|
||||
fn(2,4,6);
|
||||
fn(2,4,6,8);
|
||||
|
||||
function fn(a,b) {
|
||||
arguments[0] = 99; //将实参的第一个数改为99
|
||||
arguments.push(8); //此方法不通过,因为无法增加元素
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
262
04-JavaScript基础/12-对象的创建&构造函数.md
Normal file
262
04-JavaScript基础/12-对象的创建&构造函数.md
Normal file
@@ -0,0 +1,262 @@
|
||||
|
||||
|
||||
> 在看本文之前,可以先复习前面的一篇文章:《03-JavaScript基础/07-对象简介和对象的基本操作.md》
|
||||
|
||||
## 创建自定义对象的几种方法
|
||||
|
||||
### 方式一:对象字面量
|
||||
|
||||
**对象的字面量**就是一个{}。里面的属性和方法均是**键值对**。
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
var o = {
|
||||
name: "生命壹号",
|
||||
age: 26,
|
||||
isBoy: true,
|
||||
sayHi: function() {
|
||||
console.log(this.name);
|
||||
}
|
||||
};
|
||||
|
||||
console.log(o);
|
||||
```
|
||||
|
||||
控制台输出:
|
||||
|
||||

|
||||
|
||||
### 方式二:工厂模式
|
||||
|
||||
通过该方法可以大批量的创建对象。
|
||||
|
||||
```javascript
|
||||
/*
|
||||
* 使用工厂方法创建对象
|
||||
* 通过该方法可以大批量的创建对象
|
||||
*/
|
||||
function createPerson(name, age, gender) {
|
||||
//创建一个新的对象
|
||||
var obj = new Object();
|
||||
//向对象中添加属性
|
||||
obj.name = name;
|
||||
obj.age = age;
|
||||
obj.gender = gender;
|
||||
obj.sayName = function() {
|
||||
alert(this.name);
|
||||
};
|
||||
//将新的对象返回
|
||||
return obj;
|
||||
}
|
||||
|
||||
var obj2 = createPerson("猪八戒", 28, "男");
|
||||
var obj3 = createPerson("白骨精", 16, "女");
|
||||
var obj4 = createPerson("蜘蛛精", 18, "女");
|
||||
```
|
||||
|
||||
**弊端:**
|
||||
|
||||
使用工厂方法创建的对象,使用的构造函数都是Object。**所以创建的对象都是Object这个类型,就导致我们无法区分出多种不同类型的对象**。
|
||||
|
||||
### 方式三:利用构造函数
|
||||
|
||||
```javascript
|
||||
//利用构造函数自定义对象
|
||||
var stu1 = new Student("smyh");
|
||||
console.log(stu1);
|
||||
stu1.sayHi();
|
||||
|
||||
var stu2 = new Student("vae");
|
||||
console.log(stu2);
|
||||
stu2.sayHi();
|
||||
|
||||
|
||||
// 创建一个构造函数
|
||||
function Student(name) {
|
||||
this.name = name; //this指的是构造函数中的对象实例
|
||||
this.sayHi = function () {
|
||||
console.log(this.name + "厉害了");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
接下来,我们专门来讲一下构造函数。
|
||||
|
||||
## 构造函数
|
||||
|
||||
### 代码引入
|
||||
|
||||
|
||||
```javascript
|
||||
// 创建一个构造函数,专门用来创建Person对象
|
||||
function Person(name, age, gender) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.gender = gender;
|
||||
this.sayName = function() {
|
||||
alert(this.name);
|
||||
};
|
||||
}
|
||||
|
||||
// 创建一个构造函数,专门用来创建 Dog 对象
|
||||
function Dog() {}
|
||||
|
||||
var per = new Person("孙悟空", 18, "男");
|
||||
var per2 = new Person("玉兔精", 16, "女");
|
||||
var per3 = new Person("奔波霸", 38, "男");
|
||||
|
||||
var dog = new Dog();
|
||||
```
|
||||
|
||||
|
||||
### 构造函数和普通函数的区别
|
||||
|
||||
构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。
|
||||
|
||||
构造函数和普通函数的区别就是**调用方式**的不同:普通函数是直接调用,而构造函数需要使用new关键字来调用。
|
||||
|
||||
**this的指向也有所不同**:
|
||||
|
||||
- 1.以函数的形式调用时,this永远都是window。比如`fun();`相当于`window.fun();`
|
||||
|
||||
- 2.以方法的形式调用时,this是调用方法的那个对象
|
||||
|
||||
- 3.以构造函数的形式调用时,this是新创建的那个对象
|
||||
|
||||
### new 一个构造函数的执行流程
|
||||
|
||||
(1)开辟内存空间,存储新创建的对象
|
||||
|
||||
(2)将新建的对象设置为构造函数中的this,在构造函数中可以使用this来引用 新建的对象
|
||||
|
||||
(3)执行函数中的代码(包括设置对象属性和方法等)
|
||||
|
||||
(4)将新建的对象作为返回值返回
|
||||
|
||||
因为this指的是new一个Object之后的对象实例。于是,下面这段代码:
|
||||
|
||||
```javascript
|
||||
// 创建一个函数
|
||||
function createStudent(name) {
|
||||
var student = new Object();
|
||||
student.name = name; //第一个name指的是student对象定义的变量。第二个name指的是createStudent函数的参数。二者不一样
|
||||
}
|
||||
```
|
||||
|
||||
可以改进为:
|
||||
|
||||
```javascript
|
||||
// 创建一个函数
|
||||
function Student(name) {
|
||||
this.name = name; //this指的是构造函数中的对象实例
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
注意上方代码中的注释。
|
||||
|
||||
### 类、实例
|
||||
|
||||
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个**类**。
|
||||
|
||||
通过一个构造函数创建的对象,称为该类的**实例**。
|
||||
|
||||
### instanceof
|
||||
|
||||
使用 instanceof 可以检查**一个对象是否为一个类的实例**。
|
||||
|
||||
**语法如下**:
|
||||
|
||||
```javascript
|
||||
对象 instanceof 构造函数
|
||||
```
|
||||
|
||||
如果是,则返回true;否则返回false。
|
||||
|
||||
**代码举例**:
|
||||
|
||||
```javascript
|
||||
function Person() {}
|
||||
|
||||
function Dog() {}
|
||||
|
||||
var person1 = new Person();
|
||||
|
||||
var dog1 = new Dog();
|
||||
|
||||
console.log(person1 instanceof Person); // 打印结果: true
|
||||
console.log(dog1 instanceof Person); // 打印结果:false
|
||||
|
||||
console.log(dog1 instanceof Object); // 所有的对象都是Object的后代。因此,打印结果为:true
|
||||
```
|
||||
|
||||
根据上方代码中的最后一行,需要补充一点:**所有的对象都是Object的后代,因此 `任何对象 instanceof Object` 的返回结果都是true**。
|
||||
|
||||
|
||||
## others
|
||||
|
||||
### json的介绍
|
||||
|
||||
> 对象字面量和json比较像,这里我们对json做一个简单介绍。
|
||||
|
||||
JSON:JavaScript Object Notation(JavaScript对象表示形式)。
|
||||
|
||||
JSON和对象字面量的区别:JSON的属性必须用双引号引号引起来,对象字面量可以省略。
|
||||
|
||||
json举例:
|
||||
|
||||
```
|
||||
{
|
||||
"name" : "zs",
|
||||
"age" : 18,
|
||||
"sex" : true,
|
||||
"sayHi" : function() {
|
||||
console.log(this.name);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
注:json里一般放常量、数组、对象等,但很少放function。
|
||||
|
||||
另外,对象和json没有长度,json.length的打印结果是undefined。于是乎,自然也就不能用for循环遍历(因为遍历时需要获取长度length)。
|
||||
|
||||
**json遍历的方法:**
|
||||
|
||||
json 采用 `for...in...`进行遍历,和数组的遍历方式不同。如下:
|
||||
|
||||
|
||||
```html
|
||||
<script>
|
||||
var myJson = {
|
||||
"name": "smyhvae",
|
||||
"aaa": 111,
|
||||
"bbb": 222
|
||||
};
|
||||
|
||||
//json遍历的方法:for...in...
|
||||
for (var key in myJson) {
|
||||
console.log(key); //获取 键
|
||||
console.log(myJson[key]); //获取 值(第二种属性绑定和获取值的方法)
|
||||
console.log("------");
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
223
04-JavaScript基础/13-原型对象.md
Normal file
223
04-JavaScript基础/13-原型对象.md
Normal file
@@ -0,0 +1,223 @@
|
||||
|
||||
> 在看本文之前,我们可以先复习上一篇文章:《03-JavaScript基础/12-对象的创建&构造函数.md》
|
||||
|
||||
## 原型对象
|
||||
|
||||
### 原型的引入
|
||||
|
||||
```javascript
|
||||
function Person(name, age, gender) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.gender = gender;
|
||||
//向对象中添加一个方法
|
||||
this.sayName = function () {
|
||||
console.log("我是" + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
//创建一个Person的实例
|
||||
var per = new Person("孙悟空", 18, "男");
|
||||
var per2 = new Person("猪八戒", 28, "男");
|
||||
per.sayName();
|
||||
per2.sayName();
|
||||
|
||||
console.log(per.sayName == per2.sayName); //打印结果为false
|
||||
```
|
||||
|
||||
**分析如下**:
|
||||
|
||||
上方代码中,我们的sayName方法是写在构造函数 Person 内部的,然后在两个实例中进行了调用。造成的结果是,**构造函数每执行一次,就会给每个实例创建一个新的 sayName 方法**。也就是说,每个实例的sayName都是唯一的。因此,最后一行代码的打印结果为false。
|
||||
|
||||
按照上面这种写法,假设创建10000个对象实例,就会创建10000个 sayName 方法。这种写法肯定是不合适的。我们为何不让所有的对象共享同一个方法呢?
|
||||
|
||||
还有一种方式是,将sayName方法在全局作用域中定义:(不建议。原因看注释)
|
||||
|
||||
```javascript
|
||||
function Person(name, age, gender) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.gender = gender;
|
||||
//向对象中添加一个方法
|
||||
this.sayName = fun;
|
||||
}
|
||||
|
||||
//将sayName方法在全局作用域中定义
|
||||
/*
|
||||
* 将函数定义在全局作用域,污染了全局作用域的命名空间
|
||||
* 而且定义在全局作用域中也很不安全
|
||||
*/
|
||||
function fun() {
|
||||
alert("Hello大家好,我是:" + this.name);
|
||||
};
|
||||
```
|
||||
|
||||
比较好的方式是,在原型中添加sayName方法:
|
||||
|
||||
```javascript
|
||||
Person.prototype.sayName = function(){
|
||||
alert("Hello大家好,我是:"+this.name);
|
||||
};
|
||||
```
|
||||
|
||||
这也就引入了我们本文要讲的「原型」。
|
||||
|
||||
### 原型prototype的概念
|
||||
|
||||
**认识1**:
|
||||
|
||||
我们所创建的每一个函数,解析器都会向函数中添加一个属性 prototype。这个属性对应着一个对象,这个对象就是我们所谓的原型对象。
|
||||
|
||||
如果函数作为普通函数调用prototype没有任何作用,当函数以构造函数的形式调用时,它所创建的实例对象中都会有一个隐含的属性,指向该构造函数的原型,我们可以通过__proto__来访问该属性。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
// 定义构造函数
|
||||
function Person() {}
|
||||
|
||||
var per1 = new Person();
|
||||
var per2 = new Person();
|
||||
|
||||
console.log(Person.prototype); // 打印结果:[object object]
|
||||
|
||||
console.log(per1.__proto__ == Person.prototype); // 打印结果:true
|
||||
```
|
||||
|
||||
上方代码的最后一行:打印结果表明,`实例.__proto__` 和 `构造函数.prototype`都指的是原型对象。
|
||||
|
||||
**认识2**:
|
||||
|
||||
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
|
||||
|
||||
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样就不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。
|
||||
|
||||
**认识3**:
|
||||
|
||||
使用 `in` 检查对象中是否含有某个属性时,如果对象中没有但是**原型中**有,也会返回true。
|
||||
|
||||
可以使用对象的`hasOwnProperty()`来检查**对象自身中**是否含有该属性。
|
||||
|
||||
### 原型链
|
||||
|
||||
原型对象也是对象,所以它也有原型,当我们使用或访问一个对象的属性或方法时:
|
||||
|
||||
- 它会先在对象自身中寻找,如果有则直接使用;
|
||||
|
||||
- 如果没有则会去原型对象中寻找,如果找到则直接使用;
|
||||
|
||||
- 如果没有则去原型的原型中寻找,直到找到Object对象的原型。
|
||||
|
||||
- Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回 null
|
||||
|
||||
### 总结
|
||||
|
||||
第一次接触「原型」和「原型链」的时候,会比较难理解。多接触几次,再回过头来看,就慢慢熟悉了。
|
||||
|
||||
## 对象的 toString() 方法
|
||||
|
||||
我们先来看下面这段代码:
|
||||
|
||||
```javascript
|
||||
function Person(name, age, gender) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
var per1 = new Person("vae", 26, "男");
|
||||
|
||||
console.log("per1 = " + per1);
|
||||
console.log("per1 = " + per1.toString());
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
per1 = [object Object]
|
||||
per1 = [object Object]
|
||||
```
|
||||
|
||||
上面的代码中,我们尝试打印实例 per1 的内部信息,但是发现,无论是打印 `per1` 还是打印 `per1.toString()`,结果都是`object`,这是为啥呢?分析如下:
|
||||
|
||||
- 当我们直接在页面中打印一个对象时,其实是输出了对象的toString()方法的返回值。
|
||||
|
||||
- 如果我们希望在打印对象时,不输出[object Object],可以手动为对象添加一个toString()方法。意思是,重写 toString() 方法。
|
||||
|
||||
重写 toString() 方法,具体做法如下:
|
||||
|
||||
```javascript
|
||||
function Person(name, age, gender) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
//方式一:重写 Person 原型的toString方法。针对 Person 的所有实例生效
|
||||
Person.prototype.toString = function() {
|
||||
return (
|
||||
"Person[name=" +
|
||||
this.name +
|
||||
",age=" +
|
||||
this.age +
|
||||
",gender=" +
|
||||
this.gender +
|
||||
"]"
|
||||
);
|
||||
};
|
||||
|
||||
// 方式二:仅重写实例 per1 的 toString方法。但是这种写法,只对 per1 生效, 对 per2 无效
|
||||
/*
|
||||
per1.toString = function() {
|
||||
return (
|
||||
"Person[name=" +
|
||||
this.name +
|
||||
",age=" +
|
||||
this.age +
|
||||
",gender=" +
|
||||
this.gender +
|
||||
"]"
|
||||
);
|
||||
};
|
||||
*/
|
||||
|
||||
var per1 = new Person("smyh", 26, "男");
|
||||
|
||||
var per2 = new Person("vae", 30, "男");
|
||||
|
||||
console.log("per1 = " + per1);
|
||||
console.log("per2 = " + per2.toString());
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```javascript
|
||||
per1 = Person[name=smyh,age=26,gender=男]
|
||||
per2 = Person[name=vae,age=30,gender=男]
|
||||
```
|
||||
|
||||
代码分析:
|
||||
|
||||
上面的代码中,仔细看注释。我们重写了 Person 原型的 toString(),这样的话,可以保证对 Person 的所有实例生效。
|
||||
|
||||
从这个例子,我们可以看出 `prototype` 的作用。
|
||||
|
||||
## JS的垃圾回收(GC)机制
|
||||
|
||||
程序运行过程中会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢。所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾。
|
||||
|
||||
当一个对象没有任何的变量或属性对它进行引用时,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。
|
||||
|
||||
上面这句话,也可以这样理解:如果堆内存中的对象,没有任何变量指向它时,这个堆内存里的对象就会成为垃圾。
|
||||
|
||||
JS拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁。我们不需要也不能进行垃圾回收的操作。我们仅仅需要做的是:如果你不再使用该对象,那么,将改对象的引用设置为 null 即可。
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
176
04-JavaScript基础/14-数组简介.md
Normal file
176
04-JavaScript基础/14-数组简介.md
Normal file
@@ -0,0 +1,176 @@
|
||||
|
||||
|
||||
> 之前学习的数据类型,只能存储一个值(字符串为一个值)。如果我们想存储多个值,就可以使用数组。
|
||||
|
||||
## 数组简介
|
||||
|
||||
数组(Array)是属于**内置对象**,我们可以在[MDN](https://developer.mozilla.org/zh-CN/)网站上查询各种方法。
|
||||
|
||||
数组和普通对象的功能类似,也是用来存储一些值的。不同的是:
|
||||
|
||||
- 普通对象是使用字符串作为属性名的,而数组是使用数字来作为**索引**来操作元素。索引:从0开始的整数就是索引。
|
||||
|
||||
数组的存储性能比普通对象要好。在实际开发中我们经常使用数组来存储一些数据,使用频率非常高。
|
||||
|
||||
## 数组的基本操作
|
||||
|
||||
数组的元素可以是任意的数据类型,也可以是对象,也可以是函数,也可以是数组。
|
||||
|
||||
数组的元素中,如果存放的是数组,我们就称这种数组为二维数组。
|
||||
|
||||
### 创建数组对象
|
||||
|
||||
**方式一**:字面量定义。举例:
|
||||
|
||||
```javascript
|
||||
var arr = [1,2,3];
|
||||
```
|
||||
|
||||
**方式二**:对象定义(数组的构造函数)。
|
||||
|
||||
语法:
|
||||
|
||||
```
|
||||
var arr = new Array(参数);
|
||||
```
|
||||
|
||||
如果**参数为空**,则表示创建一个空数组;参数位置是**一个数值**时,表示数组长度;参数位置是**多个数值**时,表示数组中的元素。
|
||||
|
||||
上面的两种方式,我来举个例子:
|
||||
|
||||
|
||||
```javascript
|
||||
// 方式一
|
||||
var arr1 = [11, 12, 13];
|
||||
|
||||
// 方式二
|
||||
var arr2 = new Array(); // 参数为空
|
||||
var arr3 = new Array(4); // 参数为一个数值
|
||||
var arr4 = new Array(15, 16, 17); // 参数为多个数值
|
||||
|
||||
console.log(typeof arr1); // 打印结果:object
|
||||
|
||||
console.log("arr1 = " + JSON.stringify(arr1));
|
||||
console.log("arr2 = " + JSON.stringify(arr2));
|
||||
console.log("arr3 = " + JSON.stringify(arr3));
|
||||
console.log("arr4 = " + JSON.stringify(arr4));
|
||||
```
|
||||
|
||||
|
||||
打印结果:
|
||||
|
||||
```javascript
|
||||
object
|
||||
|
||||
arr1 = [11,12,13]
|
||||
arr2 = []
|
||||
arr3 = [null,null,null,null]
|
||||
arr4 = [15,16,17]
|
||||
```
|
||||
|
||||
从上方打印结果的第一行里,可以看出,数组的类型其实也是属于**对象**。
|
||||
|
||||
### 向数组中添加元素
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
数组[索引] = 值
|
||||
```
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var arr1 = [];
|
||||
|
||||
// 向数组中添加元素
|
||||
arr[0] = 10;
|
||||
arr[1] = 33;
|
||||
arr[2] = 22;
|
||||
arr[3] = 44;
|
||||
```
|
||||
|
||||
### 获取数组中的元素
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
数组[索引]
|
||||
```
|
||||
|
||||
数组的索引代表的是数组中的元素在数组中的位置,从0开始。
|
||||
|
||||
如果读取不存在的索引(比如元素没那么多),系统不会报错,而是返回undefined。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var arr = [21, 22, 23];
|
||||
|
||||
console.log(arr[0]); // 打印结果:21
|
||||
console.log(arr[5]); // 打印结果:undefined
|
||||
```
|
||||
|
||||
### 获取数组的长度
|
||||
|
||||
可以使用`length`属性来获取数组的长度(元素的个数)。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
数组的长度 = 数组名.length;
|
||||
```
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var arr = [21, 22, 23];
|
||||
|
||||
console.log(arr.length); // 打印结果:3
|
||||
```
|
||||
|
||||
补充:
|
||||
|
||||
对于连续的数组,使用length可以获取到数组的长度(元素的个数);对于非连续的数组,使用length会获取到数组的最大的索引+1。因此,尽量不要创建非连续的数组。
|
||||
|
||||
### 修改数组的长度(修改length)
|
||||
|
||||
- 如果修改的length大于原长度,则多出部分会空出来,置为 null。
|
||||
|
||||
- 如果修改的length小于原长度,则多出的元素会被删除,数组将从后面删除元素。
|
||||
|
||||
- (特例:伪数组arguments的长度可以修改,但是不能修改里面的元素,后面单独讲。)
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var arr1 = [11, 12, 13];
|
||||
var arr2 = [21, 22, 23];
|
||||
|
||||
// 修改数组 arr1 的 length
|
||||
arr1.length = 1;
|
||||
console.log(JSON.stringify(arr1));
|
||||
|
||||
// 修改数组 arr2 的 length
|
||||
arr2.length = 5;
|
||||
console.log(JSON.stringify(arr2));
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```javascript
|
||||
[11]
|
||||
|
||||
[21,22,23,null,null]
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
1175
04-JavaScript基础/15-数组的常见方法&数组的遍历.md
Normal file
1175
04-JavaScript基础/15-数组的常见方法&数组的遍历.md
Normal file
File diff suppressed because it is too large
Load Diff
275
04-JavaScript基础/16-内置对象:Date.md
Normal file
275
04-JavaScript基础/16-内置对象:Date.md
Normal file
@@ -0,0 +1,275 @@
|
||||
|
||||
## 内置对象简介
|
||||
|
||||
内置对象就是指这个语言自带的一些对象,供开发者使用,这些对象提供了一些常用的或是最基本而必要的功能。
|
||||
|
||||
**JavaScript的内置对象**:
|
||||
|
||||
| 内置对象 | 对象说明 |
|
||||
|:-------------|:-------------|
|
||||
| Arguments | 函数参数集合|
|
||||
| Array | 数组|
|
||||
| Boolean | 布尔对象|
|
||||
| Date | 日期时间|
|
||||
| Error | 异常对象|
|
||||
| Function | 函数构造器|
|
||||
| Math | 数学对象|
|
||||
| Number | 数值对象|
|
||||
| Object | 基础对象|
|
||||
| RegExp | 正则表达式对象|
|
||||
| String | 字符串对象|
|
||||
|
||||
前面的几篇文章中,我们专门讲到了数组 Array。今天这篇文章,我们来讲一下其他的内置对象。
|
||||
|
||||
## 内置对象:Date
|
||||
|
||||
### Date对象的创建
|
||||
|
||||
**写法一**:表示的是当前代码执行的时间(也可以理解成是获取当前时间对象)
|
||||
|
||||
```javascript
|
||||
var date1 = new Date();
|
||||
console.log(date1);
|
||||
```
|
||||
|
||||
**写法二**:在参数中传递一个表示时间的字符串(兼容性最强)
|
||||
|
||||
```javascript
|
||||
var date2 = new Date("2017/09/06 09:00:00");
|
||||
console.log(date2);
|
||||
```
|
||||
|
||||
写法三:(不常用)
|
||||
|
||||
```javascript
|
||||
var date3 = new Date('Wed Jan 27 2017 12:00:00 GMT+0800 (中国标准时间)');
|
||||
console.log(date3 );
|
||||
```
|
||||
|
||||
写法四:(不常用)
|
||||
|
||||
```javascript
|
||||
var date4 = new Date(2017, 1, 27); //写法四
|
||||
console.log(date4);
|
||||
```
|
||||
|
||||
以上四种写法的打印结果是:
|
||||
|
||||

|
||||
|
||||
### 获取日期和时间
|
||||
|
||||
Date对象 有如下方法,可以获取日期和时间:
|
||||
|
||||
- `getDate()` **获取日 1-31**
|
||||
|
||||
- `getDay()` **获取星期 0-6**(0代表周日,1代表周一)
|
||||
|
||||
- `getMonth() ` **获取月 0-11**(0代表一月)
|
||||
|
||||
- `getFullYear() ` 获取年份
|
||||
|
||||
- `getHours() ` 获取小时 0-23
|
||||
|
||||
- `getMinutes() ` 获取分钟 0-59
|
||||
|
||||
- `getSeconds()` 获取秒 0-59
|
||||
|
||||
- `getMilliseconds()` 获取毫秒 (1s = 1000ms)
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
// 我在执行这行代码时,当前时间为 2019年2月4日,周一,13:23:52
|
||||
var myDate = new Date();
|
||||
|
||||
console.log(myDate); // 打印结果:Mon Feb 04 2019 13:23:52 GMT+0800 (中国标准时间)
|
||||
console.log(myDate.getDate()); // 打印结果:4
|
||||
console.log(myDate.getDay()); // 打印结果:1
|
||||
console.log(myDate.getMonth()); // 打印结果:1
|
||||
console.log(myDate.getFullYear()); // 打印结果:2019
|
||||
console.log(myDate.getHours()); // 打印结果:13
|
||||
console.log(myDate.getMinutes()); // 打印结果:23
|
||||
console.log(myDate.getSeconds()); // 打印结果:52
|
||||
console.log(myDate.getMilliseconds()); // 打印结果:393
|
||||
|
||||
console.log(myDate.getTime()); // 获取时间戳。打印结果:1549257832393
|
||||
```
|
||||
|
||||
|
||||
### getTime():获取时间戳
|
||||
|
||||
Date对象 还有如下方法:
|
||||
|
||||
- `getTime()` 获取当前日期对象的**时间戳**。这个方法在实际开发中,用得比较多。
|
||||
|
||||
啥叫时间戳?接下来,我们解释一下。
|
||||
|
||||
**时间戳**:指的是从格林威治标准时间的`1970年1月1日,0时0分0秒`到当前日期所花费的**毫秒数**(1秒 = 1000毫秒)。
|
||||
|
||||
计算机底层在保存时间时,使用的都是时间戳。时间戳的存在,就是为了**统一**时间的单位。
|
||||
|
||||
我们再来看下面这样的代码:
|
||||
|
||||
```javascript
|
||||
var myDate = new Date("1970/01/01 0:0:0");
|
||||
|
||||
console.log(myDate.getTime()); // 获取时间戳
|
||||
```
|
||||
|
||||
打印结果(可能会让你感到惊讶)
|
||||
|
||||
```javascript
|
||||
-28800000
|
||||
```
|
||||
|
||||
为啥打印结果是`-28800000`,而不是`0`呢?这是因为,我们的当前代码,是在中文环境下运行的,与英文时间会存在**8个小时的时差**(中文时间比英文时间早了八个小时)。如果代码是在英文环境下运行,打印结果就是`0`。
|
||||
|
||||
|
||||
**利用时间戳检测代码的执行时间**:
|
||||
|
||||
我们可以在业务代码的前面定义 `时间戳1`,在业务代码的后面定义 `时间戳2`。把这两个时间戳相减,就能得出业务代码的执行时间。
|
||||
|
||||
|
||||
### format()
|
||||
|
||||
将时间对象转换为指定格式。
|
||||
|
||||
参考链接:<https://www.cnblogs.com/tugenhua0707/p/3776808.html>
|
||||
|
||||
## 练习
|
||||
|
||||
### 举例1:模拟日历
|
||||
|
||||
要求每天打开这个页面,都能定时显示当前的日期。
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
div {
|
||||
width: 800px;
|
||||
margin: 200px auto;
|
||||
color: red;
|
||||
text-align: center;
|
||||
font: 600 30px/30px "simsun";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div></div>
|
||||
|
||||
<script>
|
||||
//模拟日历
|
||||
//需求:每天打开这个页面都能定时显示年月日和星期几
|
||||
|
||||
//1.创建一个当前日期的日期对象
|
||||
var date = new Date();
|
||||
//2.然后获取其中的年、月、日和星期
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth();
|
||||
var hao = date.getDate();
|
||||
var week = date.getDay();
|
||||
// console.log(year+" "+month+" "+hao+" "+week);
|
||||
//3.赋值给div
|
||||
var arr = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
div.innerText = "今天是:"+year+"年"+(month+1)+"月"+hao+"日 "+arr[week];
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
实现效果:
|
||||
|
||||

|
||||
|
||||
|
||||
### 举例2:发布会倒计时
|
||||
|
||||
实现思路:
|
||||
|
||||
设置一个定时器,每间隔1毫秒就自动刷新一次div的内容。
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
div {
|
||||
width: 1210px;
|
||||
margin: 200px auto;
|
||||
color: red;
|
||||
text-align: center;
|
||||
font: 600 30px/30px "simsun";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div></div>
|
||||
|
||||
<script>
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
var timer = setInterval(fn, 1);
|
||||
|
||||
function fn() {
|
||||
var nowtime = new Date();
|
||||
var future = new Date("2019/02/03 11:20:00");
|
||||
var timeSum = future.getTime() - nowtime.getTime(); //获取时间差:发布会时间减去此刻的毫秒值
|
||||
var day = parseInt(timeSum / 1000 / 60 / 60 / 24);
|
||||
var hour = parseInt(timeSum / 1000 / 60 / 60 % 24);
|
||||
var minu = parseInt(timeSum / 1000 / 60 % 60);
|
||||
var sec = parseInt(timeSum / 1000 % 60);
|
||||
var millsec = parseInt(timeSum % 1000);
|
||||
|
||||
//问题处理:所有的时间小于10的时候,在前面自动补0,毫秒值要补双0(比如如,把 8 秒改成 08 秒)
|
||||
day = day < 10 ? "0" + day : day; //day小于10吗?如果小于,就补0;如果不小于,就是day本身
|
||||
hour = hour < 10 ? "0" + hour : hour;
|
||||
minu = minu < 10 ? "0" + minu : minu;
|
||||
sec = sec < 10 ? "0" + sec : sec;
|
||||
if (millsec < 10) {
|
||||
millsec = "00" + millsec;
|
||||
} else if (millsec < 100) {
|
||||
millsec = "0" + millsec;
|
||||
}
|
||||
// console.log(day);
|
||||
// console.log(parseInt(timeSum/1000/60/60/24));
|
||||
if (timeSum < 0) {
|
||||
div.innerHTML = "距离苹果发布会还有00天00小时00分00秒000毫秒";
|
||||
clearInterval(timer);
|
||||
return;
|
||||
}
|
||||
div.innerHTML = "距离苹果发布会还有" + day + "天" + hour + "小时" + minu + "分" + sec + "秒" + millsec + "毫秒";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
实现效果:
|
||||
|
||||

|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
100
04-JavaScript基础/17-内置对象:Math.md
Normal file
100
04-JavaScript基础/17-内置对象:Math.md
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
## 内置对象 Math
|
||||
|
||||
### 内置对象 Math 的常见方法
|
||||
|
||||
| 方法 | 描述 | 备注 |
|
||||
|:-------------|:-------------|:-------------|
|
||||
| Math.abs() | **返回绝对值** | |
|
||||
| Math.floor() | **向下取整**(向小取) | |
|
||||
| Math.ceil() | **向上取整**(向大取) | |
|
||||
| Math.round() | 四舍五入取整(正数四舍五入,负数五舍六入) | |
|
||||
| Math.random() | 生成0-1之间的随机数 | 不包含0和1 |
|
||||
| Math.max(x, y, z) | 返回多个数中的最大值 | |
|
||||
| Math.min(x, y, z) | 返回多个数中的最小值 | |
|
||||
| Math.pow(x,y) | 返回 x 的 y 次幂 | |
|
||||
| Math.sqrt() | 对一个数进行开方运算 | |
|
||||
|
||||
Math 和其他的对象不同,它不是一个构造函数,不需要创建对象。
|
||||
|
||||
Math属于一个工具类,里面封装了数学运算相关的属性和方法。
|
||||
|
||||
**举例**:
|
||||
|
||||
```javascript
|
||||
var num = -0.6;
|
||||
|
||||
console.log(Math.abs(num)); //取绝对值
|
||||
|
||||
console.log(Math.floor(num)); //向下取整,向小取
|
||||
|
||||
console.log(Math.ceil(num)); //向上取整,向大取
|
||||
|
||||
console.log(Math.round(num)); //四舍五入取整(正数四舍五入,负数五舍六入)
|
||||
|
||||
console.log(Math.random()); //生成0-1之间的随机数
|
||||
```
|
||||
|
||||
运行结果:
|
||||
|
||||
```
|
||||
0.6
|
||||
|
||||
-1
|
||||
|
||||
-0
|
||||
|
||||
-1
|
||||
|
||||
0.6453756205275165
|
||||
```
|
||||
|
||||
### Math.random()方法举例:生成 x-y 之间的随机数
|
||||
|
||||
生成 0-x 之间的随机数:
|
||||
|
||||
```javascript
|
||||
Math.round(Math.random()*x)
|
||||
```
|
||||
|
||||
生成 x-y 之间的随机数:
|
||||
|
||||
```javascript
|
||||
Math.round(Math.random()*(y-x)+x)
|
||||
```
|
||||
|
||||
## url 编码和解码
|
||||
|
||||
URI (Uniform ResourceIdentifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的URI中不能包含某些字符,例如空格。而这URI编码方法就可以对URI进行编码,它们用特殊的UTF-8编码替换所有无效的字符,从而让浏览器能够接受和理解。
|
||||
|
||||
```javascript
|
||||
encodeURIComponent(); //把字符串作为 URI 组件进行编码
|
||||
decodeURIComponent(); //把字符串作为 URI 组件进行解码
|
||||
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var url = "http://www.cnblogs.com/smyhvae/";
|
||||
|
||||
var str = encodeURIComponent(url);
|
||||
console.log(str); //打印url的编码
|
||||
console.log(decodeURIComponent(str)); //对url进行编码后,再解码,还原为url
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
91
04-JavaScript基础/18-包装类.md
Normal file
91
04-JavaScript基础/18-包装类.md
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
## 包装类
|
||||
|
||||
### 包装类的介绍
|
||||
|
||||
我们都知道,js中的数据类型包括以下几种。
|
||||
|
||||
- 基本数据类型:String、Number、Boolean、Null、Undefined
|
||||
|
||||
- 引用数据类型:Object
|
||||
|
||||
JS为我们提供了**三个包装类**:
|
||||
|
||||
- String():将基本数据类型字符串,转换为String对象。
|
||||
|
||||
- Number():将基本数据类型的数字,转换为Number对象。
|
||||
|
||||
- Boolean():将基本数据类型的布尔值,转换为Boolean对象。
|
||||
|
||||
通过上面这这三个包装类,我们可以**将基本数据类型的数据转换为对象**。
|
||||
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var num = new Number(3);
|
||||
|
||||
var str = new String("hello");
|
||||
|
||||
var bool = new Boolean(true);
|
||||
|
||||
console.log(typeof num); // 打印结果:object
|
||||
```
|
||||
|
||||
|
||||
**需要注意的是**:我们在实际应用中不会使用基本数据类型的对象。如果使用基本数据类型的对象,在做一些比较时可能会带来一些**不可预期**的结果。
|
||||
|
||||
比如说:
|
||||
|
||||
```javascript
|
||||
var boo1 = new Boolean(true);
|
||||
var boo2 = new Boolean(true);
|
||||
|
||||
console.log(boo1 === boo2); // 打印结果竟然是:false
|
||||
```
|
||||
|
||||
|
||||
再比如说:
|
||||
|
||||
```javascript
|
||||
var boo3 = new Boolean(false);
|
||||
|
||||
if (boo3) {
|
||||
console.log('qianguyihao'); // 这行代码竟然执行了
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 基本数据类型不能添加属性和方法
|
||||
|
||||
方法和属性只能添加给对象,不能添加给基本数据类型。
|
||||
|
||||
**注意**:当我们对一些基本数据类型的值去调用属性和方法时,浏览器会**临时使用包装类将其转换为对象**,然后在调用对象的属性和方法;调用完以后,在将其转换为基本数据类型。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var str = 123;
|
||||
|
||||
str = str.toString(); // 将 number 类型转换为 string 类型
|
||||
str.hello = "千古壹号"; // 添加属性
|
||||
|
||||
console.log(typeof str); // 打印结果:string
|
||||
console.log(str.hello); // 打印结果:undefined
|
||||
```
|
||||
|
||||
再比如,String 对象的很多内置方法,也可以直接给字符串用。此时,也是临时将字符串转换为 String 对象,然后再调用内置方法。
|
||||
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
495
04-JavaScript基础/19-内置对象:String.md
Normal file
495
04-JavaScript基础/19-内置对象:String.md
Normal file
@@ -0,0 +1,495 @@
|
||||
|
||||
## 前言
|
||||
|
||||
> 在日常开发中,String对象的使用频率是非常高的。所以有必要详细介绍。
|
||||
|
||||
### 基本数据类型不能绑定属性和方法
|
||||
|
||||
**1、基本数据类型:**
|
||||
|
||||
注意,基本数据类型`string`是**无法绑定属性和方法**的。比如说:
|
||||
|
||||
```javascript
|
||||
var str = "qianguyihao";
|
||||
|
||||
str.aaa = 12;
|
||||
console.log(typeof str); //打印结果为:string
|
||||
console.log(str.aaa); //打印结果为:undefined
|
||||
```
|
||||
|
||||
上方代码中,当我们尝试打印`str.aaa`的时候,会发现打印结果为:undefined。也就是说,不能给 `string` 绑定属性和方法。
|
||||
|
||||
当然,我们可以打印str.length、str.indexOf("m")等等。因为这两个方法的底层做了数据类型转换(**临时**将 `string` 字符串转换为 `String` 对象,然后再调用内置方法),也就是我们在上一篇文章中讲到的**包装类**。
|
||||
|
||||
**2、引用数据类型:**
|
||||
|
||||
引用数据类型`String`是可以绑定属性和方法的。如下:
|
||||
|
||||
|
||||
```javascript
|
||||
var strObj = new String("smyhvae");
|
||||
strObj.aaa = 123;
|
||||
console.log(strObj);
|
||||
console.log(typeof strObj); //打印结果:Object
|
||||
console.log(strObj.aaa);
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
内置对象Number也有一些自带的方法,比如:
|
||||
|
||||
- Number.MAX_VALUE;
|
||||
|
||||
- Number.MIN_VALUE;
|
||||
|
||||
内置对象Boolean也有一些自带的方法,但是用的不多。
|
||||
|
||||
### 在底层,字符串以字符数组的形式保存
|
||||
|
||||
在底层,字符串是以字符数组的形式保存的。代码举例:
|
||||
|
||||
```javascript
|
||||
var str = "smyhvae";
|
||||
console.log(str.length); // 获取字符串的长度
|
||||
console.log(str[2]); // 获取字符串中的第2个字符
|
||||
```
|
||||
|
||||
上方代码中,`smyhvae`这个字符串在底层是以`["s", "m", "y", "h", "v", "a", "e"]`的形式保存的。因此,我们既可以获取字符串的长度,也可以获取指定索引index位置的单个字符。这很像数组中的操作。
|
||||
|
||||
## 内置对象 String 的常见方法
|
||||
|
||||
### charAt()
|
||||
|
||||
`charAt`:返回字符串指定位置的字符。不会修改原字符串。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
字符 = str.charAt(index);
|
||||
```
|
||||
|
||||
解释:字符串中第一个字符的下标是 0。如果参数 index 不在 [0, string.length) 之间,该方法将返回一个空字符串。
|
||||
|
||||
而且,这里的 `str.charAt(index)`和`str[index]`的效果是一样的。
|
||||
|
||||
**代码举例**:
|
||||
|
||||
```javascript
|
||||
var str = new String("smyhvae");
|
||||
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
console.log(str.charAt(i));
|
||||
}
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
上面这个例子一般不用。一般打印数组和json的时候用索引,打印String不建议用索引。
|
||||
|
||||
### charCodeAt()
|
||||
|
||||
`charCodeAt`:返回字符串指定位置的字符的 Unicode 编码。不会修改原字符串。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
字符 = str.charCodeAt(index);
|
||||
```
|
||||
|
||||
**代码举例**:打印字符串的占位长度
|
||||
|
||||
提示:一个英文占一个位置,一个中文占两个位置。
|
||||
|
||||
思路:判断该字符是否在0-127之间(在的话是英文,不在是非英文)。
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<script>
|
||||
// sort(); 底层用到了charCodeAt();
|
||||
|
||||
var str = "I love my country!我你爱中国!";
|
||||
|
||||
//需求:求一个字符串占有几个字符位。
|
||||
//思路;如果是英文,站一个字符位,如果不是英文占两个字符位。
|
||||
//技术点:判断该字符是否在0-127之间。(在的话是英文,不在是非英文)
|
||||
alert(getZFWlength(str));
|
||||
alert(str.length);
|
||||
|
||||
//定义方法:字符位
|
||||
function getZFWlength(string) {
|
||||
//定义一个计数器
|
||||
var count = 0;
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
//对每一位字符串进行判断,如果Unicode编码在0-127,计数器+1;否则+2
|
||||
if (string.charCodeAt(i) < 128 && string.charCodeAt(i) >= 0) {
|
||||
count++;
|
||||
} else {
|
||||
count += 2;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```
|
||||
30
|
||||
24
|
||||
```
|
||||
|
||||
从打印结果可以看出:字符串的长度是24,但是却占了30个字符位(一个中文占两个字符位)。
|
||||
|
||||
另外,sort()方法其实底层也是用到了charCodeAt(),因为用到了Unicode编码。
|
||||
|
||||
### String.fromCharCode()
|
||||
|
||||
`String.fromCharCode()`:根据字符的 Unicode 编码获取字符。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var result1 = String.fromCharCode(72);
|
||||
var result2 = String.fromCharCode(20013);
|
||||
|
||||
console.log(result1); // 打印结果:H
|
||||
console.log(result2); // 打印结果:中
|
||||
```
|
||||
|
||||
### indexOf()/lastIndexOf()
|
||||
|
||||
`indexOf()/lastIndexOf()`:获取指定字符的索引。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
索引值 = str.indexOf(想要查询的字符);
|
||||
```
|
||||
|
||||
解释:`indexOf()` 是从前向后索引字符串的位置。同理,`lastIndexOf()`是从后向前寻找。
|
||||
|
||||
**作用**:可以检索一个字符串中是否含有指定内容。如果字符串中含有该内容,则会返回其**第一次出现**的索引;如果没有找到指定的内容,则返回 -1。
|
||||
|
||||
因此可以得出一个技巧:**如果获取的索引值为0,说明字符串是以查询的参数为开头的**。
|
||||
|
||||
这个方法还可以指定第二个参数,用来 指定开始查找的位置。
|
||||
|
||||
**代码举例1**:
|
||||
|
||||
```javascript
|
||||
var str = "abcdea";
|
||||
|
||||
//给字符查索引(索引值为0,说明字符串以查询的参数为开头)
|
||||
console.log(str.indexOf("c"));
|
||||
console.log(str.lastIndexOf("c"));
|
||||
|
||||
console.log(str.indexOf("a"));
|
||||
console.log(str.lastIndexOf("a"));
|
||||
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
**代码举例2**:(两个参数时,需要特别注意)
|
||||
|
||||
```javascript
|
||||
var str = 'qianguyihao';
|
||||
result = str.indexOf('a', 3); // 从第三个位置开始查找 'a'这个字符 【重要】
|
||||
|
||||
console.log(result); // 打印结果:9
|
||||
```
|
||||
|
||||
上方代码中,`indexOf()`方法中携带了两个参数,具体解释请看注释。
|
||||
|
||||
### concat()
|
||||
|
||||
`concat()`:字符串的连接。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
新字符串 = str1.concat(str2); //链接两个字符串
|
||||
```
|
||||
|
||||
这种方法基本不用,直接把两个字符串相加就好。
|
||||
|
||||
是的,你会发现,数组中也有`concat()`方法,用于数组的连接。这个方法在数组中用得挺多的。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var str1 = 'qiangu';
|
||||
var str2 = 'yihao';
|
||||
|
||||
var result = str1.concat(str2);
|
||||
console.log(result); // 打印结果:qianguyihao
|
||||
```
|
||||
|
||||
### slice()
|
||||
|
||||
`slice()`:从字符串中截取指定的内容。不会修改原字符串,而是将及截取到的内容返回。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
字符串 = str.slice(开始索引, 结束索引); //两个参数都是索引值。包左不包右。
|
||||
```
|
||||
|
||||
解释:上面的参数,包左不包右。参数举例如下:
|
||||
|
||||
- (2, 5) 截取时,包左不包右。
|
||||
|
||||
- (2) 表示**从指定的索引位置开始,截取到最后**。
|
||||
|
||||
- (-3) 表示从倒数第几个开始,截取到最后。
|
||||
|
||||
- (1, -1) 表示从第一个截取到倒数第一个。
|
||||
|
||||
- (5, 2) 表示前面的大,后面的小,返回值为空。
|
||||
|
||||
### substring()
|
||||
|
||||
`substring()`:从字符串中截取指定的内容。和`slice()`类似。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
字符串 = str.substring(开始索引, 结束索引); //两个参数都是索引值。包左不包右。
|
||||
```
|
||||
|
||||
`substring()`和`slice()`是类似的。但不同之处在于:
|
||||
|
||||
- `substring()`不能接受负值作为参数。如果传递了一个**负值**,则默认使用0。
|
||||
|
||||
- `substring()`还会自动调整参数的位置,如果第二个参数小于第一个,则自动交换。比如说, `substring(1, 0)`截取的是第一个字符。
|
||||
|
||||
### substr()
|
||||
|
||||
`substr()`:从字符串中截取指定的内容。不会修改原字符串,而是将及截取到的内容返回。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
字符串 = str.substr(开始索引, 截取的长度);
|
||||
```
|
||||
|
||||
参数举例:
|
||||
|
||||
- (2,4):从索引值为2的字符开始,截取4个字符。
|
||||
|
||||
- (1):从指定位置开始,截取到最后。
|
||||
|
||||
- (-3):从倒数第几个开始,剪到最后.
|
||||
|
||||
- 不包括前大后小的情况。
|
||||
|
||||
备注:ECMAscript 没有对 `substr()` 方法进行标准化,因此不建议使用它。
|
||||
|
||||
### split() 【重要】
|
||||
|
||||
`split()`:将一个字符串拆分成一个数组。
|
||||
|
||||
语法:
|
||||
|
||||
|
||||
```javascript
|
||||
数组 = str.split();
|
||||
```
|
||||
|
||||
|
||||
备注:`split()`这个方法在实际开发中用得非常多。一般来说,从接口拿到的json数据中,经常会收到类似于`"q, i, a, n"`这样的字符串,前端需要将这个字符串拆分成`['q', 'i', 'a', 'n']`数组,这个时候`split()`方法就排上用场了。
|
||||
|
||||
**代码举例1**:
|
||||
|
||||
```javascript
|
||||
|
||||
var str = "qian, gu, yi, hao"; // 用逗号隔开的字符串
|
||||
var array = str.split(","); // 将字符串 str 拆分成数组,通过逗号来拆分
|
||||
|
||||
console.log(array); // 打印结果是数组:["qian", " gu", " yi", " hao"]
|
||||
```
|
||||
|
||||
**代码举例2**:
|
||||
|
||||
```javascript
|
||||
//split()方法:字符串变数组
|
||||
var str3 = "生命壹号|许嵩|smyhvae";
|
||||
|
||||
console.log(str3);
|
||||
|
||||
console.log(str3.split()); // 无参数,表示:把字符串作为一个元素添加到数组中。
|
||||
|
||||
console.log(str3.split("")); //参数为空字符串,则表示:分隔字符串中每一个字符,分别添加到数组中
|
||||
|
||||
console.log(str3.split("|")); //参数为指定字符,表示:此字符将不会出现在数组的任意一个元素中
|
||||
|
||||
console.log(str3.split("许")); //同理
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
### trim()
|
||||
|
||||
`trim()`:去除字符串前后的空白。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
//去除前后的空格,trim();
|
||||
var str1 = " a b c ";
|
||||
console.log(str1);
|
||||
console.log(str1.trim());
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
### replace()
|
||||
|
||||
`replace()`:将字符串中的指定内容,替换为新的内容并返回。不会修改原字符串。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
新的字符串 = str.replace(被替换的内容,新的内容);
|
||||
```
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
//replace()方法:替换
|
||||
var str2 = "Today is fine day,today is fine day !!!"
|
||||
console.log(str2);
|
||||
console.log(str2.replace("today","tomorrow")); //只能替换第一个today
|
||||
console.log(str2.replace(/today/gi,"tomorrow")); //这里用到了正则,才能替换所有的today
|
||||
```
|
||||
|
||||
### 大小写转换
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var str = "abcdEFG";
|
||||
|
||||
//转换成小写
|
||||
console.log(str.toLowerCase());
|
||||
|
||||
//转换成大写
|
||||
console.log(str.toUpperCase());
|
||||
```
|
||||
|
||||
## html方法
|
||||
|
||||
- anchor() 创建a链接
|
||||
|
||||
- big()
|
||||
|
||||
- sub()
|
||||
|
||||
- sup()
|
||||
|
||||
- link()
|
||||
|
||||
- bold()
|
||||
|
||||
注意,str.link() 返回值是字符串。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
var str = "你好";
|
||||
|
||||
console.log(str.anchor())
|
||||
console.log(str.big())
|
||||
console.log(str.sub())
|
||||
console.log(str.sup())
|
||||
console.log(str.link("http://www.baidu.com"));
|
||||
console.log(str.bold())
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
## 字符串练习
|
||||
|
||||
**练习1**:"smyhvaevaesmyh"查找字符串中所有m出现的位置。
|
||||
|
||||
代码实现:
|
||||
|
||||
```javascript
|
||||
var str2 = "abcoefoxyozzopp";
|
||||
for(var i=0;i<str2.length;i++){
|
||||
//如果指定位置的符号=== "o"
|
||||
//str2[i]
|
||||
if( str2.charAt(i)==="o"){
|
||||
console.log(i);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**练习2**:判断一个字符串中出现次数最多的字符,统计这个次数
|
||||
|
||||
```html
|
||||
<script>
|
||||
var str2 = "smyhvaevaesmyhvae";
|
||||
|
||||
//定义一个json,然后判断json中是够有该属性,如果有该属性,那么值+1;否则创建一个该属性,并赋值为1;
|
||||
var json = {};
|
||||
for (var i = 0; i < str2.length; i++) {
|
||||
//判断:如果有该属性,那么值+1;否则创建一个该属性,并赋值为1;
|
||||
var key = str2.charAt(i);
|
||||
if (json[key] === undefined) {
|
||||
json[key] = 1;
|
||||
} else {
|
||||
json[key] += 1;
|
||||
}
|
||||
}
|
||||
console.log(json);
|
||||
|
||||
|
||||
console.log("----------------");
|
||||
//获取json中属性值最大的选项
|
||||
var maxKey = "";
|
||||
var maxValue = 0;
|
||||
for (var k in json) {
|
||||
// if(maxKey == ""){
|
||||
// maxKey = k;
|
||||
// maxValue = json[k];
|
||||
// }else{
|
||||
if (json[k] > maxValue) {
|
||||
maxKey = k;
|
||||
maxValue = json[k];
|
||||
}
|
||||
// }
|
||||
}
|
||||
console.log(maxKey);
|
||||
console.log(maxValue);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
349
04-JavaScript基础/20-正则表达式.md
Normal file
349
04-JavaScript基础/20-正则表达式.md
Normal file
@@ -0,0 +1,349 @@
|
||||
|
||||
## 正则表达式简介
|
||||
|
||||
**定义**:正则表达式用于定义一些字符串的规则。
|
||||
|
||||
**作用**:计算机可以根据正则表达式,来检查一个字符串是否符合指定的规则;或者将字符串中符合规则的内容提取出来。
|
||||
|
||||
如果你想查看正则更多的内容,可以查阅官方文档关于 RegExp 这个内置对象的用法。
|
||||
|
||||
## 创建正则表达式的对象
|
||||
|
||||
### 方式一:使用构造函数创建正则表达式的对象
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
var 变量 = new RegExp("正则表达式"); // 注意,参数是字符串
|
||||
|
||||
var 变量 = new RegExp("正则表达式", "匹配模式"); // 注意,两个参数都是字符串
|
||||
```
|
||||
|
||||
备注:`RegExp`的意思是 **Regular expression**。使用typeof检查正则对象,会返回object。
|
||||
|
||||
上面的语法中,既可以传一个参数,也可以传两个参数。
|
||||
|
||||
创建了正则表达式的对象后,该怎么使用呢?大致分为两个步骤:
|
||||
|
||||
- (1)创建正则表达式的对象 reg。
|
||||
|
||||
- (2)使用 reg 的test() 方法,判断指定字符串是否符合规则。
|
||||
|
||||
**正则表达式的`test()`方法**:【重要】
|
||||
|
||||
```javascript
|
||||
myReg.test(str); // 判断字符串 str 是否符合 指定的 myReg 这个正则表达式的规则
|
||||
```
|
||||
|
||||
解释:使用`test()`这个方法可以用来检查一个字符串是否符合正则表达式的规则,**如果符合则返回true,否则返回false**。
|
||||
|
||||
我们来看看下面的例子。
|
||||
|
||||
**1、传一个参数时**:
|
||||
|
||||
构造函数 RegExp 中,可以只传一个参数。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var reg = new RegExp("a"); // 定义一个正则表达式:检查一个字符串中是否含有 a
|
||||
|
||||
var str1 = "qianguyihao";
|
||||
var str2 = "smyh";
|
||||
|
||||
// 通过 test()方法,判断字符串是否符合 上面定义的 reg 规则
|
||||
console.log(reg.test(str1)); // 打印结果:true
|
||||
console.log(reg.test(str2)); // 打印结果:false
|
||||
|
||||
```
|
||||
|
||||
注意,上面的例子中,我们是先定义了一个正则表达式的规则,然后通过正则表达式的`test()`方法来判断字符串是否符合之前定义的规则。
|
||||
|
||||
**2、传两个参数时**:匹配模式 【重要】
|
||||
|
||||
构造函数 RegExp 中,也可以传两个参数。我们可以传递一个**匹配模式**作为第二个参数。这个参数可以是:
|
||||
|
||||
- `i` 忽略大小写。这里的 i 指的是 ignore。
|
||||
|
||||
- `g` 全局匹配模式。这里的 g 指的是 global。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var reg = new RegExp('A', 'i');
|
||||
var str = 'qiangu';
|
||||
|
||||
console.log(reg.test(str)); // 打印结果:true
|
||||
```
|
||||
|
||||
### 方式二:使用字面量创建正则表达式
|
||||
|
||||
我们可以使用字面量来创建正则表达式。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
var 变量 = /正则表达式/; // 注意,这个语法里没有引号
|
||||
|
||||
var 变量 = /正则表达式/匹配模式; // 注意,这个语法里没有引号
|
||||
```
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var reg = /A/i; // 定义正则表达式的规则:检查一个字符串中是否含有 a。忽略大小写。
|
||||
var str = "qiangu";
|
||||
|
||||
console.log(typeof reg); // 打印结果:object
|
||||
console.log(reg.test(str)); // 打印结果:true
|
||||
```
|
||||
|
||||
### 两种方式的对比
|
||||
|
||||
**以上两种方式的对比**:
|
||||
|
||||
- 方式一:使用构造函数创建时,更加灵活,因为参数中还可以传递变量。
|
||||
|
||||
- 方式二:使用字面量的方式创建,更加简单。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var reg = new RegExp("a", "i"); // 方式一
|
||||
|
||||
var reg = /a/i; // 方式二
|
||||
```
|
||||
|
||||
上面这两行代码的作用是等价的。
|
||||
|
||||
## 正则表达式的简单语法
|
||||
|
||||
### 检查一个字符串中是否包含 a或b
|
||||
|
||||
**写法1**:
|
||||
|
||||
```javascript
|
||||
var reg = /a|b/;
|
||||
```
|
||||
|
||||
解释:使用 `|` 表示`或`的意思。
|
||||
|
||||
**写法2**:
|
||||
|
||||
```javascript
|
||||
var reg = /[ab]/; // 跟上面的那行语法,是等价的
|
||||
```
|
||||
|
||||
解释:这里的`[]`也是表示`或`的意思。
|
||||
|
||||
`[]`这个符号在正则还是比较常用的。我们接下来看几个例子。
|
||||
|
||||
### []表示:或
|
||||
|
||||
一些规则:
|
||||
|
||||
- `/[ab]/` 等价于 `/a|b/`:检查一个字符串中是否包含 **a或b**
|
||||
|
||||
- `/[a-z]/`:检查一个字符串那种是否包含**任意小写字母**
|
||||
|
||||
- `/[A-Z]/`:任意大写字母
|
||||
|
||||
- `/[A-z]/`:任意字母
|
||||
|
||||
- `/[0-9]/`:任意数字
|
||||
|
||||
- `/a[bde]c/`:检查一个字符串中是否包含 abc 或 adc 或 aec
|
||||
|
||||
### [^ ] 表示:除了
|
||||
|
||||
举例1:
|
||||
|
||||
```javascript
|
||||
var reg = /[^ab]/; // 规则:字符串中,除了a、b之外,还有没有其他的字符内容?
|
||||
var str = "acb";
|
||||
|
||||
console.log(reg.test(str)); // 打印结果:true
|
||||
```
|
||||
|
||||
举例2:(可以用来验证某字符串是否为 纯数字)
|
||||
|
||||
```javascript
|
||||
var reg = /[^0-9]/; // 规则:字符串中,除了数字之外,还有没有其他的内容?
|
||||
var str1 = "1991";
|
||||
var str2 = "199a1";
|
||||
|
||||
console.log(reg.test(str1)); // 打印结果:false (如果字符串是 纯数字,则返回 false)
|
||||
console.log(reg.test(str2)); // 打印结果:true
|
||||
```
|
||||
|
||||
## 支持正则表达式的 String 对象的方法
|
||||
|
||||
String对象的如下方法,是支持正则表达式的:
|
||||
|
||||
| 方法 | 描述 | 备注 |
|
||||
|:-------------|:-------------|:-------------|
|
||||
| split() | 将字符串拆分成数组 | |
|
||||
| search() | 搜索字符串中是否含有指定内容,返回索引 index | |
|
||||
| match() | 根据正则表达式,从一个字符串中将符合条件的内容提取出来 | |
|
||||
| replace() | 将字符串中的指定内容,替换为新的内容并返回 | |
|
||||
|
||||
下面来分别介绍和举例。
|
||||
|
||||
### split()
|
||||
|
||||
`split()`:将一个字符串拆分成一个数组。
|
||||
|
||||
备注:关于`split()`更详细的用法,可以看之前的关于《内置对象:String》这篇文章。
|
||||
|
||||
`split()`方法可以接受一个正则表达式作为参数。
|
||||
|
||||
**正则相关的举例**:根据任意字母,将字符串拆分成数组。
|
||||
|
||||
代码实现:(通过正则)
|
||||
|
||||
```javascript
|
||||
var str = "1a2b3c4d5e6f7g";
|
||||
|
||||
var result = str.split(/[A-z]/); // 参数是一个正则表达式:表示所有字符
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||
```json
|
||||
["1", "2", "3", "4", "5", "6", "7", ""]
|
||||
```
|
||||
|
||||
### search()
|
||||
|
||||
`search()`:搜索字符串中是否含有指定内容。如果搜索到指定内容,则会返回第一次出现的索引;否则返回-1。
|
||||
|
||||
`search()`方法可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串。`serach()`只会查找第一个,即使设置全局匹配也没用。
|
||||
|
||||
**举例**:
|
||||
|
||||
```javascript
|
||||
var str = "hello abc hello aec afc";
|
||||
/*
|
||||
* 搜索字符串中是否含有abc 或 aec 或 afc
|
||||
*/
|
||||
result = str.search(/a[bef]c/);
|
||||
console.log(result); // 打印结果:6
|
||||
```
|
||||
|
||||
|
||||
### match()
|
||||
|
||||
`match()`:根据正则表达式,从一个字符串中将符合条件的内容提取出来,封装到一个数组中返回(即使只查询到一个结果)。
|
||||
|
||||
**注意**:默认情况下,`match()`方法只会找到**第一个**符合要求的内容,找到以后就停止检索。我们可以设置正则表达式为**全局匹配**模式,这样就会匹配到所有的内容,并以**数组**的形式返回。
|
||||
|
||||
另外,我们可以为一个正则表达式设置多个匹配模式,且匹配模式的顺序无所谓。
|
||||
|
||||
**代码举例**:
|
||||
|
||||
```javascript
|
||||
var str = "1a2a3a4a5e6f7A8B9C";
|
||||
|
||||
var result1 = str.match(/[a-z]/); // 找到符合要求的第一个内容,然后返回
|
||||
var result2 = str.match(/[a-z]/g); // 设置为“全局匹配”模式,匹配字符串中 所有的小写字母
|
||||
var result3 = str.match(/[a-z]/gi); // 设置多个匹配模式,匹配字符串中 所有的字母(忽略大小写)
|
||||
|
||||
console.log(result1); // 打印结果:["a"]
|
||||
console.log(result2); // 打印结果:["a", "a", "a", "a", "e", "f"]
|
||||
console.log(result3); // 打印结果:["a", "a", "a", "a", "e", "f", "A", "B", "C"]
|
||||
```
|
||||
|
||||
**总结**:
|
||||
|
||||
match()这个方法还是很实用的,可以在一个很长的字符串中,提取出**有规则**的内容。这不就是爬虫的时候经常会遇到的场景么?
|
||||
|
||||
### replace()
|
||||
|
||||
`replace()`:将字符串中的指定内容,替换为新的内容并返回。不会修改原字符串。
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
新的字符串 = str.replace(被替换的内容,新的内容);
|
||||
```
|
||||
|
||||
参数解释:
|
||||
|
||||
- 被替换的内容:可以接受一个正则表达式作为参数。
|
||||
|
||||
- 新的内容:默认只会替换第一个。如果需要替换全部符合条件的内容,可以设置正则表达式为**全局匹配**模式。
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
//replace()方法:替换
|
||||
var str2 = "Today is fine day,today is fine day !!!"
|
||||
|
||||
console.log(str2);
|
||||
console.log(str2.replace("today","tomorrow")); //只能替换第一个today
|
||||
console.log(str2.replace(/today/gi,"tomorrow")); //这里用到了正则,且为“全局匹配”模式,才能替换所有的today
|
||||
```
|
||||
|
||||
## 常见正则表达式举例
|
||||
|
||||
### 检查一个字符串是否是一个合法手机号
|
||||
|
||||
手机号的规则:
|
||||
|
||||
- 以1开头
|
||||
|
||||
- 第二位是3~9之间任意数字
|
||||
|
||||
- 三位以后任意9位数字
|
||||
|
||||
正则实现:
|
||||
|
||||
```javascript
|
||||
var phoneStr = "13067890123";
|
||||
|
||||
var phoneReg = /^1[3-9][0-9]{9}$/;
|
||||
|
||||
console.log(phoneReg.test(phoneStr));
|
||||
```
|
||||
|
||||
**备注**:如果在正则表达式中同时使用`^`和`$`符号,则要求字符串必须完全符合正则表达式。
|
||||
|
||||
### 去掉字符串开头和结尾的空格
|
||||
|
||||
正则实现:
|
||||
|
||||
```javascript
|
||||
str = str.replace(/^\s*|\s*$/g,"");
|
||||
```
|
||||
|
||||
解释如下:
|
||||
|
||||
```javascript
|
||||
str = str.replace(/^\s*/, ""); //去除开头的空格
|
||||
|
||||
str = str.replace(/\s*$/, ""); //去除结尾的空格
|
||||
```
|
||||
|
||||
### 判断字符串是否为电子邮件
|
||||
|
||||
正则实现:
|
||||
|
||||
```javascript
|
||||
var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
|
||||
|
||||
var email = "abchello@163.com";
|
||||
|
||||
console.log(emailReg.test(email));
|
||||
```
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
328
04-JavaScript基础/21-事件简介.md
Normal file
328
04-JavaScript基础/21-事件简介.md
Normal file
@@ -0,0 +1,328 @@
|
||||
|
||||
> 本文最初发表于[博客园](http://www.cnblogs.com/smyhvae/p/8366012.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
> 以下是正文。
|
||||
|
||||
## 事件简介
|
||||
|
||||
事件:就是文档或浏览器窗口中发生的一些特定的交互瞬间。对于 Web 应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、关闭弹窗等等。
|
||||
|
||||
JavaScript 是以**事件驱动为核心**的一门语言。JavaScript 与 HTML 之间的交互是通过事件实现的。
|
||||
|
||||
### 事件的三要素
|
||||
|
||||
**事件的三要素:事件源、事件、事件驱动程序**。
|
||||
|
||||
比如,我用手去按开关,灯亮了。这件事情里,事件源是:手。事件是:按开关。事件驱动程序是:灯开了或者关了。
|
||||
|
||||
再比如,网页上弹出一个广告,我点击右上角的`X`,广告就关闭了。这件事情里,事件源是:`X`。事件是:onclick。事件驱动程序是:广告关闭了。
|
||||
|
||||
于是我们可以总结出:谁引发的后续事件,谁就是事件源。
|
||||
|
||||
**总结如下:**
|
||||
|
||||
- 事件源:引发后续事件的html标签。
|
||||
|
||||
- 事件:js已经定义好了(见下图)。
|
||||
|
||||
- 事件驱动程序:对样式和html的操作。也就是DOM。
|
||||
|
||||
也就是说,我们可以在时间对应的属性中写一些js代码,当事件被触发时,这些代码将会执行。
|
||||
|
||||
**代码书写步骤如下:**(重要)
|
||||
|
||||
- (1)获取事件源:document.getElementById(“box”); // 类似于Android里面的findViewById
|
||||
|
||||
- (2)绑定事件: 事件源box.事件onclick = function(){ 事件驱动程序 };
|
||||
|
||||
- (3)书写事件驱动程序:关于DOM的操作。
|
||||
|
||||
最简单的代码举例:(点击box1,然后弹框)
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div id="box1"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 1、获取事件源
|
||||
var div = document.getElementById("box1");
|
||||
// 2、绑定事件
|
||||
div.onclick = function () {
|
||||
// 3、书写事件驱动程序
|
||||
alert("我是弹出的内容");
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
```
|
||||
|
||||
常见的事件如下:
|
||||
|
||||

|
||||
|
||||
下面针对这事件的三要素,进行分别介绍。
|
||||
|
||||
### 1、获取事件源的方式(DOM节点的获取)
|
||||
|
||||
获取事件源的常见方式如下:
|
||||
|
||||
```javascript
|
||||
var div1 = document.getElementById("box1"); //方式一:通过id获取单个标签
|
||||
|
||||
var arr1 = document.getElementsByTagName("div"); //方式二:通过 标签名 获得 标签数组,所以有s
|
||||
|
||||
var arr2 = document.getElementsByClassName("hehe"); //方式三:通过 类名 获得 标签数组,所以有s
|
||||
```
|
||||
|
||||
### 2、绑定事件的方式
|
||||
|
||||
方式一:直接绑定匿名函数
|
||||
|
||||
```html
|
||||
<div id="box1" ></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var div1 = document.getElementById("box1");
|
||||
//绑定事件的第一种方式
|
||||
div1.onclick = function () {
|
||||
alert("我是弹出的内容");
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
方式二:先单独定义函数,再绑定
|
||||
|
||||
```html
|
||||
<div id="box1" ></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var div1 = document.getElementById("box1");
|
||||
//绑定事件的第二种方式
|
||||
div1.onclick = fn; //注意,这里是fn,不是fn()。fn()指的是返回值。
|
||||
//单独定义函数
|
||||
function fn() {
|
||||
alert("我是弹出的内容");
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
注意上方代码的注释。**绑定的时候,是写fn,不是写fn()**。fn代表的是整个函数,而fn()代表的是返回值。
|
||||
|
||||
方式三:行内绑定
|
||||
|
||||
```html
|
||||
<!--行内绑定-->
|
||||
<div id="box1" onclick="fn()"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function fn() {
|
||||
alert("我是弹出的内容");
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
注意第一行代码,绑定时,是写的`"fn()"`,不是写的`"fn"`。因为绑定的这段代码不是写在js代码里的,而是被识别成了**字符串**。
|
||||
|
||||
### 3、事件驱动程序
|
||||
|
||||
我们在上面是拿alert举例,不仅如此,我们还可以操作标签的属性和样式。举例如下:
|
||||
|
||||
点击鼠标时,原本粉色的div变大了,背景变红:
|
||||
|
||||
```html
|
||||
<style>
|
||||
#box1 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: pink;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="box1" ></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var div1 = document.getElementById("box1");
|
||||
//点击鼠标时,原本粉色的div变大了,背景变红了
|
||||
div1.onclick = function () {
|
||||
div1.style.width = "200px"; //属性值要写引号
|
||||
div1.style.height = "200px";
|
||||
div1.style.backgroundColor = "red"; //属性名是backgroundColor,不是background-color
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
上方代码的注意事项:
|
||||
|
||||
- 在js里写属性值时,要用引号
|
||||
|
||||
- 在js里写属性名时,是`backgroundColor`,不是CSS里面的`background-color`。
|
||||
|
||||
实现效果如下:
|
||||
|
||||

|
||||
|
||||
### onload事件
|
||||
|
||||
> onload事件比较特殊,这里单独讲一下。
|
||||
|
||||
**当页面加载(文本和图片)完毕的时候,触发onload事件。**
|
||||
|
||||
举例:
|
||||
|
||||
```html
|
||||
<script type="text/javascript">
|
||||
window.onload = function () {
|
||||
console.log("smyhvae"); //等页面加载完毕时,打印字符串
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
有一点我们要知道:**js的加载是和html同步加载的**。因此,如果使用元素在定义元素之前,容易报错。这个时候,onload事件就能派上用场了,我们可以把使用元素的代码放在onload里,就能保证这段代码是最后执行。
|
||||
|
||||
建议是:整个页面上所有元素加载完毕再执行js内容。所以,window.onload可以预防使用标签在定义标签之前。
|
||||
|
||||
**备注**:关于 onLoad事件,在下一篇文章《24-DOM简介和DOM操作》中有更详细的讲解和示例。
|
||||
|
||||
### 事件举例:京东顶部广告栏
|
||||
|
||||

|
||||
|
||||
比如上面这张图,当鼠标点击右上角的`X`时,关掉整个广告栏,这就要用到事件。
|
||||
|
||||
代码实现如下:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.top-banner {
|
||||
background-color: pink;
|
||||
height: 80px;
|
||||
}
|
||||
.w {
|
||||
width: 1210px;
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
}
|
||||
img {
|
||||
display: block;
|
||||
width: 1210px;
|
||||
height: 80px;
|
||||
background-color: blue;
|
||||
}
|
||||
a {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
text-decoration: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font: 700 14px/20px "simsum";
|
||||
text-align: center;
|
||||
}
|
||||
.hide {
|
||||
display: none!important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-banner" id="topBanner">
|
||||
<div class="w">
|
||||
<img src="" alt=""/>
|
||||
<a href="#" id="closeBanner">×</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
//需求:点击案例,隐藏盒子。
|
||||
//思路:点击a链接,让top-banner这个盒子隐藏起来(加隐藏类名)。
|
||||
|
||||
//1.获取事件源和相关元素
|
||||
var closeBanner = document.getElementById("closeBanner");
|
||||
var topBanner = document.getElementById("topBanner");
|
||||
//2.绑定事件
|
||||
closeBanner.onclick = function () {
|
||||
//3.书写事件驱动程序
|
||||
//类控制
|
||||
// topBanner.className += " hide"; //保留原类名,添加新类名
|
||||
topBanner.className = "hide";//替换旧类名(方式一)
|
||||
// topBanner.style.display = "none"; //方式二:与上一行代码的效果相同
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
注意最后一行代码,这种方式会替换旧类名,意思是,不管之前的类名叫什么,都会被修改。
|
||||
|
||||
### 事件举例:
|
||||
|
||||
要求实现效果:当鼠标悬停在img上时,更换为另外一张图片;鼠标离开时,还原为本来的图片。
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script>
|
||||
//window.onload页面加载完毕以后再执行此代码
|
||||
window.onload = function () {
|
||||
//需求:鼠标放到img上,更换为另一张图片,也就是修改路径(src的值)。
|
||||
//步骤:
|
||||
//1.获取事件源
|
||||
//2.绑定事件
|
||||
//3.书写事件驱动程序
|
||||
|
||||
//1.获取事件源
|
||||
var img = document.getElementById("box");
|
||||
//2.绑定事件(悬停事件:鼠标进入到事件源中,立即触发事件)
|
||||
img.onmouseover = function () {
|
||||
//3.书写事件驱动程序(修改src)
|
||||
img.src = "image/jd2.png";
|
||||
// this.src = "image/jd2.png";
|
||||
}
|
||||
|
||||
//2.绑定事件(悬停事件:鼠标进入到事件源中,立即触发事件)
|
||||
img.onmouseout = function () {
|
||||
//3.书写事件驱动程序(修改src)
|
||||
img.src = "image/jd1.png";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<img id="box" src="image/jd1.png" style="cursor: pointer;border: 1px solid #ccc;"/>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
651
04-JavaScript基础/22-DOM简介和DOM操作.md
Normal file
651
04-JavaScript基础/22-DOM简介和DOM操作.md
Normal file
@@ -0,0 +1,651 @@
|
||||
|
||||
|
||||
> 本文最初发表于[博客园](http://www.cnblogs.com/smyhvae/p/8366012.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
> 以下是正文。
|
||||
|
||||
## 常见概念
|
||||
|
||||
### JavaScript的组成
|
||||
|
||||
JavaScript基础分为三个部分:
|
||||
|
||||
- ECMAScript:JavaScript的语法标准。包括变量、表达式、运算符、函数、if语句、for语句等。
|
||||
|
||||
- **DOM**:文档对象模型(Document object Model),操作**网页上的元素**的API。比如让盒子移动、变色、轮播图等。
|
||||
|
||||
- **BOM**:浏览器对象模型,操作**浏览器部分功能**的API。比如让浏览器自动滚动。
|
||||
|
||||
### 节点
|
||||
|
||||
**节点**(Node):构成 HTML 网页的最基本单元。网页中的每一个部分都可以称为是一个节点,比如:html标签、属性、文本、注释、整个文档等都是一个节点。
|
||||
|
||||
虽然都是节点,但是实际上他们的具体类型是不同的。常见节点分为四类:
|
||||
|
||||
- 文档节点(文档):整个 HTML 文档。整个 HTML 文档就是一个文档节点。
|
||||
|
||||
- 元素节点(标签):HTML标签。
|
||||
|
||||
- 属性节点(属性):元素的属性。
|
||||
|
||||
- 文本节点(文本):HTML标签中的文本内容(包括标签之间的空格、换行)。
|
||||
|
||||
节点的类型不同,属性和方法也都不尽相同。所有的节点都是Object。
|
||||
|
||||
### 什么是DOM
|
||||
|
||||
**DOM**:Document Object Model,文档对象模型。DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。目的其实就是为了能让js操作html元素而制定的一个规范。
|
||||
|
||||
DOM就是由节点组成的。
|
||||
|
||||
**解析过程**:
|
||||
HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的**属性**。
|
||||
|
||||
**DOM树**:(一切都是节点)
|
||||
|
||||
DOM的数据结构如下:
|
||||
|
||||

|
||||
|
||||
上图可知,**在HTML当中,一切都是节点**(非常重要)。节点的分类,在上一段中,已经讲了。
|
||||
|
||||
整个html文档就是一个文档节点。所有的节点都是Object。
|
||||
|
||||
### DOM可以做什么
|
||||
|
||||
- 找对象(元素节点)
|
||||
|
||||
- 设置元素的属性值
|
||||
|
||||
- 设置元素的样式
|
||||
|
||||
- 动态创建和删除元素
|
||||
|
||||
- 事件的触发响应:事件源、事件、事件的驱动程序
|
||||
|
||||
## 元素节点的获取
|
||||
|
||||
DOM节点的获取方式其实就是**获取事件源的方式**。关于事件,上一篇文章中已经讲到了。
|
||||
|
||||
想要操作元素节点,必须首先要找到该节点。有三种方式可以获取DOM节点:
|
||||
|
||||
```javascript
|
||||
var div1 = document.getElementById("box1"); //方式一:通过 id 获取 一个 元素节点(为什么是一个呢?因为 id 是唯一的)
|
||||
|
||||
var arr1 = document.getElementsByTagName("div"); //方式二:通过 标签名 获取 元素节点数组,所以有s
|
||||
|
||||
var arr2 = document.getElementsByClassName("hehe"); //方式三:通过 类名 获取 元素节点数组,所以有s
|
||||
```
|
||||
|
||||
既然方式二、方式三获取的是标签数组,那么习惯性是**先遍历之后再使用**。
|
||||
|
||||
特殊情况:数组中的值只有1个。即便如此,这一个值也是包在数组里的。这个值的获取方式如下:
|
||||
|
||||
```javascript
|
||||
document.getElementsByTagName("div1")[0]; //取数组中的第一个元素
|
||||
|
||||
document.getElementsByClassName("hehe")[0]; //取数组中的第一个元素
|
||||
```
|
||||
|
||||
## DOM访问关系的获取
|
||||
|
||||
DOM的节点并不是孤立的,因此可以通过DOM节点之间的相对关系对它们进行访问。如下:
|
||||
|
||||

|
||||
|
||||
节点的访问关系,是以**属性**的方式存在的。
|
||||
|
||||
JS中的**父子兄**访问关系:
|
||||
|
||||

|
||||
|
||||
这里我们要重点知道**parentNode**和**children**这两个属性的用法。下面分别介绍。
|
||||
|
||||
### 获取父节点
|
||||
|
||||
调用者就是节点。一个节点只有一个父节点,调用方式就是
|
||||
|
||||
```javascript
|
||||
节点.parentNode
|
||||
```
|
||||
|
||||
### 获取兄弟节点
|
||||
|
||||
**1、下一个节点 | 下一个元素节点**:
|
||||
|
||||
> Sibling的中文是**兄弟**。
|
||||
|
||||
(1)nextSibling:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是下一个节点(包括标签、空文档和换行节点)。
|
||||
|
||||
- IE678版本:指下一个元素节点(标签)。
|
||||
|
||||
(2)nextElementSibling:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是下一个元素节点(标签)。
|
||||
|
||||
**总结**:为了获取下一个**元素节点**,我们可以这样做:在IE678中用nextSibling,在火狐谷歌IE9+以后用nextElementSibling,于是,综合这两个属性,可以这样写:
|
||||
|
||||
```javascript
|
||||
下一个兄弟节点 = 节点.nextElementSibling || 节点.nextSibling
|
||||
```
|
||||
|
||||
**2、前一个节点 | 前一个元素节点**:
|
||||
|
||||
> previous的中文是:前一个。
|
||||
|
||||
(1)previousSibling:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是前一个节点(包括标签、空文档和换行节点)。
|
||||
|
||||
- IE678版本:指前一个元素节点(标签)。
|
||||
|
||||
(2)previousElementSibling:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是前一个元素节点(标签)。
|
||||
|
||||
**总结**:为了获取前一个**元素节点**,我们可以这样做:在IE678中用previousSibling,在火狐谷歌IE9+以后用previousElementSibling,于是,综合这两个属性,可以这样写:
|
||||
|
||||
```javascript
|
||||
前一个兄弟节点 = 节点.previousElementSibling || 节点.previousSibling
|
||||
```
|
||||
|
||||
**3、补充**:获得任意一个兄弟节点:
|
||||
|
||||
```javascript
|
||||
节点自己.parentNode.children[index]; //随意得到兄弟节点
|
||||
```
|
||||
|
||||
### 获取单个的子节点
|
||||
|
||||
**1、第一个子节点 | 第一个子元素节点**:
|
||||
|
||||
(1)firstChild:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是第一个子节点(包括标签、空文档和换行节点)。
|
||||
|
||||
- IE678版本:指第一个子元素节点(标签)。
|
||||
|
||||
(2)firstElementChild:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是第一个子元素节点(标签)。
|
||||
|
||||
**总结**:为了获取第一个**子元素节点**,我们可以这样做:在IE678中用firstChild,在火狐谷歌IE9+以后用firstElementChild,于是,综合这两个属性,可以这样写:
|
||||
|
||||
```javascript
|
||||
第一个子元素节点 = 节点.firstElementChild || 节点.firstChild
|
||||
```
|
||||
|
||||
**2、最后一个子节点 | 最后一个子元素节点**:
|
||||
|
||||
(1)lastChild:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是最后一个子节点(包括标签、空文档和换行节点)。
|
||||
|
||||
- IE678版本:指最后一个子元素节点(标签)。
|
||||
|
||||
(2)lastElementChild:
|
||||
|
||||
- 火狐、谷歌、IE9+版本:都指的是最后一个子元素节点(标签)。
|
||||
|
||||
**总结**:为了获取最后一个**子元素节点**,我们可以这样做:在IE678中用lastChild,在火狐谷歌IE9+以后用lastElementChild,于是,综合这两个属性,可以这样写:
|
||||
|
||||
```javascript
|
||||
最后一个子元素节点 = 节点.lastElementChild || 节点.lastChild
|
||||
```
|
||||
|
||||
### 获取所有的子节点
|
||||
|
||||
(1)**childNodes**:标准属性。返回的是指定元素的**子节点**的集合(包括元素节点、所有属性、文本节点)。是W3C的亲儿子。
|
||||
|
||||
- 火狐 谷歌等高本版会把换行也看做是子节点。
|
||||
|
||||
用法:
|
||||
|
||||
```javascript
|
||||
子节点数组 = 父节点.childNodes; //获取所有节点。
|
||||
```
|
||||
|
||||
(2)**children**:非标准属性。返回的是指定元素的**子元素节点**的集合。【重要】
|
||||
|
||||
- 它只返回HTML节点,甚至不返回文本节点。
|
||||
- 在IE6/7/8中包含注释节点(在IE678中,注释节点不要写在里面)。
|
||||
|
||||
虽然不是标准的DOM属性,但它和innerHTML方法一样,得到了几乎所有浏览器的支持。
|
||||
|
||||
用法:(**用的最多**)
|
||||
|
||||
```javascript
|
||||
子节点数组 = 父节点.children; //获取所有节点。用的最多。
|
||||
```
|
||||
|
||||
## DOM节点的操作(重要)
|
||||
|
||||
上一段的内容:节点的**访问关系**都是**属性**。
|
||||
|
||||
本段的内容:节点的**操作**都是**函数**(方法)。
|
||||
|
||||
### 创建节点
|
||||
|
||||
格式如下:
|
||||
|
||||
```javascript
|
||||
新的标签(元素节点) = document.createElement("标签名");
|
||||
```
|
||||
|
||||
比如,如果我们想创建一个li标签,或者是创建一个不存在的adbc标签,可以这样做:
|
||||
|
||||
```html
|
||||
<script type="text/javascript">
|
||||
var a1 = document.createElement("li"); //创建一个li标签
|
||||
var a2 = document.createElement("adbc"); //创建一个不存在的标签
|
||||
|
||||
console.log(a1);
|
||||
console.log(a2);
|
||||
|
||||
console.log(typeof a1);
|
||||
console.log(typeof a2);
|
||||
</script>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
### 插入节点
|
||||
|
||||
插入节点有两种方式,它们的含义是不同的。
|
||||
|
||||
方式1:
|
||||
|
||||
```javascript
|
||||
父节点.appendChild(新的子节点);
|
||||
```
|
||||
|
||||
解释:父节点的最后插入一个新的子节点。
|
||||
|
||||
方式2:
|
||||
|
||||
```javascript
|
||||
父节点.insertBefore(新的子节点,作为参考的子节点)
|
||||
```
|
||||
|
||||
解释:
|
||||
|
||||
- 在参考节点前插入一个新的节点。
|
||||
- 如果参考节点为null,那么他将在父节点里面的最后插入一个子节点。
|
||||
|
||||

|
||||
|
||||
我们可以看到,li标签确实被插入到了box1标签的里面,和box2并列了。
|
||||
|
||||
方式2的举例:
|
||||
|
||||

|
||||
|
||||
我们可以看到,b1标签被插入到了box1标签的里面,和a1标签并列,在a1标签的前面。
|
||||
|
||||
|
||||
**特别强调:**
|
||||
|
||||
关于方式1的appendChild方法,这里要强调一下。比如,现在有下面这样一个div结构:
|
||||
|
||||
```html
|
||||
<div class="box11">
|
||||
<div class="box12">生命壹号</div>
|
||||
</div>
|
||||
|
||||
<div class="box21">
|
||||
<div class="box22">永不止步</div>
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
上方结构中,子盒子box12是在父亲box11里的,子盒子box22是在父亲box21里面的。现在,如果我调用方法`box11.appendChild(box22)`,**最后产生的结果是:box22会跑到box11中**(也就是说,box22不在box21里面了)。这是一个很神奇的事情:
|
||||
|
||||
|
||||

|
||||
|
||||
### 删除节点
|
||||
|
||||
格式如下:
|
||||
|
||||
```javascript
|
||||
父节点.removeChild(子节点);
|
||||
```
|
||||
|
||||
解释:**用父节点删除子节点**。必须要指定是删除哪个子节点。
|
||||
|
||||
如果我想删除自己这个节点,可以这么做:
|
||||
|
||||
```javascript
|
||||
node1.parentNode.removeChild(node1);
|
||||
```
|
||||
|
||||
### 复制节点(克隆节点)
|
||||
|
||||
格式如下:
|
||||
|
||||
```javascript
|
||||
要复制的节点.cloneNode(); //括号里不带参数和带参数false,效果是一样的。
|
||||
|
||||
要复制的节点.cloneNode(true);
|
||||
```
|
||||
|
||||
括号里带不带参数,效果是不同的。解释如下:
|
||||
|
||||
- 不带参数/带参数false:只复制节点本身,不复制子节点。
|
||||
|
||||
- 带参数true:既复制节点本身,也复制其所有的子节点。
|
||||
|
||||
## 设置节点的属性
|
||||
|
||||
我们可以获取节点的属性值、设置节点的属性值、删除节点的属性。
|
||||
|
||||
我们就统一拿下面这个标签来举例:
|
||||
|
||||
```html
|
||||
<img src="images/1.jpg" class="image-box" title="美女图片" alt="地铁一瞥" id="a1">
|
||||
```
|
||||
|
||||
下面分别介绍。
|
||||
|
||||
### 1、获取节点的属性值
|
||||
|
||||
**方式1**:
|
||||
|
||||
```javascript
|
||||
元素节点.属性名;
|
||||
元素节点[属性名];
|
||||
```
|
||||
|
||||
举例:(获取节点的属性值)
|
||||
|
||||
```html
|
||||
<body>
|
||||
<img src="images/1.jpg" class="image-box" title="美女图片" alt="地铁一瞥" id="a1">
|
||||
|
||||
<script type="text/javascript">
|
||||
var myNode = document.getElementsByTagName("img")[0];
|
||||
|
||||
console.log(myNode.src);
|
||||
console.log(myNode.className); //注意,是className,不是class
|
||||
console.log(myNode.title);
|
||||
|
||||
console.log("------------");
|
||||
|
||||
console.log(myNode["src"]);
|
||||
console.log(myNode["className"]); //注意,是className,不是class
|
||||
console.log(myNode["title"]);
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
上方代码中的img标签,有各种属性,我们可以逐一获取,打印结果如下:
|
||||
|
||||

|
||||
|
||||
**方式2**:
|
||||
|
||||
```javascript
|
||||
元素节点.getAttribute("属性名称");
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
console.log(myNode.getAttribute("src"));
|
||||
console.log(myNode.getAttribute("class")); //注意是class,不是className
|
||||
console.log(myNode.getAttribute("title"));
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
方式1和方式2的区别在于:前者是直接操作标签,后者是把标签作为DOM节点。推荐方式2。
|
||||
|
||||
### 2、设置节点的属性值
|
||||
|
||||
方式1举例:(设置节点的属性值)
|
||||
|
||||
```javascript
|
||||
myNode.src = "images/2.jpg" //修改src的属性值
|
||||
myNode.className = "image2-box"; //修改class的name
|
||||
```
|
||||
|
||||
方式2:
|
||||
|
||||
```javascript
|
||||
元素节点.setAttribute(属性名, 新的属性值);
|
||||
```
|
||||
|
||||
方式2举例:(设置节点的属性值)
|
||||
|
||||
```javascript
|
||||
myNode.setAttribute("src","images/3.jpg");
|
||||
myNode.setAttribute("class","image3-box");
|
||||
myNode.setAttribute("id","你好");
|
||||
```
|
||||
|
||||
|
||||
### 3、删除节点的属性
|
||||
|
||||
格式:
|
||||
|
||||
```javascript
|
||||
元素节点.removeAttribute(属性名);
|
||||
```
|
||||
|
||||
举例:(删除节点的属性)
|
||||
|
||||
```javascript
|
||||
myNode.removeAttribute("class");
|
||||
myNode.removeAttribute("id");
|
||||
```
|
||||
|
||||
|
||||
|
||||
**总结:**
|
||||
|
||||
获取节点的属性值和设置节点的属性值,都有两种方式,但这两种方式是有区别的。
|
||||
|
||||
- 方式一的`元素节点.属性`和`元素节点[属性]`:绑定的属性值不会出现在标签上。
|
||||
|
||||
- 方式二的`get/set/removeAttribut`: 绑定的属性值会出现在标签上。
|
||||
|
||||
这其实很好理解,方式一操作的是属性而已,方式二操作的是标签本身。
|
||||
|
||||
另外,需要注意的是:**这两种方式不能交换使用**,get值和set值必须使用用一种方法。
|
||||
|
||||
举例:
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div id="box" title="主体" class="asdfasdfadsfd">我爱你中国</div>
|
||||
<script>
|
||||
|
||||
var div = document.getElementById("box");
|
||||
|
||||
//采用方式一进行set
|
||||
div.aaaa = "1111";
|
||||
console.log(div.aaaa); //打印结果:1111。可以打印出来,但是不会出现在标签上
|
||||
|
||||
//采用方式二进行set
|
||||
div.setAttribute("bbbb","2222"); //bbbb作为新增的属性,会出现在标签上
|
||||
|
||||
console.log(div.getAttribute("aaaa")); //打印结果:null。因为方式一的set,无法采用方式二进行get。
|
||||
console.log(div.bbbb); //打印结果:undefined。因为方式二的set,无法采用方式一进行get。
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
## DOM对象的属性
|
||||
|
||||
DOM对象的属性和HTML的标签属性几乎是一致的。例如:src、title、className、href等。
|
||||
|
||||
### innerHTML和innerText的区别
|
||||
|
||||
- value:标签的value属性。
|
||||
|
||||
- **innerHTML**:双闭合标签里面的内容(识别标签)。
|
||||
|
||||
- **innerText**:双闭合标签里面的内容(不识别标签)。(老版本的火狐用textContent)
|
||||
|
||||
|
||||
**获取内容举例:**
|
||||
|
||||
如果我们想获取innerHTML和innerText里的内容,看看会如何:(innerHTML会获取到标签本身,而innerText则不会)
|
||||
|
||||

|
||||
|
||||
**修改内容举例:**(innerHTML会修改标签本身,而innerText则不会)
|
||||
|
||||

|
||||
|
||||
### nodeType属性
|
||||
|
||||
这里讲一下nodeType属性。
|
||||
|
||||
- **nodeType == 1 表示的是元素节点**(标签) 。记住:元素就是标签。
|
||||
|
||||
- nodeType == 2 表示是属性节点。
|
||||
|
||||
- nodeType == 3 是文本节点。
|
||||
|
||||
### nodeType、nodeName、nodeValue
|
||||
|
||||
我们那下面这个标签来举例:
|
||||
|
||||
```html
|
||||
<div id="box" value="111">
|
||||
生命壹号
|
||||
</div>
|
||||
```
|
||||
|
||||
上面这个标签就包含了三种节点:
|
||||
|
||||
- 元素节点(标签)
|
||||
|
||||
- 属性节点
|
||||
|
||||
- 文本节点
|
||||
|
||||
获取这三个节点的方式如下:
|
||||
|
||||
```javascript
|
||||
var element = document.getElementById("box1"); //获取元素节点(标签)
|
||||
var attribute = element.getAttributeNode("id"); //获取box1的属性节点
|
||||
var txt = element.firstChild; //获取box1的文本节点
|
||||
|
||||
var value = element.getAttribute("id"); //获取id的属性值
|
||||
|
||||
console.log(element);
|
||||
console.log("--------------");
|
||||
console.log(attribute);
|
||||
console.log("--------------");
|
||||
console.log(txt);
|
||||
console.log("--------------");
|
||||
console.log(value);
|
||||
```
|
||||
|
||||
打印结果如下:
|
||||
|
||||

|
||||
|
||||
既然这三个都是节点,如果我想获取它们的nodeType、nodeName、nodeValue,代码如下:
|
||||
|
||||
```javascript
|
||||
var element = document.getElementById("box1"); //获取元素节点(标签)
|
||||
var attribute = element.getAttributeNode("id"); //获取box1的属性节点
|
||||
var txt = element.firstChild; //获取box1的文本节点
|
||||
|
||||
//获取nodeType
|
||||
console.log(element.nodeType); //1
|
||||
console.log(attribute.nodeType); //2
|
||||
console.log(txt.nodeType); //3
|
||||
|
||||
console.log("--------------");
|
||||
|
||||
//获取nodeName
|
||||
console.log(element.nodeName); //DIV
|
||||
console.log(attribute.nodeName); //id
|
||||
console.log(txt.nodeName); //#text
|
||||
|
||||
console.log("--------------");
|
||||
|
||||
//获取nodeValue
|
||||
console.log(element.nodeValue); //null
|
||||
console.log(attribute.nodeValue); //box1
|
||||
console.log(txt.nodeValue); //生命壹号
|
||||
```
|
||||
|
||||
打印结果如下:
|
||||
|
||||

|
||||
|
||||
## 文档的加载
|
||||
|
||||
浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行。如果将script标签写到页面的上边,在代码执行时,页面还没有加载,页面没有加载DOM对象也没有加载,会导致无法获取到DOM对象。
|
||||
|
||||
**onload 事件**:
|
||||
|
||||
onload 事件会在整个页面加载完成之后才触发。为 window 绑定一个onload事件,该事件对应的响应函数将会在页面加载完成之后执行,这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了。
|
||||
|
||||
代码举例:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title></title>
|
||||
<script type="text/javascript">
|
||||
// 【方式一:先加载,后执行】这段 js 代码是写在 <head> 标签里的,所以建议放在 window.onload 里面。
|
||||
window.onload = function() {
|
||||
// 获取id为btn的按钮
|
||||
var btn = document.getElementById("btn");
|
||||
// 为按钮绑定点击事件
|
||||
btn.onclick = function() {
|
||||
alert("hello");
|
||||
};
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<button id="btn">点我一下</button>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 【方式二:后加载,后执行】这段 js 代码是写在 <body> 标签里的,代码的位置是处在页面的下方。这么做,也可以确保:在页面加载完毕后,再执行 js 代码。
|
||||
|
||||
// 获取id为btn的按钮
|
||||
var btn = document.getElementById("btn");
|
||||
// 为按钮绑定点击事件
|
||||
btn.onclick = function() {
|
||||
alert("hello");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
```
|
||||
|
||||
上方代码中,方式一和方式二均可以确保:在页面加载完毕后,再执行 js 代码。
|
||||
|
||||
## DOM 操作:设置元素的样式
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
502
04-JavaScript基础/23-通过style对象设置行内样式.md
Normal file
502
04-JavaScript基础/23-通过style对象设置行内样式.md
Normal file
@@ -0,0 +1,502 @@
|
||||
|
||||
|
||||
## style属性的获取和修改
|
||||
|
||||
在DOM当中,如果想设置样式,有两种形式:
|
||||
|
||||
- className(针对内嵌样式)
|
||||
|
||||
- style(针对行内样式)
|
||||
|
||||
这篇文章,我们就来讲一下style。
|
||||
|
||||
需要注意的是:style是一个对象,只能获取**行内样式**,不能获取内嵌的样式和外链的样式。例如:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<style>
|
||||
div {
|
||||
border: 6px solid red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="box1" style="width: 200px;height: 100px;background-color: pink;"></div>
|
||||
|
||||
<script>
|
||||
var box1 = document.getElementsByTagName("div")[0];
|
||||
|
||||
console.log(box1.style.backgroundColor);
|
||||
console.log(box1.style.border); //没有打印结果,因为这个属性不是行内样式
|
||||
console.log(typeof box1.style); //因为是对象,所以打印结果是Object
|
||||
console.log(box1.style); //打印结果是对象
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
上图显示,因为border属性不是行内样式,所以无法通过style对象获取。
|
||||
|
||||
### 通过 js 读取元素的样式
|
||||
|
||||
语法:(方式一)
|
||||
|
||||
```javascript
|
||||
元素.style.样式名
|
||||
```
|
||||
|
||||
备注:我们通过style属性读取的样式都是**行内样式**。
|
||||
|
||||
语法:(方式二)
|
||||
|
||||
```javascript
|
||||
元素.style["属性"]; //格式
|
||||
|
||||
box.style["width"]; //举例
|
||||
```
|
||||
|
||||
方式二最大的优点是:可以给属性传递参数。
|
||||
|
||||
### 通过 js 修改元素的样式
|
||||
|
||||
语法:
|
||||
|
||||
```javascript
|
||||
元素.style.样式名 = 样式值;
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```
|
||||
box1.style.width = "300px";
|
||||
box1.style.backgroundColor = "red"; // 驼峰命名法
|
||||
|
||||
```
|
||||
|
||||
备注:我们通过style属性设置的样式都是**行内样式**,而行内样式有较高的优先级。但是如果在样式中的其他地方写了`!important`,则此时`!important`会有更高的优先级。
|
||||
|
||||
### style属性的注意事项
|
||||
|
||||
style属性需要注意以下几点:
|
||||
|
||||
(1)样式少的时候使用。
|
||||
|
||||
(2)style是对象。我们在上方已经打印出来,typeof的结果是Object。
|
||||
|
||||
(3)值是字符串,没有设置值是“”。
|
||||
|
||||
(4)命名规则,驼峰命名。
|
||||
|
||||
(5)只能获取行内样式,和内嵌和外链无关。
|
||||
|
||||
(6)box.style.cssText = “字符串形式的样式”。
|
||||
|
||||
|
||||
`cssText`这个属性,其实就是把行内样式里面的值当做字符串来对待。在上方代码的基础之上,举例:
|
||||
|
||||
```html
|
||||
<script>
|
||||
var box1 = document.getElementsByTagName("div")[0];
|
||||
|
||||
//通过cssText一次性设置行内样式
|
||||
box1.style.cssText = "width: 300px;height: 300px;background-color: green;";
|
||||
|
||||
console.log(box1.style.cssText); //这一行更加可以理解,style是对象
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
### style的常用属性
|
||||
|
||||
style的常用属性包括:
|
||||
|
||||
- backgroundColor
|
||||
|
||||
- backgroundImage
|
||||
|
||||
- color
|
||||
|
||||
- width
|
||||
|
||||
- height
|
||||
|
||||
- border
|
||||
|
||||
- opacity 设置透明度 (IE8以前是filter: alpha(opacity=xx))
|
||||
|
||||
注意DOM对象style的属性和标签中style内的值不一样,因为在JS中,`-`不能作为标识符。比如:
|
||||
|
||||
- DOM中:backgroundColor
|
||||
|
||||
- CSS中:background-color
|
||||
|
||||
## style属性的举例
|
||||
|
||||
我们针对上面列举的几个style的样式,来举几个例子:
|
||||
|
||||
- 举例1、改变div的大小和透明度
|
||||
|
||||
- 举例2、当前输入的文本框高亮显示
|
||||
|
||||
- 举例3、高级隔行变色、高亮显示
|
||||
|
||||
下面来逐一实现。
|
||||
|
||||
### 举例1:改变div的大小和透明度
|
||||
|
||||
代码举例:
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div style="width: 100px;height: 100px;background-color: pink;"></div>
|
||||
<script>
|
||||
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
div.onmouseover = function () {
|
||||
div.style.width = "200px";
|
||||
div.style.height = "200px";
|
||||
div.style.backgroundColor = "black";
|
||||
div.style.opacity = "0.2"; //设置背景色的透明度。单位是0.1
|
||||
div.style.filter = "alpha(opacity=20)"; //上一行代码的兼容性写法。注意单位是百进制
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
```
|
||||
|
||||
### 举例2:当前输入的文本框高亮显示
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
input {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul>
|
||||
<input type="text"/>
|
||||
<input type="text"/>
|
||||
<input type="text"/>
|
||||
<input type="text"/>
|
||||
<input type="text"/>
|
||||
</ul>
|
||||
<script>
|
||||
//需求:让所有的input标签获取焦点后高亮显示
|
||||
|
||||
//1.获取事件源
|
||||
var inpArr = document.getElementsByTagName("input");
|
||||
//2.绑定事件
|
||||
//3.书写事件驱动程序
|
||||
for (var i = 0; i < inpArr.length; i++) {
|
||||
//获取焦点后,所有的input标签被绑定onfocus事件
|
||||
inpArr[i].onfocus = function () {
|
||||
this.style.border = "2px solid red";
|
||||
this.style.backgroundColor = "#ccc";
|
||||
}
|
||||
//绑定onblur事件,取消样式
|
||||
inpArr[i].onblur = function () {
|
||||
this.style.border = "";
|
||||
this.style.backgroundColor = "";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 举例3:高级隔行变色、高亮显示
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: 500px;
|
||||
margin: 100px auto 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border: 1px solid #c0c0c0;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #d0d0d0;
|
||||
color: #404060;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #09c;
|
||||
font: bold 16px "微软雅黑";
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
td {
|
||||
font: 14px "微软雅黑";
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
background-color: #f0f0f0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.current {
|
||||
background-color: red !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>姓名</th>
|
||||
<th>课程</th>
|
||||
<th>成绩</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="target">
|
||||
<tr>
|
||||
<td>
|
||||
1
|
||||
</td>
|
||||
<td>生命壹号</td>
|
||||
<td>语文</td>
|
||||
<td>100</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
2
|
||||
</td>
|
||||
<td>生命贰号</td>
|
||||
<td>日语</td>
|
||||
<td>99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
3
|
||||
</td>
|
||||
<td>生命叁号</td>
|
||||
<td>营销学</td>
|
||||
<td>98</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
4
|
||||
</td>
|
||||
<td>生命伍号</td>
|
||||
<td>数学</td>
|
||||
<td>90</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
5
|
||||
</td>
|
||||
<td>许嵩</td>
|
||||
<td>英语</td>
|
||||
<td>96</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
6
|
||||
</td>
|
||||
<td>vae</td>
|
||||
<td>体育</td>
|
||||
<td>90</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
//需求:让tr各行变色,鼠标放入tr中,高亮显示。
|
||||
|
||||
//1.隔行变色。
|
||||
var tbody = document.getElementById("target");
|
||||
var trArr = tbody.children;
|
||||
//循环判断并各行赋值属性(背景色)
|
||||
for (var i = 0; i < trArr.length; i++) {
|
||||
if (i % 2 !== 0) {
|
||||
trArr[i].style.backgroundColor = "#a3a3a3";
|
||||
} else {
|
||||
trArr[i].style.backgroundColor = "#ccc";
|
||||
}
|
||||
|
||||
//鼠标进入高亮显示
|
||||
//难点:鼠标移开的时候要回复原始颜色。
|
||||
//计数器(进入tr之后,立刻记录颜色,然后移开的时候使用记录好的颜色)
|
||||
var myColor = "";
|
||||
trArr[i].onmouseover = function () {
|
||||
//赋值颜色之前,先记录颜色
|
||||
myColor = this.style.backgroundColor;
|
||||
this.style.backgroundColor = "#fff";
|
||||
}
|
||||
trArr[i].onmouseout = function () {
|
||||
this.style.backgroundColor = myColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
实现的效果如下:
|
||||
|
||||

|
||||
|
||||
代码解释:
|
||||
|
||||
上方代码中,我们**用到了计数器myColor来记录每一行最原始的颜色**(赋值白色之前)。如果不用计数器,可能很多人以为代码是写的:(错误的代码)
|
||||
|
||||
```html
|
||||
<script>
|
||||
//需求:让tr各行变色,鼠标放入tr中,高亮显示。
|
||||
|
||||
//1.隔行变色。
|
||||
var tbody = document.getElementById("target");
|
||||
var trArr = tbody.children;
|
||||
//循环判断并各行赋值属性(背景色)
|
||||
for (var i = 0; i < trArr.length; i++) {
|
||||
if (i % 2 !== 0) {
|
||||
trArr[i].style.backgroundColor = "#a3a3a3";
|
||||
} else {
|
||||
trArr[i].style.backgroundColor = "#ccc";
|
||||
}
|
||||
|
||||
//鼠标进入高亮显示
|
||||
//难点:鼠标移开的时候要回复原始颜色。
|
||||
//计数器(进入tr之后,立刻记录颜色,然后移开的时候使用记录好的颜色)
|
||||
trArr[i].onmouseover = function () {
|
||||
this.style.backgroundColor = "#fff";
|
||||
}
|
||||
trArr[i].onmouseout = function () {
|
||||
this.style.backgroundColor = "#a3a3a3";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
这种错误的代码,实现的效果却是:(未达到效果)
|
||||
|
||||

|
||||
|
||||
## 通过 js 获取元素当前显示的样式
|
||||
|
||||
我们在上面的内容中,通过`元素.style.className`的方式只能获取**行内样式**。但是,有些元素,只写了**内嵌样式或外链样式**。
|
||||
|
||||
既然样式有这么种,那么,如何获取元素当前显示的样式(包括行内样式、内嵌样式、外链样式)呢?我们接下来看一看。
|
||||
|
||||
### 获取元素当前正在显示的样式
|
||||
|
||||
(1)w3c的做法:
|
||||
|
||||
```javascript
|
||||
window.getComputedStyle("要获取样式的元素", "伪元素");
|
||||
```
|
||||
|
||||
两个参数都是必须要有的。参数二中,如果没有伪元素就用 null 代替(一般都传null)。
|
||||
|
||||
(2)IE和opera的做法:
|
||||
|
||||
```javascript
|
||||
obj.currentStyle;
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- 如果当前元素没有设置该样式,则获取它的默认值。
|
||||
|
||||
- 该方法会返回一个对象,对象中封装了当前元素对应的样式,可以通过`对象.样式名`来读取具体的某一个样式。
|
||||
|
||||
- 通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改必须通过style属性。
|
||||
|
||||
综合上面两种写法,就有了一种兼容性的写法,同时将其封装。代码举例如下:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
div {
|
||||
background-color: pink;
|
||||
/*border: 1px solid #000;*/
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="width: 100px;height: 100px;"></div>
|
||||
|
||||
<script>
|
||||
|
||||
var div1 = document.getElementsByTagName("div")[0];
|
||||
|
||||
console.log(getStyle(div1, "width"));
|
||||
console.log(getStyle(div1, "padding"));
|
||||
console.log(getStyle(div1, "background-color"));
|
||||
|
||||
//兼容方法获取元素样式
|
||||
function getStyle(ele, attr) {
|
||||
if (window.getComputedStyle) {
|
||||
return window.getComputedStyle(ele, null)[attr];
|
||||
}
|
||||
return ele.currentStyle[attr];
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
|
||||
829
04-JavaScript基础/31-事件对象Event和冒泡.md
Normal file
829
04-JavaScript基础/31-事件对象Event和冒泡.md
Normal file
@@ -0,0 +1,829 @@
|
||||
|
||||
|
||||
> 本文最初发表于[博客园](http://www.cnblogs.com/smyhvae/p/8413602.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
> 以下是正文。
|
||||
|
||||
|
||||
## 绑定事件的两种方式/DOM事件的级别
|
||||
|
||||
我们在上一篇文章 [DOM操作详解](http://www.cnblogs.com/smyhvae/p/8366012.html) 中已经讲过事件的概念。这里讲一下注册事件的两种方式,我们以onclick事件为例。
|
||||
|
||||
### DOM0的写法:onclick
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
element.onclick = function () {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
举例:
|
||||
|
||||
|
||||
```html
|
||||
<body>
|
||||
<button>点我</button>
|
||||
<script>
|
||||
var btn = document.getElementsByTagName("button")[0];
|
||||
|
||||
//这种事件绑定的方法容易被层叠。
|
||||
btn.onclick = function () {
|
||||
console.log("事件1");
|
||||
}
|
||||
|
||||
btn.onclick = function () {
|
||||
console.log("事件2");
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
```
|
||||
|
||||
点击按钮后,上方代码的打印结果:
|
||||
|
||||
```html
|
||||
事件2
|
||||
```
|
||||
|
||||
我们可以看到,这种绑定事件的方式,会层叠掉之前的事件。
|
||||
|
||||
### DOM2的写法:addEventListener
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
element.addEventListener('click', function () {
|
||||
|
||||
}, false);
|
||||
```
|
||||
|
||||
|
||||
参数解释:
|
||||
|
||||
- 参数1:事件名(注意,没有on)
|
||||
|
||||
- 参数2:事件名(执行函数)
|
||||
|
||||
- 参数3:**true表示捕获阶段触发,false表示冒泡阶段触发(默认)**。如果不写,则默认为false。【重要】
|
||||
|
||||
举例:
|
||||
|
||||
```html
|
||||
<body>
|
||||
<button>按钮</button>
|
||||
<script>
|
||||
var btn = document.getElementsByTagName("button")[0];
|
||||
|
||||
//addEventListener: 事件监听器。 原事件被执行的时候,后面绑定的事件照样被执行
|
||||
//第二种事件绑定的方法不会出现层叠。(更适合团队开发)
|
||||
btn.addEventListener("click", fn1);
|
||||
btn.addEventListener("click", fn2);
|
||||
|
||||
function fn1() {
|
||||
console.log("事件1");
|
||||
}
|
||||
|
||||
function fn2() {
|
||||
console.log("事件2");
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
点击按钮后,上方代码的打印结果:
|
||||
|
||||
|
||||
```html
|
||||
事件1
|
||||
事件2
|
||||
```
|
||||
|
||||
我们可以看到,这种绑定事件的方式,不会层叠掉之前的事件。
|
||||
|
||||
## 事件对象
|
||||
|
||||
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。比如鼠标操作时候,会添加鼠标位置的相关信息到事件对象中。
|
||||
|
||||
所有浏览器都支持event对象,但支持的方式不同。如下。
|
||||
|
||||
(1)普通浏览器支持 event。比如:
|
||||
|
||||

|
||||
|
||||
(2)ie 678 支持 window.event。
|
||||
|
||||
于是,我们可以采取一种兼容性的写法。如下:
|
||||
|
||||
```javascript
|
||||
event = event || window.event; ////兼容性写法
|
||||
```
|
||||
|
||||
代码举例:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
//点击页面的任何部分
|
||||
document.onclick = function (event) {
|
||||
event = event || window.event; ////兼容性写法
|
||||
|
||||
console.log(event);
|
||||
console.log(event.timeStamp);
|
||||
console.log(event.bubbles);
|
||||
console.log(event.button);
|
||||
console.log(event.pageX);
|
||||
console.log(event.pageY);
|
||||
console.log(event.screenX);
|
||||
console.log(event.screenY);
|
||||
console.log(event.target);
|
||||
console.log(event.type);
|
||||
console.log(event.clientX);
|
||||
console.log(event.clientY);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
||||
### event 属性
|
||||
|
||||
event 有很多属性,比如:
|
||||
|
||||

|
||||
|
||||
由于pageX 和 pageY的兼容性不好,我们可以这样做:
|
||||
|
||||
- 鼠标在页面的位置 = 被卷去的部分+可视区域部分。
|
||||
|
||||
## Event举例
|
||||
|
||||
### 举例1:鼠标跟随
|
||||
|
||||
代码实现:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
body {
|
||||
height: 5000px;
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
padding: 10px 0;
|
||||
border: 1px solid #ccc;
|
||||
cursor: pointer;
|
||||
background-color: yellowgreen;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src="" width="100" height="100"/>
|
||||
|
||||
<script>
|
||||
//需求:点击页面的任何地方,图片跟随鼠标移动到点击位置。
|
||||
//思路:获取鼠标在页面中的位置,然图片缓慢运动到鼠标点击的位置。
|
||||
// 兼容ie67做pageY和pageX;
|
||||
// 原理: 鼠标在页面的位置 = 被卷去的部分+可视区域部分。
|
||||
//步骤:
|
||||
//1.老三步。
|
||||
//2.获取鼠标在页面中的位置。
|
||||
//3.利用缓动原理,慢慢的运动到指定位置。(包括左右和上下)
|
||||
|
||||
//1.老三步。
|
||||
var img = document.getElementsByTagName("img")[0];
|
||||
var timer = null;
|
||||
var targetx = 0;
|
||||
var targety = 0;
|
||||
var leaderx = 0;
|
||||
var leadery = 0;
|
||||
//给整个文档绑定点击事件获取鼠标的位置。
|
||||
document.onclick = function (event) {
|
||||
//新五步
|
||||
//兼容获取事件对象
|
||||
event = event || window.event;
|
||||
//鼠标在页面的位置 = 被卷去的部分+可视区域部分。
|
||||
var pagey = event.pageY || scroll().top + event.clientY;
|
||||
var pagex = event.pageX || scroll().left + event.clientX;
|
||||
|
||||
targety = pagey - 30;
|
||||
targetx = pagex - 50;
|
||||
|
||||
//要用定时器,先清定时器
|
||||
clearInterval(timer);
|
||||
timer = setInterval(function () {
|
||||
//为盒子的位置获取值
|
||||
leaderx = img.offsetLeft;
|
||||
//获取步长
|
||||
var stepx = (targetx - leaderx) / 10;
|
||||
//二次处理步长
|
||||
stepx = stepx > 0 ? Math.ceil(stepx) : Math.floor(stepx);
|
||||
leaderx = leaderx + stepx;
|
||||
//赋值
|
||||
img.style.left = leaderx + "px";
|
||||
|
||||
|
||||
//为盒子的位置获取值
|
||||
leadery = img.offsetTop;
|
||||
//获取步长
|
||||
var stepy = (targety - leadery) / 10;
|
||||
//二次处理步长
|
||||
stepy = stepy > 0 ? Math.ceil(stepy) : Math.floor(stepy);
|
||||
leadery = leadery + stepy;
|
||||
//赋值
|
||||
img.style.top = leadery + "px";
|
||||
|
||||
//清定时器
|
||||
if (Math.abs(targety - img.offsetTop) <= Math.abs(stepy) && Math.abs(targetx - img.offsetLeft) <= Math.abs(stepx)) {
|
||||
img.style.top = targety + "px";
|
||||
img.style.left = targetx + "px";
|
||||
clearInterval(timer);
|
||||
}
|
||||
}, 30);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
实现效果:
|
||||
|
||||

|
||||
|
||||
## event应用举例:获取鼠标距离所在盒子的距离
|
||||
|
||||
关键点:
|
||||
|
||||
```
|
||||
鼠标距离所在盒子的距离 = 鼠标在整个页面的位置 - 所在盒子在整个页面的位置
|
||||
```
|
||||
|
||||
代码演示:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
.box {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
padding-top: 100px;
|
||||
background-color: pink;
|
||||
margin: 100px;
|
||||
text-align: center;
|
||||
font: 18px/30px "simsun";
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
|
||||
</div>
|
||||
|
||||
<script src="animate.js"></script>
|
||||
<script>
|
||||
//需求:鼠标进入盒子之后只要移动,哪怕1像素,随时显示鼠标在盒子中的坐标。
|
||||
//技术点:新事件,onmousemove:在事件源上,哪怕鼠标移动1像素也会触动这个事件。
|
||||
//一定程度上,模拟了定时器
|
||||
//步骤:
|
||||
//1.老三步和新五步
|
||||
//2.获取鼠标在整个页面的位置
|
||||
//3.获取盒子在整个页面的位置
|
||||
//4.用鼠标的位置减去盒子的位置赋值给盒子的内容。
|
||||
|
||||
//1.老三步和新五步
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
|
||||
div.onmousemove = function (event) {
|
||||
|
||||
event = event || window.event;
|
||||
//2.获取鼠标在整个页面的位置
|
||||
var pagex = event.pageX || scroll().left + event.clientX;
|
||||
var pagey = event.pageY || scroll().top + event.clientY;
|
||||
//3.获取盒子在整个页面的位置
|
||||
// var xx =
|
||||
// var yy =
|
||||
//4.用鼠标的位置减去盒子的位置赋值给盒子的内容。
|
||||
var targetx = pagex - div.offsetLeft;
|
||||
var targety = pagey - div.offsetTop;
|
||||
this.innerHTML = "鼠标在盒子中的X坐标为:" + targetx + "px;<br>鼠标在盒子中的Y坐标为:" + targety + "px;"
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
实现效果:
|
||||
|
||||

|
||||
|
||||
**举例:商品放大镜**
|
||||
|
||||
代码实现:
|
||||
|
||||
(1)index.html:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
margin: 100px;
|
||||
border: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.big {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 360px;
|
||||
border: 1px solid #ccc;
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*mask的中文是:遮罩*/
|
||||
.mask {
|
||||
width: 175px;
|
||||
height: 175px;
|
||||
background: rgba(255, 255, 0, 0.4);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: move;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.small {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="tools.js"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
//需求:鼠标放到小盒子上,让大盒子里面的图片和我们同步等比例移动。
|
||||
//技术点:onmouseenter==onmouseover 第一个不冒泡
|
||||
//技术点:onmouseleave==onmouseout 第一个不冒泡
|
||||
//步骤:
|
||||
//1.鼠标放上去显示盒子,移开隐藏盒子。
|
||||
//2.老三步和新五步(黄盒子跟随移动)
|
||||
//3.右侧的大图片,等比例移动。
|
||||
|
||||
//0.获取相关元素
|
||||
var box = document.getElementsByClassName("box")[0];
|
||||
var small = box.firstElementChild || box.firstChild;
|
||||
var big = box.children[1];
|
||||
var mask = small.children[1];
|
||||
var bigImg = big.children[0];
|
||||
|
||||
//1.鼠标放上去显示盒子,移开隐藏盒子。(为小盒子绑定事件)
|
||||
small.onmouseenter = function () {
|
||||
//封装好方法调用:显示元素
|
||||
show(mask);
|
||||
show(big);
|
||||
}
|
||||
small.onmouseleave = function () {
|
||||
//封装好方法调用:隐藏元素
|
||||
hide(mask);
|
||||
hide(big);
|
||||
}
|
||||
|
||||
//2.老三步和新五步(黄盒子跟随移动)
|
||||
//绑定的事件是onmousemove,而事件源是small(只要在小盒子上移动1像素,黄盒子也要跟随)
|
||||
small.onmousemove = function (event) {
|
||||
//新五步
|
||||
event = event || window.event;
|
||||
|
||||
//想要移动黄盒子,必须要知道鼠标在small小图中的位置。
|
||||
var pagex = event.pageX || scroll().left + event.clientX;
|
||||
var pagey = event.pageY || scroll().top + event.clientY;
|
||||
|
||||
//x:mask的left值,y:mask的top值。
|
||||
var x = pagex - box.offsetLeft - mask.offsetWidth / 2; //除以2,可以保证鼠标mask的中间
|
||||
var y = pagey - box.offsetTop - mask.offsetHeight / 2;
|
||||
|
||||
//限制换盒子的范围
|
||||
//left取值为大于0,小盒子的宽-mask的宽。
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (x > small.offsetWidth - mask.offsetWidth) {
|
||||
x = small.offsetWidth - mask.offsetWidth;
|
||||
}
|
||||
//top同理。
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
if (y > small.offsetHeight - mask.offsetHeight) {
|
||||
y = small.offsetHeight - mask.offsetHeight;
|
||||
}
|
||||
|
||||
//移动黄盒子
|
||||
console.log(small.offsetHeight);
|
||||
mask.style.left = x + "px";
|
||||
mask.style.top = y + "px";
|
||||
|
||||
//3.右侧的大图片,等比例移动。
|
||||
//如何移动大图片?等比例移动。
|
||||
// 大图片/大盒子 = 小图片/mask盒子
|
||||
// 大图片走的距离/mask走的距离 = (大图片-大盒子)/(小图片-黄盒子)
|
||||
// var bili = (bigImg.offsetWidth-big.offsetWidth)/(small.offsetWidth-mask.offsetWidth);
|
||||
|
||||
//大图片走的距离/mask盒子都的距离 = 大图片/小图片
|
||||
var bili = bigImg.offsetWidth / small.offsetWidth;
|
||||
|
||||
var xx = bili * x; //知道比例,就可以移动大图片了
|
||||
var yy = bili * y;
|
||||
|
||||
bigImg.style.marginTop = -yy + "px";
|
||||
bigImg.style.marginLeft = -xx + "px";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div class="small">
|
||||
<img src="images/001.jpg" alt=""/>
|
||||
<div class="mask"></div>
|
||||
</div>
|
||||
<div class="big">
|
||||
<img src="images/0001.jpg" alt=""/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
(2)tools.js:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Created by smyhvae on 2018/02/03.
|
||||
*/
|
||||
|
||||
//显示和隐藏
|
||||
function show(ele) {
|
||||
ele.style.display = "block";
|
||||
}
|
||||
|
||||
function hide(ele) {
|
||||
ele.style.display = "none";
|
||||
}
|
||||
|
||||
function scroll() { // 开始封装自己的scrollTop
|
||||
if (window.pageYOffset != null) { // ie9+ 高版本浏览器
|
||||
// 因为 window.pageYOffset 默认的是 0 所以这里需要判断
|
||||
return {
|
||||
left: window.pageXOffset,
|
||||
top: window.pageYOffset
|
||||
}
|
||||
}
|
||||
else if (document.compatMode === "CSS1Compat") { // 标准浏览器 来判断有没有声明DTD
|
||||
return {
|
||||
left: document.documentElement.scrollLeft,
|
||||
top: document.documentElement.scrollTop
|
||||
}
|
||||
}
|
||||
return { // 未声明 DTD
|
||||
left: document.body.scrollLeft,
|
||||
top: document.body.scrollTop
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
效果演示:
|
||||
|
||||

|
||||
|
||||
## 小窗口拖拽案例
|
||||
|
||||
暂略。
|
||||
|
||||
## DOM事件流
|
||||
|
||||
事件传播的三个阶段是:事件捕获、事件冒泡和目标。
|
||||
|
||||
- 事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标 target。(从祖先元素往子元素查找,DOM树结构)。在这个过程中,事件相应的监听函数是不会被触发的。
|
||||
|
||||
- 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
|
||||
|
||||
- 事件冒泡阶段:事件从事件目标 target 开始,往上冒泡直到页面的最上一级标签。(从子元素到祖先元素冒泡)
|
||||
|
||||
如下图所示:
|
||||
|
||||

|
||||
|
||||
PS:这个概念类似于 Android 里的 **touch 事件传递**。
|
||||
|
||||
|
||||
### 事件捕获
|
||||
|
||||
addEventListener可以捕获事件:
|
||||
|
||||
```javascript
|
||||
box1.addEventListener("click", function () {
|
||||
alert("捕获 box3");
|
||||
}, true);
|
||||
```
|
||||
|
||||
上面的方法中,参数为true,代表事件在捕获阶段执行。
|
||||
|
||||
代码演示:
|
||||
|
||||
```javascript
|
||||
//参数为true,代表捕获;参数为false或者不写参数,代表冒泡
|
||||
box3.addEventListener("click", function () {
|
||||
alert("捕获 child");
|
||||
}, true);
|
||||
|
||||
box2.addEventListener("click", function () {
|
||||
alert("捕获 father");
|
||||
}, true);
|
||||
|
||||
box1.addEventListener("click", function () {
|
||||
alert("捕获 grandfather");
|
||||
}, true);
|
||||
|
||||
document.addEventListener("click", function () {
|
||||
alert("捕获 body");
|
||||
}, true);
|
||||
```
|
||||
|
||||
效果演示:
|
||||
|
||||

|
||||
|
||||
|
||||
**说明**:捕获阶段,事件依次传递的顺序是:window --> document --> html--> body --> 父元素、子元素、目标元素。
|
||||
|
||||
PS1:第一个接收到事件的对象是 **window**(有人会说body,有人会说html,这都是错误的)。
|
||||
|
||||
PS2:JS中涉及到DOM对象时,有两个对象最常用:window、doucument。它们俩也是最先获取到事件的。
|
||||
|
||||
|
||||
事件捕获阶段的完整写法是:
|
||||
|
||||
```javascript
|
||||
window.addEventListener("click", function () {
|
||||
alert("捕获 window");
|
||||
}, true);
|
||||
|
||||
document.addEventListener("click", function () {
|
||||
alert("捕获 document");
|
||||
}, true);
|
||||
|
||||
document.documentElement.addEventListener("click", function () {
|
||||
alert("捕获 html");
|
||||
}, true);
|
||||
|
||||
document.body.addEventListener("click", function () {
|
||||
alert("捕获 body");
|
||||
}, true);
|
||||
|
||||
fatherBox.addEventListener("click", function () {
|
||||
alert("捕获 father");
|
||||
}, true);
|
||||
|
||||
childBox.addEventListener("click", function () {
|
||||
alert("捕获 child");
|
||||
}, true);
|
||||
|
||||
```
|
||||
|
||||
|
||||
**补充一个知识点:**
|
||||
|
||||
在 js中:
|
||||
|
||||
- 如果想获取 `html`节点,方法是`document.documentElement`。
|
||||
|
||||
- 如果想获取 `body` 节点,方法是:`document.body`。
|
||||
|
||||
二者不要混淆了。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 事件冒泡
|
||||
|
||||
**事件冒泡**: 当一个元素上的事件被触发的时候(比如说鼠标点击了一个按钮),同样的事件将会在那个元素的所有**祖先元素**中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层。
|
||||
|
||||
|
||||
通俗来讲,冒泡指的是:**子元素的事件被触发时,父盒子的同样的事件也会被触发**。取消冒泡就是取消这种机制。
|
||||
|
||||
代码演示:
|
||||
|
||||
```javascript
|
||||
//事件冒泡
|
||||
box3.onclick = function () {
|
||||
alert("child");
|
||||
}
|
||||
|
||||
box2.onclick = function () {
|
||||
alert("father");
|
||||
}
|
||||
|
||||
box1.onclick = function () {
|
||||
alert("grandfather");
|
||||
}
|
||||
|
||||
document.onclick = function () {
|
||||
alert("body");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
上图显示,当我点击儿子 box3的时候,它的父亲box2、box1、body都依次被触发了。即使我改变代码的顺序,也不会影响效果的顺序。
|
||||
|
||||
当然,上面的代码中,我们用 addEventListener 这种 DOM2的写法也是可以的,但是第三个参数要写 false,或者不写。
|
||||
|
||||
**冒泡顺序**:
|
||||
|
||||
一般的浏览器: (除IE6.0之外的浏览器)
|
||||
|
||||
- div -> body -> html -> document -> window
|
||||
|
||||
IE6.0:
|
||||
|
||||
- div -> body -> html -> document
|
||||
|
||||
### 不是所有的事件都能冒泡
|
||||
|
||||
以下事件不冒泡:blur、focus、load、unload、onmouseenter、onmouseleave。意思是,事件不会往父元素那里传递。
|
||||
|
||||
我们检查一个元素是否会冒泡,可以通过事件的以下参数:
|
||||
|
||||
```javascript
|
||||
event.bubbles
|
||||
```
|
||||
|
||||
如果返回值为true,说明该事件会冒泡;反之则相反。
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
box1.onclick = function (event) {
|
||||
alert("冒泡 child");
|
||||
|
||||
event = event || window.event;
|
||||
console.log(event.bubbles); //打印结果:true
|
||||
}
|
||||
```
|
||||
|
||||
### 阻止冒泡的方法
|
||||
|
||||
w3c的方法:(火狐、谷歌、IE11)
|
||||
|
||||
```javascript
|
||||
event.stopPropagation();
|
||||
```
|
||||
|
||||
IE10以下则是:
|
||||
|
||||
```javascript
|
||||
event.cancelBubble = true
|
||||
```
|
||||
|
||||
兼容代码如下:
|
||||
|
||||
```javascript
|
||||
box3.onclick = function (event) {
|
||||
|
||||
alert("child");
|
||||
|
||||
//阻止冒泡
|
||||
event = event || window.event;
|
||||
|
||||
if (event && event.stopPropagation) {
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
event.cancelBubble = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上方代码中,我们对box3进行了阻止冒泡,产生的效果是:事件不会继续传递到 father、grandfather、body了。
|
||||
|
||||
## 事件委托
|
||||
|
||||
事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素。
|
||||
|
||||
比如说有一个列表 ul,列表之中有大量的列表项 li:
|
||||
|
||||
```html
|
||||
<ul id="parent-list">
|
||||
<li id="li-1">Item 1</li>
|
||||
<li id="li-2">Item 2</li>
|
||||
<li id="li-3">Item 3</li>
|
||||
<li id="li-4">Item 4</li>
|
||||
<li id="li-5">Item 5</li>
|
||||
<li id="li-6">Item 6</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
当我们的鼠标移到Li上的时候,需要获取此Li的相关信息并飘出悬浮窗以显示详细信息,或者当某个Li被点击的时候需要触发相应的处理事件。我们通常的写法,是为每个Li都绑定类似onMouseOver或者onClick之类的事件监听:
|
||||
|
||||
|
||||
```javascript
|
||||
//每个 li 中做的事情
|
||||
function addListeners4Li(liNode){
|
||||
liNode.onclick = function clickHandler(){...};
|
||||
liNode.onmouseover = function mouseOverHandler(){...}
|
||||
}
|
||||
|
||||
window.onload = function(){
|
||||
var ulNode = document.getElementById("parent-list");
|
||||
var liNodes = ulNode.getElementByTagName("Li");
|
||||
for(var i=0, l = liNodes.length; i < l; i++){
|
||||
addListeners4Li(liNodes[i]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
但是,上面的做法会消耗内存和性能。
|
||||
|
||||
|
||||
因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是 `ul` 上,然后在执行事件的时候再去匹配判断目标元素。如下:
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
// 获取父节点,并为它注册click事件。 false 表示事件在冒泡阶段触发(默认)
|
||||
document.getElementById("parent-list").addEventListener("click", function (e) {
|
||||
// event.target 代表的是子元素。toUpperCase()方法 指的是转换为大写字母并返回
|
||||
if (e.target && e.target.nodeName.toUpperCase() == "LI") {
|
||||
// 真正的处理过程在这里
|
||||
console.log("List item ", e.target.id, " was clicked!");
|
||||
}
|
||||
}, false);
|
||||
|
||||
```
|
||||
|
||||
|
||||
上方代码,为父节点注册click事件,当子节点被点击的时候,click事件会从子节点开始**向上冒泡**。**父节点捕获到事件**之后,开始执行方法体里的内容:通过判断 e.target 拿到了被点击的子节点li。从而可以获取到相应的信息,并作处理。
|
||||
|
||||
换而言之,事件是在父节点上注册的,参数为false,说明事件是在冒泡阶段触发(往上传递),那就只有父节点能拿到事件,子节点是不可能拿到事件的。
|
||||
|
||||
所以事件委托可以减少大量的内存消耗,提高效率。
|
||||
|
||||
事件委托的参考链接:
|
||||
|
||||
- [荐 | JavaScript事件代理和委托(Delegation)](https://www.cnblogs.com/owenChen/archive/2013/02/18/2915521.html)
|
||||
|
||||
- [JavaScript 事件委托详解](https://zhuanlan.zhihu.com/p/26536815)
|
||||
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
281
04-JavaScript基础/32-BOM的常见内置方法和内置对象.md
Normal file
281
04-JavaScript基础/32-BOM的常见内置方法和内置对象.md
Normal file
@@ -0,0 +1,281 @@
|
||||
|
||||
> 本文最初发表于[博客园](http://www.cnblogs.com/smyhvae/p/8401662.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
> 以下是正文。
|
||||
|
||||
|
||||
## BOM的介绍
|
||||
|
||||
### JavaScript的组成
|
||||
|
||||
JavaScript基础分为三个部分:
|
||||
|
||||
- ECMAScript:JavaScript的语法标准。包括变量、表达式、运算符、函数、if语句、for语句等。
|
||||
|
||||
- **DOM**:文档对象模型,操作**网页上的元素**的API。比如让盒子移动、变色、轮播图等。
|
||||
|
||||
- **BOM**:浏览器对象模型,操作**浏览器部分功能**的API。比如让浏览器自动滚动。
|
||||
|
||||
### 什么是BOM
|
||||
|
||||
BOM:Browser Object Model,浏览器对象模型。
|
||||
|
||||
**BOM的结构图:**
|
||||
|
||||

|
||||
|
||||
从上图也可以看出:
|
||||
|
||||
- **window对象是BOM的顶层(核心)对象**,所有对象都是通过它延伸出来的,也可以称为window的子对象。
|
||||
|
||||
- DOM越是BOM的一部分。
|
||||
|
||||
**window对象:**
|
||||
|
||||
- **window对象是JavaScript中的顶级对象**。
|
||||
|
||||
- 全局变量、自定义函数也是window对象的属性和方法。
|
||||
|
||||
- window对象下的属性和方法调用时,可以省略window。
|
||||
|
||||
下面讲一下 **BOM 的常见内置方法和内置对象**。
|
||||
|
||||
## 弹出系统对话框
|
||||
|
||||
比如说,`alert(1)`是`window.alert(1)`的简写,因为它是window的子方法。
|
||||
|
||||
系统对话框有三种:
|
||||
|
||||
```javascript
|
||||
alert(); //不同浏览器中的外观是不一样的
|
||||
confirm(); //兼容不好
|
||||
prompt(); //不推荐使用
|
||||
|
||||
```
|
||||
|
||||
## 打开窗口、关闭窗口
|
||||
|
||||
1、打开窗口:
|
||||
|
||||
```
|
||||
window.open(url,target,param)
|
||||
```
|
||||
|
||||
**参数解释:**
|
||||
|
||||
- url:要打开的地址。
|
||||
|
||||
- target:新窗口的位置。可以是:`_blank` 、`_self`、 `_parent` 父框架。
|
||||
|
||||
- param:新窗口的一些设置。
|
||||
|
||||
- 返回值:新窗口的句柄。
|
||||
|
||||
**param**这个参数,可以填各种各样的参数(),比如:
|
||||
|
||||
- name:新窗口的名称,可以为空
|
||||
|
||||
- features:属性控制字符串,在此控制窗口的各种属性,属性之间以逗号隔开。
|
||||
|
||||
- fullscreen= { yes/no/1/0 } 是否全屏,默认no
|
||||
|
||||
- channelmode= { yes/no/1/0 } 是否显示频道栏,默认no
|
||||
|
||||
- toolbar= { yes/no/1/0 } 是否显示工具条,默认no
|
||||
|
||||
- location= { yes/no/1/0 } 是否显示地址栏,默认no。(有的浏览器不一定支持)
|
||||
|
||||
- directories = { yes/no/1/0 } 是否显示转向按钮,默认no
|
||||
|
||||
- status= { yes/no/1/0 } 是否显示窗口状态条,默认no
|
||||
|
||||
- menubar= { yes/no/1/0 } 是否显示菜单,默认no
|
||||
|
||||
- scrollbars= { yes/no/1/0 } 是否显示滚动条,默认yes
|
||||
|
||||
- resizable= { yes/no/1/0 } 是否窗口可调整大小,默认no
|
||||
|
||||
- width=number 窗口宽度(像素单位)
|
||||
|
||||
- height=number 窗口高度(像素单位)
|
||||
|
||||
- top=number 窗口离屏幕顶部距离(像素单位)
|
||||
|
||||
- left=number 窗口离屏幕左边距离(像素单位)
|
||||
|
||||
各个参数之间用逗号隔开就行,但我们最好是把它们统一放到json里。
|
||||
|
||||
2、关闭窗口:window.close()
|
||||
|
||||
(1)和(2)的代码举例:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="javascript:;">点击我打开一个新的页面</a>
|
||||
<a href="javascript:;">点击我关闭本页面</a>
|
||||
<script>
|
||||
//新窗口 = window.open(地址,是否开新窗口,新窗口的各种参数);
|
||||
var a1 = document.getElementsByTagName("a")[0];
|
||||
var a2 = document.getElementsByTagName("a")[1];
|
||||
a1.onclick = function () {
|
||||
//举例1: window.open("http://www.jx.com","_blank");
|
||||
var json = {
|
||||
"name": "helloworld",
|
||||
"fullscreen": "no",
|
||||
"location": "no",
|
||||
"width": "100px",
|
||||
"height": "100px",
|
||||
"top": "100px",
|
||||
"left": "100px"
|
||||
};
|
||||
window.open("http://www.baidu.com", "_blank", json); //举例2
|
||||
}
|
||||
|
||||
//关闭本页面
|
||||
a2.onclick = function () {
|
||||
window.close();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
3、新窗口相关:
|
||||
|
||||
- 新窗口.moveTo(5,5)
|
||||
|
||||
- 新窗口.moveBy()
|
||||
|
||||
- 新窗口.resizeTo()
|
||||
|
||||
- window.resizeBy()
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
var newWin = window.open("demo.html", "_blank", json);
|
||||
newWin.moveTo(500, 500);
|
||||
```
|
||||
|
||||
|
||||
## location对象
|
||||
|
||||
`window.location`可以简写成location。location相当于浏览器地址栏,可以将url解析成独立的片段。
|
||||
|
||||
### location对象的属性
|
||||
|
||||
- **href**:跳转
|
||||
|
||||
- hash 返回url中#后面的内容,包含#
|
||||
|
||||
- host 主机名,包括端口
|
||||
|
||||
- hostname 主机名
|
||||
|
||||
- pathname url中的路径部分
|
||||
|
||||
- protocol 协议 一般是http、https
|
||||
|
||||
- search 查询字符串
|
||||
|
||||
**location.href属性举例**:
|
||||
|
||||
**举例1:**点击盒子时,进行跳转。
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div>smyhvae</div>
|
||||
<script>
|
||||
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
|
||||
div.onclick = function () {
|
||||
location.href = "http://www.baidu.com"; //点击div时,跳转到指定链接
|
||||
// window.open("http://www.baidu.com","_blank"); //方式二
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
**举例2:5秒后自动跳转到百度**。
|
||||
|
||||
有时候,当我们访问一个不存在的网页时,会提示5秒后自动跳转到指定页面,此时就可以用到location。举例:
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
setTimeout(function () {
|
||||
location.href = "http://www.baidu.com";
|
||||
}, 5000);
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
### location对象的方法
|
||||
|
||||
- location.assign():改变浏览器地址栏的地址,并记录到历史中
|
||||
|
||||
设置location.href 就会调用assign()。一般使用location.href 进行页面之间的跳转。
|
||||
|
||||
- location.replace():替换浏览器地址栏的地址,不会记录到历史中
|
||||
|
||||
- location.reload():重新加载
|
||||
|
||||
|
||||
## navigator对象
|
||||
|
||||
window.navigator 的一些属性可以获取客户端的一些信息。
|
||||
|
||||
- userAgent:系统,浏览器)
|
||||
|
||||
- platform:浏览器支持的系统,win/mac/linux
|
||||
|
||||
举例:
|
||||
|
||||
```javascript
|
||||
console.log(navigator.userAgent);
|
||||
console.log(navigator.platform);
|
||||
```
|
||||
|
||||
效果如下:
|
||||
|
||||

|
||||
|
||||
|
||||
## history对象
|
||||
|
||||
1、历史记录管理
|
||||
|
||||
2、后退:
|
||||
|
||||
- history.back()
|
||||
|
||||
- history.go(-1):0是刷新
|
||||
|
||||
3、前进:
|
||||
|
||||
- history.forward()
|
||||
|
||||
- history.go(1)
|
||||
|
||||
用的不多。因为浏览器中已经自带了这些功能的按钮:
|
||||
|
||||

|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
|
||||
237
04-JavaScript基础/33-原型链.md
Normal file
237
04-JavaScript基础/33-原型链.md
Normal file
@@ -0,0 +1,237 @@
|
||||
|
||||
|
||||
## 常见概念
|
||||
|
||||
- 构造函数
|
||||
|
||||
- 构造函数-扩展
|
||||
|
||||
- 原型规则和示例
|
||||
|
||||
- 原型链
|
||||
|
||||
- instanceof
|
||||
|
||||
## 构造函数
|
||||
|
||||
任何一个函数都可以被new,new了之后,就成了构造方法。
|
||||
|
||||
如下:
|
||||
|
||||
```javascript
|
||||
function Foo(name, age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
//retrun this; //默认有这一行。new一个构造函数,返回一个对象
|
||||
|
||||
}
|
||||
|
||||
var fn1 = new Foo('smyhvae', 26);
|
||||
var fn2 = new Foo('vae',30); //new 多个实例对象
|
||||
```
|
||||
|
||||
与普通函数相比,构造函数有以下明显特点:
|
||||
|
||||
- 用new关键字调用。
|
||||
|
||||
- 不需要用return显式返回值的,默认会返回this,也就是新的实例对象。
|
||||
|
||||
- 建议函数名的首字母大写,与普通函数区分开。
|
||||
|
||||
参考链接:
|
||||
|
||||
- [JavaScript中的普通函数与构造函数](http://www.cnblogs.com/SheilaSun/p/4398881.html)
|
||||
|
||||
当new之后,this会先变成一个空对象,然后通过`this.name = name`来赋值。
|
||||
|
||||
### 构造函数的扩展
|
||||
|
||||

|
||||
|
||||
上图中发现,数组、对象、函数也有构造函数,它们的构造函数是Array、Object、funtion。实际开发中,都推荐前面的书写方式。
|
||||
|
||||
## 原型规则
|
||||
|
||||
原型规则是学习原型链的基础。原型规则有五条,下面来讲解。
|
||||
|
||||
### 规则1
|
||||
|
||||
所有的引用类型(数组、对象、函数),都具有对象特性,都可以**自由扩展属性**。null除外。
|
||||
|
||||
举例:
|
||||
|
||||

|
||||
|
||||
|
||||
### 规则2
|
||||
|
||||
所有的**引用类型**(数组、对象、函数),都有一个`_proto_`属性,属性值是一个**普通的对象**。`_proto_`的含义是隐式原型。
|
||||
|
||||

|
||||
|
||||
其实,规则2是规则1的特例,只不过,js语法帮我们自动加了 规则2。
|
||||
|
||||
### 规则三
|
||||
|
||||
所有的**函数**(不包括数组、对象),都有一个`prototype`属性,属性值是一个**普通的对象**。`prototype`的含义是**显式原型**。(实例没有这个属性)
|
||||
|
||||

|
||||
|
||||
|
||||
### 规则四
|
||||
|
||||
所有的**引用类型**(数组、对象、函数),`_proto_`属性指向它的**构造函数**的`prototype`值。
|
||||
|
||||

|
||||
|
||||
总结:以上四条,要先理解清楚,然后再来看下面的第五条。
|
||||
|
||||
### 规则五
|
||||
|
||||
当试图获取一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的`_proto_`中寻找(即它的构造函数的`prototype`)。
|
||||
|
||||
`举例代码1`:
|
||||
|
||||
```javascript
|
||||
//创建方法
|
||||
function Foo(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Foo.prototype.alertName = function () {// 既然 Foo.prototype 是普通的对象,那也允许给它添加额外的属性 alertName
|
||||
console.log(this.name);
|
||||
}
|
||||
|
||||
|
||||
var fn = new Foo('smyhvae');
|
||||
fn.printName = function () {
|
||||
console.log(this.name);
|
||||
}
|
||||
|
||||
//测试
|
||||
fn.printName(); //输出结果:smyhvae
|
||||
fn.alertName(); //输出结果:smyhvae
|
||||
```
|
||||
|
||||
上方代码中,虽然 alertName 不是 fn 自身的属性,但是会从它的构造函数的`prototype`里面找。
|
||||
|
||||
**扩展:**遍历循环对象自身的属性
|
||||
|
||||
我们知道,`for ... in`循环可以遍历对象。针对上面的那个fn对象,它自身有两个属性:`name`、`printName`,另外从原型中找到了第三个属性`alertName`。现在,如果我们对fn进行遍历,能遍历到两个属性还是三个属性呢?
|
||||
|
||||
答案:两个。因为,**高级浏览器中已经在 `for ... in`循环中屏蔽了来自原型的属性。但是,为了保证代码的健壮性,我们最好自己加上判断**,手动将第三个属性屏蔽掉:
|
||||
|
||||
```javascript
|
||||
for (var item in fn) {
|
||||
if (fn.hasOwnProperty(item)) {
|
||||
console.log(item);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 原型链
|
||||
|
||||
还是拿上面的``举例代码1``举例,如果此时在最后面加一行代码:
|
||||
|
||||
```
|
||||
fn.toString(); //去 fn._proto_._proto_ 中查找 toString()方法
|
||||
```
|
||||
|
||||
上面的代码中,fn直接调用了 toString()方法,这是因为它通过**原型链**,去`_proto_`的`_proto_`里找到了`Object`,而`Object`是由`toString()`方法的。
|
||||
|
||||
### instanceof
|
||||
|
||||
格式:
|
||||
|
||||
```javascript
|
||||
对象 instanceof 构造函数
|
||||
```
|
||||
|
||||
`instanceof`的作用:用于判断**引用类型**属于哪个**构造函数**。
|
||||
|
||||
例1:判断一个变量是否为数组: `变量 instanceof Array`
|
||||
|
||||
例2:
|
||||
|
||||
```javascript
|
||||
function Person(){
|
||||
}
|
||||
|
||||
//p--->Person.prototype--->Object.prototype--->null
|
||||
var p = new Person();
|
||||
//构造函数的**原型**是否在 p 对象的原型链上!
|
||||
console.log(p instanceof Person);
|
||||
```
|
||||
|
||||
例3:
|
||||
|
||||
```javascript
|
||||
fn instanceof Foo
|
||||
```
|
||||
|
||||
上面这句话,判断逻辑是:**fn 的`_proto_`一层一层往上找,看能否对应到 Foo.prototype**。
|
||||
|
||||
原型链如下:(重要)
|
||||
|
||||

|
||||
|
||||
|
||||
注意,Object这个构造方法的显式原型是null,这是一个特例。
|
||||
|
||||
|
||||
## 常见题目
|
||||
|
||||
- 如何准确判断一个变量时数组类型
|
||||
|
||||
- 写一个原型链继承的例子
|
||||
|
||||
- 描述 new 一个对象的过程
|
||||
|
||||
- zepto(或其他框架)源码中如何使用原型链
|
||||
|
||||
下面分别讲解。
|
||||
|
||||
### 题目一:如何准确判断一个变量时数组类型
|
||||
|
||||
答案:
|
||||
|
||||
```javascript
|
||||
var arr1 = [];
|
||||
|
||||
console.log(arr1 instanceof Array); //打印结果:true。
|
||||
console.log(typeof arr1); //打印结果:object。提示:typeof 方法无法判断是否为数组
|
||||
```
|
||||
|
||||
上方代码表明,只能通过 instanceof 来判断是否为数组。而 typeof 的打印结果是 object。
|
||||
|
||||
### 题目二:写一个原型链继承的例子
|
||||
|
||||
来看个基础的代码:
|
||||
|
||||

|
||||
|
||||
上面这个例子是基础,但是,在回答面试官的问题时,不要写上面的例子。要写成下面这个例子:(更贴近实战)
|
||||
|
||||
**举例:**写一个封装DOM查询的例子
|
||||
|
||||
> 这个例子有点像 jQuery 操作DOM节点。
|
||||
|
||||
表示这个例子,略难。
|
||||
|
||||
### 题目三:描述 new 一个对象的过程
|
||||
|
||||
(1)创建一个新对象
|
||||
|
||||
(2)this 指向这个新对象
|
||||
|
||||
(3)执行代码(对this 赋值)
|
||||
|
||||
(4)返回this
|
||||
|
||||
|
||||
参考链接:
|
||||
|
||||
- [原型、原型链、继承模式](https://my.oschina.net/u/2600761/blog/1524617)
|
||||
|
||||
682
04-JavaScript基础/41-JavaScript特效:offset家族和匀速动画(含轮播图的实现).md
Normal file
682
04-JavaScript基础/41-JavaScript特效:offset家族和匀速动画(含轮播图的实现).md
Normal file
@@ -0,0 +1,682 @@
|
||||
|
||||
|
||||
> 本文最初发表于[博客园](http://www.cnblogs.com/smyhvae/p/8407109.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||||
|
||||
> 以下是正文。
|
||||
|
||||
|
||||
## 前言
|
||||
|
||||
JS动画的主要内容如下:
|
||||
|
||||
1、三大家族和一个事件对象:
|
||||
|
||||
- 三大家族:offset/scroll/client。也叫三大系列。
|
||||
|
||||
- 事件对象/event(事件被触动时,鼠标和键盘的状态)(通过属性控制)。
|
||||
|
||||
2、动画(闪现/匀速/缓动)
|
||||
|
||||
3、冒泡/兼容/封装
|
||||
|
||||
4、正则
|
||||
|
||||
## offset 家族的组成
|
||||
|
||||
我们知道,三大家族包括:offset/scroll/client。今天来讲一下offset,以及与其相关的匀速动画。
|
||||
|
||||
> offset的中文是:偏移,补偿,位移。
|
||||
|
||||
js中有一套方便的**获取元素尺寸**的办法就是offset家族。offset家族包括:
|
||||
|
||||
- offsetWidth
|
||||
|
||||
- offsetHight
|
||||
|
||||
- offsetLeft
|
||||
|
||||
- offsetTop
|
||||
|
||||
- offsetParent
|
||||
|
||||
下面分别介绍。
|
||||
|
||||
### 1、offsetWidth 和 offsetHight
|
||||
|
||||
用于检测盒子自身的**宽高+padding+border**,不包括margin。如下:
|
||||
|
||||
- offsetWidth = width + padding + border;
|
||||
|
||||
- offsetHeight = Height + padding + border;
|
||||
|
||||
这两个属性,他们绑定在了所有的节点元素上。获取之后,只要调用这两个属性,我们就能够获取元素节点的宽和高。
|
||||
|
||||
举例如下:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
border: 10px solid #000;
|
||||
margin: 100px;
|
||||
background-color: pink;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="box"></div>
|
||||
<script>
|
||||
var div1 = document.getElementsByTagName("div")[0];
|
||||
|
||||
console.log(div1.offsetHeight); //打印结果:140(100+20+20)
|
||||
console.log(typeof div1.offsetHeight); //打印结果:number
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 2、offsetLeft 和 offsetTop
|
||||
|
||||
返回距离上级盒子(带有定位)左边的位置;如果父级都没有定位,则以body为准。
|
||||
|
||||
offsetLeft: 从父亲的 padding 开始算,父亲的 border 不算。
|
||||
|
||||
举例:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
.box1 {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
padding: 100px;
|
||||
margin: 100px;
|
||||
position: relative;
|
||||
border: 100px solid #000;
|
||||
background-color: pink;
|
||||
}
|
||||
|
||||
.box2 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: red;
|
||||
/*position: absolute;*/
|
||||
/*left: 10px;*/
|
||||
/*top: 10px;*/
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box1">
|
||||
<div class="box2" style="left: 10px"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
var box2 = document.getElementsByClassName("box2")[0];
|
||||
|
||||
//offsetTop和offsetLeft
|
||||
console.log(box2.offsetLeft); //100
|
||||
console.log(box2.style.left); //10px
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
在父盒子有定位的情况下,offsetLeft == style.left(去掉px之后)。注意,后者只识别行内样式。但区别不仅仅于此,后面会讲。
|
||||
|
||||
### 3、offsetParent
|
||||
|
||||
检测父系盒子中带有定位的**父盒子节点**。返回结果是该对象的父级(带有定位)。
|
||||
|
||||
- 如果当前元素的父级元素,**没有CSS定位**(position为absolute、relative、fixed),那么offsetParent的返回结果为**body**。
|
||||
|
||||
- 如果当前元素的父级元素,**有CSS定位**(position为absolute、relative、fixed),那么offsetParent的返回结果为**最近的**那个父级元素。
|
||||
|
||||
举例:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box1" style="position: absolute;">
|
||||
<div class="box2" style="position: fixed;">
|
||||
<div class="box3"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
//offsetParent:复习盒子中带有定位的盒子
|
||||
//复习盒子中都没有定位,返回body
|
||||
//如果有,谁有返回最近哪个
|
||||
|
||||
var box3 = document.getElementsByClassName("box3")[0];
|
||||
|
||||
console.log(box3.offsetParent);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
打印结果:
|
||||
|
||||

|
||||
|
||||
### offsetLeft和style.left区别
|
||||
|
||||
(1)最大区别在于:
|
||||
|
||||
offsetLeft 可以返回没有定位盒子的距离左侧的位置。如果父系盒子中都没有定位,以body为准。
|
||||
|
||||
style.left 只能获取行内式,如果没有,则返回""(意思是,返回空);
|
||||
|
||||
(2)offsetTop 返回的是数字,而 style.top 返回的是字符串,而且还带有单位:px。
|
||||
|
||||
比如:
|
||||
|
||||
```javascript
|
||||
|
||||
div.offsetLeft = 100;
|
||||
div.style.left = "100px";
|
||||
|
||||
```
|
||||
|
||||
(3)offsetLeft 和 offsetTop **只读**,而 style.left 和 style.top 可读写(只读是获取值,可写是赋值)
|
||||
|
||||
|
||||
(4)如果没有给 HTML 元素指定过 top 样式,则style.top 返回的是空字符串。
|
||||
|
||||
总结:我们一般的做法是:**用offsetLeft 和 offsetTop 获取值,用style.left 和 style.top 赋值**(比较方便)。理由如下:
|
||||
|
||||
- style.left:只能获取行内式,获取的值可能为空,容易出现NaN。
|
||||
|
||||
- offsetLeft:获取值特别方便,而且是现成的number,方便计算。它是只读的,不能赋值。
|
||||
|
||||
|
||||
## 动画的种类
|
||||
|
||||
- 闪现(基本不用)
|
||||
|
||||
- 匀速(本文重点)
|
||||
|
||||
- 缓动(后续重点)
|
||||
|
||||
简单举例如下:(每间隔500ms,向右移动盒子100px)
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: pink;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button>动画</button>
|
||||
<div class="box" style="left: 0px"></div>
|
||||
|
||||
<script>
|
||||
var btn = document.getElementsByTagName("button")[0];
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
|
||||
//1、闪动
|
||||
// btn.onclick = function () {
|
||||
// div.style.left = "500px";
|
||||
// }
|
||||
|
||||
//2、匀速运动
|
||||
btn.onclick = function () {
|
||||
//定时器,每隔一定的时间向右走一些
|
||||
setInterval(function () {
|
||||
console.log(parseInt(div.style.left));
|
||||
//动画原理: 盒子未来的位置 = 盒子现在的位置 + 步长;
|
||||
//用style.left赋值,用offsetLeft获取值。
|
||||
div.style.left = div.offsetLeft + 100 + "px";
|
||||
//div.style.left = parseInt(div.style.left)+10+"px"; //NaN不能用
|
||||
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
效果如下:
|
||||
|
||||

|
||||
|
||||
## 匀速动画的封装:每间隔30ms,移动盒子10px【重要】
|
||||
|
||||
|
||||
代码如下:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
.box1 {
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
height: 300px;
|
||||
background-color: #ddd;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.box2 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: red;
|
||||
position: absolute;
|
||||
left: 195px;
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
.box3 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: yellow;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 150px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box1">
|
||||
<button>运动到 left = 200px</button>
|
||||
<button>运动到 left = 400px</button>
|
||||
<div class="box2"></div>
|
||||
<div class="box3"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var btnArr = document.getElementsByTagName("button");
|
||||
var box2 = document.getElementsByClassName("box2")[0];
|
||||
var box3 = document.getElementsByClassName("box3")[0];
|
||||
|
||||
//绑定事件
|
||||
btnArr[0].onclick = function () {
|
||||
//如果有一天我们要传递另外一个盒子,那么我们的方法就不好用了
|
||||
//所以我们要增加第二个参数,被移动的盒子本身。
|
||||
animate(box2, 200);
|
||||
animate(box3, 200);
|
||||
}
|
||||
|
||||
btnArr[1].onclick = function () {
|
||||
animate(box2, 400);
|
||||
animate(box3, 400);
|
||||
}
|
||||
|
||||
//【重要】方法的封装:每间隔30ms,将盒子向右移动10px
|
||||
function animate(ele, target) {
|
||||
//要用定时器,先清除定时器
|
||||
//一个盒子只能有一个定时器,这样的话,不会和其他盒子出现定时器冲突
|
||||
//我们可以把定时器本身,当成为盒子的一个属性
|
||||
clearInterval(ele.timer);
|
||||
//我们要求盒子既能向前又能向后,那么我们的步长就得有正有负
|
||||
//目标值如果大于当前值取正,目标值如果小于当前值取负
|
||||
var speed = target > ele.offsetLeft ? 10 : -10; //speed指的是步长
|
||||
ele.timer = setInterval(function () {
|
||||
//在执行之前就获取当前值和目标值之差
|
||||
var val = target - ele.offsetLeft;
|
||||
ele.style.left = ele.offsetLeft + speed + "px";
|
||||
//移动的过程中,如果目标值和当前值之差如果小于步长,那么就不能在前进了
|
||||
//因为步长有正有负,所有转换成绝对值来比较
|
||||
if (Math.abs(val) < Math.abs(speed)) {
|
||||
ele.style.left = target + "px";
|
||||
clearInterval(ele.timer);
|
||||
}
|
||||
}, 30)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
实现的效果:
|
||||
|
||||

|
||||
|
||||
上方代码中的方法封装,可以作为一个模板步骤,要记住。其实,这个封装的方法,写成下面这样,会更严谨,更容易理解:(将if语句进行了改进)
|
||||
|
||||
```javascript
|
||||
//【重要】方法的封装:每间隔30ms,将盒子向右移动10px
|
||||
function animate(ele, target) {
|
||||
//要用定时器,先清除定时器
|
||||
//一个盒子只能有一个定时器,这样的话,不会和其他盒子出现定时器冲突
|
||||
//我们可以把定时器本身,当成为盒子的一个属性
|
||||
clearInterval(ele.timer);
|
||||
//我们要求盒子既能向前又能向后,那么我们的步长就得有正有负
|
||||
//目标值如果大于当前值取正,目标值如果小于当前值取负
|
||||
var speed = target > ele.offsetLeft ? 10 : -10; //speed指的是步长
|
||||
ele.timer = setInterval(function () {
|
||||
//在执行之前就获取当前值和目标值之差
|
||||
var val = target - ele.offsetLeft;
|
||||
|
||||
//移动的过程中,如果目标值和当前值之差如果小于步长,那么就不能在前进了
|
||||
//因为步长有正有负,所有转换成绝对值来比较
|
||||
if (Math.abs(val) < Math.abs(speed)) { //如果val小于步长,则直接到达目的地;否则,每次移动一个步长
|
||||
ele.style.left = target + "px";
|
||||
clearInterval(ele.timer);
|
||||
} else {
|
||||
ele.style.left = ele.offsetLeft + speed + "px";
|
||||
}
|
||||
}, 30)
|
||||
}
|
||||
```
|
||||
|
||||
## 代码举例:轮播图的实现
|
||||
|
||||
完整版代码如下:(注释已经比较详细)
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>无标题文档</title>
|
||||
<style type="text/css">
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.all {
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
padding: 7px;
|
||||
border: 1px solid #ccc;
|
||||
margin: 100px auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.screen {
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.screen li {
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.screen ul {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0px;
|
||||
width: 3000px;
|
||||
}
|
||||
|
||||
.all ol {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.all ol li {
|
||||
float: left;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.all ol li.current {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
#arr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#arr span {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 50%;
|
||||
margin-top: -20px;
|
||||
background: #000;
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-family: '黑体';
|
||||
font-size: 30px;
|
||||
color: #fff;
|
||||
opacity: 0.3;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
#arr #right {
|
||||
right: 5px;
|
||||
left: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
|
||||
//需求:无缝滚动。
|
||||
//思路:赋值第一张图片放到ul的最后,然后当图片切换到第五张的时候
|
||||
// 直接切换第六章,再次从第一张切换到第二张的时候先瞬间切换到
|
||||
// 第一张图片,然后滑动到第二张
|
||||
//步骤:
|
||||
//1.获取事件源及相关元素。(老三步)
|
||||
//2.复制第一张图片所在的li,添加到ul的最后面。
|
||||
//3.给ol中添加li,ul中的个数-1个,并点亮第一个按钮。
|
||||
//4.鼠标放到ol的li上切换图片
|
||||
//5.添加定时器
|
||||
//6.左右切换图片(鼠标放上去隐藏,移开显示)
|
||||
|
||||
|
||||
//1.获取事件源及相关元素。(老三步)
|
||||
var all = document.getElementById("all");
|
||||
var screen = all.firstElementChild || all.firstChild;
|
||||
var imgWidth = screen.offsetWidth;
|
||||
var ul = screen.firstElementChild || screen.firstChild;
|
||||
var ol = screen.children[1];
|
||||
var div = screen.lastElementChild || screen.lastChild;
|
||||
var spanArr = div.children;
|
||||
|
||||
//2.复制第一张图片所在的li,添加到ul的最后面。
|
||||
var ulNewLi = ul.children[0].cloneNode(true);
|
||||
ul.appendChild(ulNewLi);
|
||||
//3.给ol中添加li,ul中的个数-1个,并点亮第一个按钮。
|
||||
for (var i = 0; i < ul.children.length - 1; i++) {
|
||||
var olNewLi = document.createElement("li");
|
||||
olNewLi.innerHTML = i + 1;
|
||||
ol.appendChild(olNewLi)
|
||||
}
|
||||
var olLiArr = ol.children;
|
||||
olLiArr[0].className = "current";
|
||||
|
||||
//4.鼠标放到ol的li上切换图片
|
||||
for (var i = 0; i < olLiArr.length; i++) {
|
||||
//自定义属性,把索引值绑定到元素的index属性上
|
||||
olLiArr[i].index = i;
|
||||
olLiArr[i].onmouseover = function () {
|
||||
//排他思想
|
||||
for (var j = 0; j < olLiArr.length; j++) {
|
||||
olLiArr[j].className = "";
|
||||
}
|
||||
this.className = "current";
|
||||
//鼠标放到小的方块上的时候索引值和key以及square同步
|
||||
// key = this.index;
|
||||
// square = this.index;
|
||||
key = square = this.index;
|
||||
//移动盒子
|
||||
animate(ul, -this.index * imgWidth);
|
||||
}
|
||||
}
|
||||
|
||||
//5.添加定时器
|
||||
var timer = setInterval(autoPlay, 1000);
|
||||
|
||||
//固定向右切换图片
|
||||
//两个定时器(一个记录图片,一个记录小方块)
|
||||
var key = 0;
|
||||
var square = 0;
|
||||
|
||||
function autoPlay() {
|
||||
//通过控制key的自增来模拟图片的索引值,然后移动ul
|
||||
key++;
|
||||
if (key > olLiArr.length) {
|
||||
//图片已经滑动到最后一张,接下来,跳转到第一张,然后在滑动到第二张
|
||||
ul.style.left = 0;
|
||||
key = 1;
|
||||
}
|
||||
animate(ul, -key * imgWidth);
|
||||
//通过控制square的自增来模拟小方块的索引值,然后点亮盒子
|
||||
//排他思想做小方块
|
||||
square++;
|
||||
if (square > olLiArr.length - 1) {//索引值不能大于等于5,如果等于5,立刻变为0;
|
||||
square = 0;
|
||||
}
|
||||
for (var i = 0; i < olLiArr.length; i++) {
|
||||
olLiArr[i].className = "";
|
||||
}
|
||||
olLiArr[square].className = "current";
|
||||
}
|
||||
|
||||
//鼠标放上去清除定时器,移开后在开启定时器
|
||||
all.onmouseover = function () {
|
||||
div.style.display = "block";
|
||||
clearInterval(timer);
|
||||
}
|
||||
all.onmouseout = function () {
|
||||
div.style.display = "none";
|
||||
timer = setInterval(autoPlay, 1000);
|
||||
}
|
||||
|
||||
//6.左右切换图片(鼠标放上去显示,移开隐藏)
|
||||
spanArr[0].onclick = function () {
|
||||
//通过控制key的自增来模拟图片的索引值,然后移动ul
|
||||
key--;
|
||||
if (key < 0) {
|
||||
//先移动到最后一张,然后key的值取之前一张的索引值,然后在向前移动
|
||||
ul.style.left = -imgWidth * (olLiArr.length) + "px";
|
||||
key = olLiArr.length - 1;
|
||||
}
|
||||
animate(ul, -key * imgWidth);
|
||||
//通过控制square的自增来模拟小方块的索引值,然后点亮盒子
|
||||
//排他思想做小方块
|
||||
square--;
|
||||
if (square < 0) {//索引值不能大于等于5,如果等于5,立刻变为0;
|
||||
square = olLiArr.length - 1;
|
||||
}
|
||||
for (var i = 0; i < olLiArr.length; i++) {
|
||||
olLiArr[i].className = "";
|
||||
}
|
||||
olLiArr[square].className = "current";
|
||||
}
|
||||
spanArr[1].onclick = function () {
|
||||
//右侧的和定时器一模一样
|
||||
autoPlay();
|
||||
}
|
||||
|
||||
|
||||
function animate(ele, target) {
|
||||
clearInterval(ele.timer);
|
||||
var speed = target > ele.offsetLeft ? 10 : -10;
|
||||
ele.timer = setInterval(function () {
|
||||
var val = target - ele.offsetLeft;
|
||||
ele.style.left = ele.offsetLeft + speed + "px";
|
||||
|
||||
if (Math.abs(val) < Math.abs(speed)) {
|
||||
ele.style.left = target + "px";
|
||||
clearInterval(ele.timer);
|
||||
}
|
||||
}, 10)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="all" id='all'>
|
||||
<div class="screen" id="screen">
|
||||
<ul id="ul">
|
||||
<li><img src="images/1.jpg" width="500" height="200"/></li>
|
||||
<li><img src="images/2.jpg" width="500" height="200"/></li>
|
||||
<li><img src="images/3.jpg" width="500" height="200"/></li>
|
||||
<li><img src="images/4.jpg" width="500" height="200"/></li>
|
||||
<li><img src="images/5.jpg" width="500" height="200"/></li>
|
||||
</ul>
|
||||
<ol>
|
||||
|
||||
</ol>
|
||||
<div id="arr">
|
||||
<span id="left"><</span>
|
||||
<span id="right">></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
```
|
||||
|
||||
实现效果:
|
||||
|
||||

|
||||
|
||||
温馨提示:动图太大,可以把<http://img.smyhvae.com/20180202_2020.gif>单独在浏览器中打开。
|
||||
|
||||
工程文件:
|
||||
|
||||
- [2018-02-02-JS动画实现轮播图.rar](http://download.csdn.net/download/smyhvae/10237662)
|
||||
|
||||
|
||||
## 我的公众号
|
||||
|
||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||||
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||

|
||||
|
||||
1165
04-JavaScript基础/42-JavaScript特效:scroll家族和缓动动画.md
Normal file
1165
04-JavaScript基础/42-JavaScript特效:scroll家族和缓动动画.md
Normal file
File diff suppressed because it is too large
Load Diff
180
04-JavaScript基础/43-JavaScript特效:client家族(可视区).md
Normal file
180
04-JavaScript基础/43-JavaScript特效:client家族(可视区).md
Normal file
@@ -0,0 +1,180 @@
|
||||
|
||||
|
||||
|
||||
## client 家族的组成
|
||||
|
||||
### clientWidth 和 clientHeight
|
||||
|
||||
盒子调用时:
|
||||
|
||||
- clientWidth:获取盒子区域宽度(padding + width)。
|
||||
|
||||
- clientHeight:获取盒子区域高度(padding + height)。
|
||||
|
||||
body/html调用时:
|
||||
|
||||
- clientWidth:获取网页可视区域宽度。
|
||||
|
||||
- clientHeight:获取网页可视区域高度。
|
||||
|
||||
|
||||
### clientX 和 clientY
|
||||
|
||||
event调用:
|
||||
|
||||
- clientX:鼠标距离可视区域左侧距离。
|
||||
|
||||
- clientY:鼠标距离可视区域上侧距离。
|
||||
|
||||
|
||||
|
||||
### clientTop 和 clientLeft
|
||||
|
||||
- clientTop:盒子的上border。
|
||||
|
||||
- clientLeft:盒子的左border。
|
||||
|
||||
|
||||
## 三大家族 offset/scroll/client 的区别
|
||||
|
||||
### 区别1:宽高
|
||||
|
||||
- offsetWidth = width + padding + border
|
||||
- offsetHeight = height + padding + border
|
||||
|
||||
- scrollWidth = 内容宽度(不包含border)
|
||||
- scrollHeight = 内容高度(不包含border)
|
||||
|
||||
- clientWidth = width + padding
|
||||
- clientHeight = height + padding
|
||||
|
||||
|
||||
### 区别2:上左
|
||||
|
||||
|
||||
offsetTop/offsetLeft:
|
||||
|
||||
- 调用者:任意元素。(盒子为主)
|
||||
- 作用:距离父系盒子中带有定位的距离。
|
||||
|
||||
|
||||
scrollTop/scrollLeft:
|
||||
|
||||
- 调用者:document.body.scrollTop(window调用)(盒子也可以调用,但必须有滚动条)
|
||||
- 作用:浏览器无法显示的部分(被卷去的部分)。
|
||||
|
||||
|
||||
clientY/clientX:
|
||||
|
||||
- 调用者:event
|
||||
- 作用:鼠标距离浏览器可视区域的距离(左、上)。
|
||||
|
||||
|
||||
|
||||
|
||||
## 函数封装:获取浏览器的宽高(可视区域)
|
||||
|
||||
函数封装如下:
|
||||
|
||||
```javascript
|
||||
//函数封装:获取屏幕可视区域的宽高
|
||||
function client() {
|
||||
if (window.innerHeight !== undefined) {
|
||||
//ie9及其以上的版本的写法
|
||||
return {
|
||||
"width": window.innerWidth,
|
||||
"height": window.innerHeight
|
||||
}
|
||||
} else if (document.compatMode === "CSS1Compat") {
|
||||
//标准模式的写法(有DTD时)
|
||||
return {
|
||||
"width": document.documentElement.clientWidth,
|
||||
"height": document.documentElement.clientHeight
|
||||
}
|
||||
} else {
|
||||
//没有DTD时的写法
|
||||
return {
|
||||
"width": document.body.clientWidth,
|
||||
"height": document.body.clientHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**案例:根据浏览器的可视宽度,给定不同的背景的色。**
|
||||
|
||||
> PS:这个可以用来做响应式。
|
||||
|
||||
代码如下:(需要用到上面的封装好的方法)
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script src="tools.js"></script>
|
||||
<script>
|
||||
//需求:浏览器每次更改大小,判断是否符合某一标准然后给背景上色。
|
||||
// // >960红色,大于640小于960蓝色,小于640绿色。
|
||||
|
||||
window.onresize = fn; //页面大小发生变化时,执行该函数。
|
||||
//页面加载的时候直接执行一次函数,确定浏览器可视区域的宽,给背景上色
|
||||
fn();
|
||||
|
||||
//封装成函数,然后指定的时候去调用和绑定函数名
|
||||
function fn() {
|
||||
if (client().width > 960) {
|
||||
document.body.style.backgroundColor = "red";
|
||||
} else if (client().width > 640) {
|
||||
document.body.style.backgroundColor = "blue";
|
||||
} else {
|
||||
document.body.style.backgroundColor = "green";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
||||
上当代码中,`window.onresize`事件指的是:在窗口或框架被调整大小时发生。各个事件的解释如下:
|
||||
|
||||
- window.onscroll 屏幕滑动
|
||||
|
||||
- window.onresize 浏览器大小变化
|
||||
|
||||
- window.onload 页面加载完毕
|
||||
|
||||
- div.onmousemove 鼠标在盒子上移动(注意:不是盒子移动)
|
||||
|
||||
|
||||
|
||||
## 获取显示器的分辨率
|
||||
|
||||
比如,我的电脑的显示器分辨率是:1920*1080。
|
||||
|
||||
|
||||
获取显示器的分辨率:
|
||||
|
||||
```javascript
|
||||
window.onresize = function () {
|
||||
document.title = window.screen.width + " " + window.screen.height;
|
||||
}
|
||||
```
|
||||
|
||||
显示效果:
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
上图中,不管我如何改变浏览器的窗口大小,title栏显示的值永远都是我的显示器分辨率:1920*1080。
|
||||
|
||||
|
||||
|
||||
27
04-JavaScript基础/51-常见代码解读.md
Normal file
27
04-JavaScript基础/51-常见代码解读.md
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
### `callback && callback()`的含义
|
||||
|
||||
```javascript
|
||||
callback && callback()
|
||||
```
|
||||
|
||||
|
||||
含义是:如果callback存在,则执行callback()函数。
|
||||
|
||||
这个 callback 通常作为函数的参数使用。举例:
|
||||
|
||||
|
||||
```javascript
|
||||
function foo(callback) {
|
||||
{
|
||||
// do something
|
||||
}
|
||||
callback && callback() // 不传 callback 参数,则不会执行 callback() 函数
|
||||
}
|
||||
|
||||
foo(); // 只执行do something中的代码
|
||||
foo(callback);//callback是另一个函数,将此函数传入 foo,将会执行callback()
|
||||
```
|
||||
|
||||
|
||||
|
||||
80
04-JavaScript基础/52-JS的小知识.md
Normal file
80
04-JavaScript基础/52-JS的小知识.md
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
|
||||
### 方法的注释
|
||||
|
||||
|
||||
方法写完之后(注意,一定要先写完整),我们在方法的前面输入`/**`,然后回车,会发现,注释的格式会自动补齐。
|
||||
|
||||
比如:
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 功能:给定元素查找他的第一个元素子节点,并返回
|
||||
* @param ele
|
||||
* @returns {Element|*|Node}
|
||||
*/
|
||||
function getFirstNode(ele){
|
||||
var node = ele.firstElementChild || ele.firstChild;
|
||||
return node;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 断点调试
|
||||
|
||||
(1)先让程序运行一遍。
|
||||
|
||||
(2)f12,弹出代码调试工具
|
||||
|
||||
(3)打断点:
|
||||
|
||||

|
||||
|
||||
然后刷新页面。
|
||||
|
||||
(4)一步步调试,每点击一次,执行一步:
|
||||
|
||||

|
||||
|
||||
(5)监视变量:
|
||||
|
||||
当然,也可以添加变量或者表达式到监视窗口。操作如下:
|
||||
|
||||

|
||||
|
||||
上图中,选择变量或表达式,然后右键add to watch.
|
||||
|
||||
然后监视窗口:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user