🍀基本语法
入门
helloworld
<!--JS代码需要编写到script标签中-->
<script type="text/javascript">
/*
* 控制浏览器弹出一个警告框
* alert("哥,你真帅啊!!");
*/
/*
* 让计算机在页面中输出一个内容
* document.write()可以向body中输出一个内容
* document.write("看我出不出来~~~");
*/
/*
* 向控制台输出一个内容
* console.log()的作用是向控制台输出一个内容
* console.log("你猜我在哪出来呢?");
*/
alert("哥,你真帅啊!!");
document.write("看我出不出来~~~");
console.log("你猜我在哪出来呢?");
</script>
js代码是从上到下依次执行的
严格区分大小写
js编写位置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--
可以将js代码编写到外部js文件中,然后通过script标签引入
写到外部文件中可以在不同的页面中同时引用,也可以利用到浏览器的缓存机制
推荐使用的方式
-->
<!--
script标签一旦用于引入外部文件了,就不能在编写代码了,即使编写了浏览器也会忽略
如果需要则可以在创建一个新的script标签用于编写内部代码
-->
<script type="text/javascript" src="js/script.js"></script>
<script type="text/javascript">
alert("我是内部的JS代码");
</script>
<!--
可以将js代码编写到script标签
<script type="text/javascript">
alert("我是script标签中的代码!!");
</script>
-->
</head>
<body>
<!--
可以将js代码编写到标签的onclick属性中
当我们点击按钮时,js代码才会执行
虽然可以写在标签的属性中,但是他们属于结构与行为耦合,不方便维护,不推荐使用
-->
<button onclick="alert('讨厌,你点我干嘛~~');">点我一下</button>
<!--
可以将js代码写在超链接的href属性中,这样当点击超链接时,会执行js代码
-->
<a href="javascript:alert('让你点你就点!!');">你也点我一下</a>
<a href="javascript:;">你也点我一下</a>
</body>
</html>
基本语法
注释
– 单行注释://注释内容
– 多行注释:/注释内容/
- JS中严格
区分大小写
- JS中每一条语句
以分号(;)结尾
如果不写分号,浏览器会自动添加,但是会消耗一些系统资源
而且有些时候,浏览器会加错分号,所以在开发中分号必须写 - JS中会
忽略多个空格和换行
,所以我们可以利用空格和换行对代码进行格式化
字面量 & 变量 (概念)
-
字面量
比如 :1 2 3 4 5
字面量都是可以直接使用,但是我们一般都不会直接使用字面量 -
变量 : 变量可以用来保存字面量,而且变量的值是可以任意改变的
开发中都是通过变量去保存一个字面量,而很少直接使用字面量
可以通过变量对字面量进行描述-
变量的声明:
– 使用var关键字声明一个变量。
–var a;
-
变量的赋值:
– 使用=为变量赋值。
–a=123;
-
声明和赋值同时进行:
– var a = 123;
//使用,运算符同时声明多个变量 //var a , b , c; //可以同时声明多个变量并赋值 //var a=1 , b=2 , c=3; //alert(b);
-
标识符
指变量、函数、属性的名字,或函数的参数
命名一个标识符时需要遵守如下的规则:
1.标识符中可以含有字母、数字、_、$
2.标识符不能以数字开头
3.标识符不能是ES中的关键字或保留字
4.标识符一般都采用驼峰命名法
🍃数据类型
数据类型指的就是字面量的类型
在JS中一共有六种数据类型
- String 字符串
- Number 数值
- Boolean 布尔值
- Null 空值
- Undefined 未定义
- Object 对象
其中String Number Boolean Null Undefined属于基本数据类型
而Object属于引用数据类型
String
- 在JS中字符串需要使用引号引起来
- 使用双引号或单引号都可以,但是不要混着用
- 引号不能嵌套,双引号不能放双引号,单引号不能放单引号
- 在字符串中我们可以使用\作为转义字符,当表示一些特殊符号时可以使用\进行转义
\" 表示 "
\' 表示 '
\n 表示换行
\t 制表符
\\ 表示\
var str = 'hello';
str = '我说:"今天天气真不错!"';
str = "我说:\"今天\t天气真不错!\"";
Number
① 在JS中所有的数值都是Number类型,包括整数和浮点数(小数)
//数字123
var a = 123;
//字符串123
var b = "123";
②可以使用一个运算符 typeof来检查一个变量的类型
- 语法:typeof 变量
- 检查字符串时,会返回string
- 检查数值时,会返回numbe
console.log(typeof b); //string
③JS中可以表示的数字的最大值
Number.MAX_VALUE : 1.7976931348623157e+308
Number.MIN_VALUE: 5e-324
大于0的最小值
如果使用Number表示的数字超过了最大值,则会返回一个
- Infinity 表示正无穷
- -Infinity 表示负无穷
- 使用typeof检查Infinity也会返回number
a = -Number.MAX_VALUE * Number.MAX_VALUE;
console.log(typeof a); //number
NaN 是一个特殊的数字,表示Not A Number
使用typeof检查一个NaN也会返回number
④在JS中整数的运算基本可以保证精确
var c = 1865789 + 7654321;
如果使用JS进行浮点运算,可能得到一个不精确的结果
所以千万不要使用JS进行对精确度要求比较高的运算
var c = 0.1 + 0.2;
console.log(c);
Boolean
布尔值只有两个,主要用来做逻辑判断
true:表示真
false:表示假
使用typeof检查一个布尔值时,会返回boolean
var bool = false;
console.log(typeof bool); //boolean
Null
Null(空值)类型的值只有一个,就是null
null这个值专门用来表示一个为空的对象
使用typeof检查一个null值时,会返回object
var a = null;
Undefined
Undefined(未定义)类型的值只有一个,就undefind
声明了未定义
var b
console.log(typeof b);//undefind
🟥强制类型转换
指将一个数据类型强制转换为其他的数据类型
类型转换主要指,将其他的数据类型,转换为
String Number Boolean
xxx–>String
方式一: 调用被转换数据类型的toString()方法
- 该方法
不会影响到原变量
,它会将转换的结果返回
- 但是注意:
null和undefined
这两个值没有toString()方法
,如果调用他们的方法,会报错
var a = 123;
//调用a的toString()方法
//调用xxx的yyy()方法,就是xxx.yyy()
a = a.toString(); //"123"
a = true;
a = a.toString(); //"true"
a = null;
//a = a.toString(); //报错
a = undefined;
//a = a.toString(); //报错
方式二:调用String()函数,并将被转换的数据作为参数传递给函数
- 使用String()函数做强制类型转换时,对于Number和Boolean实际上就是调用的toString()方法
- 但是对于null和undefined,就不会调用toString()方法它会
将 null 直接转换为 “null”
将 undefined 直接转换为 “undefined”
//Number和Boolean实际上就是调用的toString()方法
a = 123;
//调用String()函数,来将a转换为字符串
a = String(a);
a = null;
a = String(a); // "null"
a = undefined;
a = String(a); // "undefined"
方式三:运用 + 运算符
传送
任何的值和字符串做加法运算
***,都会先转换为字符串
,然后再和字符串做拼串
的操作
var c = 123;
c = c + ""; // number --> string
xxx–>Number
转换方式一:使用Number()函数
字符串 --> 数字
- 如果是
纯数字的字符串
,则直接将其转换为数字
- 如果字符串中有
非数字的内容
,则转换为NaN
- 如果字符串是一个
空串
或者是一个全是空格的字符串
,则转换为0
- 布尔 --> 数字
- true 转成 1
- false 转成 0
null --> 数字 0
undefined --> 数字 NaN
var a = "123";
a = Number(a); //123
a = false;
a = Number(a); //0
a = null;
a = Number(a); //0
a = undefined;
a = Number(a);//NaN
转换方式二:「这种方式专门用来对付字符串」
- parseInt() 把一个字符串转换为一个整数
parseInt()可以将一个字符串中的有效的整数内容去出来,然后转换为Number - parseFloat() 把一个字符串转换为一个浮点数
- 如果对非String使用parseInt()或parseFloat()
它会先将其转换为String然后在操作
a = "123567a567px";
a = parseInt(a); //123567
a = "123.456.789px";
a = parseFloat(a); //123.456
//非String使用parseInt()
a = true;
a = parseInt(a);// NaN
a = 198.23;
a = parseInt(a);// 198
其他进制数字
可以在parseInt()中传递一个第二个参数,来指定数字的进制
a = parseInt(a,10);
//十六进制
a = 0x10;
a = 0xff;
a = 0xCafe;
//八进制数字
a = 070;
//二进制数字
//a = 0b10;
//向"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析
a = "070";
//可以在parseInt()中传递一个第二个参数,来指定数字的进制
a = parseInt(a,10);
方式三: 通过 - * / 转换
传送到知识点
可以通过为一个值 -0 *1 /1来将其转换为Number
原理和Number()函数一样,使用起来更加简单
a = "12" - 0;
a = "12" * 1;
a = "12" / 1;
方式四: 一元运算符 +
传送到知识点
可以对一个其他的数据类型使用+,来将其转换为number
它的原理和Number()函数一样
+ 1 // 1
+ "1" // 1
+ "false" //NaN
+ "null" //NaN
+ null // 0
+ undefined // NaN
+ false // 0
xxx–>Boolean: 使用Boolean()函数
方法一:使用Boolean()函数
数字 ---> 布尔
- 除了
0和NaN
,其余的都是true
字符串 ---> 布尔
- 除了
空串
,其余的都是true
null和undefined都会转换为false
对象也会转换为true
var a = 123; //true
a = -123; //true
a = 0; //false
a = Infinity; //true
a = NaN; //false
//调用Boolean()函数来将a转换为布尔值
a = Boolean(a);
//除了`空串`,其余的都是true
a = "hello" //true
a = " "; //true
a = "false" //true
a = "" //false
a = Boolean(a);
a = null; //false
a = Boolean(a);
a = undefined; //false
a = Boolean(a);
方法二:逻辑!运算符
- 如果对一个值进行两次取反,它不会变化
- 如果对
非布尔值进行元素
,则会将其转换为布尔值
,然后再取反
所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值
可以为一个任意数据类型取两次反,来将其转换为布尔值,
原理和Boolean()函数一样
var b = 10;
b = !!b; //
!!0 //false
!!12 //true
!!-12 //true
!!NaN //false
!!Infinity
!!"0" //true
!!"false" //true
!!"" //false
!!" "//true
!!null //false
!!undefined //false
🍃运算符
运算符也叫操作符,通过运算符可以对一个或多个值进行运算,并获取运算结果
- 比如:typeof就是运算符,可以来获得一个值的类型
它会将该值的类型以字符串的形式返回
number string boolean undefined object
算数运算符
- 当对
非Number
类型的值进行运算时,会将这些值转换为Number
然后再运算
(除 + 对字符串外) - 任何值做- * /运算时都会自动转换为Number,
可以通过为一个值 -0 *1 /1来将其转换为Number
原理和Number()函数一样,使用起来更加简单
+
- +对值进行加法运算,并将结果返回
- 对两
字符串
进行加法运算
,则会做拼串
,会将两个字符串拼接为一个字符串,并返回
任何的值和字符串做加法运算
,都会先转换为字符串
,然后再和字符串做拼串
的操作
//number
var a = 123;
result = a + 1; //result = 124, a = 123
result = 456 + 789;//1245
//boolean、null、NaN
result = true + 1;//1 + 1 = 2
result = true + false;//1 + 0 = 1
result = 2 + null; // 2 + 0 = 2
result = 2 + NaN; //2 + 0 =2
//string
result = "你好" + "大帅哥";//你好大帅哥
result = 123 + "1"; //
result = true + "hello";
var c = 123;
c = c + ""; // number --> string
result = 1 + 2 + "3"; //33
result = "1" + 2 + 3; //123
-
- 可以对两个值进行减法运算,并将结果返回
result = 100 - 5; //95
result = 100 - true;//100 - 1 =99
result = 100 - "1";//100 - 1 = 99
result = 100 - "1a";//100 - NaN = NaN
result = 100 - null;//100 - 0 = 100
result = 100 - undefined;//100 - NaN = NaN
*
result = 2 * 2; //4
result = 2 * "8"; // 2 * 8 = 16
result = 2 * undefined; // 2 * NaN = NaN
result = 2 * null; // 2 * 0 = 0
result = 2 * true; // 2 * 1 = 2
/
result = 4 / 2; //2
result = 3 / 2; //1.5
result = 3 / "1"; //3 / 1 = 3
result = 3 / "1a"; // 3 / NaN = NaN
result = 3 / true; //3 / 1 = 3
result = 3 / false //3 / 0 = Infinity
result = 3 / null; //3 / 0 = Infinity
result = 3 / undefined; //3 / NaN = NaN
%
% 取模运算(取余数)
result = 9 % 3; //0
result = 9 % 4; //1
result = 9 % 5; //4
一元运算符
一元运算符,只需要一个操作数
+ 正号
正号不会对数字产生任何影响
- 负号
负号可以对数字进行负号的取反
- 对于非Number类型的值,它会将先转换为Number,然后在运算
- 可以对一个其他的数据类型使用+,来将其转换为number,它的原理和Number()函数一样
自增 & 自减
自增 ++
- 对于一个变量自增以后,原变量的值会立即自增1
- 后++(a++) 和 前++(++a)
无论是a++ 还是 ++a,都会立即使原变量的值自增1
a++的值等于原变量的值(自增前的值)
++a的值等于新值 (自增后的值)
自减 --: 同自增
var num = 10;
num = ++num;//11
num = num++;//11
分析num = ++ num
① num自增运算
局部变量:11 操作数栈:
② 压入操作数栈
局部变量:11 操作数栈:11
③ 赋值操作(将操作数栈的值赋值给局部变量num)
局部变量:11 操作数栈:
num = 11
分析num = num ++
num = 11 局部变量
① 将局部变量压入操作数栈
局部变量:11 操作数栈:11
② 局部变量自增
局部变量:12 操作数栈:11
③ 赋值操作(将操作数栈的值赋值给局部变量num)
局部变量:11 操作数栈:
num = 11
var i = 1;
i = i++;
var j = i++;
var k = i + ++i*i++;
分析:
var i = 1;
i = i++;//通过上面知识易得 i = 1
var j = i++;//通过上面知识易得 j = 1,i=2
var k = i + ++i*i++;
1.压栈操作时从左向右,i 的值入栈
i = 2 栈 2
2. ++i 先自增,后入栈
i = 3 栈 2 3
3. i++ 先入栈,后自增
i = 3 栈 2 3 3
↓
i = 4 栈 2 3 3
4.做运算 先乘
3*3 = 9
i = 4 栈 2 9
5.做运算 加操作
2 + 9
i = 4 栈 11
6. 赋值操作
将操作数栈的值赋给 k 变量
i = 4 栈
k = 11
j = 1
逻辑运算符
JS中为我们提供了三种逻辑运算符
! 非
- 所谓非运算就是值对一个布尔值进行取反操作,true变false,false变true
- 如果对一个值进行两次取反,它不会变化
- 如果对
非布尔值进行元素
,则会将其转换为布尔值
,然后再取反
所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值
可以为一个任意数据类型取两次反,来将其转换为布尔值,
原理和Boolean()函数一样
var a = false;
a = !a; // true
var b = 10;
b = !!b; //
!!0 //false
!!12 //true
!!-12 //true
!!NaN //false
!!Infinity
!!"0" //true
!!"false" //true
!!"" //false
!!" "//true
!!null //false
!!undefined //false
&& 与
- 两个值中
有false就false
,只有两个值都为true,才true
- JS中的“与”属于
短路与
,如果第一个false
,则不会看第二个值
|| 或
- 两个值中只要
有true,就true
如果两个值都为false,才false
- JS中的“或”属于
短路或
,如果第一个true
,则不会检查第二个值
&& || 非布尔值的情况
对于非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且返回原值
与运算
第一个值为true
,则必然返回第二个值
第一个值为false
,则直接返回第一个值
或运算
第一个值为true
,则直接返回第一个值
第一个值为false
,则返回第二个值
1 && 2; //2
0 && 1; //0
//同理
NaN && 0; //NaN
0 && NaN; //0
//同理
"aaa" && 666 //666
"aaa" && "bbb" //"bbb"
"" && 666 //""
2 || 1 //2
2 || NaN; //2
2 || 0; //2
NaN || 1; //1
NaN || 0; //0
-1 || "你好"; // -1
"" || "hello"; //"hello"
赋值运算符
=
可以将符号右侧的值赋值给符号左侧的变量
+=
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
> 大于号
>= 大于等于
< 小于号
<= 小于等于
非数值的情况
- 非数值比较时,会将其转换为数字再比较
- 符号两侧的值都是
字符串时
,不会将其转换为数字进行比较
而会分别比较字符串中字符的Unicode编码
相等运算符
==
- 当使用==来比较两个值时,类型不同,则会自动进行类型转换,将其转换为相同的类型,然后在比较
- 转换的类型不一定,大部分情况转员number
- undefined 衍生自 null,所以这两个值做相等判断时,会返回true
- NaN不和任何值相等,包括他本身
- 通过isNaN()函数来判断一个值是否是NaN
1 == 1; //true
1 == "1"; //true (string --> number)
true == "1" //true (string --> number ,boolean --> number)
true == "hello" //false (string --> number ,boolean --> number)
null == 0 //false
undefined == null //true
NaN == NaN //false
//判断b的值是否是NaN
var b = NaN;
isNaN(b)
!=
同上
===
判断两个值是否全等,它和相等类似,不同的是它不会做自动的类型转换
!==
条件运算符
条件表达式?语句1:语句2;
a > b ? alert("a大"):alert("b大");
代码块
JS中{} 只有分组作用没有作用域作用
流程控制
1.条件判断语句
2.条件分支语句
3.循环语句
if语句
if(a > 10 && a <= 20){
alert("a大于10,并且 a小于等于20");
}
if(age > 17 && age <= 30){
alert("你已经成年了");
}else if(age > 30 && age <= 60){
alert("你已经中年了");
}else if(age > 60 && age <= 80){
alert("你已经退休了");
}else{
alert("你岁数挺大的了~~");
}
switch语句
switch(num){
case 1:
console.log("壹");
//使用break可以来退出switch语句
break;
case 2:
console.log("贰");
break;
case 3:
console.log("叁");
break;
default:
console.log("非法数字~~");
break;
}
while循环
while(true){
alert(n++);
//判断n是否是10
if(n == 10){
//退出循环
break;
}
}
do while
do{
document.write(i++ +"<br />");
}while(i <= 10);
for
for(var i = 0 ; i < 10 ; i++ ){
alert(i);
}
break
outer:
for(var i=0 ; i<5 ; i++){
console.log("@外层循环"+i)
for(var j=0 ; j<5; j++){
break outer;
console.log("内层循环:"+j);
}
}
continue
outer:
for(var i=0 ; i<5 ; i++){
for(var j=0 ; j<5 ; j++){
continue;
console.log("-->"+j);
}
console.log("@--->"+i);
}
常用方法
console.time("test");
console.timeEnd("test");
Math.sqrt(i)
🍀面向对象
🍃对象
对象的分类:
-
内建对象 (类似jdk中的类)
由ES标准中定义的对象,在任何的ES的实现中都可以使用
比如:Math String Number Boolean Function Object… -
宿主对象(浏览器对象)
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
比如 BOM DOM -
自定义对象
由开发人员自己创建的对象
创建对象
- 对象的属性可以是任何数据类型,也可以是一个函数
- 当函数是一个对象的属性:称该函数时该对象的方法
方式一:new Object()
使用new关键字调用的函数,是构造函数constructor
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
var obj = new Object();
//向obj中添加一个name属性
obj.name = "孙悟空";
//向obj中添加一个gender属性
obj.gender = "男";
//向obj中添加一个age属性
obj.age = 18;
//读取对象中的属性
obj.name = "tom";
//修改对象的属性值
obj.name = "tom";
//删除对象的属性
delete obj.name;
方式二:`字面量形式
对象字面量的属性名可以加引号也可以不加,建议不加,
如果要使用一些特殊的名字,则必须加引号
var obj = {};
obj.name = "孙悟空";
var obj2 = {
name:"猪八戒",
age:13,
gender:"男",
test:{name:"沙僧"}
};
🍃函数(function)
- 函数也是一个对象
- 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
- 函数中可以保存一些代码在需要的时候调用
- 使用typeof检查一个函数对象时,会返回function
var fun = new Function("console.log('Hello 这是我的第一个函数');");
我们在实际开发中很少使用构造函数来创建一个函数对象
使用函数声明创建对象
function fun2(){
console.log("这是我的第二个函数~~~");
alert("哈哈哈哈哈");
document.write("~~~~(>_<)~~~~");
}
函数表达式声明
var fun3 = function(){
console.log("我是匿名函数中封装的代码");
};
形参声明,调用
- 调用函数时解析器不会检查实参的类型
- 多余实参不会被赋值,如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined
function sum(a,b){
console.log("a = "+a);
console.log("b = "+b);
console.log(a+b);
}
sum(1,2);
实参可以是一个对象,也可以是一个函数
function fun(a){
console.log("a = "+a);
//a(obj);
}
fun(function(){alert("hello")});
返回值
- return后的值将会会作为函数的执行结果返回,可以定义一个变量,来接收该结果
- 如果return语句后不跟任何值就相当于返回一个undefined
- 如果函数中不写return,则也会返回undefined
- return后可以跟任意类型的值,也可以是一个对象,也可以是一个函数
- 变量result的值就是函数的执行结果
function sum(a , b , c){
//alert(a + b +c);
var d = a + b + c;
return d;
}
var result = sum(4,7,8);
function fun2(){
//返回一个对象
return {name:"沙和尚"};
}
function fun3(){
//在函数内部再声明一个函数
function fun4(){
alert("我是fun4");
}
//将fun4函数对象作为返回值返回
return fun4;
}
fun3()();
立即执行函数
- 函数定义完,立即被调用,这种函数叫做立即执行函数
- 立即执行函数往往只会执行一次
(function(){
alert("我是一个匿名函数~~~");
})();
对象属性
- 可以是任何数据类型,也可以是函数
- 当函数时对象属性,称该函数时对象的方法
var obj2 = {
name:"猪八戒",
age:18,
sayName:function(){
console.log(obj2.name);
}
};
obj2.sayName();
枚举对象中的属性
for…in语句 对象中有几个属性,循环体就会执行几次
每次执行时,会将对象中的一个属性的名字赋值给变量
var obj = {
name:"孙悟空",
age:18,
gender:"男",
address:"花果山"
};
for(var n in obj){
console.log("属性名:"+n);
//当对象的属性是变量时,使用[]调用
console.log("属性值:"+obj[n]);
}
🍃作用域
全局作用域
-
直接编写在
script标签中
的JS代码,都在全局作用域
-
全局作用域在
页面打开时创建
,在页面关闭时销毁
-
在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
-
在全局作用域中:
创建的变量都会作为window对象的属性保存
创建的函数都会作为window对象的方法保存
var a = 10;
var b = 20;
var c = "hello";
console.log(window.c);
function fun(){
console.log("我是fun函数");
}
window.fun();
变量的声明提前
使用var关键字声明的变量
,会在所有的代码执行之前被声明
(但是不会赋值),但是如果声明变量时不使用var关键字,则变量不会被声明提前
console.log("a = "+a);//undefined
var a = 123;
console.log("a = "+a);//报错
a = 123;
函数的声明提前
使用函数声明形式创建的函数 function 函数(){}
它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
fun();
//函数声明,会被提前创建
function fun(){
console.log("我是一个fun函数");
}
//函数表达式,不会被提前创建
var fun2 = function(){
console.log("我是fun2函数");
};
fun2();
函数作用域
调用函数时
创建
函数作用域,函数执行完毕以后
,函数作用域销毁
- 每调用一次函数就会
创建一个新的函数作用域
,他们之间是互相独立
的 - 在
函数作用域
中可以访问
到全局作用域
的变量,在全局作用域中无法访问到函数作用域的变量 - 先找自身作用域,有就用,没有则向上找,直到找到全局作用域,全局中依然没有,则报错ReferenceError
- 在函数中要访问全局变量可以使用window对象
//创建一个变量
var a = 10;
function fun(){
var a = "我是fun函数中的变量a";
var b = 20;
//console.log("a = "+a);
function fun2(){
//使用window对象
console.log("a = "+window.a);
}
fun2();
}
- 在
函数作用域
也有声明提前
的特性,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明,函数声明也会在函数中所有的代码执行之前执行 - 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
function fun3(){
fun4();
//console.log(a);
var a = 35;
function fun4(){
alert("I'm fun4");
}
}
- 在函数中,不使用var声明的变量都会成为全局变量
- 定义形参就相当于在函数作用域中声明了变量
🍃this
- 解析器在调用函数每次都会向函数内部传递进一个隐含的参数,
这个隐含的参数就是this,this指向的是一个对象,
这个对象我们称为函数执行的 上下文对象,
根据函数的调用方式的不同,this会指向不同的对象
1、以函数的形式调用时,this永远都是window
2、以方法的形式调用时,this就是调用方法的那个对象
3、当以构造函数的形式
调用时,this就是新创建的那个对象
4、使用call和apply调用时,this是指定的那个对象
function fun(){
//console.log("a = "+a+", b = "+b);
console.log(this.name);
}
//创建一个name变量
var name = "全局";
//创建一个fun()函数
function fun(){
console.log(this.name);
}
//创建两个对象
var obj = {
name:"孙悟空",
sayName:fun
};
var obj2 = {
name:"沙和尚",
sayName:fun
};
//我们希望调用obj.sayName()时可以输出obj的名字
//obj.sayName();
obj.sayName();
工厂方法创建对象
/*
* 使用工厂方法创建对象
* 通过该方法可以大批量的创建对象
*/
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;
}
/*
* 用来创建狗的对象
*/
function createDog(name , age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayHello = function(){
alert("汪汪~~");
};
return obj;
}
var obj2 = createPerson("猪八戒",28,"男");
var obj3 = createPerson("白骨精",16,"女");
var obj4 = createPerson("蜘蛛精",18,"女");
/*
* 使用工厂方法创建的对象,使用的构造函数都是Object
* 所以创建的对象都是Object这个类型,
* 就导致我们无法区分出多种不同类型的对象
*/
//创建一个狗的对象
var dog = createDog("旺财",3);
🍃构造函数
创建一个构造函数,专门用来创建Person对象的
- 构造函数就是一个普通的函数,创建方式和普通函数没有区别,
- 不同的是构造函数习惯上首字母大写
构造函数和普通函数的区别就是调用方式的不同
- 普通函数是直接调用,而构造函数需要使用new关键字来调用
构造函数的执行流程:
1.立刻创建一个新的对象
2.将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){
alert(this.name);
};
}
function Dog(){
}
var per = new Person("孙悟空",18,"男");
var per2 = new Person("玉兔精",16,"女");
var per3 = new Person("奔波霸",38,"男");
var dog = new Dog();
在Person构造函数中,为每一个对象都添加了一个sayName方法,
也就是构造函数每执行一次就会创建一个新的sayName方法
导致了构造函数执行一次就会创建一个新的方法,
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方法
Person.prototype.sayName = function(){
alert("Hello大家好,我是:"+this.name);
};
//创建一个Person的实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
per.sayName();
per2.sayName();
🍃原型 prototype
-
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
这个属性对应着一个对象,这个对象就是我们所谓的原型对象 -
如果函数作为普通函数调用prototype没有任何作用
-
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
function MyClass(){
}
var mc = new MyClass();
var mc2 = new MyClass();
//console.log(MyClass.prototype);
//console.log(mc2.__proto__ == MyClass.prototype); //true
//console.log(mc.__proto__ == MyClass.prototype); //true
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,
我们可以将对象中共有的内容,统一设置到原型对象中。 - 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
如果没有则会去原型对象中寻找,如果找到则直接使用 - 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,
这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
- 使用in检查对象中是否含有某个属性
- 使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
/*
* 创建一个构造函数
*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mc = new MyClass();
mc.age = 18;
console.log(mc.name);
//使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
console.log("name" in mc);
console.log(mc.hasOwnProperty("age"));
console.log(mc.hasOwnProperty("hasOwnProperty"));
- 原型对象也是对象,所以它也有原型
- 当我们使用一个对象的属性或方法时,会现在自身中寻找,
自身中如果有,则直接使用
如果没有则去原型对象中寻找,如果原型对象中有,则使用,
如果没有则去原型的原型中寻找,直到找到Object对象的原型,
Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
console.log(mc.__proto__.__proto__.__proto__);//null
console.log(mc.hello);
console.log(mc.__proto__.__proto__.__proto__)
toString
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
}
console.log(per.__proto__.__proto__.hasOwnProperty("toString"));//true
//修改Person原型的toString
Person.prototype.toString = function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};
//当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值
//如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法
//Person[name=孙悟空,age=18,gender=男]
/*per.toString = function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};*/
//创建一个Person实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
垃圾回收
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,
此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢, - 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作
- 我们需要做的只是要将不再使用的对象设置null即可
var obj = new Object();
//对对象进行各种操作。。。。
obj = null;
🍀内建对象
🍃数组(Array)
- 数组也是一个对象,它和我们普通对象功能类似,也是用来存储一些值的
- 不同的是普通对象是使用字符串作为属性名的,而数组是使用数字来作为索引操作元素
- 索引:从0开始的整数就是索引
- 数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据
- 如果读取不存在的索引,他不会报错而是返回undefined
//创建数组对象
var arr = new Array();
/*
* 向数组中添加元素
* 语法:数组[索引] = 值
*/
arr[0] = 10;
arr[1] = 33;
arr[2] = 22;
arr[3] = 44;
/*
* 读取数组中的元素
* 语法:数组[索引]
* 如果读取不存在的索引,他不会报错而是返回undefined
*/
console.log(arr[3]);
Array 属性
/*
* 获取数组的长度
* 可以使用length属性来获取数组的长度(元素的个数)
* 语法:数组.length
*
* 对于连续的数组,使用length可以获取到数组的长度(元素的个数)
* 对于非连续的数组,使用length会获取到数组的最大的索引+1
* 尽量不要创建非连续的数组
*/
console.log(arr.length);
console.log(arr);
/*
* 修改length
* 如果修改的length大于原长度,则多出部分会空出来
* 如果修改的length小于原长度,则多出的元素会被删除
*/
arr.length = 10;
arr.length = 2;
//向数组的最后一个位置添加元素
//语法:数组[数组.length] = 值;
arr[arr.length] = 70;
arr[arr.length] = 80;
arr[arr.length] = 90;
数组字面量
- 使用字面量来创建数组
- 使用字面量创建数组时,可以在创建时就指定数组中的元素
- 数组中的元素可以是任意的数据类型
//使用字面量来创建数组
//语法:[]
var arr = [];
//使用字面量创建数组时,可以在创建时就指定数组中的元素
var arr = [1,2,3,4,5,10];
//使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作文构造函数的参数传递
//元素之间使用,隔开
var arr2 = new Array(10,20,30);
//创建一个长度为10的数组
arr2 = new Array(10);
//数组中的元素可以是任意的数据类型
arr = ["hello",1,true,null,undefined];
//也可以是对象
var obj = {name:"孙悟空"};
arr[arr.length] = obj;
arr = [{name:"孙悟空"},{name:"沙和尚"},{name:"猪八戒"}];
//也可以是一个函数
arr = [function(){alert(1)},function(){alert(2)}];
//数组中也可以放数组,如下这种数组我们称为二维数组
arr = [[1,2,3],[3,4,5],[5,6,7]];
数组方法
方法 | 描述 |
---|---|
🍃concat() | 连接两个或多个数组,并返回已连接数组的副本。 |
copyWithin() | 将数组中的数组元素复制到指定位置或从指定位置复制。 |
entries() | 返回键/值对数组迭代对象。 |
every() | 检查数组中的每个元素是否通过测试。 |
fill() | 用静态值填充数组中的元素。 |
filter() | 使用数组中通过测试的每个元素创建新数组。 |
find() | 返回数组中第一个通过测试的元素的值。 |
findIndex() | 返回数组中通过测试的第一个元素的索引。 |
🍃forEach() | 为每个数组元素调用函数。 |
from() | 从对象创建数组。 |
includes() | 检查数组是否包含指定的元素。 |
indexOf() | 在数组中搜索元素并返回其位置。 |
isArray() | 检查对象是否为数组。 |
🍃join() | 将数组的所有元素连接成一个字符串。 |
keys() | 返回 Array Iteration 对象,包含原始数组的键. |
lastIndexOf() | 在数组中搜索元素,从末尾开始,并返回其位置。 |
map() | 使用为每个数组元素调用函数的结果创建新数组。 |
🍃pop() | shift() | 删除 数组的最后一个元素 ,并返回 该元素 。 |
🍃push() | unshift() | 将新元素添加到数组的末尾 ,并返回 新的长度 。 |
reduce() | 将数组的值减为单个值(从左到右)。 |
reduceRight() | 将数组的值减为单个值(从右到左)。 |
reverse() | 反转数组中元素的顺序。 |
🍃shift() | 删除数组的第一个元素,并返回该元素。 |
🍃slice() | 选择数组的一部分 ,并返回新数组 。 |
some() | 检查数组中的任何元素是否通过测试。 |
sort() | 对数组的元素进行排序。 |
🍃splice() | 从数组中添加/删除 元素。 |
toString() | 将数组转换为字符串,并返回结果。 |
🍃unshift() | 将新元素添加到数组的开头,并返回新的长度。 |
valueOf() | 返回数组的原始值。 |
遍历数组
for遍历
//创建一个数组
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
for(var i=0 ; i<arr.length ; i++){
console.log(arr[i]);
}
forEach方法
终止或者跳出forEach()循环,除非抛出异常,所以想执行一个数组是否满足某种条件然后返回某值,可以用一般的for循环实现,或者用Array.every()或者Array.some();
Array.every()用于检测数组所有元素是否全部都符合指定条件
Array.some()用于检测数组中的元素是否有任意一个满足指定条件
语法:array.forEach(callback(currentvalue,index,arr) ,thisValue)
//forEach没有返回值
var arr = [1, 3, 5, 13, 2];
var res = arr.forEach(function(item,index) {
console.log(`数组第${index+1}个元素是${item}`);
})
console.log(res);//forEach的返回值为undefined,
- forEach() 方法无法提前结束
var arr = [1, 3, 5, 13, 2];
for (var i = 0; i < arr.length; i++) {
if (arr[i] == 3) {
console.log("找到了3,并结束循环");
break;
}
console.log(arr[i]);
}
var arr = [1, 3, 5, 13, 2];
arr.forEach(function(item) {
if (item == 3) {
return console.log('找到了3,但未结束遍历');
}
console.log(item);
})
- forEach()会跳过空值
var arr1 = [1, 3, , 13, 2];
var arr2 = [1, 3, , 13, 2];
for (var i = 0; i < arr1.length; i++) {
arr1[i] = 2;
}
console.log(arr1);
var newarr = [];
arr2.forEach(function(item, index) {
// item = 2; //修改不了原数组
arr2[index] = 2;
})
console.log(arr2);
- forEach()的循环次数不受数组长度增长影响
- forEach适用于只是进行集合或数组遍历,for则在较复杂的循环中效率更高
其他方法
var arr = ["孙悟空","猪八戒","沙和尚"];
var arr2 = ["白骨精","玉兔精","蜘蛛精"];
var arr3 = ["二郎神","太上老君","玉皇大帝"];
/*
* concat()可以连接两个或多个数组,并将新的数组返回
* - 该方法不会对原数组产生影响
*/
var result = arr.concat(arr2,arr3,"牛魔王","铁扇公主");
/*
* join()
* - 该方法可以将数组转换为一个字符串
* - 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
* - 在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
* 如果不指定连接符,则默认使用,作为连接符
*/
arr = ["孙悟空","猪八戒","沙和尚","唐僧"];
result = arr.join("@-@");
/*
* reverse()
* - 该方法用来反转数组(前边的去后边,后边的去前边)
* - 该方法会直接修改原数组
*/
arr.reverse();
/*
* sort()
* - 可以用来对数组中的元素进行排序
* - 也会影响原数组,默认会按照Unicode编码进行排序
*/
arr.sort();
arr = [5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
//前边的大
/*if(a > b){
return -1;
}else if(a < b){
return 1;
}else{
return 0;
}*/
//升序排列
//return a - b;
//降序排列
return b - a;
});
函数对象方法
call()和apply()
function fun(a,b) {
alert(this);
}
//效果一样
fun.apply();
fun.call();
fun();
在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
function fun(a,b) {
alert(this);
}
var obj = {};
//修改this指向的对象
fun.call(obj);
fun.apply(obj);
var obj = {
name: "obj",
sayName:function(){
alert(this.name);
}
};
obj.sayName.apply(obj2);
call()方法可以将实参在对象之后依次传递
apply()方法需要将实参封装到一个数组中统一传递
function fun(a,b) {
console.log("a = "+a);
console.log("b = "+b);
//alert(this);
}
fun.call(obj,2,3);
fun.apply(obj,[2,3]);
arguments 隐含属性
在调用函数时,浏览器每次都会传递进两个隐含的参数:
1.函数的上下文对象 this
2.封装实参的对象 arguments
- arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
- 在调用函数时,我们所传递的实参都会在arguments中保存
- arguments.length可以用来获取实参的长度
- 我们即使不定义形参,也可以通过arguments来使用实参,
只不过比较麻烦
arguments[0] 表示第一个实参
arguments[1] 表示第二个实参 。。。 - 它里边有一个属性叫做callee,这个属性对应一个函数对象,就是当前正在指向的函数的对象
function fun(a,b){
//console.log(arguments instanceof Array);
//console.log(Array.isArray(arguments));
//console.log(arguments[1]);
//console.log(arguments.length);
console.log(arguments.callee == fun);
}
fun("hello",true);
Date对象
- 创建一个Date对象
- 创建一个指定的时间对象
- 获取当前日期对象是几日
- 获取当前日期对象是周几
- 获取当前时间对象的月份
- 获取当前日期对象的年份
- 获取当前日期对象的时间戳
- 利用时间戳来测试代码的执行的性能
//创建一个Date对象
//如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
var d = new Date();
//创建一个指定的时间对象
//需要在构造函数中传递一个表示时间的字符串作为参数
//日期的格式 月份/日/年 时:分:秒
var d2 = new Date("2/18/2011 11:10:30");
/*
* getDate()
* - 获取当前日期对象是几日
*/
var date = d2.getDate();
/*
* getDay()
* - 获取当前日期对象时周几
* - 会返回一个0-6的值
* 0 表示周日
* 1表示周一
* 。。。
*/
var day = d2.getDay();
/*
* getMonth()
* d2 = new Date("12/18/2011 11:10:30");
* - 获取当前时间对象的月份
* - 会返回一个0-11的值
* 0 表示1月
* 1 表示2月
* 11 表示12月
*/
var month = d2.getMonth();
/*
* getFullYear()
* - 获取当前日期对象的年份
*/
var year = d2.getFullYear();
/*
* getTime()
* - 获取当前日期对象的时间戳
* - 时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒
* 到当前日期所花费的毫秒数(1秒 = 1000毫秒)
* - 计算机底层在保存时间时使用都是时间戳
*/
var time = d2.getTime();
//利用时间戳来测试代码的执行的性能
//获取当前的时间戳
var start = Date.now();
for(var i=0 ; i<100 ; i++){
console.log(i);
}
var end = Date.now();
console.log("执行了:"+(end - start)+"毫秒");
Math
- Math.PI 表示的圆周率
- abs()可以用来计算一个数的绝对值
- Math.ceil() 向上取整
- Math.floor() 向下取整
- Math.round() 四舍五入取整
- Math.random() 生成一个0-1之间的随机数
- max() 、min()
- Math.pow(x,y) x的y次幂
- Math.sqrt() 开方运算
/*
* Math
* - Math和其他的对象不同,它不是一个构造函数,
* 它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法
* - 比如
* Math.PI 表示的圆周率
*/
console.log(Math.PI);
/*
* abs()可以用来计算一个数的绝对值
*/
console.log(Math.abs(-1));
/*
* Math.ceil()
* - 可以对一个数进行向上取整,小数位只有有值就自动进1
* Math.floor()
* - 可以对一个数进行向下取整,小数部分会被舍掉
* Math.round()
* - 可以对一个数进行四舍五入取整
*/
console.log(Math.ceil(1.1));
console.log(Math.floor(1.99));
console.log(Math.round(1.4));
/*
* Math.random()
* - 可以用来生成一个0-1之间的随机数
* - 生成一个0-10的随机数
* - 生成一个0-x之间的随机数
* Math.round(Math.random()*x)
*
* - 生成一个1-10
* - 生成一个x-y之间的随机数
* Math.round(Math.random()*(y-x)+x)
*/
for(var i=0 ; i<100 ; i++){
//console.log(Math.round(Math.random()*10));
//console.log(Math.round(Math.random()*20));
//console.log(Math.round(Math.random()*9)+1);
//console.log(Math.round(Math.random()*8)+2);
//生成1-6之间的随机数
console.log(Math.round(Math.random()*5+1));
}
/*
* max() 可以获取多个数中的最大值
* min() 可以获取多个数中的最小值
*/
var max = Math.max(10,45,30,100);
var min = Math.min(10,45,30,100);
//console.log(min);
/*
* Math.pow(x,y)
* 返回x的y次幂
*/
console.log(Math.pow(12,3));
/*
* Math.sqrt()
* 用于对一个数进行开方运算
*/
console.log(Math.sqrt(2));
包装类
/*
* 基本数据类型
* String Number Boolean Null Undefined
* 引用数据类型
* Object
*
* 在JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象
* String()
* - 可以将基本数据类型字符串转换为String对象
* Number()
* - 可以将基本数据类型的数字转换为Number对象
* Boolean()
* - 可以将基本数据类型的布尔值转换为Boolean对象
* 但是注意:我们在实际应用中不会使用基本数据类型的对象,
* 如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
*/
//创建一个Number类型的对象
//num = 3;
var num = new Number(3);
var num2 = new Number(3);
var str = new String("hello");
var str2 = new String("hello");
var bool = new Boolean(true);
var bool2 = true;
//向num中添加一个属性
num.hello = "abcdefg";
//console.log(str === str2);
var b = new Boolean(false);
/*if(b){
alert("我运行了~~~");
}*/
/*
* 方法和属性之能添加给对象,不能添加给基本数据类型
* 当我们对一些基本数据类型的值去调用属性和方法时,
* 浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法
* 调用完以后,在将其转换为基本数据类型
*/
var s = 123;
s = s.toString();
s.hello = "你好";
console.log(s.hello);
//console.log(typeof s);
字符串相关方法
- 在底层字符串是以字符数组的形式保存的
- length属性 : 可以用来获取字符串的长度
- charAt() : 返回字符串中指定位置的字符
- charCodeAt() : 获取指定位置字符的字符编码(Unicode编码)
- formCharCode() :根据字符编码去获取字符
- concat()
//创建一个字符串
var str = "Hello Atguigu";
/*
* 在底层字符串是以字符数组的形式保存的
* ["H","e","l"]
*/
/*
* length属性
* - 可以用来获取字符串的长度
*/
//console.log(str.length);
//console.log(str[5]);
/*
* charAt()
* - 可以返回字符串中指定位置的字符
* - 根据索引获取指定的字符
*/
str = "中Hello Atguigu";
/*
* charCodeAt()
* - 获取指定位置字符的字符编码(Unicode编码)
*/
result = str.charCodeAt(0);
/*
* String.formCharCode()
* - 可以根据字符编码去获取字符
*/
result = String.fromCharCode(0x2692);
/*
* concat()
* - 可以用来连接两个或多个字符串
* - 作用和+一样
*/
result = str.concat("你好","再见");
/*
* indexof()
* - 该方法可以检索一个字符串中是否含有指定内容
* - 如果字符串中含有该内容,则会返回其第一次出现的索引
* 如果没有找到指定的内容,则返回-1
* - 可以指定一个第二个参数,指定开始查找的位置
*
* lastIndexOf();
* - 该方法的用法和indexOf()一样,
* 不同的是indexOf是从前往后找,
* 而lastIndexOf是从后往前找
* - 也可以指定开始查找的位置
*/
str = "hello hatguigu";
result = str.indexOf("h",1);
result = str.lastIndexOf("h",5);
/*
* slice()
* - 可以从字符串中截取指定的内容
* - 不会影响原字符串,而是将截取到内容返回
* - 参数:
* 第一个,开始位置的索引(包括开始位置)
* 第二个,结束位置的索引(不包括结束位置)
* - 如果省略第二个参数,则会截取到后边所有的
* - 也可以传递一个负数作为参数,负数的话将会从后边计算
*/
str = "abcdefghijk";
result = str.slice(1,4);
result = str.slice(1,-1);
/*
* substring()
* - 可以用来截取一个字符串,可以slice()类似
* - 参数:
* - 第一个:开始截取位置的索引(包括开始位置)
* - 第二个:结束位置的索引(不包括结束位置)
* - 不同的是这个方法不能接受负值作为参数,
* 如果传递了一个负值,则默认使用0
* - 而且他还自动调整参数的位置,如果第二个参数小于第一个,则自动交换
*/
result = str.substring(0,1);
/*
* substr()
* - 用来截取字符串
* - 参数:
* 1.截取开始位置的索引
* 2.截取的长度
*/
str = "abcdefg";
result = str.substr(3,2);
/*
* split()
* - 可以将一个字符串拆分为一个数组
* - 参数:
* -需要一个字符串作为参数,将会根据该字符串去拆分数组
*/
str = "abcbcdefghij";
result = str.split("d");
/*
* 如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
*/
result = str.split("");
//console.log(Array.isArray(result));
//console.log(result[0]);
console.log(result);
str = "abcdefg";
/*
* toUpperCase()
* - 将一个字符串转换为大写并返回
*/
result = str.toUpperCase();
str = "ABCDEFG";
/*
* toLowerCase()
* -将一个字符串转换为小写并返回
*/
result = str.toLowerCase();
//console.log(result);
正则表达式
- 创建正则表达式的对象
正则表达式的方法:
- test()
/*
* 正则表达式
* - admin@atguigu.com
* - admin@.com adminatguigu.com
* - 邮件的规则:
* 1.前边可以是xxxx乱七八糟
* 2.跟着一个@
* 3.后边可以是xxxx乱七八糟
* 4..com获取其他的乱七八糟
*
* - 正则表达式用于定义一些字符串的规则,
* 计算机可以根据正则表达式,来检查一个字符串是否符合规则,
* 获取将字符串中符合规则的内容提取出来
*/
//创建正则表达式的对象
/*
* 语法:
* var 变量 = new RegExp("正则表达式","匹配模式");
* 使用typeof检查正则对象,会返回object
* var reg = new RegExp("a"); 这个正则表达式可以来检查一个字符串中是否含有a
* 在构造函数中可以传递一个匹配模式作为第二个参数,
* 可以是
* i 忽略大小写
* g 全局匹配模式
*/
var reg = new RegExp("ab","i");
var str = "a";
/*
* 正则表达式的方法:
* test()
* - 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,
* 如果符合则返回true,否则返回false
*/
var result = reg.test(str);
//console.log(result);
console.log(reg.test("Ac"));
/*
* 使用字面量来创建正则表达式
* 语法:var 变量 = /正则表达式/匹配模式
* 使用字面量的方式创建更加简单
* 使用构造函数创建更加灵活
*
*/
//var reg = new RegExp("a","i");
var reg = /a/i;
//console.log(typeof reg);
//console.log(reg.test("abc"));
//创建一个正则表达式,检查一个字符串中是否有a或b
/*
* 使用 | 表示或者的意思
*/
reg = /a|b|c/;
/*
* 创建一个正则表达式检查一个字符串中是否有字母
*/
//reg = /a|b|c|d|e|f|g/;
/*
* []里的内容也是或的关系
* [ab] == a|b
* [a-z] 任意小写字母
* [A-Z] 任意大写字母
* [A-z] 任意字母
* [0-9] 任意数字
*/
reg = /[A-z]/;
//检查一个字符串中是否含有 abc 或 adc 或 aec
reg = /a[bde]c/;
/*
* [^ ] 除了
*/
reg = /[^ab]/;
reg = /[^0-9]/;
console.log(reg.test("12a3456"));
字符串正则
- split()
- search()
- match()
- replace()
var str = "1a2b3c4d5e6f7";
/*
* split()
* - 可以将一个字符串拆分为一个数组
* - 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
* - 这个方法即使不指定全局匹配,也会全都插分
*/
/*
* 根据任意字母来将字符串拆分
*/
var result = str.split(/[A-z]/);
//console.log(result);
/*
* search()
* - 可以搜索字符串中是否含有指定内容
* - 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
* - 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
* - serach()只会查找第一个,即使设置全局匹配也没用
*/
str = "hello abc hello aec afc";
/*
* 搜索字符串中是否含有abc 或 aec 或 afc
*/
result = str.search(/a[bef]c/);
//console.log(result);
/*
* match()
* - 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
* - 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索
* 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
* 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
* - match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
*
*
*/
str = "1a2a3a4a5e6f7A8B9C";
result = str.match(/[a-z]/ig);
//console.log(result[2]);
/*
* replace()
* - 可以将字符串中指定内容替换为新的内容
* - 参数:
* 1.被替换的内容,可以接受一个正则表达式作为参数
* 2.新的内容
* - 默认只会替换第一个
*/
//result = str.replace(/[a-z]/gi , "@_@");
result = str.replace(/[a-z]/gi , "");
//console.log(result);
🍀宿主对象
DOM
节点
节点属性
文档节点(document)
- 文档节点document,代表的是整个HTML文档,网页中的所有节点都是它的子节点。
- document对象作为window对象的属性存在的,我们不用获取可以直接使用。
- 通过该对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。
元素节点(Element)
- HTML中的各种标签都是元素节点,这也是我们最常用的一个节点。
- 浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document的方法来获取元素节点。
- 比如:
– document.getElementById()
– 根据id属性值获取一个元素节点对象。
文本节点(Text)
- 文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点。
- 它包括可以字面解释的纯文本内容。
- 文本节点一般是作为元素节点的子节点存在的。
- 获取文本节点时,一般先要获取元素节点。在通过元素节点获取文本节点。
- 例如:
– 元素节点.firstChild;
– 获取元素节点的第一个子节点,一般为文本节点
属性节点(Attr)
- 属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。
- 可以通过元素节点来获取指定的属性节点。
- 例如:
– 元素节点.getAttributeNode(“属性名”); - 注意:我们一般不使用属性节点。
事件
- 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。
- JavaScript 与 HTML 之间的交互是通过事件实现的。
- 对于 Web 应用来说,有下面这些代表性的事件:
点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键,等等。
<button id="btn" onmousemove="alert('讨厌,你点我干嘛!');">我是一个按钮</button>
<button onclick="this.innerHTML=Date()">现在的时间是?</button>
<button id="btn">我是一个按钮</button>
var btn = document.getElementById("btn");
btn.onclick = function(){
alert("你还点~~~");
};
<button onclick="displayDate()">现在的时间是?</button>
/*
* onload事件会在整个页面加载完成之后才触发
* 为window绑定一个onload事件
* 该事件对应的响应函数将会在页面加载完成之后执行,
* 这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
*
*/
window.onload = function(){
//获取id为btn的按钮
var btn = document.getElementById("btn");
//为按钮绑定一个单击响应函数
btn.onclick = function(){
alert("hello");
};
};
获取元素节点
- 通过document对象调用
getElementsByClassName() 可以根据class属性值获取一组元素节点对象,
但是该方法不支持IE8及以下的浏览器
//var box1 = document.getElementsByClassName("box1");
方法 | 描述 |
---|---|
document.getElementById(id) | 通过id 属性获取一个 元素节点对象 |
document.getElementsByTagName(name) | 通过标签 名获取一组 元素节点对象 |
document.getElementsByClassName(name) | 通过name 属性获取一组 元素节点对象 |
//为id为btn01的按钮绑定一个单击响应函数
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//查找#bj节点
var bj = document.getElementById("bj");
//打印bj
//innerHTML 通过这个属性可以获取到元素内部的html代码
alert(bj.innerHTML);
};
//为id为btn02的按钮绑定一个单击响应函数
var btn02 = document.getElementById("btn02");
btn02.onclick = function(){
//查找所有li节点
//getElementsByTagName()可以根据标签名来获取一组元素节点对象
//这个方法会给我们返回一个类数组对象,所有查询到的元素都会封装到对象中
//即使查询到的元素只有一个,也会封装到数组中返回
var lis = document.getElementsByTagName("li");
//打印lis
//alert(lis.length);
//变量lis
for(var i=0 ; i<lis.length ; i++){
alert(lis[i].innerHTML);
}
};
//为id为btn03的按钮绑定一个单击响应函数
var btn03 = document.getElementById("btn03");
btn03.onclick = function(){
//查找name=gender的所有节点
var inputs = document.getElementsByName("gender");
//alert(inputs.length);
for(var i=0 ; i<inputs.length ; i++){
/*
* innerHTML用于获取元素内部的HTML代码的
* 对于自结束标签,这个属性没有意义
*/
//alert(inputs[i].innerHTML);
/*
* 如果需要读取元素节点属性,
* 直接使用 元素.属性名
* 例子:元素.id 元素.name 元素.value
* 注意:class属性不能采用这种方式,
* 读取class属性时需要使用 元素.className
*/
alert(inputs[i].className);
}
};
图片切换练习
获取元素节点的子节点
• 通过具体的元素节点调用
- getElementsByTagName()
–方法
,返回当前节点的指定标签名后代节点 childNodes
–属性
,表示当前节点的所有子节点children
属性
可以获取当前元素的所有子元素- firstChild
–属性
,表示当前节点的第一个子节点 - lastChild
–属性
,表示当前节点的最后一个子节点
//为id为btn04的按钮绑定一个单击响应函数
var btn04 = document.getElementById("btn04");
btn04.onclick = function(){
//获取id为city的元素
var city = document.getElementById("city");
//查找#city下所有li节点
var lis = city.getElementsByTagName("li");
for(var i=0 ; i<lis.length ; i++){
alert(lis[i].innerHTML);
}
};
- childNodes属性会获取包括文本节点在呢的所有节点
根据DOM标签标签间空白也会当成文本节点 - 注意:在IE8及以下的浏览器中,不会将空白文本当成子节点,所以该属性在IE8中会返回4个子元素而其他浏览器是9个
//为id为btn05的按钮绑定一个单击响应函数
var btn05 = document.getElementById("btn05");
btn05.onclick = function(){
//获取id为city的节点
var city = document.getElementById("city");
//返回#city的所有子节点
var cns = city.childNodes;
//alert(cns.length);
/*for(var i=0 ; i<cns.length ; i++){
alert(cns[i]);
}*/
/*
* children属性可以获取当前元素的所有子元素
*/
var cns2 = city.children;
alert(cns2.length);
};
firstElementChild获取当前元素的第一个子元素
firstElementChild不支持IE8及以下的浏览器,如果需要兼容他们尽量不要使用
//为id为btn06的按钮绑定一个单击响应函数
var btn06 = document.getElementById("btn06");
btn06.onclick = function(){
//获取id为phone的元素
var phone = document.getElementById("phone");
//返回#phone的第一个子节点
//phone.childNodes[0];
//firstChild可以获取到当前元素的第一个子节点(包括空白文本节点)
var fir = phone.firstChild;
//firstElementChild获取当前元素的第一个子元素
//fir = phone.firstElementChild;
alert(fir);
};
获取父节点和兄弟节点
• 通过具体的节点调用
- parentNode
– 属性,表示当前节点的父节点 - previousSibling
– 属性,表示当前节点的前一个兄弟节点
previousElementSiblingIE8不兼容 - nextSibling
– 属性,表示当前节点的后一个兄弟节点
元素节点的属性
-
获取,元素对象.属性名
• 例:element.value
• element.id
• element.className -
设置,元素对象.属性名=新的值
• 例:element.value = “hello”
• element.id = “id01”
• element.className = “newClass”
其他属性
• nodeValue (文本节点调用)
– 文本节点可以通过nodeValue属性获取和设置文本节点的内容
• innerHTML
– 元素节点通过该属性获取和设置标签内部的html代码
• innerText (文本父节点调用)
//获取id为bj的元素
var bj = document.getElementById("bj");
//alert(bj.innerHTML);
//alert(bj.innerText);
//获取bj中的文本节点
/*var fc = bj.firstChild;
alert(fc.nodeValue);*/
alert(bj.firstChild.nodeValue);
全选练习
items[i].checked = true;
/*
* 全选/全不选 多选框
* - 当它选中时,其余的也选中,当它取消时其余的也取消
*
* 在事件的响应函数中,响应函数是给谁绑定的this就是谁
*/
//为checkedAllBox绑定单击响应函数
checkedAllBox.onclick = function(){
//alert(this === checkedAllBox);
//设置多选框的选中状态
for(var i=0; i <items.length ; i++){
items[i].checked = this.checked;
}
};
dom查询其他方法
//获取body标签
//var body = document.getElementsByTagName("body")[0];
/*
* 在document中有一个属性body,它保存的是body的引用
*/
var body = document.body;
/*
* document.documentElement保存的是html根标签
*/
var html = document.documentElement;
/*
* document.all代表页面中所有的元素
*/
var all = document.all;
//console.log(all.length);
/*for(var i=0 ; i<all.length ; i++){
console.log(all[i]);
}*/
使用CSS选择器进行查询
- querySelector()
- querySelectorAll()
- 这两个方法都是用document对象来调用,两个方法使用相同,都是传递一个选择器字符串作为参数,方法会自动根据选择器字符串去网页中查找元素。
- 不同的地方是querySelector()只会返回找到的第一个元素,而
querySelectorAll()会返回所有符合条件的元素。
🌿节点的修改
-
这里的修改我们主要指对元素节点的操作。
-
创建节点
– document.createElement(标签名) -
删除节点
– 父节点.removeChild(子节点) -
替换节点
– 父节点.replaceChild(新节点 , 旧节点) -
插入节点
– 父节点.appendChild(子节点)
– 父节点.insertBefore(新节点 , 旧节点)
//创建一个"广州"节点,添加到#city下
myClick("btn01",function(){
//创建广州节点 <li>广州</li>
//创建li元素节点
/*
* document.createElement()
* 可以用于创建一个元素节点对象,
* 它需要一个标签名作为参数,将会根据该标签名创建元素节点对象,
* 并将创建好的对象作为返回值返回
*/
var li = document.createElement("li");
//创建广州文本节点
/*
* document.createTextNode()
* 可以用来创建一个文本节点对象
* 需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点返回
*/
var gzText = document.createTextNode("广州");
//将gzText设置li的子节点
/*
* appendChild()
* - 向一个父节点中添加一个新的子节点
* - 用法:父节点.appendChild(子节点);
*/
li.appendChild(gzText);
//获取id为city的节点
var city = document.getElementById("city");
//将广州添加到city下
city.appendChild(li);
});
//将"广州"节点插入到#bj前面
myClick("btn02",function(){
//创建一个广州
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");
/*
* insertBefore()
* - 可以在指定的子节点前插入新的子节点
* - 语法:
* 父节点.insertBefore(新节点,旧节点);
*/
city.insertBefore(li , bj);
});
//使用"广州"节点替换#bj节点
myClick("btn03",function(){
//创建一个广州
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");
/*
* replaceChild()
* - 可以使用指定的子节点替换已有的子节点
* - 语法:父节点.replaceChild(新节点,旧节点);
*/
city.replaceChild(li , bj);
});
//删除#bj节点
myClick("btn04",function(){
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");
/*
* removeChild()
* - 可以删除一个子节点
* - 语法:父节点.removeChild(子节点);
*
* 子节点.parentNode.removeChild(子节点);
*/
//city.removeChild(bj);
bj.parentNode.removeChild(bj);
});
- 使用innerHTML也可以完成DOM的增删改的相关操作
myClick("btn07",function(){
//向city中添加广州
var city = document.getElementById("city");
/*
* 使用innerHTML也可以完成DOM的增删改的相关操作
* 一般我们会两种方式结合使用
*/
//city.innerHTML += "<li>广州</li>";
//创建一个li
var li = document.createElement("li");
//向li中设置文本
li.innerHTML = "广州";
//将li添加到city中
city.appendChild(li);
});
练习:表格增删
//点击超链接以后需要删除超链接所在的那行
//这里我们点击那个超链接this就是谁
//获取当前tr
var tr = this.parentNode.parentNode;
🌿dom操作css
操作内联样式
元素.style.样式名 = 样式值
修改被import修饰的样式 -->传送门
//为按钮绑定单击响应函数
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//修改box1的宽度
/*
* 通过JS修改元素的样式:
* 语法:元素.style.样式名 = 样式值
*
* 注意:如果CSS的样式名中含有-,
* 这种名称在JS中是不合法的比如background-color
* 需要将这种样式名修改为驼峰命名法,
*
* 我们通过style属性设置的样式都是内联样式,
* 而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示
*
* 但是如果在样式中写了!important,则此时样式会有最高的优先级,
* 即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效
* 所以尽量不要为样式添加!important
*/
box1.style.width = "300px";
box1.style.height = "300px";
box1.style.backgroundColor = "yellow";
};
获取元素当前样式
: 只有IE浏览器支持,其他的浏览器都不支持box1.currentStyle.width
/*
* 获取元素的当前显示的样式
* 语法:元素.currentStyle.样式名
* 它可以用来读取当前元素正在显示的样式
* 如果当前元素没有设置该样式,则获取它的默认值
*
* currentStyle只有IE浏览器支持,其他的浏览器都不支持
*/
//alert(box1.currentStyle.width);
//box1.currentStyle.width = "200px";
//alert(box1.currentStyle.backgroundColor);
getComputedStyle()
:是window的方法,可以直接使用
/*
* 在其他浏览器中可以使用
* getComputedStyle()这个方法来获取元素当前的样式
* 这个方法是window的方法,可以直接使用
* 需要两个参数
* 第一个:要获取样式的元素
* 第二个:可以传递一个伪元素,一般都传null
*
* 该方法会返回一个对象,对象中封装了当前元素对应的样式
* 可以通过对象.样式名来读取样式
* 如果获取的样式没有设置,则会获取到真实的值,而不是默认值
* 比如:没有设置width,它不会获取到auto,而是一个长度
*
* 但是该方法不支持IE8及以下的浏览器
*
* 通过currentStyle和getComputedStyle()读取到的样式都是只读的,
* 不能修改,如果要修改必须通过style属性
*/
//var obj = getComputedStyle(box1,null);
/*alert(getComputedStyle(box1,null).width);*/
//正常浏览器的方式
//alert(getComputedStyle(box1,null).backgroundColor);
var w = getStyle(box1,"width");
/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj , name){
//属性没找到返回undefined
if(window.getComputedStyle){
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj , null)[name];
}else{
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}
//return window.getComputedStyle?getComputedStyle(obj , null)[name]:obj.currentStyle[name];
}
获取其他样式属性
属性 / 方法 | 描述 |
---|---|
element.clientHeight | 返回元素的可见高度。 |
element.clientWidth | 返回元素的可见宽度。 |
element.offsetHeight | 返回元素的高度。 |
element.offsetWidth | 返回元素的宽度。 |
element.offsetLeft | 返回元素的水平偏移位置。 |
element.offsetTop | 返回元素的垂直偏移位置。 |
element.offsetParent | 返回元素的偏移容器。 |
element.scrollHeight | 返回元素的整体高度。 |
element.scrollLeft | 返回元素左边缘与视图之间的距离。 |
element.scrollTop | 返回元素上边缘与视图之间的距离。 |
element.scrollWidth | 返回元素的整体宽度。 |
- 这些属性都是不带px的,返回都是一个数字,可以直接进行计算
- 这些属性都是只读的,不能修改
/*
* clientWidth
* clientHeight
* - 这两个属性可以获取元素的可见宽度和高度
* - 这些属性都是不带px的,返回都是一个数字,可以直接进行计算
* - 会获取元素宽度和高度,包括内容区和内边距
* - 这些属性都是只读的,不能修改
*/
//alert(box1.clientWidth);
//alert(box1.clientHeight);
//box1.clientHeight = 300;
/*
* offsetWidth
* offsetHeight
* - 获取元素的整个的宽度和高度,包括内容区、内边距和边框
*/
//alert(box1.offsetWidth);
/*
* offsetParent
* - 可以用来获取当前元素的定位父元素
* - 会获取到离当前元素最近的开启了定位的祖先元素
* 如果所有的祖先元素都没有开启定位,则返回body
*/
var op = box1.offsetParent;
//alert(op.id);
/*
* offsetLeft
* - 当前元素相对于其定位父元素的水平偏移量
* offsetTop
* - 当前元素相对于其定位父元素的垂直偏移量
*/
//alert(box1.offsetLeft);
/*
* scrollWidth
* scrollHeight
* - 可以获取元素整个滚动区域的宽度和高度
*/
//alert(box4.clientHeight);
//alert(box4.scrollWidth);
/*
* scrollLeft
* - 可以获取水平滚动条滚动的距离
* scrollTop
* - 可以获取垂直滚动条滚动的距离
*/
//alert(box4.scrollLeft);
//alert(box4.scrollTop);
//alert(box4.clientHeight); // 283
//当满足scrollHeight - scrollTop == clientHeight
//说明垂直滚动条滚动到底了
//当满足scrollWidth - scrollLeft == clientWidth
//说明水平滚动条滚动到底
//alert(box4.scrollHeight - box4.scrollTop); // 600
事件
获取div内鼠标坐标
- 在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
event = event || window.event;
clientX
可以获取鼠标指针的水平坐标,cilentY
可以获取鼠标指针的垂直坐标
var areaDiv = document.getElementById("areaDiv");
var showMsg = document.getElementById("showMsg");
areaDiv.onmousemove = function(event){
//解决事件对象的兼容性问题
event = event || window.event;
var x = event.clientX;
var y = event.clientY;
//在showMsg中显示鼠标的坐标
showMsg.innerHTML = "x = "+x + " , y = "+y;
};
div随鼠标移动
代码传送门
重点关注
- 获取事件对象的兼容性问题
//解决兼容问题
event = event || window.event;
- 获取pageX以及pageY的兼容性处理方法
- 如何兼容scrollTop,以及scrollLeft中对父子元素选定状态不同的情况
//获取滚动条滚动的距离
/*
* chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取
* 火狐等浏览器认为浏览器的滚动条是html的,
*/
var st = document.body.scrollTop || document.documentElement.scrollTop;
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
//var st = document.documentElement.scrollTop;
//获取到鼠标的坐标
/*
* clientX和clientY
* 用于获取鼠标在当前的可见窗口的坐标
* div的偏移量,是相对于整个页面的
*
* pageX和pageY可以获取鼠标相对于当前页面的坐标
* 但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用
*/
var left = event.clientX;
var top = event.clientY;
//设置div的偏移量
box1.style.left = left + sl + "px";
box1.style.top = top + st + "px";
事件冒泡
- 可以将事件对象的cancelBubble设置为true,即可取消冒泡
event.cancelBubble = true;
//为s1绑定一个单击响应函数
var s1 = document.getElementById("s1");
s1.onclick = function(event){
event = event || window.event;
alert("我是span的单击响应函数");
//取消冒泡
//可以将事件对象的cancelBubble设置为true,即可取消冒泡
event.cancelBubble = true;
};
事件委派
- 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素从而通过祖先元素的响应函数来处理事件。
- 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
window.onload = function(){
var u1 = document.getElementById("u1");
//点击按钮以后添加超链接
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//创建一个li
var li = document.createElement("li");
li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";
//将li添加到ul中
u1.appendChild(li);
}
var allA = document.getElementsByTagName("a");
//为ul绑定一个单击响应函数
u1.onclick = function(event){
event = event || window.event;
//可以使用正则判断hasClass
if(event.target.className == "link"){
alert("我是ul的单击响应函数");
}
};
};
/*
* 判断一个元素中是否含有指定的class属性值
* 如果有该class,则返回true,没有则返回false
*
*/
function hasClass(obj, cn) {
//判断obj中有没有cn class
//创建一个正则表达式
//var reg = /\bb2\b/;
var reg = new RegExp("\\b" + cn + "\\b");
return reg.test(obj.className);
}
事件绑定
- 使用 对象.事件 = 函数 的形式绑定响应函数,它只能同时为一个元素的一个事件绑定一个响应函数,不能绑定多个,如果绑定了多个,则后边会覆盖掉前边的
- addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数(不支持IE8及以下的浏览器)
- attachEvent() 在IE8中可以使用attachEvent()来绑定事件
不同的是它是后绑定先执行,执行顺序和addEventListener()相反
/*
* addEventListener()
* - 通过这个方法也可以为元素绑定响应函数
* - 参数:
* 1.事件的字符串,不要on
* 2.回调函数,当事件触发时该函数会被调用
* 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
*
* 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
* 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
* 这个方法不支持IE8及以下的浏览器
*/
btn01.addEventListener("click",function(){
alert(1);
},false);
/*
* attachEvent()
* - 在IE8中可以使用attachEvent()来绑定事件
* - 参数:
* 1.事件的字符串,要on
* 2.回调函数
*
* - 这个方法也可以同时为一个事件绑定多个处理函数,
* 不同的是它是后绑定先执行,执行顺序和addEventListener()相反
*/
btn01.attachEvent("onclick",function(){
alert(1);
});
定义一个函数,用来为指定元素绑定响应函数
obj.addEventListener 是否有该方法使用哪个方式
addEventListener()中的this,是绑定事件的对象
attachEvent()中的this,是window
外套一层匿名函数,在中调用回调函数并指定this对象
//定义一个函数,用来为指定元素绑定响应函数
/*
* addEventListener()中的this,是绑定事件的对象
* attachEvent()中的this,是window
* 需要统一两个方法this
*/
/*
* 参数:
* obj 要绑定事件的对象
* eventStr 事件的字符串(不要on)
* callback 回调函数
*/
function bind(obj , eventStr , callback){
if(obj.addEventListener){
//大部分浏览器兼容的方式
obj.addEventListener(eventStr , callback , false);
}else{
/*
* this是谁由调用方式决定
* callback.call(obj)
*/
//IE8及以下
obj.attachEvent("on"+eventStr , function(){
//在匿名函数中调用回调函数
callback.call(obj);
});
}
}
事件传播
* 事件的传播
* - 关于事件的传播网景公司和微软公司有不同的理解
* - 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,
* 然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
* - 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,
* 然后在向内传播给后代元素
* - W3C综合了两个公司的方案,将事件传播分成了三个阶段
* 1.捕获阶段
* - 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
* 2.目标阶段
* - 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
* 3.冒泡阶段
* - 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
*
* - 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
* 一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
*
* - IE8及以下的浏览器中没有捕获阶段
拖拽
拖拽的流程
1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
兼容性处理
在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
event = event || window.event;
setCapture()
:当鼠标点击后捕获所有的事件到该事件下只有IE支持,但是在火狐中调用时不会报错,而如果使用chrome调用,会报错
obj.setCapture && obj.setCapture();
同理
releaseCapture()
:当鼠标抬起时释放捕获的事件obj.releaseCapture && obj.releaseCapture();
/* * 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容, * 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为, * 如果不希望发生这个行为,则可以通过return false来取消默认行为 * * 但是这招对IE8不起作用 */ return false;
细节处理
鼠标在元素中的位置,鼠标的坐标 - 元素的偏移量 = 鼠标在元素中的偏移量
//div的偏移量 鼠标.clentX - 元素.offsetLeft //div的偏移量 鼠标.clentY - 元素.offsetTop var ol = event.clientX - obj.offsetLeft; var ot = event.clientY - obj.offsetTop;
鼠标移动时,元素的定位位置与鼠标位置相同,但需要计算出对应之前的偏移量(即鼠标在元素中的位置)
//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove //获取鼠标的坐标 : 不用考虑出现滚动条的问题了 var left = event.clientX - ol; var top = event.clientY - ot; // //修改box1的位置 obj.style.left = left+"px"; obj.style.top = top+"px";
结构
<body>
我是一段文字
<div id="box1"></div>
<div id="box2"></div>
<img src="img/an.jpg" id="img1" style="position: absolute;"/>
</body>
滚动事件
代码传送门
实验需求: 给box添加鼠标滚动事件,让盒子边长变短
- 获取事件兼容处理
event = event || window.event;
- 绑定滚动事件兼容性处理
- onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发,但是火狐不支持该属性
- 在火狐中需要使用 DOMMouseScroll 来绑定滚动事件,注意该事件需要通过addEventListener()函数来绑定
window.onload = function(){ var box1 = document.getElementById("box1"); box1.onmousewheel = function(event){ //xxxxxx } //为火狐绑定滚轮事件 bind(box1,"DOMMouseScroll",box1.onmousewheel); }; function bind(obj , eventStr , callback){ if(obj.addEventListener){ //大部分浏览器兼容的方式 obj.addEventListener(eventStr , callback , false); }else{ /* * this是谁由调用方式决定 * callback.call(obj) */ //IE8及以下 obj.attachEvent("on"+eventStr , function(){ //在匿名函数中调用回调函数 callback.call(obj); }); } }
- 滚轮方向兼容性处理
//event.wheelDelta 可以获取鼠标滚轮滚动的方向 //向上滚 120 向下滚 -120 //wheelDelta这个值我们不看大小,只看正负 //wheelDelta这个属性火狐中不支持 //在火狐中使用event.detail来获取滚动的方向 //向上滚 -3 向下滚 3 //alert(event.detail); /* * 当鼠标滚轮向下滚动时,box1变长 * 当滚轮向上滚动时,box1变短 */ //判断鼠标滚轮滚动的方向 if(event.wheelDelta > 0 || event.detail < 0){ //向上滚,box1变短 box1.style.height = box1.clientHeight - 10 + "px"; }else{ //向下滚,box1变长 box1.style.height = box1.clientHeight + 10 + "px"; }
- 兼容阻止默认行为
/* * 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false * 需要使用event来取消默认行为event.preventDefault(); * 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错 */ event.preventDefault && event.preventDefault(); /* * 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动, * 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为 */ return false;
键盘事件
onkeydown
onkeyup
键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document
- 使用keyCode获取按键值
document.onkeydown = function(event){ event = event || window.event; /* * 可以通过keyCode来获取按键的编码 * 通过它可以判断哪个按键被按下 * 除了keyCode,事件对象中还提供了几个属性 * altKey * ctrlKey * shiftKey * - 这个三个用来判断alt ctrl 和 shift是否被按下 * 如果按下则返回true,否则返回false */ //console.log(event.keyCode); //判断一个y是否被按下 //判断y和ctrl是否同时被按下 if(event.keyCode === 89 && event.ctrlKey){ console.log("ctrl和y都被按下了"); } };
- 取消默认行为
//console.log(event.keyCode); //数字 48 - 57 ,小键盘是 96-105 //使文本框中不能输入数字 if(event.keyCode >= 48 && event.keyCode <= 57){ //在文本框中输入内容,属于onkeydown的默认行为 //如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中 return false; }
将按键存储在对象中或集合中
var map = {}; // You could also use an array
onkeydown = onkeyup = function(e){
e = e || window.event; // to deal with IE
map[e.keyCode] = e.type == 'keydown';
/* insert conditional here */
}
test_keys(13, 16, 65)
test_keys('ctrl', 'shift', 'A')
test_key(65)
test_key('A')
if(test_keys('ctrl', 'shift')){
if(test_key('A')){
alert('Control Shift A');
} else if(test_key('B')){
alert('Control Shift B');
} else if(test_key('C')){
alert('Control Shift C');
}
}
function test_key(selkey){
var alias = {
"ctrl": 17,
"shift": 16,
"A": 65,
/* ... */
};
return key[selkey] || key[alias[selkey]];
}
function test_keys(){
var keylist = arguments;
for(var i = 0; i < keylist.length; i++)
if(!test_key(keylist[i]))
return false;
return true;
}
Navigator
* BOM
* - 浏览器对象模型
* - BOM可以使我们通过JS来操作浏览器
* - 在BOM中为我们提供了一组对象,用来完成对浏览器的操作
* - BOM对象
* Window
* - 代表的是整个浏览器的窗口,同时window也是网页中的全局对象
* Navigator
* - 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
* Location
* - 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
* History
* - 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
* 由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页
* 而且该操作只在当次访问时有效
* Screen
* - 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息
*
*
* 这些BOM对象在浏览器中都是作为window对象的属性保存的,
* 可以通过window对象来使用,也可以直接使用
识别浏览器是哪个
* Navigator
* - 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
* - 由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了
* - 一般我们只会使用userAgent来判断浏览器的信息,
* userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,
* 不同的浏览器会有不同的userAgent
*
* 火狐的userAgent
* Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
*
* Chrome的userAgent
* Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36
*
* IE8
* Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
*
* IE9
* Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
*
* IE10
* Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
*
* IE11
* Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko
* - 在IE11中已经将微软和IE相关的标识都已经去除了,所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了
var ua = navigator.userAgent;
console.log(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,枪毙了你~~~");
}
/*
* 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息
* 比如:ActiveXObject
*/
/*if("ActiveXObject" in window){
alert("你是IE,我已经抓住你了~~~");
}else{
alert("你不是IE~~~");
}*/
/*alert("ActiveXObject" in window);*/
History
对象可以用来操作浏览器向前或向后翻页
* length
* - 属性,可以获取到当成访问的链接数量
alert(history.length);
* back()
* - 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
history.back();
* forward()
* - 可以跳转下一个页面,作用和浏览器的前进按钮一样
history.forward();
* go()
* - 可以用来跳转到指定的页面
* - 它需要一个整数作为参数
* 1:表示向前跳转一个页面 相当于forward()
* 2:表示向前跳转两个页面
* -1:表示向后跳转一个页面
* -2:表示向后跳转两个页面
window.onload = function(){
//获取按钮对象
var btn = document.getElementById("btn");
btn.onclick = function(){
history.go(-2);
};
};
Location
该对象中封装了浏览器的地址栏的信息
- 如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
alert(location); //https://www.bilibili.com/video/BV1YW411T7GX?p=126&spm_id_from=pageDriver
- 如果直接将location属性修改为一个完整的路径,或相对路径,
则我们页面会自动跳转到该路径,并且会生成相应的历史记录
location = "http://www.baidu.com"; location = "01.BOM.html";
- assign() 用来跳转到其他的页面,作用和直接修改location一样
location.assign("http://www.baidu.com");
- reload()
用于重新加载当前页面,作用和刷新按钮一样
如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
location.reload(true);
- replace()
可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
不会生成历史记录,不能使用回退按钮回退
location.replace("01.BOM.html");
window 方法
定时调用
setInterval() :可以将一个函数,每隔一段时间执行一次
参数: 1.回调函数,该函数会每隔一段时间被调用一次 2.每次调用间隔的时间,单位是毫秒 返回值: 返回一个Number类型的数据 这个数字用来作为定时器的唯一标识
var timer = setInterval(function(){ count.innerHTML = num++; if(num == 11){ //关闭定时器 clearInterval()可以用来关闭一个定时器 //方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器 clearInterval(timer); } },1000);
延时调用
延时调用
延时调用一个函数不马上执行,而是隔一段时间以后在执行,而且只会执行一次
延时调用和定时调用的区别,定时调用会执行多次,而延时调用只会执行一次
延时调用和定时调用实际上是可以互相代替的,在开发中可以根据自己需要去选择var timer = setTimeout(function(){ console.log(num++); },3000); //使用clearTimeout()来关闭一个延时调用 clearTimeout(timer);
定时应用(一)
类的操作
通过style属性来修改元素的样式,每修改一个样式,浏览器就需要重新渲染一次页面
这样的执行的性能是比较差的,而且这种形式当我们要修改多个样式时,也不太方便
//定义一个函数,用来向一个元素中添加指定的class属性值
/*
* 参数:
* obj 要添加class属性的元素
* cn 要添加的class值
*
*/
function addClass(obj , cn){
//检查obj中是否含有cn
if(!hasClass(obj , cn)){
obj.className += " "+cn;
}
}
/*
* 判断一个元素中是否含有指定的class属性值
* 如果有该class,则返回true,没有则返回false
*
*/
function hasClass(obj , cn){
//判断obj中有没有cn class
//创建一个正则表达式
//var reg = /\bb2\b/;
var reg = new RegExp("\\b"+cn+"\\b");
return reg.test(obj.className);
}
/*
* 删除一个元素中的指定的class属性
*/
function removeClass(obj , cn){
//创建一个正则表达式
var reg = new RegExp("\\b"+cn+"\\b");
//删除class
obj.className = obj.className.replace(reg , "");
}
/*
* toggleClass可以用来切换一个类
* 如果元素中具有该类,则删除
* 如果元素中没有该类,则添加
*/
function toggleClass(obj , cn){
//判断obj中是否含有cn
if(hasClass(obj , cn)){
//有,则删除
removeClass(obj , cn);
}else{
//没有,则添加
addClass(obj , cn);
}
}
二级菜单
JSON
* JSON
* - JS中的对象只有JS自己认识,其他的语言都不认识
* - JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,
* 并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的交互
* - JSON
* - JavaScript Object Notation JS对象表示法
* - JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号
* 其他的和JS语法一致
* JSON分类:
* 1.对象 {}
* 2.数组 []
*
* JSON中允许的值:
* 1.字符串
* 2.数值
* 3.布尔值
* 4.null
* 5.对象
* 6.数组
//创建一个对象
var arr = '[1,2,3,"hello",true]';
var obj2 = '{"arr":[1,2,3]}';
var arr2 ='[{"name":"孙悟空","age":18,"gender":"男"},{"name":"孙悟空","age":18,"gender":"男"}]';
/*
* 将JSON字符串转换为JS中的对象
* 在JS中,为我们提供了一个工具类,就叫JSON
* 这个对象可以帮助我们将一个JSON转换为JS对象,也可以将一个JS对象转换为JSON
*/
var json = '{"name":"孙悟空","age":18,"gender":"男"}';
/*
* json --> js对象
* JSON.parse()
* - 可以将以JSON字符串转换为js对象
* - 它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
*/
var o = JSON.parse(json);
var o2 = JSON.parse(arr);
//console.log(o.gender);
//console.log(o2[1]);
var obj3 = {name:"猪八戒" , age:28 , gender:"男"};
/*
* JS对象 ---> JSON
* JSON.stringify()
* - 可以将一个JS对象转换为JSON字符串
* - 需要一个js对象作为参数,会返回一个JSON字符串
*/
var str = JSON.stringify(obj3);
//console.log(str);
/*
* JSON这个对象在IE7及以下的浏览器中不支持,所以在这些浏览器中调用时会报错
*/
var str3 = '{"name":"孙悟空","age":18,"gender":"男"}';
JSON.parse(str3);
var str = '{"name":"孙悟空","age":18,"gender":"男"}';
/*
* eval()
* - 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
* - 如果使用eval()执行的字符串中含有{},它会将{}当成是代码块
* 如果不希望将其当成代码块解析,则需要在字符串前后各加一个()
*
* - eval()这个函数的功能很强大,可以直接执行一个字符串中的js代码,
* 但是在开发中尽量不要使用,首先它的执行性能比较差,然后它还具有安全隐患
*/
var str2 = "alert('hello');";
var obj = eval("("+str+")");