JS学习笔记

260 阅读25分钟

JS—01

一、js编写位置

1)将js代码写在标签中,属于结构与行为耦合,不方便维护,不推荐使用

示例:

<button onclick="alert('hello');">我是按钮</button>  
<a href="javascript:alert('aaa');">超链接</a>

2)可以将js代码写在外部js文件中,然后通过script标签引入(src属性),该写法可以在不同的页面中同时引入,也可以利用浏览器缓存方式利用,推荐使用

示例:

<script type="text/javascript">//编写js代码</script>

3)也可以将js代码写入script标签中,但script标签一旦引入外部文件,就无法再写入js代码

示例:

<script type="text/javascript" src="文件路径"></script>

二、js基本语法

1)js代码严格区分大小写

2)js语句结束末尾都需添加 ;(封号)

​ 因为不写分号,浏览器会自动添加,此举会消耗一些系统资源

3)js中会忽略多个空格和换行

三、标识符

在js中所有可以由我们自主命名的都可以称为标识符

——通常遵循的规则:

1)标识符中可以含有字母、数字、_ 、$

2)标识符不能以数字开头

3)标识符一般采用驼峰命名法

——首字母小写,每个单词首字母大写,其余小写

4)标识符不能是js中的关键字或保留字

四、数据类型

js中六种数据类型:(前五种属于基本数据类型,后一种属于引用数据类型)

1.String

​ 字符串需要搭配引号使用

2.Number

​ 1)js中整数和小数也属于Number数据类型

​ 2)在js中整数运算基本可以保证精确,但位数不能太长

​ 3)在js中千万不要进行对精确度较高的运算,因为结果可能不精确

3.Boolean

​ 用来进行逻辑判断,只有两个值 true/false

4.Null

​ 1)值只有一个,就是null

​ 2)null这个值专门用来表示一个空的对象

​ 3)使用typeof检查一个null值时,会返回object

5.Undefined

​ 1)值只有一个,就是undefined

​ 2) 使用typeof检查一个undefined值时,会返回undefined

​ 3)当声明一个变量但未赋值时,值也是undefined

6.Object

五、强制类型转换

1.将其他类型转换为String:

方法一:

​ 调用被转换数据类型的toString()方法

​ 该方法不会影响到原变量,它会将转换的结果返回

​ 但注意:null 和 undefined 这两个值没有toString()方法

示例:

var a = 123;
a = a.toString(); 

方法二:

​ 调用String()函数,并将被转换的数据作为参数传递给函数

​ 此方法也能转换null 和 undefined

示例:

var a = 123; 
a = String(a);

2.将其他类型转换为Number:

方法一:

​ 调用Number()函数(用法和String()函数相同)

示例:

var s = "123";  
s = Number(s);

转换的情况:

  1. 字符串 > 数字 如果字符串是一个合法的数字,则直接转换为对应的数字 如果字符串是一个非法的数字,则转换为NaN 如果是一个空串或纯空格的字符串,则转换为0
  2. 布尔值 > 数字 true转换为1 false转换为0
  3. 空值 > 数字 null转换为0
  4. 未定义 > 数字 undefined 转换为NaN

方法二: 调用parseInt()或parseFloat()

parseInt()可以将一个字符串中有效的整数位提取出来,并转换为Number 示例:

var a = "123.456px";  
a = parseInt(a); //123

parseFloat()作用和 parseInt()类似,不过它可以将有效的小数位提取出来 示例:

var a = "123.456px";  
a = parseFloat(a); //123.456

补充:可以在parseInt()中传递一个第二个参数,来指定数字的进制

示例:

var a = "070"

a = parseInt(a,10) //70

a = parseInt(a,8) //56 

十六进制表示:0x....(0x10)

八进制表示:0....(070)

二进制表示:0b...(0b10)

3.将其他类型转换为Boolean

方法一:

​ 使用Boolean()函数 示例:

var s = "false";  
s = Boolean(s); //true

转换的情况 字符串 > 布尔 除了空串其余全是true

数值 > 布尔 除了0和NaN其余的全是true

null、undefined > 布尔 都是false

对象 > 布尔 都是true

方法二:

​ 为任意的数据类型做两次非运算,即可将其转换为布尔值 示例:

var a = "hello";  
a = !!a; //true

六、运算符

运算符也称为操作符 通过运算符可以对一个或多个值进行运算或操作

1.typeof运算符

用来检查一个变量的数据类型 语法:typeof 变量 它会返回一个用于描述类型的字符串作为结果

示例:

var a = "hello"

console.log(typeof a)  //string

2.算数运算符

+ 对两个值进行加法运算并返回结果 - 对两个值进行减法运算并返回结果 * 对两个值进行乘法运算并返回结果 / 对两个值进行除法运算并返回结果 % 对两个值进行取余运算并返回结果

除了加法以外,对非Number类型的值进行运算时,都会先转换为Number然后在做运算。 而做加法运算时,如果是两个字符串进行相加,则会做拼串操作,将两个字符连接为一个字符串。 任何值和字符串做加法,都会先转换为字符串,然后再拼串

3.一元运算符

一元运算符只需要一个操作数

一元的+

就是正号,不会对值产生任何影响,但是可以将一个非数字转换为数字 示例:

var a = true;  
a = +a;

一元的-

就是负号,可以对一个数字进行符号位取反 示例:

var a = 10;  
a = a;

自增

自增可以使变量在原值的基础上自增1 自增使用 ++ 自增可以使用 前++(++a)后++(a++) 无论是++a 还是 a++都会立即使原变量自增1 不同的是++a和a++的值是不同的, ++a的值是变量的新值(自增后的值) a++的值是变量的原值(自增前的值)

自减

自减可以使变量在原值的基础上自减1 自减使用 自减可以使用 前(a)后(a) 无论是a 还是 a都会立即使原变量自减1 不同的是a和a的值是不同的, a的值是变量的新值(自减后的值) a的值是变量的原值(自减前的值)

4.逻辑运算符

! 非运算可以对一个布尔值进行取反,true变false false边true 当对非布尔值使用 ! 时,会先将其转换为布尔值然后再取反 我们可以利用 ! 来将其他的数据类型转换为布尔值

&& &&可以对符号两侧的值进行与运算 只有两端的值都为true时,才会返回true。只要有一个false就会返回false。 与是一个短路的与,如果第一个值是false,则不再检查第二个值 对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值 规则: 1.如果第一个值为false,则返回第一个值 2.如果第一个值为true,则返回第二个值

|| ||可以对符号两侧的值进行或运算 只有两端都是false时,才会返回false。只要有一个true,就会返回true。 或是一个短路的或,如果第一个值是true,则不再检查第二个值 对于非布尔值,它会将其转换为布尔值然后做运算,并返回原值 规则: 1.如果第一个值为true,则返回第一个值 2.如果第一个值为false,则返回第二个值

5.赋值运算符

=:可以将符号右侧的值赋值给左侧变量 +=

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,关系不成立则返回false。 如果比较的两个值是非数值,会将其转换为Number然后再比较。 如果比较的两个值都是字符串,此时会比较字符串的Unicode编码,而不会转换为Number。

7.相等运算符

相等,判断左右两个值是否相等,如果相等返回true,如果不等返回false 相等会自动对两个值进行类型转换,如果对不同的类型进行比较,会将其转换为相同的类型然后再比较,转换后相等它也会返回true,null == undifined

!= 不等,判断左右两个值是否不等,如果不等则返回true,如果相等则返回false 不等也会做自动的类型转换。

=== 全等,判断左右两个值是否全等,它和相等类似,只不过它不会进行自动的类型转换, 如果两个值的类型不同,则直接返回false

!== 不全等,和不等类似,但是它不会进行自动的类型转换,如果两个值的类型不同,它会直接返回true

特殊的值: null和undefined 由于undefined衍生自null,所以null == undefined 会返回true。 但是 null === undefined 会返回false。 NaN NaN不与任何值相等,报告它自身 NaN == NaN //false

判断一个值是否是NaN 使用isNaN()函数

8.三元运算符

? : 语法:条件表达式 ? 语句1 : 语句2; 执行流程: 先对条件表达式求值判断, 如果判断结果为true,则执行语句1,并返回执行结果 如果判断结果为false,则执行语句2,并返回执行结果

优先级: 和数学中一样,JS中的运算符也是具有优先级的, 比如 先乘除 后加减 先与 后或 具体的优先级可以参考优先级的表格,在表格中越靠上的优先级越高, 优先级越高的越优先计算,优先级相同的,从左往右计算。 优先级不需要记忆,如果越到拿不准的,使用()来改变优先级。

JS—02

一、对象

1.对象简介

如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体,而对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性

对象的分类:

1)内建对象:

​ 由ES标准中定义的对象,在任何的ES的实现中都可以使用(比如:Math Sting Number Boolean......)

2)宿主对象:

​ 由JS的运行环境提高的对象,目前来讲主要指由浏览器提供的对象(比如:BOM DOM)

3)自定义对象:

​ 由开发人员自己定义自己定义

2.对象基本操作

四项基本操作:增、删、改、查

//创建对象
var obj = new Object();
/*
使用new关键字调用的函数是构造函数constructor
而构造函数是专门用来创建对象的
*/

//向对象中添加属性
//语法:对象.属性名 = 属性值
obj.name = "孙悟空";
obj.gender = "男";

//读取对象中的属性
//语法:对象.属性名
console.log(obj.name); //孙悟空
/*
若读取对象中没有的属性,不会报错,但会返回undefined
*/
console.log(obj.age); //undefined

//修改对象属性值
//语法:对象.属性名 = 新值
obj.name = "猪八戒";
console.log(obj.name); //猪八戒

//删除对象中的属性
//语法:delete 对象.属性名
delete obj.name;

3.对象中的属性名和属性值

属性名:

​ 对象中的属性名不强制要求遵循标识符的规范,但还是尽量按照标识符的规范使用

/*
如果要使用特殊的属性名,不能采用.的方式来操作
而需要使用另外一种方式
	语法:对象["属性名"] = 属性值
*/
obj.123 = 789; 
console.log(obj.123); //报错

obj["123"] = 789; 
console.log(obj[123]); //没有问题(怎么设置属性值就怎么读取属性值)
// 而且使用[]这种形式去操作属性,更加的灵活
obj["nihao"] = "你好";
n = 123;
console.log(obj[n]); //789
n = "nihao";
console.log(obj[n]); //你好

属性值:

​ 属性值可以是任意的数据类型

in 运算符:

/*
in 运算符
	通过该运算符可以检查一个对象中是否含有指定的属性
语法:"属性名" in 对象
*/
console.log(obj.age); //false
console.log(obj.gender); //true

4.创建对象的另外方式

1)使用字面量来创建对象

/*
使用对象字面量,可以在创建对象时,直接指定对象中的属性
语法:{属性名:属性值,属性名:属性值......}
对象字面量的属性名可以加引号也可以不加,建议不加
如果要使用一些特殊的对象名,则必须加引号
*/
var obj = {
    name:"张三",
    age:18,
    gender:"男"
    "!@#$":123  //特殊对象名
}

2)使用工厂方法创建对象

/*
使用工厂方法创建对象
	通过该方法可以大批量的创建对象
	但该方法所创建的对象都属于Object,无法进一步区分,所有不推荐使用
*/
function createObj(name,age,gender){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.gender = gender;
    return obj; //注意:需要将新对象返回
}
var obj = createObj("张三",18,"男")
var obj2 = createObj("李四",28,"男")
var obj3 = createObj("王五",38,"男")

3)使用构造函数来创建对象

/*
语法:
function 构造函数名(){
	this.属性 = 值;
	this.方法 = function(){};
}
*/

/*
创建一个构造函数,专门用来创建可以区分出对象的
	构造函数就是一个普通的函数,创建方式和普通函数没有区别
	不同的是构造函数习惯首字母大写
构造函数和普通函数的区别就是调用方式的不同
	普通函数是直接调用,而构造函数需要使用new关键字来调用
构造函数的执行流程:
	1.立刻创建一个新的对象
	2.将新建的对象设置为函数中的this,在构造函数中可以使用this
	3.逐行执行函数中的代码
	4.将新建的对象作为返回值返回
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类
	我们将通过一个构造函数创建的对象,称为是该类的示例
*/
function Person(name,age,gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.sayName = funtion(){
        alter(this.name);
    }
}
var per = new Person("张三",18,"男");

function Dog(name,age){
    this.name = name;
    this.age = age;
}
var dog = new Dog("旺财",3);
console.log(per); //Person类型对象
console.log(dog); //Dog类型对象

二、函数

1.函数简介

函数也是一个对象,函数中可以封装一些功能(代码),在需要时可以执行这些功能

封装到函数中的代码不会立即执行,需要调用函数时才执行其中代码

2.函数的创建方式

1)函数声明

/*
使用函数声明来创建一个函数
语法:function 函数名([参数1,参数2,.....]){
		代码...
}
调用函数语法:函数名()
*/
function fun(){
    console.log("我是函数声明创建的函数");
}
fun(); //我是函数声明创建的函数

2)函数表达式

console.log("我是函数声明创建的函数")/*
使用函数表达式来创建一个函数
var 函数名 = function([参数1,参数2,.....]){
		代码...
}
*/
var fun2 = function(){
    console.log("我是函数表达式创建的函数");
}
fun2(); //我是函数表达式创建的函数

3.函数的形参与实参

/*
可以在函数的()中来指定一个或多个形参
多个形参之间使用,隔开,声明形参就相当与在函数内部声明了对应的变量,但没有赋值
*/
function sum(a.b){
    console.log(a+b);
}

//在调用函数时,可以在()中指定实参
sum(1,2); //3

/*
调用函数时,解析器不会检查实参的数量
多余的实参不会被赋值
而如果实参的数量少于形参的数量,则没有对应实参的形参被赋值为undefined
*/
sum(1,2,3,4,5,6) //3
sum(1) //NaN

补充:实参可以是任意数据类型的数据

4.立即执行函数

函数定义后,立即执行,且只执行一次

(function(){
    console.log("立即执行函数")
})();

//带参数的立即执行函数
(function(a,b){
    console.log(a+b)
})(1,2);

5.枚举对象中的属性

for...in...语句

/*
语法 for(var 变量 in 对象){
		代码...
}
for...in...语句 对象中有几个属性,循环体就会执行几次
*/
var obj = {
    name:"张三",
    age:18,
    gender:"男",
    address:"牢房"
}
for (var o in obj){
    console.log(o) //依次输出对象中的属性名
    console.log(obj.o) // undefined,obj对象中没有o这个属性名
    console.log(obj[0]) //依次输出对应的对象名中的对象值
}

6.作用域

作用域指一个变量的作用的范围

1)全局作用域

​ —— 直接编写在script标签中的JS代码

​ —— 全局作用域在页面打开时创建,在页面关闭时销毁

​ —— 在全局作用域中有一个全局对象window(它代表的时一个浏览器的窗口,由浏览器创建我们可以直接使用)

​ —— 在全局作用域中:

​ 创建的变量都会作为window对象的属性保存

​ 创建的函数都会作为window对象的方法保存

​ —— 全局作用域中的变量在页面的任意部分都可以访问的到

2)函数作用域

​ —— 调用函数时创建函数作用域,函数执行完毕后,函数作用域消耗

​ —— 每调用依次函数就会创建一个新的函数作用域,它们之间是相互独立的

​ —— 在函数作用域中可以访问到全局作用域的变量

​ 但在全局作用域中无法访问到函数作用域的变量

​ —— 当函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接用

​ 如果没有则向上一级作用域中寻找,直到找到全局作用域

​ 如果全局作用域中依然没有找到,则会报错

7.变量于函数的提升

1)变量提升

/*
变量的声明提前
	使用var关键字声明的变量,会在所有的代码执行前被声明(但是不会被赋值)
*/
console.log(a); //输出undefined
var a = 1;

console.log(a); //会报错
a = 1;

2)函数提升

/*
函数的声明提前
	使用函数声明形式创建的函数function 函数(){},它会在所有的代码执行前就被创建
*/
fun(); //我是函数声明所创建的
fun2(); //报错,因为undefined不是一个函数
function fun(){
    console.log("我是函数声明所创建的");
}
var fun2 = function(){
    console.log("我是函数表达式创建的");
}

注意:在函数作用域也有变量声明提前的特性

即使用var关键字声明的变量,会在函数中所有执行的代码之前被声明

在函数中,如果不使用var声明的变量,则会成为全局变量

8.提升练习

------------------------------------
var a = 123;
function fun(){
    alter(a);
}
fun(); //123
------------------------------------
var a = 123;
function fun(){
    alter(a);
    var a = 456;
}
fun(); //undefined,在函数作用域中使用var声明了变量a
alter(a); //123,在函数作用域中使用了var声明变量a
------------------------------------
var a = 123;
function fun(){
    alter(a);
    a = 456;
}
fun(); //123,在函数作用域中没有使用var声明了变量a
alter(a); //456, 在函数作用域中没有使用var声明了变量a
------------------------------------
var a = 123;
function fun(a){
    alter(a);
    a = 456;
}
fun(); //undefined,实参数量小于形参
alter(a); //456
------------------------------------
var a = 123;
function fun(a){
    alter(a);
    a = 456;
}
fun(123); //123
alter(a); //123,因为在此函数作用域中已经存在变量a,所有不会找到全局作用域中的a
------------------------------------

9.this相关知识

解析器在调用函数每次都会向函数内部传递一个隐含的参数,

​ 这个隐含的参数就是this,this指向一个对象,

​ 这个对象就是我们称为函数执行的 上下文对象,

​ 根据函数的调用方式不同,this会指向不同的对象

/*
this的情况:
	1.当以函数的形式调用时,this是window
	2.当以方法的形式调用时,谁调用方法this就是谁
	3.当以构造函数的形式调用时,this就是新创建的那个对象
	4.使用call()和apply()调用时,this是指定的那个对象
*/
function fun(){
    console.log(this);
}
var obj = {
    name:"张三",
    sayName:fun
};
fun(); //此时this为window
obj.sayName(); //此时this为obj

10.原型对象(prototype)

问题:

在构造函数中定义方法,那么每创建一个对象就会生成一个对应的相同的方法,从而浪费大量的内存空间

而将函数定义在全局作用域,则污染了全局作用域的命名空间,且不安全

/*
原型prototype
	我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
		这个属性对应着一个对象,这个对象就是我们所谓的原型对象
	如果函数作为普通函数调用prototype没有任何作用
	但当以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性(__proto__)来指向该构造函数的原型对象
*/
function Fun(){
    
}
var fun = new Fun();
var fun2 = new Fun();
console.log(fun.__proto__ == Fun.prototype) //true
console.log(fun2.__proto__ == Fun.prototype) //true

/*
原型对象就相当于一个公共区域,所有同一个类的实例都可以访问到这个原型对象,
	所以我们可以将对象中共有的内容,统一设置到原型对象中
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
	如果没有则会去原型对象中寻找,找到则也直接使用
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中去,
	这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象拥有这些属性和方法了
*/
Fun.prototype.salary = 8000;
Fun.prototype.sayName = funtion(){
    console.log(this.name);
}

注意:

使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true

所以可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性

11.toSting()方法

当我们直接在页面中打印一个对象时,事实上是输出对象的toString()方法的返回值

/*
如果我们希望在输出对象时不输出[object object],可以为对象添加一个toString()方法
*/
function Fun(){
    
}
var fun = new Fun();
fun.toString = function(){
    console.log("我是一个快乐又积极的person");
}
console.log(fun); //我是一个快乐又积极的person

JS—03

一、数组

1.数组简介

数组也是一个对象

它和我们普通对象功能类似,也是用来存储一些值的

不同的是普通对象使用字符串作为属性名,而数组使用数组作为索引来操作元素

数组中的元素可以是任意数据类型

2.数组的基本操作

/*
创建数组:
	1)利用构造函数来创建数组对象
	2)利用数组字面量来创建数组
*/
var arr = new Array();
var arr = [];

/*
向数组中添加元素
	语法: 数组[索引] = 值
读取数组中的元素
	语法 数组[索引]
	如果读取不存在的索引,它不会报错而是返回undefined
*/
arr[0] = 0;
arr[1] = 1;
console.log(arr[0]); // 0
console.log(arr[2]); //undefined

/*
可以使用length属性来获取数组的长度
	语法:数组.length
对于连续的数组,使用length可以获取到数组的长度
而对于非连续的数组,使用length会获取到数组的最大索引+1
*/
console.log(arr.length) // 2
arr[10] = 10
console.log(arr.length) //11

//向数组的最后一个位置添加元素
//语法:数组[数组.length] = 元素
arr[arr.length] = xxx

3.数组中的方法(常用)

var arr = [];
/*
push()
	该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
*/
arr.push(1);
var length = arr.push(2,3);
console.log(arr); // 1,2,3
console.log(length); //3

/*
pop()
	该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
*/
var result = arr.pop();
console.log(arr); // 1,2
console.log(result); // 3

/*
unshift()
	向数组开头添加一个或多个元素,并返回新的数组长度
	向前边插入元素以后,其他的元素索引会依次调整
*/
var length = arr.unshift(0);
console.log(arr); // 0,1,2
console.log(length); // 3

/*
shift()
	可以删除数组的第一个元素,并将被删除的元素作为返回值返回
*/
var result = arr.shift();
console.log(arr); // 1,2
console.log(result); // 0

/*
slice(start,end)
	可以用来从数组中提前指定元素
	该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回
	参数:
		1.截取开始位置的索引(包含开始位置)
		2.截取结束位置的索引(不包含结束位置)
		当第二个参数省略不屑时,此时会截取从开始索引往后位置的所以元素
		索引可以传递一个负值,如果传递一个负值,则从后往前计算
			-1 倒数第一个
			-2 倒数第二个
*/
var arr = [1,2,3,4,5];
var newArr = arr.slice(0,2);
console.log(arr); // 1,2,3,4,5
console.log(newArr); // 1,2

/*
splice(start,much)
	可以用于删除数组中指定的元素
	使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除元素作为返回值返回
	参数:
		1.表示开始位置的索引
		2.表示删除的数量
*/
var arr = [1,2,3];
var result = arr.splict(0,2);
console.log(arr); // 3
console.log(result); // 1,2

/*
concat()可以连接两个或多个数组,并将新的数组返回(该方法不会对原数组产生影响)
*/
var arr = [0];
var arr2 = [1];
var result = arr.concat(arr2);
console.log(result); // 0,1

/*
join()
	该方法可以将数组转换为一个字符串
	该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
	在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
	如果不指定连接符,则,默认为连接符
*/
var arr = [1,2,3];
result = arr.join("-");
console.log(result); // 1-2-3
result = arr.join();
console.log(result); // 1,2,3

/*
reverse()
	该方法用来翻转数组,会直接修改原数组
*/
var arr = [1,2,3];
arr.reverse();
console.log(arr); // 3,2,1

/*
sort()
	可以用来对数组中的元素进行排序
	会影响原数组,默认按照Unicode编码进行排序
	所以我们可以自己来指定排序规则
	我们可以在sotr()中添加一个回调函数,来指定排序顺序
		浏览器会分别使用数组中的元素作为实参去调用回调函数
		如果需要升序排列,则返回a-b
				降序排列,则返回b-a
*/
var arr = [5,4,1,3,2];
arr.sort(function(a,b){
    //return a-b;
    return b-a;
})
//console.log(arr); // 1,2,3,4,5
console.log(arr); // 5,4,3,2,1

4.数组中的循环遍历(forEach)

/*
forEach()方法需要一个函数作为参数
	像这种函数,由我们创建但是不由我们调用的,称为回调函数
	数组中由几个元素,函数就会执行几次,每次执行时,浏览器都会遍历到的元素,会以实参的形式传递进来,我们可以来定义形参读取这些内容
	而浏览器会在回调函数中传递三个参数:
		第一个参数:就是当前正在遍历的元素
		第二个参数:就是当前正在遍历元素的索引
		第三个参数:就是正在遍历的数组
*/
var arr = [1,2,3];
arr.forEach(function(value,index,obj){
    console.log(value); // 1,2,3
    console.log(index); // 0,1,2
    console.log(obj == arr); //true true true
})

二、call()和apply()

/*
call()和apply()
	这两个方法都是函数对象的方法,需要通过函数对象来调用
	在调用这两个方法时可以将第一个参数指定为一个对象
		此时这个对象将会成为函数执行时的this
	call()方法可以将实参在对象之后依次传递
	apply()方法需要将实参封装到一个数组中统一传递
*/
function fun(){
    alter("我是fun函数");
}
var obj = {
    name:"张三",
    sayName:function(){
        alter(this.name);
    }
}
var obj2 = {
    name:"李四",
    sayName:function(){
        alter(this.name);
    }
}
fun.call() //我是fun函数
fun.apply() //我是fun函数
fun.call(obj)或者fun.apply(obj) //张三
fun.call(obj2)或者fun.apply(obj2) //李四

三、arguments(封装实参对象)

在调用函数时,浏览器不止会传递this这个隐含参数,还会传递arguments这个隐含参数

arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度

而调用函数时,我们所传递的实参都会在arguments中保存

arguments[0]表示第一个实参,arguments[1]表示第二个实参

其中有一个属性叫callee

​ 这个属性对应一个函数对象,就是当前正在指向的函数对象

四、Date对象

/*
直接使用构造函数创建一个Date对象,则会封装为当前代码执行的事件
创建一个指定时间对象,需要在构造函数中传递一个表示时间字符串作为参数
	格式:约/日/年/ 时:分:秒
*/
var d = new Date();
var d2 = new Date("2/23/2022 00:00:00");

/*
getDate()
	获取当前日期对象是这个月中第几天
*/
var date = d2.getDate();
console.log(date); //23

/*
getDay()
	获取当前日期对象是星期几
	会返回一个0-6的值
*/
var day = d2.getDay();
console.log(day); //3

/*
getMonth()
	获取当前时间对象的月份
	会返回一个0-11值
*/
var month = d2.getMonth();
console.log(month); //1

/*
getFullYear()
	获取当前日期对象的年份
*/
var year = d2.getFullYear();
console.log(year); //2022

/*
getTime()
	获取当前日期对象的时间戳
	指的是从格林威治标准时间的1970年1月1日,0时0分0秒到当前日期所花费的毫秒数
*/

/*
Date.now()
	获取当前的时间戳
	可以来测试执行代码的性能
*/
var date = Date.now();
for(var i=0;i<100;i++){
    console.log(i);
}
var date2 = Date.now();
console.log(date2 - date)

五、Math对象

Math和其他的对象不同,它不是一个构造函数

​ 它属于一个工具类,不用创建对象,它里边封装了数学运算相关的属性和方法

/*
abs()可以用来计算一个数的绝对值
*/
console.log(Math.abs(-1)); // 1

/*
Math.ceil():可以对一个数进行向上取整
Math.floor():可以对一个数进行向下取整
Math.round():可以对一个数进行四舍五入
*/
console.log(Math.ceil(1.1)); // 2
console.log(Math.cel(1.9)); // 2
console.log(Math.floor(1.1)); // 1
console.log(Math.floor(1.9)); // 1
console.log(Math.round(1.1)); // 1
console.log(Math.round(1.9)); // 2

/*
Math.random()
	可以生成一个0-1之间的随机数
		生成一个x-y之间的随机数
			语法:
				Math.round(Math.random()*(y-x)+x)
*/
console.log(Math.round(Math.random()*9+1)); //生成1-10之间的随机数 

/*
Math.max() 可以获取多个数中的最大值
Math.min() 可以获取多个数中的最小值
Math.pow(x,y) 返回x的y次幂
*/

六、字符串相关方法(常用)

在底层字符串是以字符数组的形式保存的,所以大部分属性和方法都和数组类似

/*
charAt()
	可以根据索引返回字符串中指定位置的字符
charCodeAt()
	获取指定位置字符的字符编码(Unicode编码)
*/
var str = "Hello";
console.log(str.charAt(0)); // H
console.log(str.charCodeAt(0)); // 72

/*
concat()
	可以用来连接两个或多个字符串,作用和+号差不多
	用法和数组类似
*/

/*
indexOf()
	该方法可以检索一个字符串中是否含有指定内容
	如果字符串含有该内容,则会返回其第一次出现的索引,如果没有,则返回-1
	可以指定一个第二个参数,那么会从指定位置开始查找
lastIndexOf()
	该方法的用法和indexOf是一样的
	不同的是从后往前找
*/
var str = "Hello";
console.log(str.indexOf(l)); // 2
console.log(str.indexOf(l,3)); // 3,此时从第二个l处开始查找

/*
slice()
	可以从字符串中截取指定的内容,不会影响原字符串,而是将截取到的内容返回,和数组中用法类似
substring()
	作用、用法和slice()方法类似
	不同的是这个方法不能接受负值作为参数
		如果传递了一个负值,则默认使用0
		而且还会自动调正参数位置,从小到大调整
*/

/*
split()
	可以将一个字符串拆分为一个数组
	需要一个字符串作为参数,将会根据该字符串去拆分数组
*/
var str = "123,456,789";
console.log(str.split(",")) // 123,456,789
console.log(typeof str.split(",")) // Object

/*
toUpperCase():将一个字符串转换为大写并返回
toLowerCase():将一个字符串转换为小写并返回
*/

七、正则表达式

1.简介

正则表达式用于定义一些字符串的规则:

​ 计算机可以根据正则表达式,来检查一个字符串是否符合规则

​ 也可以将字符串中符合规则的内容提取出来

/*
创建正则表达式的两种方法:(使用字面量的方式创建更加简单,使用构造函数创建更加灵活)
1)构造函数法:
	var reg(变量名) = new RegExp("正则表达式","匹配模式")
	
2)字面量法:
	var reg(变量名) = /正则表达式/+匹配模式
可以传递一个匹配模式(两个一起也行)作为第二个参数:
	i 忽略大小写
	g 全局匹配模式

正则表达式的方法:
	reg.test()
		使用这个方法可以用来检查一个字符串是否符合正则表达式的规则
			如果符合返回true,否则返回false
*/

2.正则语法

/*
检测一个字符串中是否含有a或b
使用 | 或 [] 表示或者的意思
[A-z] 表示任意字母
[^ ] 表示除了什么意外
*/
var reg = /[ab]/;
var str = "ac";
var str2 = "bc";
var str3 = "c";
console.log(reg.test(str)); // true
console.log(reg.test(str2)); // true
console.log(reg.test(str3)); // false

3.字符串和正则相关的语法

/*
split()
	可以将一个字符串拆分为一个数组
	方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
*/
var str = "1a2b3c4d5e6f";
var reg = /[a-z]/;
console.log(str.split(reg)); // 1,2,3,4,5,6

/*
search()
	可以搜索字符串中是否有指定内容
	如果有,则会返回第一次出现的索引,如果没有,则返回-1
	它可以接受一个正则表达式作为参数,任何会根据正则表达式去检索
*/
var str = "hello abc hello aec afc";
var reg = /a[bef]c/;
console.log(str.search(reg)); // 6

/*
match()
	可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
	默认情况下match只会找到第一个符合要求的内容,然后就停止搜索
		我们可以将匹配模式设置为全局,这样就能匹配全局内容
	match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
*/
var str = "1a2b3c4d5e6f";
var reg = /[a-z]/g;
console.log(str.match(reg)); // a,b,c,d,e,f

/*
replace()
	可以将字符串中指定内容替换为新的内容
	参数:
		1.被替换的内容,可以接受一个正则表达式作为参数
		2.新的内容
	默认只会被替换第一个
*/
var str = "1a2b3c";
var reg = /[a-z]/g;
console.log(str.replace(reg,"=.=")); // 1=.=2=.=3=.= 

4.正则表达式语法

量词:

​ 通过量词可以设置一个内容出现的次数

​ 量词只对它前边的一个内容起作用

​ {n} 正好出现 n 次

​ {m,n} 出现 m - n 次

​ {m,} 出现m次以上

​ + 至少一个,相当于{1, }

​ * 0个或多个,相当于{0, }

​ ? 0个或一个,相当于{0,1}

开头/结尾:

​ ^ 表示开头

​ $ 表示结尾

​ 如果在正则表达式中同时使用^ $,则要求字符串必须完全符合正则表达式

在正则表达式中使用 \ 作为转义字符

\ . 来表示 . (. 表示任意字符)

\ \ 来表示 \

\w 来表示:任意的字母、数字、_ [A-z0-9_]

\W 来表示:除了字母、数字、_ [ ^A-z0-9_]

\d 来表示 任意的数字

\D 来表示:除了数字

\s 来表示: 空格

\S 来表示:除了空格

\b 来表示:单词边界

\B 来表示:除了单词边界

5.正则相关练习

/*
创建一个正则表达式检测一个字符串中是否含有单词 xxx
*/
var reg = /\bxxx\b/;
console.log(reg.test("hello xxxren")); // false
console.log(reg.test("hello xxx ")); // true

/*
去除字符串中的前后空格(即使用""来替换空格)
*/
var str = "     hel  lo        ";
console.log(str.replace(/^\s* | \s*$/g,"")); // hel  lo

/*
判断邮箱的正则表达式:
	只允许英文字母、数字、下划线、英文句号、以及中划线组成
*/
var str = "zhangsan-001@gmail.com";
var reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
console.log(reg.test(str)); // true

/*
判断手机号的正则表达式
*/
var str = "13567890123";
var reg = /^1[3-9][0-9]{9}$/;
console.log(reg.test(str)); // true

八、DOM

1.简介

DOM:全称Document Object Model文档对象

JS中通过DOM来对HTML文档进行操作

节点:Node——构成HTML文档最基本的单元

常用节点分为四类:

​ 文档节点:整个HTML文档

​ 元素节点:HTML文档中的HTML标签

​ 属性节点:元素的属性

​ 文本节点:HTML标签中的文本内容

2.事件

事件:就是用户和浏览器之间的交互行为

浏览器在加载一个页面时,是按照自上向下的顺序加载,即读取到一行就运行一行,如果将script标签写到页面的上边,那么代码执行时,页面还没有加载

而window.onload事件会在整个页面加载完成后才触发(这样可以确保我们的代码执行时所以的DOM对象已经加载完毕了)

3.DOM查询

获取元素节点:

1)getElementById()

​ 通过id属性获取一个元素节点对象

2)getElemensByTagName()

​ 通过标签名获取一组元素节点对象

3)getElementsByName()

​ 通过name属性获取一组元素节点对象

4)getElementsByClassName() (有兼容性问题)

​ 通过calss属性获取一组元素节点对象

获取元素节点的子节点:

1)getElemensByTagName()

​ 方法,返回当前节点的指定标签名后代节点

2)childNodes

​ 属性,表示当前节点的所有节点(包含换行文本节点)

3)firstChild

​ 属性,表示当前节点的第一个节点(包含换行文本节点)

4)lastChild

​ 属性,表示当前节点的最后一个节点(包含换行文本节点)

获取父节点和兄弟节点:

1)parentNode()

​ 属性,表示当前节点的父节点

2)previousSibling()

​ 属性,表示当前节点的前一个兄弟节点

3)nextSibling()

​ 属性,表示当前节点的后一个兄弟节点

JS—04

一、事件对象

当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进相应函数(在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标,鼠标滚轮滚动的方向....)

获取的事件对象名称.绑定的事件 = function(e/event) {
    alter(e/event); //其中e/event就是事件对象
}

二、事件对象相关知识

1.事件的委派

指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件

事件委派是利用了事件冒泡,通过委派可以减少事件绑定的次数,提高程序的性能

2.事件的绑定

使用 对象.事件 = 函数 的形式绑定响应函数

​ 它只能同时为一个元素的一个事件绑定一个响应函数,不能绑定多个

​ 如果绑定多个,则后边会覆盖掉前边的

addEventListener()

​ 通过这个方法也可以为元素绑定响应函数

​ 参数:

​ 1.事件的字符串,不需要使用on

​ 2.回调函数,当事件触发时该函数会被调用

​ 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false

而通过addEventListener()可以同时为一个元素的相同事件绑定多个响应函数

​ 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行

3.事件的传播

1)捕获阶段

​ 在该阶段时从最外层的祖先元素,向目标元素进行事件捕获

2)目标阶段

​ 事件捕获到目标元素,捕获结束开始在目标元素上触发事件

3)冒泡阶段

​ 事件从目标元素向它的祖先元素传递,依次触发祖先元素上的事件

如果希望在捕获阶段就触发事件,可以将addEventListener()第三个参数设置为true

三、BOM

1.简介

全称: Browser Object Model ,浏览器对象模型

BOM可以使我们通过JS来操作浏览器,为我们提供了一组对象,用来完成对浏览器的操作

2.BOM对象

1)Window

​ 代表的是整个浏览器的窗口,同时window也是网页中的全局对象

2)Navigator

​ 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器

3)Location

​ 代表当前浏览器的地址栏信息,通过location可以获取地址栏信息,或者操作浏览器跳转界面

4)History

​ 代表浏览器的历史记录,但由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,且只在当次访问时有效

5)Screen

​ 代表用户的屏幕信息,通过该对象可以获取到用户的显示器的相关信息

注意:BOM对象的使用自行了解!!!