JavaScript起步
JavaScript 是一种脚本,一门编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新,交互式的地图,2D/3D 动画,滚动播放的视频等等.它是标准 Web 技术蛋糕的第三层
API
JavaScript 语言核心之上所构建的功能更令人兴奋。应用程序接口(Application Programming Interfaces(API))将为你的代码提供额外的超能力。
API 是已经建立好的一套代码组件,可以让开发者实现原本很难甚至无法实现的程序。就像现成的家具套件之于家居建设,用一些已经切好的木板组装一个书柜,显然比自己设计,寻找合适的木材,裁切至合适的尺寸和形状,找到正确尺寸的螺钉,再组装成书柜要简单得多。
API 通常分为两类。
浏览器 API 内建于 web 浏览器中,它们可以将数据从周边计算机环境中筛选出来,还可以做实用的复杂工作。例如:
- 文档对象模型 API(DOM(Document Object Model)API) 能通过创建、移除和修改 HTML,为页面动态应用新样式等手段来操作 HTML 和 CSS。比如当某个页面出现了一个弹窗,或者显示了一些新内容(像上文小 demo 中看到那样),这就是 DOM 在运行。
- 地理位置 API(Geolocation API) 获取地理信息。这就是为什么 谷歌地图 可以找到你的位置,而且标示在地图上。
- 画布(Canvas) 和 WebGL API 可以创建生动的 2D 和 3D 图像。人们正运用这些 web 技术制作令人惊叹的作品。参见 Chrome Experiments 以及 webglsamples。
- 诸如 HTMLMediaElement 和 WebRTC 等 影音类 API 让你可以利用多媒体做一些非常有趣的事,比如在网页中直接播放音乐和影片,或用自己的网络摄像头获取录像,然后在其他人的电脑上展示(试用简易版 截图 demo 以理解这个概念)。
第三方 API 并没有默认嵌入浏览器中,一般要从网上取得它们的代码和信息。比如:
- Twitter API、新浪微博 API 可以在网站上展示最新推文之类。
- 谷歌地图 API、高德地图 API 可以在网站嵌入定制的地图等等。
二,JS输入输出语句
- 控制台输出:console.log() 打印日志
- 弹窗 :
alert('你好'); - 弹出输入框:prompt()语句
prompt('请输入你的名字:');
三,JS 书写位置
- 行内式:写在标签内部。
- 内嵌式(内联式):写在 head 标签中。
- 外链式:引入外部 JS 文件。
四,常量(字面量)
- 数字常量(数值常量)
- 字符串常量
- 布尔常量
- 自定义常量
五,变量
变量是程序在内存中申请的一块用来存放数据的空间。
//ES5
var name = '江江'; // 定义一个名为 name 的变量。name是变量名。
//ES6
const name ='江江'; // 定义一个常量
let age = 12; // 定义一个变量
//只声明,不赋值
var a;
console.log(a); // 打印结果:undefined
六,变量命名规范
- 由字母(A—Za—z)、数字(0—9)、下划线()、美元符号(5)组成,如: usrAge, num01, name
- 严格区分大小写。var app;和var App;是两个变量
- 不能以数字开头。18age是错误的
- 不能是关键字、保留字。例如: var, for, while
- 变量名必须有意义。MMD BBD nl— age
- 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。myFirstName推荐翻译网站:有道爱词霸
- 尽量不要使用
name作为变量名
1.标识符
标识符:在 JS 中所有的可以由我们自主命名的都可以称之为标识符。包括:变量名、函数名、属性名、参数名都是属于标识符。
2.关键字
关键字:被JS赋予了特殊含义的单词。也就是说,关键字是 JS 本身已经使用了的单词,我们不能再用它们充当变量名、函数名等标识符。关键字在开发工具中会显示特殊的颜色。
3.保留字
保留字:实际上就是预留的“关键字”。它们虽然现在还不是关键字,但是未来可能会成为关键字。同样不能用它们当充当变量名、函数名等标识符。
数据类型
- 基本数据类型(值类型):String 字符串、Number 数值、BigInt 大型数值(number类型无法安全地表示大于 (253-1)、Boolean 布尔值、Null 空值、Undefined 未定义、Symbol(用于创建对象的唯一标识符)。
- 引用数据类型(引用类型):Object 对象。
栈内存和堆内存
JS 中,所有的变量都是保存在栈内存中的。
- 基本数据类型:
基本数据类型的值,直接保存在栈内存中。值与值之间是独立存在,修改一个变量不会影响其他的变量。
- 引用数据类型:
对象是保存到堆内存中的。每创建一个新的对象,就会在堆内存中开辟出一个新的空间;而变量保存了对象的内存地址(对象的引用),保存在栈内存当中。如果两个变量保存了同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。
1.字符串 String
(1)语法
字符串型可以是引号中的任意文本,其语法为:双引号 "" 或者单引号 ''。
字符串的扩展
- includes(str):判断是否包含指定的字符串
- startsWith(str):判断是否以指定字符串开头
- endsWith(str):判断是否以指定字符串结尾
- repeat(count):重复指定次数
(2)字符串转义符
类似HTML里面的特殊字符,字符串中也有特殊字符,我们称之为转义符转义符都是\开头的,常用的转义符及其说明如下:
| 转义符 | 解释说明 |
|---|---|
\\n | 换行符, n是 newline 的意思 |
\\\\ | \ |
\\' | 单引号' |
\\" | 双引号" |
\\t | tab 缩进 |
\\b | 空格,b 是 blank 的意思 |
举例
var str1 = '我说:"今天\t天气真不错!"';
var str2 = '\\\\\\';
console.log(str1);
console.log(str2);
上方代码的打印结果:
我说:"今天 天气真不错!"
\\\
(3)获取字符串的长度length
var str = 'hello';
console.log(str.length);
charAt获取对应索引位置的字符
concat 拼接字符串,返回新的拼接 字符串结果,不影响原始值
(4)字符串拼接
多个字符串之间可以使用加号 + 进行拼接。
拼接语法:
字符串 + 任意数据类型 = 拼接之后的新字符串;
字面量
字面量是在源代码中一个固定的表示法,通俗来说,就是字面量如何表达这个值。
- 数字字面量:
1、0 - 字符串字面量:
mphy、aaa - 布尔字面量:
true、false
(5)模板字符串(模板字面量)语法 : $ { }
var name = 'qianguyihao';
var age = '26';
//字符串拼接
console.log('我是' + name + ',age:' + age); //传统写法
console.log(`我是${name},age:${age}`); //ES6 写法。注意语法格式
在模板字符串中插入表达式
模板字符串中可以调用函数
模板字符串支持嵌套使用
2.数字型 Number
数字型进制
常见:二进制、八进制、十进制、十六进制
0123:0开头表示八进制0b11:0b开头表示二进制0x11:0x开头表示十六进制- 直接打印出来会转化为十进制
NaN:是一个特殊的数字,表示 Not a Number,非数值。在进行数值运算时,如果得不到正常结果,就会返回 NaN。
isNaN()
isNaN 方法用来判断一个变量和或者一个值是数字类型,若不是数字类型则返回 true;否则返回 false。
tofixed
返回包含指定小数点位数的字符串
3.布尔型 Boolean 值:true/false
4.Undefined
如果一个变量声明未赋值 就是 undefined 未定义数据类型
undefined 和数字相加 最后的结果是 NaN
console.log(undefined+1); // NaN
console.log(undefined+NaN); // NaN
console.log(undefined+true); // NaN
console.log(undefined+'aaa'); // undefinedaaa
console.log(undefined+undefined); // NaN
5.空值 Null
console.log(null+1); // 1
console.log(null+undefined); // NaN
console.log(null+NaN); // NaN
console.log(null+true); // 1
console.log(null+'aaa'); // nullaaa
console.log(null+null); // 0
数据类型转换
typeof 获取变量数据类型
typeof variable (typeof(variable)) 返回一个字符串,值为该变量的数据类型。
1.转换成字符串的三种方法
一般用第三种方式,隐式转换。
toString()方法String()方法- 加号
+拼接字符串
2.转换为数字型
parseInt(变量) 可以把 字符型的转换为数字型 得到是整数
| 方式 | 说明 | 案例 |
|---|---|---|
parseInt(str)函数 | string->整数型 | parseInt('10') |
parseFloat()函数 | string->浮点型 | parseFloat('3.14') |
Number()强转换函数 | string->数字型 | Number('12') |
| JS 隐式转换 | 算术运算符隐式转换为数字型 | '12'- 0或 '12' - ''或 '12'*1 |
3.转换为布尔型
使用 Boolean() 函数转换。
- 转换值为
false:'',0,NaN,null,undefined(5个) - 其他的转换值均为
true
显式类型转换
- toString()
- String()
- Number()
- parseInt(string)
- parseFloat(string)
- Boolean()
隐式类型转换
- isNaN ()
- 自增/自减运算符:
++、—- - 正号/负号:
+a、-a - 加号:
+ - 运算符:
-、*、/
运算符
1.算术运算符
| 运算符 | 描述 |
|---|---|
| + | 加、字符串连接 |
| - | 减 |
| * | 乘 |
| / | 除 |
| % | 获取余数(取余、取模) |
2.递增++和递减--运算符
3.比较运算符
- < 小于号
- >= 大于或等于
- <= 小于或等于
- == 等于
- === 全等于
- != 不等于
- !== 不全等于
4.逻辑运算符
逻辑运算符有三个:
- &&: 与(且)。两个都为真,结果才为真。特点:一假则假。
- || :或。只要有一个是真,结果就是真。特点:特点: 一真则真。
- ! :非。对一个布尔值进行取反。特点: 真变假, 假变真。
5.赋值运算符
=直接赋值。比如var a = 5。意思是,把 5 这个值,往 a 里面存一份。简称:把 5 赋值给 a。+=:比如 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。
6.关于 == 与===
区别
需要注意的是 == 和 === 的区别。
==比较的时候只判断值,因为会进行隐式转换。值相等则返回true===比较判断的时同时需要值相等和类型相同,两者均满足则返回true
7.三目运算符
三目运算符也叫三元运算符、条件运算符。
语法:
条件表达式 ? 语句1 : 语句2;
执行流程——条件运算符在执行时,首先对条件表达式进行求值:
- 如果该值为 true,则执行语句 1,并返回执行结果
- 如果该值为 false,则执行语句 2,并返回执行结果
流程控制
- 顺序结构
- 选择结构:if 语句、switch 语句
- 循环结构:while 语句、for 语句
1.顺序结构
按照代码的先后顺序,依次执行。
2.选择结构
if-else
if (条件表达式) {
// 条件为真时,做的事情
} else {
// 条件为假时,做的事情
}
switch-case
switch(表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
...
default:
语句体 n+1;
break;
}
3.循环
for 循环
语法
for(①初始化表达式; ②条件表达式; ④更新表达式){
③循环体
}
for (let i = 1; i <= 100; i++) {
console.log(i);
}
执行流程:
①执行初始化表达式,初始化变量(初始化表达式只会执行一次)
②执行条件表达式,判断是否执行循环:
如果为true,则执行循环③
如果为false,终止循环
④执行更新表达式,更新表达式执行完毕继续重复②
while 循环
while(条件表达式){
循环体
}
执行流程:
while语句在执行时,先对条件表达式进行求值判断:
如果值为true,则执行循环体:
循环体执行完毕后,继续对表达式进行判断
如果为true,则继续执行循环体,以此类推
如果值为false,则终止循环
如果有必要的话,我们可以使用 break 来终止循环。
do...while
语法
do{
循环体
}while(条件表达式)
break 与 continue
break:跳出当前循环,不再进行当前循环。continue:跳过本轮循环,进行当前循环的下一轮。break与continue均可配合label语句使用来跳转循环。
数组
数组是一种特殊的对象,适用于存储和管理有序的数据项。
创建空数组
let arr = new Array(); 别用!
let arr = [];
判断数组长度 用length 属性
获取元素
- 你可以通过元素的索引获取元素,例如 arr[0]
- 我们也可以使用允许负索引的 at(i) 方法。对于负值的 i,它会从数组的末尾往回数。如果 i >= 0,它的工作方式与 arr[i] 相同。
检测一个值是否为数组用 instanceof 而不是 typeof
或者 isArray():判断是否为数组
function isArray(test) {
if (test instanceof Array) return true;
return false;
}
console.log(isArray([1, 2])); // true
console.log(isArray(1)); // false
遍历数组的元素
- for (let i=0; i<arr.length; i++) — 运行得最快,可兼容旧版本浏览器。
- for (let item of arr) — 现代语法,只能访问 items。
比较数组时
不要使用 == 运算符(当然也不要使用 > 和 < 等运算符), 因为它们不会对数组进行特殊处理。它们通常会像处理任意对象那样处理数组,这通常不是我们想要的。 但是,我们可以使用 for..of 循环来逐项比较数组。
let styles = ["Jazz","Blues"];
styles.push("Rock-n-Roll");
styles[1] = "Classics";
alert(styles.shift()) ;
styles.unshift("Rap" , "Reggae")
数组方法
添加/移除数组元素pop/push, shift/unshift 方法
队列(queue)是最常见的使用数组的方法之一。 在计算机科学中,这表示支持两个操作的一个有序元素的集合:
-
push 在末端添加一个元素.
-
shift 取出队列首端的一个元素,整个队列往前移,这样原先排第二的元素现在排在了第一。
数组还有另一个用例,就是数据结构 栈。 它支持两种操作:
-
push 在末端添加一个元素.
-
pop 从末端取出一个元素.
所以新元素的添加和取出都是从“末端”开始的。 栈通常被被形容成一叠卡片:要么在最上面添加卡片,要么从最上面拿走卡片: 对于栈 LIFO(Last-In-First-Out)即后进先出法则。 队列相对应的叫做 FIFO(First-In-First-Out),即先进先出。 JavaScript 中的数组既可以用作队列,也可以用作栈。它们允许你从首端/末端来添加/删除元素。 这在计算机科学中,允许这样的操作的数据结构被称为 双端队列(deque)。 我们已经学了从数组的首端或尾端添加和删除元素的方法:
- arr.push(...items) —— 从尾端添加元素,
- arr.pop() —— 从尾端提取元素,
- arr.shift() —— 从首端提取元素,
- arr.unshift(...items) —— 从首端添加元素。
如何从数组中删除元素?
数组是对象,所以我们可以尝试使用 delete:删除但还会保留位置
arr.splice 方法
可以说是处理数组的瑞士军刀。 它可以做所有事情:添加,删除和插入元素。 语法是: arr.splice(start[, deleteCount, elem1, ..., elemN]) 它从索引 start 开始修改 arr:删除 deleteCount 个元素并在当前位置插入 elem1, ..., elemN。最后返回被删除的元素所组成的数组。
let arr = ["I", "study", "JavaScript", "right", "now"];
// 删除数组的前三项,并使用其他内容代替它们
arr.splice(0, 3, "Let's", "dance");
alert( arr ) // 现在 ["Let's", "dance", "right", "now"]
arr.slice 方法
比 arr.splice 简单得多。 语法是: arr.slice([start], [end]) 它会返回一个新数组,将所有从索引 start 到 end(不包括 end)的数组项复制到一个新的数组。 start 和 end 都可以是负数,在这种情况下,从末尾计算索引。 它和字符串的 str.slice 方法有点像,就是把子字符串替换成子数组。
let arr = ["t", "e", "s", "t"];
alert( arr.slice(1, 3) ); // e,s(复制从位置 1 到位置 3 的元素)
alert( arr.slice(-2) ); // s,t(复制从位置 -2 到尾端的元素)
arr.concat
创建一个新数组,其中包含来自于其他数组和其他项的值。 语法是: arr.concat(arg1, arg2...) 它接受任意数量的参数 —— 数组或值都可以。 结果是一个包含来自于 arr,然后是 arg1,arg2 的元素的新数组。 如果参数 argN 是一个数组,那么其中的所有元素都会被复制。否则,将复制参数本身。
let arr = [1, 2];
// 从 arr 和 [3,4] 创建一个新数组
alert( arr.concat([3, 4]) ); // 1,2,3,4
// 从 arr、[3,4] 和 [5,6] 创建一个新数组
alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6
// 从 arr、[3,4]、5 和 6 创建一个新数组
alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
遍历:forEach
arr.forEach 方法允许为数组的每个元素都运行一个函数。
arr.forEach(function(item, index, array) {
// ... do something with item
});
在数组中搜索
indexOf/lastIndexOf 和 includes
- arr.indexOf(item, from) —— 从索引 from 开始搜索 item,如果找到则返回索引,否则返回 -1。
- arr.includes(item, from) —— 从索引 from 开始搜索 item,如果找到则返回 true(译注:如果没找到,则返回 false)。
let arr = [1, 0, false];
alert( arr.indexOf(0) ); // 1
alert( arr.indexOf(false) ); // 2
alert( arr.indexOf(null) ); // -1
alert( arr.includes(1) ); // true
方法 arr.lastIndexOf 与 indexOf 相同,但从右向左查找。
find 和 findIndex/findLastIndex
想象一下,我们有一个对象数组。我们如何找到具有特定条件的对象? 这时可以用 arr.find 方法。 语法如下:
let result = arr.find(function(item, index, array) {
// 如果返回 true,则返回 item 并停止迭代
// 对于假值(falsy)的情况,则返回 undefined
});
依次对数组中的每个元素调用该函数:
- item 是元素。
- index 是它的索引。
- array 是数组本身。
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let user = users.find(item => item.id == 1);
alert(user.name); // John
arr.findIndex 方法(与 arr.find)具有相同的语法,但它返回找到的元素的索引,而不是元素本身。如果没找到,则返回 -1。 arr.findLastIndex 方法类似于 findIndex,但从右向左搜索,类似于 lastIndexOf。
filter
filter()函数用于过滤出满足条件的数据,返回一个新的数组,不会改变原来的数组。 针对简单类型的数组,找出数组中所有为奇数的数字 首先我们需要自定义过滤的函数,然后将数值对2取模,结果不是0则该数值为奇数. 在JavaScript中数字不为0,就可以返回“true”,恰好可以作为返回值。因此我们得到以下函数。
var filterFn = function (x) {
return x % 2;
};
/定义一个数组,调用filter()函数测试结果。
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var result = arr.filter(filterFn);
console.log(result);
/得到的结果为“[1, 5, 9, 15]”,符合前面对filter()函数的描述。
转换数组
数组转换和重新排序
map
arr.map 方法是最有用和经常使用的方法之一。
let result = arr.map(function(item, index, array) {
// 返回新值而不是当前元素
})
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length);
alert(lengths); // 5,7,6
sort(fn)
arr.sort 方法对数组进行 原位(in-place) 排序,更改元素的顺序。(译注:原位是指在此数组内,而非生成一个新数组。)
let arr = [ 1, 2, 15 ];
// 该方法重新排列 arr 的内容
arr.sort();
alert( arr ); // 1, 15, 2
reverse
arr.reverse 方法用于颠倒 arr 中元素的顺序。
let arr = [1, 2, 3, 4, 5];
arr.reverse();
alert( arr ); // 5,4,3,2,1
当我们需要遍历一个数组时 —— 我们可以使用 forEach,for 或 for..of。 当我们需要遍历并返回每个元素的数据时 —— 我们可以使用 map。
| 方法名 | 说明 | 是否修改原数组 |
|---|---|---|
reverse() | 颠倒数组中元素顺序,无参数 | 会改变原数组,返回新数组 |
sort() | 对数组的元素进行排序 | 会改变原数组,返回新数组 |
数组的解构赋值
把数组中的元素赋值给其他变量
let [a, b, c] = [1, 2, [3, 4]];
console.log(a); // 1
console.log(b); // 2
console.log(c); // [3, 4]
arguments 的使用
arguments 是所有JS函数内置的对象,但也只有函数具有。
函数的 arguments 是一种伪数组:
- 具有数组的
length属性 - 按照索引方式进行存储
- 没有真正数组的一些方法
pop()、push()
对象
JavaScript 对象是拥有属性和方法的数据。JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等。在 JavaScript 中,对象是拥有属性和方法的数据。
var obj = {
key : value,
键 : 值,
属性: 属性值;
}
var car = {
type:"Fiat",
model:500,
color:"white",
money:undefined,
newCar:false,
fn2: function() {
console.log('千古壹号,永不止步!');
},
}
// 增加对象属性
car.width = "1.6m";
// 删除对象属性
delete car.width;
// 修改对象属性
car.width = "1.5m";
1.1 什么是对象?
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的。
- 属性:事物的特征,在对象中用属性来表示(常用名词)
- 方法:事物的行为,在对象中用方法来表示(常用动词)
2. 创建对象
- 使用字面量创建对象
- 使用
new Object创建对象 - 利用构造函数创建对象
2.1 字面量创建
使用 {} 创建,包含属性和方法,采用键值对表示,创建的对象称为对象字面量。
var obj = {
uname: 'MurphyChen',
age: 18,
sayHi: function () {
console.log('Hi!);
}
}
2.2 使用对象的属性和方法
- 调用对象的属性
// 方法一
objectName.attrName
// 方法二
objectName['attrName'] // 不要忘记引号
- 调用对象的方法
objectName.funcName();//不要忘记括号
2.3 使用 newObject 创建对象
// 创建空对象
let obj = new Object();
//添加属性
obj.uname = 'MurphyChen';
obj.age = 18;
obj.sayHi = function() {
console.log('Hi!');
}
2.4 利用构造函数创建对象
前两种创建对象的方法,每次都只能创建一个对象。但需要多个具有相同属性和方法的对象的时候,就需要使用构造函数来创建。
构造函数将相同的属性和方法封装在一个函数里。
构造函数语法:
// 定义
function ConFuncName(params) {
this.attr = value;
this.methods = function() {};
}
// 调用
let obj = new ConFuncName(params);
- 构造函数名单词首字母均大写
- 函数不需要返回值
举例
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
}
let ldh = new Star('刘德华', 18, '男');
let zxy = new Star('张学友', 19, '男');
console.log(typeof ldh); // object
console.log(ldh.sex); // 男
console.log(zxy.name); // 张学友
构造函数的实质
构造函数相当于创建了一个抽象的类,使用关键字 new 创建一个对象的过程称为类的实例化,对象是具体的。
new 关键字的执行过程
- 在内存中创建一个空的对象;
this指向这个空对象;- 执行构造函数里面的代码,给空对象添加属性和方法;
- 返回此对象。
3. 遍历对象
for...in 可以对数组和对象进行遍历。
语法
for (const key in obj) {
console.log(key); // 遍历属性名
console.log(obj[key]); // 遍历属性值
}
内置对象
1.内置对象
- Javascript中的对象分为3种:自定义对象、内置对象、浏览器对象
- 前面两种对象是IS基础内容,属于ECMAScript ;第三个浏览器对象属于我们JS独有的,我们JS APl讲解
- 内置对象就是指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
2. 数学对象 Math
2.1 Math 的使用
查询 MDN 文档
const arr = [3,4,11,24,89,2,34]
console.log(Math.max(...arr)); // 89
console.log(Math.PI); // 3.141592653589793
console.log(Math.max()); // -Infinity
2.1 自定义自己的 Math 对象
我们可以自定义自己的对象。
const myMath = {
PI: 3.141592654,
max: function () {
let max = arguments[0];
for (let i = 1; i < arguments.length; i++) {
max = arguments[i] > max ? arguments[i] : max;
}
return max;
},
min: function () {
let min = arguments[0];
for (let i = 1; i < arguments.length; i++) {
min = arguments[i] < min ? arguments[i] : min;
}
return min;
}
}
2.3 Math 常用方法
Math.PI // 圆周率
Math.floor() // 向下取整
Math.ceil() // 向上取整
Math.round() // 四舍五入,遇到 .5 往大了取
Math.abs() // 绝对值
Math.max() // 最大值
Math.min() // 最小值
console.log(Math.abs('-1')); // 1
console.log(Math.floor(-2.5)); // 3
console.log(Math.ceil(-2.5)); // -2
console.log(Math.round(-3.5)); // -3
console.log(Math.round(3.5)); // 4
2.4 Math.random 随机数
Math.random 方法返回一个位于区间 [0, 1) 的伪随机浮点数。
Math.random(); // 0.41713485547506424
获取闭区间 [a, b] 之间的整数:
let ran = parseInt(Math.random() * (b - a + 1)) + a;
获取前闭后开区间 [a, b) 之间的整数:
let ran = parseInt(Math.random() * (b - a)) + a;
实例:定义自己的取整函数
// [a, b)
function getRandom1(a, b) {
return parseInt(Math.random() * (b -a)) + a;
}
// [a, b]
function getRandom2(a, b) {
return parseInt(Math.random() * (b - a + 1)) + a;
}
应用:随机点名
let names = new Array('Peter', 'Murphy', 'Jack', 'Darcy', 'Alice');
console.log(names[getRandom2(0, names.length-1)]);
3. 日期对象 Date
3.1 时间格式化
Date 对象是一个构造函数,需要使用 new 来创建日期对象(实例化)。
若没有参数,则默认返回当前系统的当前时间
let date = new Date();
console.log(date);
若有参数,则返回参数里面的时间。
参数常用写法
let date = new Date();
console.log(date);
// 2021-03-15T05:39:52.204Z
let date1 = new Date(2019, 10, 1);
console.log(date1);
// 2019-10-31T16:00:00.000Z
let date2 = new Date('2019-10-1 8:8:8');
console.log(date2);
// 2019-10-01T00:08:08.000Z
一般使用以下参数形式
let date3 = new Date('2019-10-1 10:10:10');
let date4 = new Date('2019/10/1');
常用返回日期格式:
let date = new Date();
console.log(date.getFullYear()); // 2021
console.log(date.getMonth() + 1); // 3,注意得到的月份要加 1
console.log(date.getDate()); // 15
console.log(date.getDay()); // 1
实例一:返回 今天是 2021 年 3 月 15 日 周一 的日期格式。
let year = date.getFullYear();
let month = date.getMonth() + 1;
let dates = date.getDate();
let day = date.getDay();
let days = ['日', '一', '二', '三', '四', '五', '六']
console.log(`今天是 ${year} 年 ${month} 月 ${dates} 日 周${days[day]}`);
实例二:输出时分秒 15:06:09 格式化时间串。
function getTime() {
let time = new Date();
let h, m, s;
[h, m, s] = [time.getHours(), time.getMinutes(), time.getSeconds()]
function check(t) {
return t < 10 ? '0' + t : t;
}
[h, m, s] = [check(h), check(m), check(s)];
return h + ':' + m + ':' +s;
}
console.log(getTime());
3.2 时间戳(获取1971年1月1日至今过去的毫秒数)
// 1. valueOf(), getTime()
let date = new Date();
console.log(date.valueOf());
console.log(date.getTime());
// 2. 推荐写法
let date1 = +new Date();
console.log(date1);
// 3. H5新增写法
let date2 = Date.now();
console.log(date2);
4. 字符串对象
4.1 基本包装类型
- 对象才有属性和方法
- 复杂数据类型才有属性和方法
- 那么为什么简单数据类型
'aaa'有length属性呢? - 基本包装类型:把简单数据类型包装成复杂数据类型,这样基本数据类型也有了属性和方法
// 1. 简单数据类型包装成复杂数据类型
let temp = new String('aaa');
// 2. 把临时变量赋值给 str
str = temp;
// 3. 销毁临时变量
- 三种基本包装类型:
String、Number、Boolean
4.2 字符串的不可变
指的是其值不变。虽然看上去是可以改变的,但其实是地址变了,内存中开辟了一个内存空间。
4.3 根据字符串返回位置
语法
从 start 索引开始查找 c 。
str.indexOf('c', start)
4.4 根据位置返回字符
- charAt()
str.charAt(index);
- charCodeAt()
返回该位置的字符的 ASCII 值。一般用于判断用户按下了哪个键。
str.charCodeAt(i)
- str[index]
H5 新增写法。
str[i];
4.5 拼接以及截取字符串
- 字符长拼接
str.concat(str1, str2, str3, ...)
- 获取子串,[start, start+length]
str.substr(start, length)
- 切片,前闭后开:[start, end)
str.slice(start, end)
- 获取子串,前闭后开:[start, end)
str.substring(start, end)
[!warning]
警告: 尽管String.prototype.substr()没有严格被废弃 (as in "removed from the Web standards"), 但它被认作是遗留的函数并且可以的话应该避免使用。它并非JavaScript核心语言的一部分,未来将可能会被移除掉。如果可以的话,使用substring()替代它.
4.6 替换、转换为数组
- 替换
replace,只换一次。
str.replace('a', 'b');
- 转换为数组
split()
let str1 = 'red pink blue';
console.log(str1.split(' '))
// [ 'red', 'pink', 'blue' ]
let str2 = 'red&pink&blue';
console.log(str2.split('&'))
// [ 'red', 'pink', 'blue' ]
4.7 查找某个字符出现的位置和次数
// 查找某个字符出现的位置和次数
function findLocation(str, char) {
let res = {
loc: [],
count: 0
};
for (let i = 0; i < str.length; i++) {
if (str[i] === char) {
res.loc.push(i);
res.count++;
}
}
return res;
}
let ans = findLocation("abcaaadef", "a");
console.log(ans.count, ans.loc); // 4 [ 0, 3, 4, 5 ]
4.8 统计出现次数最多的字符
function findMost(str) {
let res = {};
for (const i in str) {
if (str[i] in res) {
res[str[i]]++;
} else {
res[str[i]] = 1;
}
}
let temp = -Infinity;
let ans;
for (const k in res) {
if (res[k] > temp) {
temp = res[k];
ans = k;
}
}
return [ans, temp];
};
console.log(findMost("abbcaaa")); // [ 'a', 4 ]
函数
1. 概述
函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
封装:把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。
- 函数也是一个对象
- 使用typeof检查一个函数对象时,会返回 function
- 函数未指定返回值则默认返回
undefined
2. 函数的声明与调用
// 声明
function funcName(params) {
// function statements
}
funcName(params);
// 调用
3. 形参与实参
声明时传入的为形参,调用时传入的为实参。
4. 实参个数与形参个数不匹配的情况
| 参数个数 | 说明 |
|---|---|
| 形参和实参个数相等 | 输出正确结果 |
| 实参个数多于形参 | 只取到形参的个数 |
| 实参个数少于形参 | 多的形参定义为undefined,结果为NaN |
function sum(num1, num2) {
console.log(num1 + num2);
}
sum(100, 200); // 300, 形参和实参个数相等,输出正确结果
sum(100, 400, 500, 700); // 500, 实参个数多于形参,只取到形参的个数
sum(200); // NaN, 实参个数少于形参,多的形参定义为undefined,结果为NaN
在JavaScript中,形参的默认值是
undefined。
5. 声明函数的三种方法
5.1 function 命令
function funcName(params) {
// function statements
}
5.2 函数表达式
const funcName = function(params) {
// function statements
}
5.3 Function 构造函数
const add = new Function(
'x',
'y',
return 'x + y'
);
5.4 箭头函数 =>
创建一个函数更加简洁的方式,有两种方式:
- 不带花括号:
(...args) => expression,计算表达式,直接返回。 - 带花括号:
(...args) => { bodu },可以编写多行多个语句,需要return语句返回。
let sum = (a, b) => a + b;
6.函数的调用
// 写法1(最常用)
函数名();
// 写法2
函数名.call();
7.函数返回值
return 关键字
函数体内可以没有返回值,也可以根据需要加返回值。语法格式:return 函数的返回值。
return关键字的作用既可以是终止函数,也可以给函数添加返回值。
解释:
(1)return 后的返回值将会作为函数的执行结果返回,可以定义一个变量,来接收该返回值。
(2)在函数中,return后的语句都不会执行。也就是说,函数在执行完 return 语句之后,会立即退出函数。
(3)如果return语句后不跟任何值,就相当于返回一个undefined
(4)如果函数中不写return,则也会返回undefined
(5)返回值可以是任意的数据类型,可以是对象,也可以是函数。
(6)return 只能返回一个值。如果用逗号隔开多个值,则以最后一个为准。
break、continue、return 的区别
- break :结束当前的循环体(如 for、while)
- continue :跳出本次循环,继续执行下次循环(如 for、while)
- return :1、退出循环。2、返回 return 语句中的值,同时结束当前的函数体内的代码,退出当前函数。
8.函数名、函数体和函数加载问题(重要)
函数名 == 整个函数。
console.log(fn) == console.log(function fn(){alert(1)});
//定义fn方法
function fn(){
alert(1)
};
我们知道,当我们在调用一个函数时,通常使用fn()这种格式;
可如果,我们是直接使用fn这种格式,它的作用相当于整个函数。
函数的加载问题:
函数不调用不执行 . JS加载的时候,只加载函数名,不加载函数体。如果想使用内部的成员变量,需要调用函数。
fn() 和 fn 的区别【重要】
- fn():调用函数。调用之后,还获取了函数的返回值。
- fn:函数对象。相当于直接获取了整个函数对象。
方法
函数也可以成为对象的属性。
如果一个函数是作为一个对象的属性保存,那么,我们称这个函数是这个对象的方法。
调用这个函数就说调用对象的方法(method)。函数和方法,有什么本质的区别吗?它只是名称上的区别,并没有其他的区别。 // 调用方法 obj.fn();
9. 类数组对象arguments 的使用
arguments 是所有JS函数内置的对象,但也只有函数具有。
function test() {
return arguments;
}
console.log(test(1,2,3,4));
输出:
Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
函数的 arguments 是一种伪数组:
- 具有数组的
length属性 - 按照索引方式进行存储
- 没有真正数组的一些方法
pop()、push()
10.递归函数
代码演示:计算阶乘
提问:求一个正整数的阶乘。
普通写法:
// 函数:计算一个正整数的阶乘
function factorial(n) {
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
}
return result;
}
console.log(factorial(5)); // 120
////////////////////////////////////////////////////////////////
递归写法:
// 递归函数:计算一个正整数的阶乘
function factorial(n) {
// 递归出口:如果计算1的阶乘,就不用递归了
if (n == 1) return 1;
// 开始递归:如果当前这个 n 不是1,就返回 n * (n-1)!
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
概念: 如果一个函数在内部调用这个函数自身,这个函数就是递归函数。
递归的要素
- 递归模式:把大问题拆解为小问题进行分析。也称为递归体。
- 边界条件:需要确定递归到何时结束。也称为递归出口。
11.立即执行函数IIFE
函数定义完,就立即被调用
(function() {
console.log('我是立即执行函数');
})();
斐波那契数列
斐波那契数列是这样一个数列:1、1、2、3、5、8、13、21、34......最早是由意大利数学家斐波那契开始研究的。它的规律是:下标为0和1的项,值为1;从下标为2的项开始,每一项等于前面两项之和。
提问:请找出斐波那契数列的前10项。
//找规律
//找出口
//例子:写一个斐波那契数列
//fb(n) ==fb(n-1)+fb(n-2)
function fb(n){
if( n == 1 ||n ==2 ){
return 1;
}
return fb(n-1) + fb(n-2);
}
fb(5) ==> fb(4) + fb(3)
fb(4) ==> fb(3) + fb(2)
fb(3) ==> fb(2) + ..
DOM
DOM
文档对象模型(Document Object Model,简称DOM )
DOM可以做什么
- 找对象(元素节点)
- 设置元素的属性值
- 设置元素的样式
- 动态创建和删除元素
- 事件的触发响应:事件源、事件、事件的驱动程序
获取页面元素
1.使用 getElementByld() 方法可以获取带有 ID 的元素对象,并返回一个 Element 对象。
console.dir()可打印元素的属性和方法-
2.getElementsByTagName() 方法可以返回带有指定标签名的对象的集合。
返回的是 元素对象的集合,伪数组形式表示。
3.根据类名返回元素对象集合。
document.getElementsByClassName('类名');
4.根据指定选择器返回第一个元素对象。
document.querySelector('选择器');
5.返回指定选择器的所有元素集合。
document.querySelectorAll('选择器')
获取特殊元素
- 获取
body元素
document.body;
- 获取
html元素
document.documentElement;
事件
- 获取事件源
<button id="btn">唐伯虎</button>
- 注册事件
let btn = document.getElementById('btn');
- 添加事件处理程序
btn.onclick = () => alert('点秋香');
改变元素内容
innerText不识别 html 标签,innerHTML识别 html 标签。
div.innerHTML = ' <strong>今天是:</strong>2021-3-23';
innerText会取出空格和换行,innerHTML保留换行和空格。
样式属性操作
我们可以通过JS修改元素的大小、颜色、位置等样式。
element.style:行内样式操作element.className:类名样式操作
排他思想
如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法:
- 所有元素全部清除样式(干掉其他人)
- 给当前元素设置样式(留下我自己)
获取元素的属性值
(1) element.属性
(2) element.getAttribute('属性') get得到获取 attribute 属性的意思 我们程序员自己添加的属性我们称为自定义属性 index
设置元素属性值
(1) element.属性= '值'
(2) element.setAttribute('属性', '值'); 主要针对于自定义属性
移除属性
element.removeAttribute(属性);
节点
节点(Node):构成 HTML 网页的最基本单元。网页中的每一个部分都可以称为是一个节点,比如:html标签、属性、文本、注释、整个文档等都是一个节点。
虽然都是节点,但是实际上他们的具体类型是不同的。常见节点分为四类:
- 文档节点(文档):整个 HTML 文档。整个 HTML 文档就是一个文档节点。
- 元素节点(标签):HTML标签。
- 属性节点(属性):元素的属性。
- 文本节点(文本):HTML标签中的文本内容(包括标签之间的空格、换行)。
节点的类型不同,属性和方法也都不尽相同。所有的节点都是Object。
DOM就是由节点组成的。
解析过程: HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的属性。
DOM树:(一切都是节点)
DOM的数据结构如下:
节点层级
父级节点
获取离元素最近的父节点,若找不到则返回 null。
node.parentNode
子节点
更加好的方法:获取子元素节点
parentNode.children;
方法:
parentNode.childNodes
返回包含了所有的子节点,包括元素节点,文本节点等。
子节点方法:
① 获取 所有结点 中的第一个和最后一个:
parentNode.firstChildparentNode.lastChild
② 获取 元素节点中第一个和最后一个
parentNode.firstElementChildparentNode.lastElementChild
③ 实际开发:
parentNode.children[0]parentNode.children[parentNode.children.length -1]
兄弟节点
- 返回下一个兄弟节点:
node.nextSibling
- 返回上一个的兄弟节点:
node.previousSibling
3. 返回下一个 兄弟元素节点(≥IE9)
node.nextElementSibling
- 返回上一个 兄弟元素节点(≥IE9)
node.previousElementSibling
创建并添加节点
元素节点
document.createElement("tagName");
给元素节点添加子元素节点
parentNode.appendChild(chileNode)
在指定元素的前面插入节点
`insertBefore()`
删除节点
removeChild(childNode) 方法
// 方式一
parentNode.removeChild(childNode);
// 方式二
let oldChild = parentNode.removeChild(childNode);
复制节点
node.cloneNode() 方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点。其中 node 为被克隆的元素节点。
node.cloneNode([deep]);
或者
let newClone = node.cloneNode([deep]);
对于 deep 参数,可以为 true 或 false,或为空的:
总结
创建元素
document.write()element.innerHTMLelement.createElement()
区别:
document.write()创建元素,是直接将内容写入页面的内容流,但是 当文档流执行完毕,会导致页面全部重绘。即覆盖原本的页面。innerHTML是将内容写入某个 DOM 节点,不会导致页面全部重绘。innerHTML创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂。createElement()创建多个元素效率稍低一点点,但是结构更清晰。
增
appendChildinsertBefore
删
removeChild
改
主要修改 dom 的元素属性,dom 元素的内容、属性,表单的值等。
- 修改元素属性:
src、href、title等 - 修改普通元素内容:
innerHTML、innerText - 修改表单元素:
value、type、disabled等 - 修改元素样式:
style、className
查
主要获取查询dom的元素
- DOM提供的API 方法:
getElementById、getElementsByTagName(古老用法不太推荐) - H5提供的新方法:
querySelector、querySelectorAll提倡 - 利用节点操作获取元素:父(
parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)提倡
属性操作
主要针对于自定义属性
setAttribute:设置dom的属性值getAttribute:得到dom的属性值removeAttribute:移除属性
事件操作
给元素注册事件,格式:事件源.事件类型 = 事件处理程序
| 鼠标事件 | 触发条件 |
|---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
事件
注册事件有两种方式:传统方式 和 事件监听注册方式。
传统注册方式
- 利用on 开头的事件onclick
<button onclick="alert('hi~')"></button>btn.onclick = function() {};- 特点:注册事件的 唯一性
- 同一个元素同一个事件只能设置一个处理函数,最
后注册的处理函数将会 覆盖 前面注册的处理函数。
btns[0].onclick = function() {
alert('hi');
}
事件监听注册方式
addEventListener()- 特点:同一个元素同一个事件可以注册多个监听器
- 里面的事件类型是字符串 必定加引号 而且不带on
- 按注册顺序依次执行
btns[1].addEventListener('click', function() {
alert(22);
})
删除事件(解绑事件)
传统注册方式
eventTarget.onclick = null;
方法监听注册方式
removeEventListener
DOM 事件流
定义
事件流 描述的是从页面中接收事件的顺序。
注意
- JS 代码中只能执行捕获或者冒泡其中的一个阶段。
onclick和attachEvent只能得到冒泡阶段。addEventListener(type, listener[, useCapture])第三个参数如果是true,表示在事件捕
获阶段调用事件处理程序;如果是false(不写默认就是false),表示在事件冒泡阶段调用事件处理
程序。- 实际开发中我们很少使用事件捕获,我们 更关注事件冒泡。
- 有些事件是没有冒泡的,比如
onblur、onfocus、onmouseenter、onmouseleave
事件对象
eventTarget.onclick = function(event) {}
eventTarget.addEventListener('click', function(event) {})
// 这个event 就是事件对象,我们还喜欢的写成 e 或者evt
- 官方解释:
event对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。 - 简单理解:事件发生后,跟 事件相关的一系列信息数据的集合 都放到这个对象里面,这个对象就是事件对象
event,它有很多属性和方法
事件对象的常见属性和方法
| 事件对象属性方法 | 说明 |
|---|---|
e.target | 返回触发事件的对象(标准) |
e.srcElement | 返回触发事件的对象(非标准) |
e.type | 返回事件类型 |
e.preventDefault() | 阻止默认事件(标准) |
e.returnValue = true | 阻止默认事件(非标准,IE678) |
e.stopPropagation() | 阻止冒泡(标准) |
e.cancelBubble | 阻止冒泡(非标准,IE678) |
事件委托
事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
常用的鼠标事件
- 禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单。
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
- 禁止鼠标选中(
selectstart开始选中)
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
鼠标事件对象
event 对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent。
| 鼠标事件对象 | 说明 |
|---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的 X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的 Y坐标 |
e.pageX | 返回鼠标相对于文档页面的 X坐标IE9+支持 |
e.pageY | 返回鼠标相对于文档页面的 Y坐标IE9+支持 |
e.screenX | 返回鼠标相对于电脑屏幕的 X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的 Y坐标 |
定时器
setTimeout() 定时器
window.setTimeout(调用函数 [, 延迟的毫秒数]);
setInterval() 定时器
window.setInterval(回调函数 [, 间隔的毫秒数]);
setInterval() 方法重复调用一个函数,每隔这个时间,
this 指向问题
this 的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定 this 到底指向谁,一般情况下的最终指向的是那个调用它的对象
现阶段,我们先了解一下几个 this 指向:
- 全局作用域或者普通函数中
this指向全局对象window(注意定时器里面的this指向window) - 方法调用中谁调用
this指向谁 - 构造函数中
this指向构造函数的实例
同步任务
同步任务都在主线程上执行,形成一个 执行栈。
异步任务
JS 的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:
- 普通事件,如
click、resize等 - 资源加载,如
load、error等 - 定时器,包括
setInterval、setTimeout等异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。
location 对象
window 对象给我们提供了一个 location 属性用于 获取或设置窗体的URL
URL
统一资源定位符(Uniform Resource Locator, URL)是互联网上标准资源的地址。互联网上的每个文件都有
一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL 的一般语法格式为:
格式
protocol://host[:port]/path/[?query]#fragment
举例
http://www.itcast.cn/index.html?name=andy&age=18#link
| 组成 | 说明 |
|---|---|
protocol | 通信协议(http、ftp) |
host | 主机(域名) |
port | 端口号(可选),省略时使用方案的默认端口,如http默认端口80 |
path | 路径,由零或多个 /隔开的字符串,一般表示主机上的一个目录或文件地址 |
query | 参数,以键值对的形式,通过 &符号分隔开 |
fragment | 片段,#后面内容,常见于链接、锚点 |
navigator 对象
navigator 对象包含有关浏览器的信息
history 对象
window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。
BOM
常见概念
JavaScript的组成
JavaScript基础分为三个部分:
- ECMAScript:JavaScript的语法标准。包括变量、表达式、运算符、函数、if语句、for语句等。
- DOM:文档对象模型(Document object Model),操作网页上的元素的API。比如让盒子移动、变色、轮播图等。
- BOM:浏览器对象模型(Browser Object Model),操作浏览器部分功能的API。比如让浏览器自动滚动。
常见的 BOM 对象
BOM可以让我们通过JS来操作浏览器。BOM中为我们提供了一些对象,来完成对浏览器相关的操作。
常见的 BOM对象有:
- Window:代表整个浏览器的窗口,同时 window 也是网页中的全局对象。
- Navigator:代表当前浏览器的信息,通过该对象可以识别不同的浏览器。
- Location:代表当前浏览器的地址栏信息,通过 Location 可以获取地址栏信息,或者操作浏览器跳转页面。
- History:代表浏览器的历史记录,通过该对象可以操作浏览器的历史记录。由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,而且该操作只在当次访问时有效。
- Screen:代表用户的屏幕信息,通过该对象可以获取用户的显示器的相关信息。
备注:这些 BOM 对象都是作为 window 对象的属性保存的,可以通过window对象来使用,也可以直接使用。比如说,我可以使用 window.location.href,也可以直接使用 location.href,二者是等价的。
备注2:不要忘了,之前学习过的document也是在window中保存的。
这篇文章,我们先来讲一下 几个常见的 BOM 对象。
Navigator 和 navigator.userAgent
Navigator代表当前浏览器的信息,通过该对象可以识别不同的浏览器。
由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了。
一般我们只会使用**navigator.userAgent**来获取浏览器的信息。
userAgent 的值是一个字符串,简称 UA,这个字符串中包含了用来描述浏览器信息的内容,不同的浏览器会有不同的userAgent。
代码举例:(获取当前浏览器的UA)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var ua = navigator.userAgent; // 获取当前浏览器的 userAgent
console.log('qianguyihao 当前浏览器的UA是:' + ua);
if (/firefox/i.test(ua)) {
alert('是火狐浏览器');
} else if (/chrome/i.test(ua)) {
alert('是Chrome浏览器');
} else if (/msie/i.test(ua)) {
alert('是IE浏览器');
} else if ('ActiveXObject' in window) {
alert('是 IE11 浏览器');
}
</script>
</body>
</html>
在电脑上模拟移动端浏览器
不同浏览器(包括微信内置的浏览器)的 userAgent 信息,是不一样的,我们可以根据 navigator.userAgent属性来获取。
比如说,我们在电脑浏览器上,按F12,然后在控制台输入navigator.userAgent,如下:
上图显示,MacOS上的Chrome浏览器的 userAgent 是:
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"
我们还可以在电脑浏览器的控制台里可以添加很多设备,通过这种方式,可以模拟移动端浏览器的场景,非常有用,请务必掌握。操作如下:
(1)需要点击 edit,手动添加:
(2)添加时,根据 User agent 来识别不同的浏览器:
不同浏览器的 userAgent
iOS 版微信浏览器:
Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13E233 MicroMessenger/6.3.15 NetType/WIFI Language/zh_CN
Android 版微信浏览器:
Mozilla/5.0 (Linux; Android 5.0.1; GT-I9502 Build/LRX22C; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.121 Mobile Safari/537.36 MicroMessenger/6.1.0.78_r1129455.543 NetType/WIFI
iOS 版本QQ浏览器:
Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_2 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Mobile/15C202 QQ/7.3.5.473 V1_IPH_SQ_7.3.5_1_APP_A Pixel/1125 Core/UIWebView Device/Apple(iPhone X) NetType/WIFI QBWebViewType/1
Android 版 QQ浏览器:
Mozilla/5.0 (Linux; Android 4.4.2; PE-TL20 Build/HuaweiPE-TL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 V1_AND_SQ_7.3.2_762_YYB_D QQ/7.3.2.3350 NetType/WIFI WebP/0.3.0 Pixel/1080
参考链接:
History 对象
History对象:可以用来操作浏览器的向前或向后翻页。
History对象的属性
history.length
解释:获取浏览器历史列表中的 url 数量。注意,只是统计当次的数量,如果浏览器关了,数量会重置为1。
History对象的方法
方法1:
history.back();
解释:用来回退到上一个页面,作用和浏览器的「回退按钮」一样。
方法2:
history.forward();
解释:用来跳转下一个页面,作用和浏览器的「前进按钮」一样。
方法3:
history.go( int n); // 需要整数作为参数
// 代码举例:
history.go( 1 ); // 向前跳转一个页面,相当于 history.forward()
history.go( 2 ); // 表示向前跳转两个页面
history.go( 0 ); // 刷新当前页面
history.go( -1 ); // 向后跳转一个页面,相当于 history.back()
history.go( -2 ); // 向后跳转两个页面
解释:向前/向后跳转 n 个页面。
备注:浏览器的前进按钮、后退按钮,在这个位置:
Location 对象
Location 对象:封装了浏览器地址栏的 URL 信息。
下面介绍一些常见的属性和方法。
Location 对象的属性:location.href
location.href
location.href = 'https://xxx';
解释:获取当前页面的 url 路径(或者设置 url 路径);或者跳转到指定路径。
举例1:
console.log(location.href); // 获取当前页面的url 路径
举例2:
location.href = 'www.baidu.com'; // 跳转到指定的页面链接。通俗理解就是:跳转到其他的页面
从上方的举例2中可以看出:如果直接将location.href属性修改为一个绝对路径(或相对路径),则页面会自动跳转到该路径,并生成相应的历史记录。
window.location.href 是异步代码:
需要特别注意的是:window.location.href的赋值,并不会中断Javascript的执行立即进行页面跳转。因为 LocationChange 行为在浏览器内核中是起定时器异步执行的。异步执行的好处是为了防止代码调用过深,导致栈溢出,另外也是为了防止递归进入加载逻辑,导致状态紊乱,保证导航请求是顺序执行的。
解决办法:在 location.href 的下一行,加上 return 即可。意思是,执行了 location.href 之后,就不要再继续往下执行了。
参考链接:location.href的异步机制
Location 对象的方法
方法1:
location.assign(str);
解释:用来跳转到其他的页面,作用和直接修改location.href一样。
方法2:
location.reload();
解释:用于重新加载当前页面,作用和刷新按钮一样。
代码举例:
location.reload(); // 重新加载当前页面。
location.reload(true); // 在方法的参数中传递一个true,则会强制清空缓存刷新页面。
方法3:
location.replace();
解释:使用一个新的页面替换当前页面,调用完毕也会跳转页面。但不会生成历史记录,不能使用「后退按钮」后退。