JavaScript笔记

312 阅读26分钟

JavaScript起步

JavaScript 是一种脚本,一门编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新,交互式的地图,2D/3D 动画,滚动播放的视频等等.它是标准 Web 技术蛋糕的第三层

API

JavaScript 语言核心之上所构建的功能更令人兴奋。应用程序接口(Application Programming Interfaces(API))将为你的代码提供额外的超能力。

API 是已经建立好的一套代码组件,可以让开发者实现原本很难甚至无法实现的程序。就像现成的家具套件之于家居建设,用一些已经切好的木板组装一个书柜,显然比自己设计,寻找合适的木材,裁切至合适的尺寸和形状,找到正确尺寸的螺钉,再组装成书柜要简单得多。

API 通常分为两类。
浏览器 API 内建于 web 浏览器中,它们可以将数据从周边计算机环境中筛选出来,还可以做实用的复杂工作。例如:

第三方 API 并没有默认嵌入浏览器中,一般要从网上取得它们的代码和信息。比如:

二,JS输入输出语句

  • 控制台输出:console.log() 打印日志
  • 弹窗 :alert('你好');
  • 弹出输入框:prompt()语句 prompt('请输入你的名字:');

三,JS 书写位置

  1. 行内式:写在标签内部。
  2. 内嵌式(内联式):写在 head 标签中。
  3. 外链式:引入外部 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 的意思
\\\\\
\\'单引号'
\\"双引号"
\\ttab 缩进
\\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)字符串拼接

多个字符串之间可以使用加号 + 进行拼接。
拼接语法

字符串 + 任意数据类型 = 拼接之后的新字符串;

字面量

字面量是在源代码中一个固定的表示法,通俗来说,就是字面量如何表达这个值。

  • 数字字面量:10
  • 字符串字面量:mphyaaa
  • 布尔字面量:truefalse

(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 variabletypeof(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(表达式) {
 case1:
  语句体1;
  break;

 case2:
  语句体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:跳过本轮循环,进行当前循环的下一轮。
  • breakcontinue 均可配合 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 是一种伪数组:

  1. 具有数组的 length 属性
  2. 按照索引方式进行存储
  3. 没有真正数组的一些方法 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 使用对象的属性和方法

  1. 调用对象的属性
// 方法一
objectName.attrName
// 方法二
objectName['attrName'] // 不要忘记引号
  1. 调用对象的方法
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 关键字的执行过程

  1. 在内存中创建一个空的对象;
  2. this 指向这个空对象;
  3. 执行构造函数里面的代码,给空对象添加属性和方法;
  4. 返回此对象。

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. 销毁临时变量
  • 三种基本包装类型: StringNumberBoolean

4.2 字符串的不可变

指的是其值不变。虽然看上去是可以改变的,但其实是地址变了,内存中开辟了一个内存空间。

4.3 根据字符串返回位置

语法
start 索引开始查找 c

str.indexOf('c', start)

4.4 根据位置返回字符

  1. charAt()
str.charAt(index);
  1. charCodeAt()
    返回该位置的字符的 ASCII 值。一般用于判断用户按下了哪个键。
str.charCodeAt(i)
  1. str[index]
    H5 新增写法。
str[i];

4.5 拼接以及截取字符串

  1. 字符长拼接
str.concat(str1, str2, str3, ...)
  1. 获取子串,[start, start+length]
str.substr(start, length)
  1. 切片,前闭后开:[start, end)
str.slice(start, end)
  1. 获取子串,前闭后开:[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 是一种伪数组:

  1. 具有数组的 length 属性
  2. 按照索引方式进行存储
  3. 没有真正数组的一些方法 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('选择器')

获取特殊元素

  1. 获取 body 元素
document.body;
  1. 获取 html 元素
document.documentElement;

事件

  1. 获取事件源
<button id="btn">唐伯虎</button>
  1. 注册事件
 let btn = document.getElementById('btn');
  1. 添加事件处理程序
btn.onclick = () => alert('点秋香');

改变元素内容

  1. innerText 不识别 html 标签,innerHTML 识别 html 标签。
div.innerHTML = ' <strong>今天是:</strong>2021-3-23';
  1. innerText 会取出空格和换行,innerHTML 保留换行和空格。

样式属性操作

我们可以通过JS修改元素的大小、颜色、位置等样式。

  1. element.style:行内样式操作
  2. element.className:类名样式操作

排他思想

如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法:

  1. 所有元素全部清除样式(干掉其他人)
  2. 给当前元素设置样式(留下我自己)

获取元素的属性值

(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的数据结构如下:
image.png

节点层级

父级节点

获取离元素最近的父节点,若找不到则返回 null

node.parentNode

子节点

更加好的方法:获取子元素节点

parentNode.children;

方法:

parentNode.childNodes

返回包含了所有的子节点,包括元素节点,文本节点等。

子节点方法:

① 获取 所有结点 中的第一个和最后一个:

  • parentNode.firstChild
  • parentNode.lastChild

② 获取 元素节点中第一个和最后一个

  • parentNode.firstElementChild
  • parentNode.lastElementChild

实际开发

  • parentNode.children[0]
  • parentNode.children[parentNode.children.length -1]

兄弟节点

  1. 返回下一个兄弟节点:
node.nextSibling
  1. 返回上一个的兄弟节点:
node.previousSibling

3. 返回下一个 兄弟元素节点(≥IE9)

node.nextElementSibling
  1. 返回上一个 兄弟元素节点(≥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 参数,可以为 truefalse,或为空的:

总结

创建元素

  • document.write()
  • element.innerHTML
  • element.createElement()

区别:

  1. document.write() 创建元素,是直接将内容写入页面的内容流,但是 当文档流执行完毕,会导致页面全部重绘。即覆盖原本的页面。
  2. innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘。
  3. innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂。
  4. createElement() 创建多个元素效率稍低一点点,但是结构更清晰。

  • appendChild
  • insertBefore

  • removeChild

主要修改 dom 的元素属性,dom 元素的内容、属性,表单的值等。

  • 修改元素属性:srchreftitle
  • 修改普通元素内容:innerHTMLinnerText
  • 修改表单元素:valuetypedisabled
  • 修改元素样式:styleclassName

主要获取查询dom的元素

  • DOM提供的API 方法:getElementByIdgetElementsByTagName古老用法不太推荐
  • H5提供的新方法:querySelectorquerySelectorAll 提倡
  • 利用节点操作获取元素:父(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 事件流

定义

事件流 描述的是从页面中接收事件的顺序。  

注意

  1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
  2. onclickattachEvent 只能得到冒泡阶段。
  3. addEventListener(type, listener[, useCapture]) 第三个参数如果是 true,表示在事件捕
    获阶段调用事件处理程序;如果是 false(不写默认就是 false),表示在事件冒泡阶段调用事件处理
    程序。
  4. 实际开发中我们很少使用事件捕获,我们 更关注事件冒泡
  5. 有些事件是没有冒泡的,比如 onbluronfocusonmouseenteronmouseleave

事件对象

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)

事件委托

事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点

常用的鼠标事件

  1. 禁止鼠标右键菜单
    contextmenu 主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单。
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
})
  1. 禁止鼠标选中(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 指向:

  1. 全局作用域或者普通函数中 this 指向全局对象 window(注意定时器里面的 this 指向 window
  2. 方法调用中谁调用 this 指向谁
  3. 构造函数中 this 指向构造函数的实例

同步任务

同步任务都在主线程上执行,形成一个 执行栈

异步任务

JS 的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:

  1. 普通事件,如 clickresize
  2. 资源加载,如 loaderror
  3. 定时器,包括 setIntervalsetTimeout 等异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。

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();

解释:使用一个新的页面替换当前页面,调用完毕也会跳转页面。但不会生成历史记录,不能使用「后退按钮」后退。