完整的JavaScript由三部分组成
JavaScript的核心(ECMAScript)
文档对象模型(DOM, Document Object Model)
浏览器对象模型(BOM, Browser Object Model)
HTML5 “就是” JavaScript
HTML5的威力在于让你能用JavaScript来创建这些标签。如果没有后台代码的支持,来创建一个动画效果、游戏、或是可视化工具,那么,图形画布(Canvas)毫无用处。自从出现支持Canvas的浏览器,我们看到了Asteroids游戏的上百个实现,这些都是开发人员为了熟悉HTM5新特性。有的比较粗糙,而有的则极其精致。这些工作完全归功于JavaScript。
不推荐在html结构的事件属性中书写JS代码
JS代码可以写在Scirpt元素中
一个页面可以拥有多个script元素
并且 script元素可以出现在页面的任意位置
script元素type属性默认是 text/javascript 一般可以省略
alert('我是在head中的script元素');
JavaScript中所有的符号都是英文符号。
<script src="./eg02.outter.js">
// 当一个script元素被用于引入外部文件时
// 该元素内部的代码会被自动忽略
alert('123');
</script>
结果不会输出123
<script>
console.log(1);
console.Log(2);
// 代码一旦出现错误 JS解释器就会终止执行
console.abc(3);
console.log(4);
</script>
<script>
console.log(5);
console.log(6);
</script>
这段代码最后的结果是1 5 6
ECMASJavaScript的变量是松散类型的,所谓松散类型就是可以用来保存任何类型
的数据。定义变量时要使用var(var是一个关键字),后跟变量名(即一个标识符)。
当声明一个变量时,就创建了一个新的对象。
什么是变量
变量是存储信息的容器
例如:
x = 1;
y = 3;
sum = x + y;
在JavaScript中,这些字母被成为变量。
var age1 = 20, // 20
age2; // undefined
1. var a = 10;
var b = 8;
var c;
c = a;
a = b;
b = c;
console.log(a);
console.log(b);
2. a = a + b; // a = 18 , b = 8
b = a - b; // b = 10 , a = 18
a = a - b; // a = 8 , b = 10
console.log(a);
console.log(b);
保留字在某种意义上是为将来的关键字而保留的单词,因此保留字也不能被用作变
量名或函数名。
注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,
该单词将被看做关键字,如此将出现关键字错误。
var a;
a = 1;
var a = "1234";
var b = a;
var age = 1;
age = 2;
UNdefined类型只有一个值就是undefined
该值表示一个变量声明没有赋值的情况
var num;
console.log(num); // undefined
console.log(typeof num); // 'undefined'
var car = undefined; // 无意义 默认值就是undefined
Null类型 只有一个值 就是null
var car = null;
console.log(car);//null
console.log(typeof car); // 'object' 因为null是空对象指针 所以返回'object'
console.log(num == car); // true
Number类型 表示数值
var x = 10;
var y = 3.14;
console.log(typeof x); // 'number'
console.log(typeof y); // 'number'
Not a Number
表示一个要返回数值的操作没有返回数值的结果
console.log(typeof NaN); // 'number'
console.log(3 + 5);//8
console.log(3 * 5);// 15
console.log(3 * 'a');//NaN
判断是否是无效数字
如果是无效数字(NaN)则返回 true(真)
否则返回false(假)
console.log(isNaN(NaN));//true
字符串类型 引号中所有内容都叫字符串 无论是单引号 或双引号’’ “”
Java语言中’'是字符 char类型 单个字符 ‘a’
"“是字符串 string类型 多个字符"abc”
在JS中单引号和双引号 都是String类型
一般使用情况 外层使用单引号
console.log('你好世界');//'你好世界'
console.log("");
console.log('你好\\世界'); //'你好\世界'
console.log(typeof 'hello'); // 'string'
console.log(typeof typeof 3); // 'string'
布尔类型
只有两个值 true和false
在实际运算中 true== 1 false == 0
布尔值可以直接参与运算
console.log(1 + true);//2
console.log(3 - false);//3
console.log(3 / false); // Infinity 无穷 任何数除以0 都会得到 Infinity
console.log(true);//true
console.log('123');//'123'
console.log(123);//123
console.log(undefined);//undefined
console.log(null);//null
new关键字用于创建对象 new后面跟随的是构造函数
var o = new Object();
console.log(o);//'object'
console.log(typeof o); // 'object'
为新创建的对象性添加属性我们使用’.'操作符
对象是由无序的名值对组成 属性是没有顺序的
名值对 在编程中通常被称作为键值对key-value
var o = new Object();
o.name = 'zhansgan';
o.age = 18;
console.log(o);//{name: "zhansgan", age: 18}
对象的属性可以直接通过key进行访问
对象中可以保存多个键值对
键可以理解是变量名
console.log(o.name);//'zhansgan'
需求:存储一个用户名字 性别 年龄 身高 4条信息描述的是一个整体 一个个体
var userName = 'zhangsan'; var sex = '男'; var age = 21; var height = '170cm';
为对象赋值不存在的属性叫做添加属性
为对象赋值已存在的属性叫做修改属性值
var user = new Object();
user.name = '张三';
user.sex = '男';
user.age = 21;
user.height = '170cm';
user.age = 25;
console.log(user);//{name: "张三", sex: "男", age: 25, height: "170cm"}
console.log(user.height);//'170cm'
由于我们的JavaScript是弱类型语言
在声明变量时不需要指定数据类型
所以需要数据类型检测手段
typeof就是用来满足该需求的
typeof返回的是字符串
console.log(typeof isNaN);//'function'
• 算数运算 + - * / % ++ –
• 关系运算> < >= <= == === != !==
• 逻辑运算 && || !
• 赋值运算 = += -= *= /= %=
• 字符链接 +
• 条件(三目)运算 ? :
判断一个数是奇数还是偶数
console.log(3 % 2);//1
console.log(9 % 3);//0
console.log(5 % 2); // 任何整数模2 余数为1的是奇数 否则是偶数
自增/自减 运算符
将值自身+1或-1
var num = 3;
num++; // num = num + 1; 4
num--; // num = num - 1; 3
在使用自增和自减 运算符时
++/–在前 先运算后使用
++/–在后 先使用后运算
var a = 5;
console.log(a++ - --a + a++ + a++ - --a + a - ++a - a); // -3
5 - 5 + 5 + 6 - 6 + 6 - 7 - 7
6 5 6 7 6 6 7 7
console.log(a); // 7
console.log(3 > 5);//false
console.log(5 < 7);//true
console.log(3 >= 3);//true
console.log(0 <= 0);//true
正常比较数字的时候 比较数值大小
但是在出现字符串比较的时候 情况不一样
在第2个字符串比较大小的时候 比较的是字符串的Unicode编码
当第一个字符的编码相同的时 比较第二个字符的Unicode编码
数字的Unicode编码是48-57 表示0-9
console.log('你' < '好');//true
console.log(1 >= true);//true
console.log("11" > "110");//false
console.log("22" > "23");//false
console.log("12" > "13");//false
console.log(1 < "3");//true
相等操作符(==) 如果比较两个值相等 则返回true 否则返回false
不相等操作符(!=) 如果比较的两个值不相等 则返回true 否则返回false
相等操作符和不相等操作符 在比较值之前都会进行数据类型的转换(相同类型除外)
如果有布尔值 先将布尔值转成数值进行比较
如果有一个操作数是字符串 另一个操作数是数值 先将字符串转换成数值 再进行比较
console.log(123 == '123'); // 转换后是 123 == 123 true
console.log(25 != '25'); // 转换后是 25 != 25 false
console.log(1 == true); // 转换后是 1 == 1 true
console.log(23 == '23a'); // 转换后是 23 == NaN false
可以用于JS中的任意值(任意类型)
console.log(Boolean(-1));//true
console.log(!3);//false
console.log(!0);//true
console.log(!!0);//false
console.log(!null);//true
console.log(!undefined);//true
console.log(!NaN);//true
var obj = new Object();
console.log(!obj);false
console.log(!'123'); // false
console.log(!'abc'); // false
console.log(!' '); // false
console.log(!''); // true
逻辑与(&&)
逻辑与有两个表达式组成
两个表达式都为布尔表达式
当两个布尔表达式的结果同为true的时候 逻辑与的结果为true
只要有一个结果为false 逻辑与的结果就为false
console.log(5 > 3 && 3 > 2);//true
console.log(3 + 3 == 5 && 2 + 2 == 4);//false
console.log(!123 && !false);//false
短路逻辑(最小化求值)
是计算机的一种求值策略
当逻辑与 左右两边的值
第一个值为true的时候 返回第二个值
第一个值为false的时候 返回第一个值
console.log(2 && 3);//3
console.log(4 && 3);//3
console.log(0 && 3);//0
console.log(-1 && 3);//3
console.log(3 && -1);//-1
console.log('35' && false);//false
console.log(-5 && NaN);//NaN
console.log(null && 123);//null
逻辑或(||)
两个布尔表达式
当两个布尔表达式任意一个结果为true时 逻辑或结果为true
两个布尔表达式结果都为false时 结果为false
console.log(3 > 5 || 5 > 3);//true
console.log(3 + 3 == 7 || 3 % 2 == 0);//false
短路逻辑
逻辑或
第一个值为true时 返回第一个值
第一个值为false时 返回第二个值
console.log(3 || 5);//3
console.log(0 || 3);//3
console.log(null || undefined);//undefined
var obj = new Object();
console.log(obj || 123);//Object
var num1 = 10;
// num1 = num1 + 5;
num1 += 5;
num1 -= 3; // num1 = num1 - 3;
num1 *= 2; // num1 = num1 * 2;
num1 /= 8; // num1 = num1 / 8;
num1 %= 2;
console.log(num1);
console.log(!3 * 5);//0
用于字符串的连接
如果+左右都是字符串 直接连接
console.log(‘123’ + ‘123’);//‘123123’
console.log(123 + '3'); // '123' + '3'
console.log(undefined + '123'); //undefined 转字符串 'undefined'
console.log(null + '123'); // null 转字符串 'null'
console.log(NaN + 'a'); // NaN 转字符串 'NaN'
console.log(true + 'abc'); // true转字符串 'true'
console.log(false + '123'); //false 转字符串 'false'
console.log(null + 5); // 5
console.log(NaN + 3); // NaN和任何数值进行任何运算 结果都是NaN
条件运算符(三元运算符 三目运算符)
? :
语法:表达式1?表达式2:表达式3;
条件运算符 共有三个表达式 也可以看作是三个操作数
条件运算符 会先判断表达式1(布尔表达式)的值
如果表达式1的结果为true 则执行表达式2(整个条件运算符的结果是表达式2)
如果表达式1的结果为false 则执行表达式3(整个条件运算符的结果是表达式3)
条件运算符可以配合赋值运算符使用
var age = 18;
// console.log(age >= 18 ? '成年' : '未成年');
var result = age >= 18 ? '成年' : '未成年';
console.log(result);
如果条件运算符的第一个表达式 不是 布尔表达式
它会自动将其转换为布尔值
var num = 67;
console.log(num % 2 ? "奇数" : "偶数");//'偶数'
var num;
console.log(num ? '1' : '2');//'2'
JS是弱类型语言 不需要指定数据的类型
数据类型是由赋值操作来决定的
console.log(3 + '5'); // '35'
算术运算符 结果一定是number类型
如果算术运算表达式不是number类型 会自动转换为number类型 进行运算
console.log(3 * '5'); // 15
console.log(32 + null); // 32
undefined参数的任何算术运算 结果都是 NaN
console.log(2 + undefined); // NaN
console.log('3' * '2'); // 6
console.log(15 * '1.1a'); // NaN // Number('1.1a') NaN
快速转换
快速转number类型
加号和减号可以进行快速转换
如果是减号 转换结果是负数
console.log(+'35');//'35'
console.log(3 + +'2');//5
console.log(-'3');//-3
console.log(+'-123');//-123
console.log(-'-123');//123
快速转字符串
拼接空字符串
console.log(354 + '');//'354'
快速转布尔值
使用双!!进行转换
console.log(!!'123');//true
console.log(true + '');//'true'
Numebr()
将一个字符串解析为number类型,如果有不可解析的部分则返回NaN
console.log(Number('123'));//'123'
console.log(Number('123.123'));'123.123'
console.log(Number('123.12a')); // NaN
parseFloat()
将一个字符串解析为number类型,保留浮点部分,若字符串不可解析则返回NaN
console.log(parseFloat('123.123'));//123.123
console.log(parseFloat('123.12a')); // 123.12
console.log(parseFloat('12a3.123')); // 12
console.log(parseFloat('a123.123')); // NaN
console.log(parseFloat('.123')); // 0.123
console.log(parseFloat('.12.3')); // 0.12
parseInt()
将一个字符串解析为number类型,保留整数部分,若字符串不可解析则返回NaN
console.log(parseInt('123.12'));//123
console.log(parseInt('12a3')); // 12
console.log(parseInt('0.12a3')); // 0
console.log(parseInt('a13')); // NaN
Boolean()
将操作数转为布尔类型
任意非0数 true
任意非空字符串 true
任意对象 true
console.log(Boolean(null));
console.log(Boolean(NaN));
console.log(Boolean(undefined));
console.log(Boolean(0));
console.log(Boolean(0.0));
console.log(Boolean(""));
//都为false
toString()
将一个值转换字符串 JS中任何数据类型都能转字符串
true false undefined null NaN 原样转换
var PI = 3.14; // 常量命名规范全大写
console.log(PI.toString());//3.14
console.log(true.toString());//true
console.log(NaN.toString());//NaN
二进制数
3 11
9 1001
2147483647 2^31-1
var num = 2147483647;
console.log(num.toString(2));
八进制
在JS中以0开头的数为8进制数
var num = 13;
console.log(num.toString(8));
console.log(013);
十六进制
在JS中十六进制的数以0x开头
var num = 255;
console.log(num.toString(16));
console.log(0x16)
var o = new Object();
o.a = 123;
console.log(o.toString()); // 所有对象转字符串都是 ‘[object Obejct]’
流程控制简介
if语句用于处理分支逻辑
• if判定中默认必须一个Boolean值。
• 若出现的值不是boolean类型,则会自动转换
• 下列值默认都会自动转换为false
• if(0){}
• if(null){}
• if(undefined){}
• if(NaN){}
• if(’’){}
• if(0.0){}
var age = 18;
console.log(1);
if (age >= 18) { // 当if语句中的小括号内的布尔表达式结果为真
// 执行大括号内的语句
console.log(2);
console.log('成年人');
}
console.log(3);
if ('abc') { // 当if语句中的值不是布尔类型时 会自动将其转换为布尔类型
console.log('ok');
}
由于if语句会自动将括号内的值转成布尔类型 所以经常被用来判断东西是否存在
var a;
if (!a) {
a = 10;
console.log(a);
}
当if语句内只有一条语句时可以省略大括号
如果要省略大括号 将语句和if关键字写在同一行
if (false) console.log('ok');
console.log('no');
else关键字必须和if关键字配合使用 无法单独使用
使用if-else可以实现基本的分支功能
if语句的布尔表达式 如果为true 执行if代码块
if语句的布尔表达式 如果未false 执行else代码块
var age = 17;
if (age >= 18) {
console.log('成年人');
} else {
console.log('未成年人 ');
}
var result = age >= 18 ? "成年人" : "未成年人";
console.log(result);
所有的三目运算都可以使用if-else代替
但是不是所有的if-else都能用三目运算代替
age >= 18 ? console.log('成年人') : console.log('未成年');
prompt() 用于接收用户输入的信息 接收到的输入内容是字符串类型
var num = prompt('请输入一个数字');
console.log(num);
var age = parseInt(prompt('请输入年龄'));
if (age >= 18) {
alert('成年人,蹦迪');
} else {
alert('未成年,禁止入内');
}
if语句的嵌套
在else中又写了一个if条件
在第一个条件不满足的情况下 判断第二个条件是否满足情况
照成了if-else的嵌套写法
else-if 语句
用于解决if-else的嵌套问题
else-if允许有多个 从上往下依次判断,只要有任意一个条件为true 则执行代码段 结束
var age = parseInt(prompt('请输入年龄'));
1.if (isNaN(age)) {
alert('年龄输入错误');
} else {
if (age >= 18) {
alert('蹦迪');
} else {
alert('禁止入内');
}
}
2.if (isNaN(age)) {
alert('年龄输入错误');
} else if (age >= 18) {
alert('蹦迪');
} else {
alert('禁止入内');
}
程序流程图是人们对解决问题的方法、思
路或算法的一种描述。
1.流程图的优点:
(a)采用简单规范的符号,画法简单;
(b)结构清晰,逻辑性强;
(c)便于描述,容易理解。
2.流程图采用的符号
(a)椭圆表示开始和结束
(b)箭头表示的是控制流
(c)菱形表示的是逻辑条件
(d)矩形表示的是加工步骤
天数判断练习
接收用户输入的 年份 月份
判断用户输入的这个月份有多少天
大月 1 3 5 7 8 10 12 31天
小月 4 6 9 11 30天
2月 闰年29天 平年28天
var y = parseInt(prompt('请输入一个年份'));
var m = parseInt(prompt('请输入一个月份'));
console.log('您输入的年份是' + y + ',您输入的月份是' + m);
判断平年还剩闰年
闰年指的是能被4整除且不能被100整除 或者 可以被400整除的
if (m == 2) {
//判断平年 闰年
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
console.log('您输入的' + y + '年,2月有29天');
} else {
console.log('您输入的' + y + '年,2月有28天');
}
} else if (m == 4 || m == 6 || m == 9 || m == 11) {
console.log('您输入的' + y + '年,' + m + '月有30天');
} else {
console.log('您输入的' + y + '年,' + m + '月有31天');
}
switch-case语句是一种特殊的分支结构,可以根据一个表达式的不同取值,
从不同的程序入口开始执行
switch-case和break联合使用,break语句的作用在于跳出switch结构
switch 用于实现分支结构
switch-case 当case等于某个值的时候开始执行,程序往下继续执行直到遇到break关键字为止
所有switch能完成的任务都可以使用if-else结构代替
siwtch-case 的结构更清晰 并且执行效率更高
语法:
switch(表达式){
case 值:
语句1;
break;
default:
语句n;
}
switch-case的优势
• switch-case常常和break语句结合使用实现分支功能
• switch-case在实现分支功能时和if–else的主要区别在于:
• if…else…可以判定相等或不等的情况,适用性广
• switch…case…结构更清晰、效率更高;但是一般只用于指定变量相等于某个范围内的某个特定的值
常量 值是恒定不可变的 命名规范全大写
变量 存储信息的容器 值可以改变
1.获取系统中的星期
var day = new Date().getDay(); // 获取系统中的星期 取值返回是0-6
switch (day) {
case 1:
console.log('星期一');
break;
case 2:
console.log('星期二');
break;
case 3:
console.log('星期三');
break;
case 4:
console.log('星期四');
console.log('...');
break;
case 5:
console.log('星期五');
break;
case 6:
console.log('星期六');
break;
default:
console.log('星期天');
}
2.天数判断
var y = parseInt(prompt('请输入一个年份'));
var m = parseInt(prompt('请输入一个月份'));
if (m == 2) {
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
console.log('您输入的' + y + '年,2月有29天');
} else {
console.log('您输入的' + y + '年,2月有28天');
}
} else {
switch (m) {
// switch不写break
// 代码会继续往下执行
// 穿透执行
case 4:
case 6:
case 9:
case 11:
console.log('30天');
break;
default:
console.log('31天');
}
}
3.用户输入一个 年月日
判断该天是该年的第几天
使用switch的穿透写法 进行数据累加
var y = parseInt(prompt('请输入年份'));
var m = parseInt(prompt('请输入月份'));
var d = parseInt(prompt('请输入日期'));
// 假设 2019年 3月 22日
// 31+28+22
// 使用switch的穿透写法 进行数据累加
var sum = 0; // 总天数
switch (m) {
case 12:
sum += 30; //加的是11月的天数
case 11:
sum += 31; //10月
case 10:
sum += 30;
case 9:
sum += 31;
case 8:
sum += 31;
case 7:
sum += 30;
case 6:
sum += 31;
case 5:
sum += 30;
case 4:
sum += 31;
case 3:
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
sum += 29;
} else {
sum += 28;
}
case 2:
sum += 31;
case 1:
sum += d;
}
console.log(y + '年' + m + '月' + d + '日,是' + y + '年的第' + sum + '天');
什么是循环结构
while语句的循环语法格式:
while(boolean表达式){
循环体语句
}
含义:若boolean表达式为true,则执行一遍循环体中的语句;然后再判断
一次boolean表达式,若为true,则再次执行一遍循环体中的语句…直到
boolean表达式的值false 则循环结束
含义:
while语句是一个循环结构,小括号内放的是循环条件的布尔表达式,如果给定的表达式不是布尔表达式,则会自动转换成布尔值
JS引擎从上往下执行代码 当执行到while语句时
1. 需要先判断布尔表达式的结果
2. 如果结果为真 执行代码段内的代码
如果结果为假 跳过while代码段 从while之后继续执行
3. 条件为真 执行完毕代码段以后 会继续判断布尔表达式
如果结果为真 执行代码段内的代码
如果结果为假 跳过while代码段 从while之后继续执行
直到布尔表达式结果为false为止
如果布尔表达式结果为真切无法变成假的情况 叫做死循环
while (true) {
console.log(1);
}
写循环时 一定要有出口(条件可以变成false的情况)
var i = 1;
console.time('start');
while (i <= 100) {
// console.log(i++);
i++;
}
console.timeEnd('start');
while语句用于处理循环逻辑
var i = 0;
while(i < 10){
console.log(i);
i++; //循环条件每执行一次就改变一次
}
break关键字 出现在循环中 表示跳出最近的一个循环
在执行break关键字以后 后面的语句都不会执行
• break用于循环,可使程序终止循环而执行循环后面的语句,常常与条件语
句一起使用。
var i = 0;
while (i < 10) {
console.log(i); //0 1 2 3 4 5 6
if (i > 5) break;
i++; //1 2 3 4 5 6
}
console.log(i);
continue在循环结构中,用于单次循环 进入到下一次循环
• continue关键字只能用于循环中
• 作用为跳过本次循环体中剩余语句而执行下一次循环
break和continue可以出现在任何循环结构中
显示100以内 个位数不等于3的数
var i = 0;
while (i < 100) {
i++;
if (i % 10 == 3) {
continue; // 跳过当前的循环 继续判断布尔表达式
}
console.log(i);
}
语法格式:
do{
可执行语句;
}while(boolean表达式);
• while循环 “先判断再执行”
• do-while循环 “先执行再判断”
• 当初始情况不满足循环条件时,while循环一次都不会执行;do-while循
环不管任何情况至少执行一次。
• while和do-while的不同仅仅体现在第一次循环条件就不满足的循环中;
此外的情形是完全一样的
do {
console.log('ok');
} while (false)
while (false) {
console.log('while');
}
猜数字
需要一个随机数 1-100之间
猜数字是多少
var randomNumber = Math.floor(Math.random() * 100) + 1; // 生成一个1-100的随机数
var userInput;
do {
userInput = parseInt(prompt('请输入一个1-100之间的数字'));
// 判断用户输入是有效输入
if (isNaN(userInput)) {
alert('输入的数字有误,请从新输入');
continue; // 输入错误 继续
}
if (userInput === randomNumber) { // 判断猜对
alert('恭喜你猜对了');
} else if (userInput > randomNumber) {
alert('太大了,请继续猜');
} else {
alert('太小了,请继续猜');
}
} while (userInput != randomNumber); // 循环条件 不相等
语法:
for(表达式1;表达式2;表达式3){
代码段
}
for (var i = 0; i < 10; i++) {
console.log(i);//0 1 2 3 4 5 6 7 8 9
}
var sum = 10000;
for (var i = 1; i <= 50; i++) {
sum *= 1.05;
}
console.log(sum);//114673.997857537
for (var i = 0; i < 100; i++) {
if (i % 7 == 0 && i != 0) console.log(i);
}
var sum = 0;
for (var i = 0; i < 100; i++) {
if (i % 2) sum += i;
}
console.log(sum);//2500
指的是循环体内还有循环
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
console.log(i, j);//
0 0
0 1
0 2
0 3
0 4
1 0
1 1
1 2
1 3
1 4
2 0
2 1
2 2
2 3
2 4
3 0
3 1
3 2
3 3
3 4
4 0
4 1
4 2
4 3
4 4
}
}
以上代码执行顺序
1. var i = 0;
2. 0<5 true
3. var j = 0;
4. 0<5 true
5. 输出 0 0
6. j++ j=1
7. 1<5 true
8. 输出 0 1
9. j++ j=2
10. 2<5 true
11. 输出 0 2
12. j++ j=3
…
j=5
5<5 false 内层循环结束
i++ i = 1
1<5 true
var j = 0;
• 需要多次重复执行一个或多个任务的问题考虑使用循环来解决;
• for/while/do-while三种循环在很多情况下是可以互换的;一般情况,用for
比较多
1.循环嵌套打印三角形
*
**
***
****
*****
for (var i = 1; i <= 5; i++) {
for (var j = 1; j <= i; j++) {
document.write('*');
}
document.write('
');
}
var sum = 0;
var n = 1;
for (var i = 1; i <= 20; i++) {
n *= i; // 计算的是n = n * i
sum += n;
}
console.log(sum);
for (var i = 100; i <= 999; i++) {
var digit = i % 10; // 获得个位
var ten = parseInt(i % 100 / 10); //获得十位
var hund = parseInt(i / 100); //获得百位
if (digit * digit * digit + ten * ten * ten + hund * hund * hund == i) {
console.log('水仙花数:' + i);
}
}
var count = 0; // 用于纪录打印个数
for (var year = 1000; year <= 2000; year++) {
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
count++;
document.write(year + ' ');
if (count % 4 == 0) { // 计数为4的倍数 打印换行
document.write('
');
}
}
}
var userInput = parseInt(prompt('请输入一个整数'));
质数只有两个因子
var count = 0; //用于纪录因子的个数
for (var i = 2; i <= userInput; i++) {
if (userInput % i == 0) {
count++;
}
}
if (count == 1) {
alert('是质数');
} else {
alert('不是质数');
}
--------------------------------------
通过一个开关判断是否是质数
var flag = true;
for (var i = 2; i < userInput; i++) {
if (userInput % i == 0) {
flag = false;
break;
}
}
if (flag) {
alert('是质数');
} else {
alert('不是质数')
}
函数有两种常用的创建方式
关键字 function 用于函数声明
使用function声明一个函数
function 函数名(){
代码段
}
function myFunction() {
console.log('myfunction');
console.log('myfunction1');
console.log('myfunction2');
console.log('myfunction3');
}
myFunction();
myFunction();
myFunction();
myFunction();
myFunction();
结果:
输出5次
myfunction
myfunction1
myfunction2
47 myfunction3
将一个函数赋值给一个变量 或者 对象的属性,也称作函数表达式
var fn= function(){
代码段
}
var myFn = function() {
console.log('test');
}
myFn();
var obj = new Object();
obj.myFn = function() {
console.log('obj');
}
obj.myFn();
• JavaScript中的函数可以带参数也可以不带参数
• 参数的声明写在小括号中,多个参数使用逗号隔开
• 小括号内的参数叫做形(式)参(数),命名规范与变量命名相同
• 函数体内使用的参数叫做实(际)参(数)
JS的函数 可以有参数 也可以没有参数
写在小括号中的叫做形参
形参 类似于变量 只能在函数内使用
当声明的形参没有接收到实参时,形参变量的值为undefined
function fn(num) {
console.log(num);//undefined
}
fn();
调用函数时 传入的参数叫做实参
实参会为形参进行赋值
传入的实参 可以是常量也可以是变量
var a = 8;
function fn(num) {
console.log(num);//8
}
fn()
函数允许拥有多个参数 使用英文逗号隔开
function plus(a, b, c) {
console.log(a + b + c);//15 16 '358'
}
plus(2, 5, 8);
plus(3, 5, 8);
plus("3", 5, 8);
var num1 = 10;
var num2 = 8;
function fn(a,b){
a+=b;
console.log(a); //18
}
fn(num1,num2);
console.log(num1,num2); //10 8
上面代码调用fn函数时传入的num1,num2是传入的这两个变量的值(将值复制一份传入函数内),函数内对参数的修改不会影响外部变量的值,
函数时参数是按值传递的
传入的参数 其实传入的是值的复制品
当把变量a,b传入函数中时,传入的是a,b的值
函数的参数的值不会影响外部的变量
var a = 10;
var b = 5;
function fn(a, b) {
a += b;
console.log(a);
}
fn(a, b);
console.log(a);//15
arguments 是一个ArrayLike(类数组)
arguments 里面的属性通过数字(索引 insex i 下标)来进行访问
所有的ArrayLike 都拥有length属性 用于保存 元素的长度(个数)
所有的ArrayLike 都是通过索引进行访问元素的
并且索引 都是从0开始计算的
0表示第一个元素 1表示第二个元素 …
function fn() {
// console.log(arguments[2]);
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log(sum);
}
fn(1, 2, 3, 4, 5);//15
fn(2, 6, 8, 1, 55, 1);//73
var userInput = parseInt(prompt('请输入一个数字'));
fn(userInput);
function fn(num) {
var flag = true;
for (var i = 2; i < num; i++) {
if (num % 2 == 0) {
flag = false;
break;
}
}
if (flag) alert('是质数');
else alert('不是质数');
}
function fn2(row) {
for (var i = 1; i <= row; i++) {
for (var j = 1; j <= i; j++) {
document.write('*');
}
document.write('
');
}
}
fn2(7);
fn2(5);
function fn3(arg1, arg2) {
console.log('和是:' + (arg1 + arg2));
console.log('差是:' + (arg1 - arg2));
console.log('积是:' + (arg1 * arg2));
console.log('商是:' + (arg1 / arg2));
}
fn3(5, 2);
function fn4(num1, num2, num3) {
var num4;
if (num1 > num2) { // 如果第一个数大于第二个数 交换位置
num4 = num1;
num1 = num2;
num2 = num4;
}
if (num2 > num3) {
num4 = num2;
num2 = num3;
num3 = num4; // num3 最大
}
if (num1 > num2) {
num4 = num2;
num1 = num2;
num2 = num4;
}
console.log(num1 + '<' + num2 + '<' + num3);
}
fn4(56, 5, 11);
我们可以使用arguments处理不同数量的参数
函数重载
相同或相近的功能 使用相同的函数名
参数的不同
function fn() {
if (arguments.length == 2) {
console.log(arguments[0] * arguments[1]);
} else if (arguments.length == 3) {
console.log(arguments[0] + arguments[1] + arguments[2])
} else {
console.log('参数错误');
}
}
fn(1, 2);
fn(1, 2, 3);
fn(1, 2, 3, 1);
function fn() {
if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
console.log(arguments[0] * arguments[1]);
} else if (typeof arguments[0] === 'string' || typeof arguments[1] === 'string') {
console.log(arguments[0] + arguments[1]);
}
}
fn(3, 2);
fn(5, 'true');
function fn() {
arguments.callee() //arguments.callee === fn
}
fn();
• 函数可以设置返回值也可以没有返回值
• 当函数没有返回值时默认返回undefined
• 使用return语句为函数设置返回值
• 函数的返回值可以是任意数据类型,且只能有一个返回值
• 当return执行时,跳出函数体的执行
• return用来终止或跳出函数执行
• 调用有返回值的函数时,可以使用变量接收返回值
在JS的函数中 可以有返回值的设置 也可以没有
设置返回值 使用的是return关键字
每个函数只有一个返回值,返回值可以是任意数据类型
返回值指的是函数的运行结果
返回值可以使用变量接收
一个函数没有设置返回值时,默认返回undefined
return关键字
function fn() {
return 123; // 返回123
}
var result = fn();
console.log(result);//1 2
function fn2() {
console.log(1);
console.log(2);
return;
console.log(3);
}
fn2();
function fn3() {
}
var result = fn3();
console.log(result);//undefined
console.log(fn3());//undefined
JS的编译和执行分为两个阶段
编译阶段
对于常见编译型语言(例如:J濴v濴)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节生成。
对于解释型语言(例如JavaScript)来说,通过词法分析和语法分析得到语法树后,就可以开始解释执行了。
(1)词法分析是将字符流(char stream)转换为记号流(token stream),就像英文句子一个个单词独立翻译,举例:
代码:var result = testNum1 - textNum2;
词法分析后 :
NAME “result”
EQUALS
NAME “testNum1”
MINUS
NAME “testNum2”
SEMICOLON
(2)语法分析得到语法树,举例:
条件语句 if(typeof a == “undefinef” ){ a = 0; } else { a = a; } alert(a);
当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语法错误,并结束整个代码块的解析。
(3)“预编译”(并非完全的顺序执行)
“function函数”是一等公民!编译阶段,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率!
总结:当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理!并且是先预声明变量,再预定义函数!
二、JavaScript执行过程
在解释过程中,JavaScript引擎是严格按着作用域机制(scope)来执行的。JavaScript语法采用的是词法作用域(lexcical scope),也就是说JavaScript的变量和函数作用域是在定义时决定的,而不是执行时决定的,由于词法作用域取决于源代码结构,所以 JavaScriptr濼瀃t解释器只需要通过静态分析就能确定每个变量、函数的作用域,这种作用域也称为静态作用域(static scopr)。补充:但需要注意,with和eval的语义无法仅通过静态技术实现,实际上,只能说JS的作用域机制非常接近lexcical scope。
JavaScript中的变量作用域在函数体内有效,无块作用域;
JavaScrip引擎在执行每个函数实例时,都会创建一个执行环境(execution context)。执行环境中包含一个调用对象(call object), 调用对象是一个scriptObject结构(“运行期上下文”),用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表upvalue等语法分析 结构(注意:varDecls和funDecls等信息是在语法分析阶段就已经得到,并
保存在语法树中。函数实例执行时,会将这些信息从语法树复制到 scriptObject上)。scriptObject是与函数相关的一套静态系统,与函数实例的生命周期保持一致,函数执行完
毕,该对象销毁。
JavaScript引擎通过作用域链(scope chain)把多个嵌套的作用域串连在一起,并借助这个链条帮助JavaScript解释器检索变量的值。这个作用域链相当于一个索引表,并通过编号来存 储它们的嵌套关系。当JavaScript解释器检索变量的值,会按着这个索引编号进行快速查找,直到找到全局对象(global object)为止,如果没有找到值,则传递一个特
殊的undefined值。
预编译
JS引擎会在执行代码之前 优先进行一些优化操作 提高执行效率
JS引擎会找到所有的var关键字 和function关键字
对变量和函数的声明进行提前
var 声明的变量提前了 赋值为undefined
function 申明的函数 整体 提前执行
执行阶段
脚本随解释器进行顺序执行
console.log(a);//undefined
var a = 10;
console.log(a);//10
fn();
function fn() {
console.log(1);//1
}
fn2();
var fn2 = function() {
console.log(2);//fn2 is not a function
}
又名作用区域 作用范围
JavaScript的作用域分为两种
var a = 8;
function fn() {
console.log(a);//undefined
var a = 5;
}
fn();
for (var i = 0; i < 10; i++) {
}
console.log(i);//10
if (false) {
var a = 10;
} else {
var b = 5;
}
console.log(a);//5
console.log(b);//undefined
递归指的是函数在执行过程中的自调用
如果递归没有出口(变成非递归情况)那么会造成 栈(内存)溢出
构成递归需具备的条件:
1.
function fn() {
arguments.callee // 返回当前函数的引用 fn
console.log(arguments.callee);
//ƒ fn() {
arguments.callee // 返回当前函数的引用 fn
console.log(arguments.callee);
// arguments.callee();
}
arguments.callee();//Maximum call stack size exceeded
}
fn();
2.
function fn(n) {
console.log(n);//5 4 3 2 1 0
if (n == 0) { // 递归出口
return 0;
} else {
fn(n - 1); // 参数的递减
}
}
fn(5);
点击事件改变元素背景颜色
<style>
#box {
width: 200px;
height: 200px;
background-color: red;
}
</style>
<script>
window.onload = function() {
var box = document.getElementById('box');
// var flag = true;
var count = 0;
box.onclick = function() {
// if (flag) {
// box.style = "background-color:blue;";
// flag = !flag; // 求反
// } else {
// box.style = "background-color:red;";
// flag = !flag;
// }
count++;
box.style = count % 2 ? 'background:blue' : 'background:red';
}
}
</script>
<body>
<div id="box"></div>
</body>
斐波那契数列
斐波那契数列 fibonacci
黄金数列
两个已知数 1 1
数列后每一位数 都是前两位的和
1 1 2 3 5 8 13 21…
求斐波那契数列的第n位
n = fibonacci(n-1) + fibonacci(n-2)
var count = 0;
function fibonacci(n) {
count++;
if (n <= 2) { // 递归出口
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
console.time('go');//输出运行时间
console.log(fibonacci(42));
console.log(count);
console.timeEnd('go');
辗转相除法
使用辗转相除法计算最大公约数
辗转相除法, 又名欧几里得算法(Euclidean algorithm),
目的是求出两个正整数的最大公约数。它是已知最古老的
算法, 其可追溯至公元前300年前。
这条算法基于一个定理:两个正整数a和b(a>b),它们
的最大公约数等于a除以b的余数c和b之间的最大公约数。
比如10和25,25除以10商2余5,那么10和25的最大公约
数,等同于10和5的最大公约数。
function fn(m, n) {
var r = m % n;
m = n;
n = r;
if (r == 0) {
return m;
} else {
return fn(m, n);
}
}
console.log(fn(20, 5));//5
console.log(fn(7, 21));//7
变量作用域:
变量作用域是程序中定义这个变量的区域:
全局变量拥有全局作用域
局部变量,其作用域是局部性的
在JavaScript中,变量的作用域分为两种:
1.全局作用域 — 一旦定义在程序任何地方都可以访问
2.函数作用域 — 指在函数中定义的变量只能在函数内部访问
在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象.函数对象和其他对象一样,拥有可以通过代码访问的属性和一系列仅提供JavaScript引擎访问的内部属性,其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问.
当一个函数创建后,它实际上保存了一个作用域链,并且作用域链会被创建此函数的作用域中可访问的数据对象填充.
在函数fn创建时,它的作用域中会填入一个全局对象,该全局对象包含了所有全局变量
执行此函数时会创建一个称为“运行期上下文(execution context)”(有人称为运行环境)的
内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。
• 这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。
函数也是对象
function sayHello() {
}
console.log(sayHello.name);//sayHello
匿名函数,就是定义时未直接指定名称的函数
指的是声明函数时没有指定函数名
function(num1,num2){
console.log(num1+num2);
}
尽量避免使用全局变量
非要用全局变量的时候
在作用域的顶部声明 并且加注释
1. (function() {
var user = 'zhangsan';
console.log(user);
})();
console.log(user);//zhangsan
2. ! function() {
console.log(2);
}()
3. ~ function() {
console.log(3);
}();
(function(a, b, c) {
// var a = 10;
console.log(a + b + c);
})(3, 5, 6);//14
(function() {
var a = 5;
console.log(a);//5
})();
将匿名函数作为参数使用
函数的参数可以是任意数据类型
JS中的函数是对象
– >> 将函数作为参数使用
• 回调函数,将一个函数作为另一个函数的参数叫做回调函数
function isOdd(num, callback) {
if (num % 2) {
callback('这个数是奇数');
} else {
callback('这个数是偶数');
}
}
所有的函数作为参数的使用情况 都叫回调函数
isOdd(5, function(msg) {
console.log(msg);
});
isOdd(8, function(msg) {
console.log(msg);
});
函数名
赋值式的函数 变量名就是函数名
function myFn() {
}
console.log(myFn.name);//myFn
var fn = function() {
}
console.log(fn.name); // 赋值式的函数 变量名就是函数名
结果是fn
console.log(function() {}.name === '');//true匿名函数的函数名为空
编程风格
定义变量名时
1.不推荐
var a = 5;
var b = 3;
var c = 2;
2.尽量使用这种方法
var a = 5,
b = 3,
c = 2;
使用循环语句时
1.bad
if (5 > 3) {
console.log('ok');
} //bad
2.good
if (5 > 3) console.log('ok'); //good
3.best
5 > 3 && console.log('ok'); //best
做比较时 常量写前面
var flag = true;
1.
if (flag == 1) {
console.log('ok');
}
2.
if (1 == flag) { // 做比较时 常量写前面
console.log('ok');
}
JavaScript基于 对象和事件驱动的一个web开发脚本语言
• 当用与Web页面进行某些交互时,解释器就会创建相应的event对象以描述事
件信息。常见的事件有:
函数是可以被事件触发执行的
window.onload = function() {
// window 指的是浏览器窗口
// 当窗口内的资源加载完毕
alert(1);
}
通过id获取元素
通过document.getElementById()获取的到所有元素(标签)都是对象
对象是数据和功能的集合
数据体现 属性
<script>
window.onload = function() {
var btn = document.getElementById('btn'); // 通过id获取元素
// 通过 document.getElementById() 获取的到所有 元素(标签) 都是对象
// alert()会将所有输出的内容进行 toString() 操作
// alert(btn); // [object HTMLButtonElement]
// var o = new Object();
// console.log(o.toString()); // [object Object]
// console.log(btn.toString());
// 对象是数据和功能的集合
// 数据体现 属性
// console.log(btn.id);
// console.log(btn.title);
// btn.title = 'hello world';
btn.onclick = function() {
// 事件 onclick 鼠标左键单击事件
btn.title = "hello";
alert('我修改自己的title');
}
}
</script>
<body>
<button id="btn" title="button element">按钮</button>
</body>
1.随机色块
window.onload = function() {
var btn = document.getElementById('btn');//获取按钮元素的id
var box = document.getElementById('box');//获取id名为box元素
// 随机颜色
function getColor() {
var color = '#';//定义一个color拼接生成的随机小数的16进制的颜色值
var randomNumber = 0;//定义一个随机小数
//随机生成6个颜色值并拼接成一个16进制的rgb颜色
for (var i = 0; i < 6; i++) {
// Math.random()
// 生成一个0-1之间的随机小数
randomNumber = parseInt(Math.random() * 16);//生成一个0-15之间的随机小数
color += randomNumber.toString(16); // 拼接16进制数字
}
return color;//返回生成的颜色
}
// box里添加元素 innerHTML
btn.onclick = function() {
box.innerHTML += '+ getColor() + '">';//每点击一次就生成一个随机颜色的色块
}
}
<body>
<div style="text-align: center">
<input type="button" id="btn" value="按钮">
</div>
<div id="box">
</div>
</body>
2.鼠标事件
window.onload = function() {
var box = document.getElementById('box');
var list1 = document.getElementById('list1');
// onmouseenter
// onmouseleave
box.onmouseover = function() { // 鼠标悬停事件
list1.style = "background:green";
}
box.onmouseout = function() { // 鼠标离开事件
list1.style = "background:red";
}
}
<body>
<div id="box">
</div>
<div>
<ul>
<li id="list1">第一个li</li>
</ul>
</div>
</body>
键盘事件
// onkeydown 键盘按下
window.onkeydown = function() {
console.log('你按键了');
}
window.onkeyup = function() {
console.log('按键回弹');
}
具体使用方式请查看:Less中文地址
Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。
Less 可以运行在 Node 或浏览器端。
首先安装easy less
创建一个文件后缀名为.less,会自动生成一个css文件
支持css语言
要设置编码
@charset “utf-8”;
好处:
header{
img{
width:300px;
}
nav{
.list{
list-style:none;
overflow: hidden;
li{
float: left;
margin:5px;
&:hover{ // & 表示父级选择器
color:@color1;
}
>a{
color:@color1;
}
}
}
}
}
以上代码会在css文件中自动生成
header img {
width: 300px;
}
header nav .list {
list-style: none;
overflow: hidden;
}
header nav .list li {
float: left;
margin: 5px;
}
header nav .list li:hover {
color: black;
}
header nav .list li > a {
color: black;
}
li{
float: left;
width: floor(100%/7); // floor() 向下取整 ceil()向上取整
}
在css代码中自动生成
.box ul li {
float: left;
width: 14%;
}
3.变量的使用
@是声明一个变量
@color1:black;
>a{
color:@color1;
}
ECMAScript中的对象其实就是一组数据和功能的集合.对象可以通过执行new操作符后跟要创建的对象类型的名称来创建.而创建Object类型的实例并为其添加属性和(或)方法,就可以自定义对象:
使用构造函数创建对象
var o = new Object();
使用点操作符设置属性
o.name = 'zhangsan';
为不存在的属性直接赋值 是添加属性
o.age = 25;
为已存在的属性赋值 是修改属性
o.age = 18;
使用语法量 直接量的方式 创建对象
{} 它其实是 new Object()的语法糖
var obj = {}; // 底层依旧执行 new Object()
属性名和属性值之间使用英文冒号隔开
每个属性之间使用逗号隔开
var o2 = {
name: 'zhangsan',
age: 20,
sex: 'nan'
};
console.log(o2);//Objectname: "zhangsan"age: 20sex: "nan"__proto__: Object
对象的属性可以是任意数据类型
var o3 = {
// 对象的属性可以是任意数据类型
name: 'lisi',
fn: function() {
console.log('hello');//hello
}
};
o3.fn();
对象的属性操作
CRUD Create Read Update Delete
delete关键字用于删除对象的属性
var o4 = {
name: 'lisi',
age: 20,
abc: 123,
fn: function() {
console.log('ok');
}
}
delete o4.abc;
console.log(o4);//{name: "lisi", age: 20, fn: ƒ}
name: "lisi"
age: 20
fn: ƒ ()
delete o4; //{name: "lisi", age: 20, fn: ƒ}
arguments.length不可以被delete删除
function fn() {
delete arguments.length;
console.log(arguments);//Arguments {0: 1, 1: 2, 2: 3, 3: 4, callee: ƒ, Symbol(Symbol.iterator): ƒ}
}
fn(1, 2, 3, 4);
对象属性的访问
对象的属性名是字符串类型
JSON 轻量级数据交换格式
JSON 是中立于语言和平台的一种数据交换格式
var o5 = {
"a": 1,
"b": 2,
"c": 3
}
console.log(o5.b);//2
console.log(o5['b']);//2
使用一个变量保存多个值 (对象 数组)
JavaScript的数组可以保存任意数据类型的值
数据结构
将数据和数据之间的关系按照特定结构进行保存
队伍 堆 栈 数 哈希 字典 列表 散列表…
数组也是一种数据结构
1.所有内容都是有序排列
2.排列顺序 最小值是0 最大值是长度-1
3.数组中的数据类型
Number String Null Undefined Boolean Object Function Array
var arr1=[];
//定义一个不包含元素的数组 语法糖var arr2=[1,2,3];
//定义一个包含3个元素的数组var arr3=new Array();
//定义一个不包含元素的数组var arr4=new Array(“tom”,”marry”,”john”);
delete arr4.length; console.log(arr4.length);
console.log(arr4[1]);
// 获取数组的元素 通过[index]获取引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。
本教程会讨论大量的 ECMAScript 预定义引用类型。
从现在起,将重点讨论与已经讨论过的原始类型紧密相关的引用类型。
注意:从传统意义上来说,ECMAScript 并不真正具有类。事实上,除了说
明不存在类,在 ECMA-262 中根本没有出现“类”这个词。ECMAScript
定义了“对象定义”,逻辑上等价于其他程序设计语言中的类。
所有使用new关键字创建的对象 都是引用类型
var arr = [1, 2, 3, 4];
// []是 new Array()语法糖
var arr2 = arr;
// 引用赋值的是地址
arr2[0] = 0;
//修改的是同一条数据
console.log(arr);
//Array(4)0: 01: 22: 33: 4length: 4__proto__: Array(0)
var obj = {
x: 1,
y: 2
};
var obj2 = obj;
obj2.x = 0;
console.log(obj.x);//0
引用类型比较的是地址
只有地址相同才相等
var arr = [1, 2, 3, 4]; // new Array() 0x0656347
var arr2 = [1, 2, 3, 4]; // new Array() 0x0674612
console.log(arr == arr2);//false
var arr = [];
var arr2 = arr;
console.log(arr === arr2);//true
var o = {
x: 1
}
var o2 = {
x: 1
}
console.log(o == o2);//false
• 引用类型:值不保存在变量本地的数据类型
var n=100;
• 值类型:保存在栈中,速度快。
var arr=new Array(‘北京’,‘哈尔滨’);
引用类型作为参数传递时 传递的也是地址
function fn(arr) {
arr[0] = 0;
}
var a = [1, 2, 3, 4, 5]; // 引用类型的值保存再堆 栈中储存的是地址
fn(a);
console.log(a);//Array(5)0: 01: 22: 33: 44: 5length: 5__proto__: Array(0)
引用类型:数据保存在堆中,栈中只有内存的编号,要通过此编号到堆中查找真正的数据
ECMAScript 提供了三种基本包装类型
Boolean Number String
基本包装类型 使用了new关键字
var num2 = new Number(12);
基本包装类型有基本类型的特点
console.log(num + num2);
//基本包装类型由于基本类型的特点 输出结果:24
console.log(typeof num2);
//object
console.log(num2);
//Number
var bool = new Boolean(true);
console.log(bool);//Boolean
console.log(typeof bool);//object
var str = '123';
var str2 = new String('abc');
console.log(str + str2);//123abc
console.log(typeof str2);//object
var num = 123;
console.log(num.toString());//'123'
var box = document.getElementById('box');
var obj = {};
var arr = [];
var n = null;
console.log(typeof box);//object
console.log(typeof obj);//object
console.log(typeof arr);//object
console.log(typeof n);//object
所有的引用类型 使用 instanceof Object均返回为true 不靠谱
console.log(obj.constructor === Object);
console.log(arr.constructor === Array);
console.log(arr.constructor === Object);
console.log(box.constructor === HTMLDivElement);
function getType(o) {
return Object.prototype.toString.call(o).slice(8, -1);
}
var a = 123;
var b = true;
var c = [];
var d = {};
var e = 'aaaa';
var f;
var g = null;
console.log(getType(a));
console.log(getType(b));
console.log(getType(c));
console.log(getType(d));
console.log(getType(e));
console.log(getType(f));
console.log(getType(g));
var arr = [];
console.log(Array.isArray(arr));//true
• 什么是null?
• null专门表示一个变量不能再指向任何对象的地址。
• null与undefined:
• 共同点:
• 都是原始类型,保存在栈中变量本地
• 不同点:
• undefined:表示变量声明过但未赋值。是所有未赋值变量的默认值。
一般不主动使用。例如 var a; //a被自动赋值为undefined
• null:表示一个变量将来可能指向一个对象,但目前暂时什么都没指
向。一般用于主动释放指向对象的引用。
例如:var emps =[“Tom”,”Marry”];
emps=null;//释放指向数组的引用,清空掉栈中的编号,对中的
数据没人用,被回收
数组操作(GET/SET)
• 设置数组元素的值–SET操作
var arr = [1,2,3];
arr[2] = 100; //将值为3的元素重新赋值为100;
arr[3] = 99; //在数组尾部添加一个新的元素;
• 获取数组元素的值–GET操作
var add = new Array(‘Hello’,‘World’);
console.log(add[0]); //Hello
var arr = [‘苹果’, ‘橘子’, ‘芒果’, ‘西瓜’, ‘菠萝’];
arr.length = 8; //数组的长度可以修改
console.log(arr.length);
console.log(arr[5]); // 空的元素被取值为 undefined
arr.length = 0; // 将数组长印度设置为0 清空数组内的元素
console.log(arr);
arr = []; //使用新数组替换老数组
遍历 在编程语言中的含义就是 全部访问一边
正序遍历
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
倒序遍历
for (var j = arr.length - 1; j >= 0; j–) {
console.log(arr[j]);
}
1. 使用数组 求 斐波那契数列的第50位
var fibonacci = [1, 1];
for (var i = 2; i < 50; i++) {
fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
}
console.log(fibonacci);
// 2. 冒泡排序
// 相邻的两个数进行比较大小 较大的数移到后面
// 理论最大排序轮数是 数组的长度-1 次
var arr = [64, 67, 189, 77, 16, 167, 66];
// [64,67,189,77,16,167,66];
// 64,67,77,16,167,66,189
// 64,67,16,77,66,167
var temp;
for (var j = 0; j < arr.length - 1; j++) {
for (var i = 0; i < arr.length - j - 1; i++) {
if (arr[i] > arr[i + 1]) { // 如果第一个数大于第二个数 交换位置
temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp
}
}
}
console.log(arr);
for - in 用于遍历对象
for-in访问存在的数组元素
in关键字 可以判断 属性在对象中是否存在
length 属于不可枚举属性
// var city = ['北京', '上海', '广州', , , '深圳', , '南京', , '杭州', '长沙', '重庆'];
// console.log(city.length);
// console.log(city);
// for (var i = 0; i < city.length; i++) { //index
// console.log(city[i]);
// }
// for - in 用于遍历对象
// for (var i in city) { // item 项
// // for-in访问存在的数组元素
// console.log(i, city[i]);
// }
// -------------------------------
// for-in 用于遍历对象的可枚举属性
// length 属于不可枚举属性
var obj = {
name: 'zhangsan',
age: 20,
sex: '男'
}
// for (var key in obj) { // key 属性名
// console.log(key + ":" + obj[key]); // obj[key] 属性值
// }
// in关键字 可以判断 属性在对象中是否存在
console.log('name' in obj);
console.log('age' in obj);
console.log('abc' in obj);
JS的数组有两种数组
var arr = []; //关联数组长度是0
arr['name'] = 'zhangsan';
arr['age'] = 20;
arr['sex'] = 'nan';
console.log(arr);//Array(0)name: "zhangsan"age: 20sex: "nan"length: 0__proto__: Array(0)
关联数组不计算长度 无法使用for循环遍历
但是数组是对象 可以使用for-in遍历
for (var i in arr) {
console.log(arr[i]);
}
API 应用程序接口( 函数/方法 )
Array.prototype 里面所有的方法 都可以在数组实例中被访问(所有数组都能访问)
var arr = [1, 2, 3];
// var result = arr.push('ok', 4, 5, 6);
// console.log(arr);//Array(8)0: 11: 22: 33: "ok"4: 45: 56: 67: "ok"length: 8__proto__: Array(0)
// console.log(result);//7
arr.push('ok');
console.log(arr);//Array(8)0: 11: 22: 33: "ok"4: 45: 56: 67: "ok"length: 8__proto__: Array(0)
var arr = [1, 2, 3];
var arr2 = arr.concat(4, 5, 6);
console.log(arr2);//
(6) [1, 2, 3, 4, 5, 6]
0: 1
1: 2
2: 3
3: 4
4: 5
5: 6
length: 6
__proto__: Array(0)
console.log(arr);//(3) [1, 2, 3]0: 11: 22: 3length: 3__proto__: Array(0)
concat 可以将数组扁平化 将数组展开后的结果依次倒入新数组中
只展开第一层
var arr = [1, 2, 3];
var arr2 = arr.concat([4, [5, 6]]);
console.log(arr2);//(5) [1, 2, 3, 4, Array(2)]
var arr = [2, 6, 7, true, , false, null, 123, {
x: 1
}];
var str = arr.join();
console.log(str);//2,6,7,true,,false,,123,[object Object]
var arr = [1, 2, 3, 4, 5];
var result = arr.join('----');
console.log(result);//1----2----3----4----5
var arr = [1, 2, 3, 'ok'];
arr.reverse();
console.log(arr);//(4) ["ok", 3, 2, 1]
var arr = [1, 2, 3, 4];
var arr2 = arr.concat(4, 5, 'ok'); // [1,2,3,4,4,5,'ok']
arr.reverse();
arr2.push(6);
arr2.reverse();
var str = arr2.join();
console.log(str);//6,ok,5,4,4,3,2,1
var arr = [3, 6, 8];
var del = arr.shift();
console.log(arr);//(2) [6, 8]
console.log(del);//3
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.slice(1, 3);
var arr3 = arr.slice(1);
console.log(arr2);//Array(2)0: 21: 3length: 2__proto__: Array(0)
console.log(arr3);//Array(4)0: 21: 32: 43: 5length: 4__proto__: Array(0)
var arr2 = arr.slice();
console.log(arr2);//Array(5)0: 11: 22: 33: 44: 5length: 5__proto__: Array(0)
console.log(arr);//Array(5)0: 11: 22: 33: 44: 5length: 5__proto__: Array(0)
console.log(arr === arr2);//false
var arr4 = arr.slice(1, -2);
console.log(arr4);//Array(2)0: 21: 3length: 2__proto__: Array(0)
var arr = [167, 12, 66, 123, 121, 77, 56, 57, 111];
console.log(arr.sort(function(a, b) {
return a - b; // 升序
}));
console.log(arr.sort(function(a, b) {
return b - a; // 降序
}));
console.log(arr.sort((a, b) => a - b));
console.log(arr.sort((a, b) => b - a));
var arr = [1, 2, 4, 5];
console.log(arr.toString());//1,2,4,5
var arr = [1, 2, 3];
arr.unshift('ok', 'true');
console.log(arr);//Array(5)0: "ok"1: "true"2: 13: 24: 3length: 5__proto__: Array(0)
var arr = [1, 2, 3, 4, 5];
var result = arr.splice(1, 0);
console.log(arr);//Array(6)
0: 5
1: (2) [6, 7]
2: 2
3: 3
4: 4
5: 5
length: 6
__proto__: Array(0)
console.log(result);//Array(0)length: 0__proto__: Array(0)
arr.splice(1, 0, 1);
console.log(arr);//
Array(6)
0: 5
1: Array(2)
0: 6
1: 7
length: 2
__proto__: Array(0)
2: 2
3: 3
4: 4
5: 5
length: 6
__proto__: Array(0)
arr.splice(0, 2, 5, [6, 7]);
console.log(arr);//
Array(6)
0: 5
1: Array(2)
0: 6
1: 7
length: 2
__proto__: Array(0)
2: 2
3: 3
4: 4
5: 5
length: 6
__proto__: Array(0)
练习:
var arr = [];
for (var i = 1; i <= 100; i++) {
arr[i] = i;
}
console.log(arr);
do {
for (var j = arr.length - 1; j > 0; j--) {
if (j % 2 == 0) {
arr.splice(j, 1);
}
}
console.log(arr);
} while (arr.length > 3);
1. 排序
//首先使用sort将数组内的元素按照顺序排序
arr.sort(function(a, b) {
return a - b
});
console.log(arr);
2. 比较
var result = [];//定义一个空数组用于接收比较后得到的数字内的元素
for (var i = 0; i < arr.length; i++) {//循环遍历数组
if (arr[i] !== arr[i + 1]) {//将数组内的元素和后一个元素作比较,如果不相等就推入result中
result.push(arr[i]);
}
}
console.log(result);
var arr = [1, 654, 111, 654, 123, 11, 63, 12, 1, 111, 111];
// 创建一个新数组,在新数组中查找原数组中的每一个值 如果没有找到 则插入该值
var result = [];
function indexOf(arr, value) {
for (var i = 0; i < arr.length; i++) { // 在传入的数组中查找传入的值
if (arr[i] === value) return i; // 如果值存在则返回 索引
}
return -1; //如果循环结束都没有找到 则返回-1
}
for (var i = 0; i < arr.length; i++) {
if (indexOf(result, arr[i]) === -1) {
result.push(arr[i]);
}
}
console.log(result);
var arr = [1, 654, 111, 654, 123, 11, 63, 12, 1, 111, 111];
var result = [...new Set(arr)];
console.log(result);
二维数组:从整体上来看,是一个数组,只是其中的每个元素又是一个数组,既数组的数组;
二维数组指的是在数组内的元素全部都是数组
var arr = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
访问二维数组中的某个元素
var arr = [[1,2,3],[3,4,5],[6,7,8]]; console.log(arr[0][0]); arr[1][2] = 200;
遍历二维数组—循环嵌套
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
// 二级联动菜单
var data = [
['北京', '朝阳', '海淀', '丰台', '昌平', '大兴', '顺义'],
['上海', '杨浦', '青浦', '徐汇', '浦东', '静安', '宝山'],
['广州', '白云', '海珠', '天河', '越秀'],
['杭州', '江干', '西湖', '上城', '下城', '萧山', '余杭', '富阳', '临安']
];
window.onload = function() {
var city = document.getElementById('city');
var area = document.getElementById('area');
// 1. 把城市放入city
// innerHTML += ""
var cityStr = '';
for (var i = 0; i < data.length; i++) {
cityStr += ' i + '">' + data[i][0] + '';
}
city.innerHTML += cityStr;
// select 是表单元素
// change事件
city.onchange = function() {
// 获得select的value属性
// value属性和数据的索引是一一对应的
// console.log(city.value);
var _index = this.value; // this在事件处理函数中 指向的是事件触发的对象
var areaStr = '';
for (var j = 1; j < data[_index].length; j++) {
areaStr += ' + data[_index][j] + '';
}
area.innerHTML = areaStr;
}
}
<body>
<select id="city">
<option>请选择</option>
</select>
<select id="area">
<option>请选择</option>
</select>
</body>
es5 ECMAScript5
es6 ECMAScript 不再使用版本号命名 而是使用年份命名 es2015
es7 es8 es9 es10都发布了
var arr = [54, 65, 11, 76, 11, 74, 62, 65];
console.log(arr.indexOf(12, 3));//-1
var arr = [54, 65, 11, 76, 11, 74, 62, 65];
arr.forEach(function(value, index) {
console.log(value, index);
})
function forEach(arr, callback) {
for (var i = 0; i < arr.length; i++) {
callback(arr[i], i);
}
}
forEach(arr, function(value, index) {
console.log(value)
})
var arr = [176, 2, 67, 27, 658, 1875, 12347, 134];
1.
var arr2 = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2) {
arr2.push(arr[i]);
}
}
console.log(arr2);
var arr3 = [];
arr.forEach(function(value) {
if (value % 2) arr3.push(value);
});
console.log(arr3);
2.
var arr4 = arr.filter(function(value, index) {
// 1. 遍历数组
// 2. 使用逻辑表达式检测数组中的每一个元素
// 3. 将结果为true放入一个新的数组
// 4. 返回新数组
// console.log(value, index);
return value % 2;
})
console.log(arr4);
var users = [{
username: 'zhangsan',
age: 25
}, {
username: 'lisi',
age: 15
}, {
username: 'lisa',
age: 18
}, {
username: 'wangwu',
age: 22
}, {
username: 'zhaoliu',
age: 16
}, {
username: 'xixi',
age: 20
}];
var result = users.filter(function(value, index) {
return value.age < 18;
});
console.log(result);
var arr = [1, 2, 3, 4, 5];
var result = [];
arr.forEach(function(value, index) {
// 1. 遍历数组
// 2. 做操数组
// 3. 将操作结果放入新数组
if (value % 2) {
result.push(value * 2);
} else {
result.push(value / 2);
}
});
console.log(result);
var result = arr.map(function(value) {
// 1. 遍历数组
// 2. 操作每个数组的值
// 3. 将结果返回输出生成一个新数组
return value % 2 ? value * 2 : value / 2;
});
console.log(result);
var res = arr.map(function(value) {
return value + 10;
});
console.log(res);
var arr = [5, 4, 3, 2, 1];
var result = arr.reduce(function(pre, next) {
// 第一次执行reduce回调时 ,pre第一个数组元素
// next是第二个数组元素
// 后面每次一遍历执行时 pre都是上一次的返回值
// next依旧是下一个数组元素
console.log('pre' + pre + ',next' + next);
return pre * next;
});
console.log(result);
String类型是字符串的包装类型
• String类型是字符串的对象包装类型,可以使用构造函数来创建。
• String对象的方法也可以在所有基本的字符串值中访问到。其中,继承的
valueOf() toLocale-String() 和toString()方法,都返回对象所表示的基本字
符串值。
在JavaScript字符串可以使用 单引号 或 双引号
在Java中'a' char 字符类型 单引号
"abc" string 字符串类型 双引号
Strring.lenght
• 语法
• string.length
• 描述
• 属性String.length是一个只读整数,它声明了指定字符串string中的字符数。对于任何一个字符串s,
它最后一个字符的下标都是s.lenghth-1。用for/in循环不能枚举出字符串的lenghth属性,用delete运算符也不能删除它。
字符串也拥有长度 length 属性
length属性可以在所有的基本字符串中访问到
length是一个只读的(正)整数
var str = 'abc';
console.log(str.charAt(1)); // str[1]
String.prototype.charCodeAt();
语法: str.charCodeAt(index)
参数: index(number) str的索引值
描述: 返回指定索引字符的 Unicode 编码 0-65535
返回值: number Unicode编码
常用Unicode编码
数字 48-57
小写字母 97-122
大写字母 65-90
var str = 'Z';
console.log(str.charCodeAt(0));
var str = '放学别走,小树林见';
var arr = [];
for (var i = 0; i < str.length; i++) {
arr.push(str.charCodeAt(i) + 520);
}
console.log(arr);
arr.forEach(function(value) {
// String.fromCharCode() 用于将Unicode编码转换成字符串
console.log(String.fromCharCode(value - 520));
})
String.prototype.concat()
语法: str.concat(value[,…valueN]);
描述: 方法用于在str后连接多个值
参数: value 字符串类型
返回值: 新的字符串
平时时候+连接
解决复杂字符串问题
var str = 'hello';
var str2 = str.concat(' ', 'world');
console.log(str2);//hello world
console.log(str);//hello
var str = "JavaScript";
console.log(str.indexOf('a', 2));//3
var str = 'JavaScript';
console.log(str.lastIndexOf('a'));//3
var str = 'hello world';
// replace函数的第一个参数如果不是正则表达式 会被自动转换成正则表达式
var newStr = str.replace('h', 'H');
console.log(newStr);//Hello world
window.onload = function() {
var btn = document.getElementById('btn');
var text = document.getElementById('text');
var word = ['cnm', 'qnmlgb', 'mmp', '中共'];
var str = word.join('|');
var reg = new RegExp(str, 'g'); // 将字符串转成正则表达式
btn.onclick = function() {
text.value = text.value.replace(reg, '**');
}
}
var str = 'abcdefg';
console.log(str.slice(2));//cdefg
console.log(str.slice(2, 5));//cde
console.log(str.slice(1, -2));//bcde
console.log(str.slice(10, 15) === ''); //没有截取成功返回空字符串//true
var str = '12-23-34-45';
console.log(str.split('-'));//(4) ["12", "23", "34", "45"]
var str2 = 'abcdefg';
var arr = str2.split(''); // join的反向操作
arr.reverse();
str2 = arr.join('');
console.log(str2)//gfedcba
var email = "[email protected]";
console.log(email.split('@')[0]);//zhangsan
var str = 'abcdefg';
console.log(str.substr(2, 5));//cdefg
var str = 'abcdefg';
console.log(str.substring(1));//bcdefg
console.log(str.substring(1, 3));//bc
console.log(str.substring(3, 1));//bc
console.log(str.substring(3, -1));//abc
var str = 'HELLO';
console.log(str.toLowerCase());//hello
var str = 'hello';
console.log(str.toUpperCase());//HELLO
var str = 'no zuo no die';
// No,Zuo,No,Die
var arr = str.split(' '); // 将字符串拆分成数组
arr = arr.map(function(value) {
// 遍历数组
// 操作数组的每一个元素
// 返回一个新数组
return value.charAt(0).toUpperCase() + value.slice(1);
});
str = arr.join();
console.log(str);
// 统计大写字母个数 小写字母个数 数字个数
var big = 0,
small = 0,
num = 0;
var code;
for (var i = 0; i < str2.length; i++) {
// 数字 48-57
// 小写字母 97-122
// 大写字母 65-90
code = str2.charCodeAt(i);
if (code >= 48 && code <= 57) {
num++;
} else if (code >= 65 && code <= 90) {
big++;
} else if (code >= 97 && code <= 122) {
small++;
}
}
console.log('数字有' + num + '个', '小写字母有' + small + '个', '大写字母有' + big + '个');
归并做法
var arr = str2.split('');//先将字符串转为数组
var res = arr.reduce(function(result, current) {
var code = current.charCodeAt(0);
if (code >= 48 && code <= 57) {
result.num++;
} else if (code >= 65 && code <= 90) {
result.big++;
} else if (code >= 97 && code <= 122) {
result.small++;
}
return result;
}, {
big: 0,
small: 0,
num: 0
});
console.log(res);
var str3 = 'aaaaabbbccccccddddeeefffgg';
// 5a3b6c4d3e3f2g
var count = 1;
var result = '';
for (var i = 0; i < str3.length; i++) {
if (str3[i] === str3[i + 1]) { // 如果相邻的字符相同 计数+1
count++;
} else { //不同
result += count + str3[i]; //将结果拼接
count = 1; //计数初始化
}
}
console.log(result);
var arr = str3.split('');
var res = arr.reduce(function(result, current) {
// reduce回遍历数组
// 第一次执行回调时,result是传入的对象
// 判断对象中是否用于某个属性,如果有则+1 没有则赋值为1
result[current] ? result[current]++ : result[current] = 1;
return result;
}, {});
console.log(res);
var str4 = '';
for (var i in res) {
str4 += res[i] + i;
}
console.log(str4);
var arr = [546, 53, 11, 76, 231, 7671, 5654, 771, 54];
// 统计数组中有多少奇数
var result = arr.reduce(function(result, current) {
// 第一次执行时 传入一个对象作为参数
// 第二次开始 result是上次执行的返回值
// console.log(result);
// console.log(current);
current % 2 ? result.odd++ : null;
return result;
}, {
odd: 0
});
console.log(result);
var arr = [65, 11, 63, 11, 77, 23];
var res = arr.every(function(value) {
return value % 2;
});
console.log(res);
var arr = [65, 11, 63, 12, 77, 23];
var res = arr.some(function(value) {
return value % 2 == 0;
});
console.log(res);
var arr = [344, 674, 65, 98, 96, 3456, 344];
var output = arr.find(function(value, index) {
// return value === 123;
return value < 100 && value % 2 == 0;
});
console.log(output);
•Math对象是ECMAScript提供的一个全局对象,它主要封装了一些常用的数学
函数和常数
•Math对象没有构造函数,无法创建它的实例;调用其属性和方法时,直接使用Math对象名即可。
//Math对象不能实例化
var m1 = new Math(); //type Error
console.log(Math.PI); //直接使用对象名调用属性
Math 是 ECMAScript的全局对象
没有构造函数 无法进行实例(不能new)
直接使用对象名访问其成员(属性、方法)
console.log(Math.PI); //圆周率
console.log(Math.E); // 自然对数
console.log(Math.abs(-3)); // 绝对值
console.log(Math.ceil(3.00000000000000001)); // 向上取整
console.log(Math.log(2)); // 自然对数
console.log(Math.floor(-3.14)); // 向下取整
console.log(Math.max(3, 5)); // 返回较大的值
console.log(Math.min(3, 5)); // 返回较小的值
console.log(Math.pow(2, 31) - 1); // x的y次幂
console.log(Math.round(-3.51)); // 四舍五入
console.log(Math.sqrt(9)); // 平方根
三角函数
Math.sin() = 对边/斜边
Math.cos() = 邻边/斜边
勾股定理
a^2+b^2=c^2
var a = 3;
var b = 4;
var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
console.log(c);
Math.random();
Math.random()函数返回一个0-1之间的小数,伪随机数
0.00000000000001
0.99999999999999
0-100之间的数
random * 100 四舍五入
0-99 向下取整
1-100 向上取整
function getNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
// 10,20
function getNumber(min, max) {
// return Math.round(Math.random() * (max - min) + min);
return Math.floor(Math.random() * (max - min + 1) + min);
}
for (var i = 0; i < 100; i++) {
console.log(getNumber(10, 20));
}
function getCode() {
var checkCode = '';
var codeType;
// 随机出6组Unicode编码
for (var i = 0; i < 6; i++) {
codeType = getNumber(1, 3);
switch (codeType) {
case 1:
// 生成指定范围的随机数
// 将随机的Unicode编码转成 字符串
// 拼接字符串
checkCode += String.fromCharCode(getNumber(48, 57));
break;
case 2:
checkCode += String.fromCharCode(getNumber(97, 122));
break;
case 3:
checkCode += String.fromCharCode(getNumber(65, 90));
break;
}
}
return checkCode;
}
console.log(getCode());
function getColor(opa) {
// 使用短路逻辑解决 默认参数问题
opa = opa || 1; // 断路逻辑
var color = 'rgba(';
for (var i = 0; i < 3; i++) {
color += getNumber(0, 255) + ',';
}
return color + opa + ')';
}
console.log(getColor());
window.onload = function() {
// 双色球
// 红色球 1-32
// 蓝色球 1-16
var list = document.getElementById('list');
var btn = document.getElementById('btn');
function getNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
btn.onclick = doubleColorBall; //给事件赋值实名函数
function doubleColorBall() {
// 初始化
list.innerHTML = '';
var redBall = [];
// var redBallResult = [];
var temp; //临时变量
for (var i = 0; i < 32; i++) {
redBall.push(i + 1);
}
// 从抽奖箱(数组中)获取6个红色球
for (var j = 0; j < 6; j++) {
// 循环6次获得6个红色球
temp = getNumber(0, redBall.length - 1); // 从数组中随机一个索引值
// redBallResult.push(redBall.splice(temp, 1)[0]); // 删除的数组元素 存入数组
list.innerHTML += '' + redBall.splice(temp, 1)[0] + '';
}
// console.log(redBallResult);
// console.log(redBall);
// 随机出一个蓝色球
list.innerHTML += '' + getNumber(1, 16) + '';
}
}
<body>
<button id="btn">按钮</button>
<ul id="list">
</ul>
</body>
• Date对象用于对时期和时间进行存储和计算
//使用指定的年月日[时分秒]进行初始化
var d1 = new Date(2008,7,8); //月份是从0~11
var d2 = new Date(2008,7,8,21,31,42);
var d3 = new Date(‘2008,2,8’) ;//把String转换为Date
//初始化为系统时间
var d = new Date();
var d1 = newDate;
// var d3 = Date(); 构建一个string,值为当前系统时间
//初始化为距离计算机元年指定毫秒数的时间
var dd = new Date(0); var d2 = new Date(1000360024*365)
Date 是ECMAScript的内置对象
拥有构造函数 可以 new
创建时间对象
var d = new Date(); // 获得当前系统时间
console.log(d);
创建时间对象 带参数
指定一个时间 年,月,日,时,分,秒
var d2 = new Date(2008, 0, 10);
console.log(d2);
var d3 = new Date('2020,5,1 15:12:00');
console.log(d3);
var d4 = new Date();
console.log(d4.getDate()); // 获得日期部分 1-31
console.log(d4.getDay()); // 获得星期 0-6
console.log(d4.getFullYear()); // 获得年份
console.log(d4.getHours()); // 获得小时 0-23
console.log(d4.getMinutes()); // 获得分钟 0-59
console.log(d4.getSeconds()); // 获得秒 0-59
console.log(d4.getMilliseconds()); // 获得毫秒 0-999
console.log(d4.getMonth() + 1 + '月'); // 获得月份 0-11 需要使用月份时+1
getTime() 时间戳 它是编程中唯一不重复的数
电商网站订单号
20200110094352+用户id 10002354378 + 时间戳
console.log(d4.getTime()); // 获得当前时间距离UTC时间1970年1月1日12点的毫秒差
console.log(d4.getTimezoneOffset() / 60); // 时区
设置时间
var d = new Date();
d.setHours(8);
console.log(d.getHours());
JS的时间容错
如果在设置时间时超出取值范围 自动计算到下一个运算周期
d.setTime(65);
d.setDate(d.getDate() + 22);
console.log(d);
console.log(Date.now()); // 快速获得时间戳
时间格式
var d = new Date();
// console.log(d);
// console.log(d.toString());
// console.log(d.toLocaleString());
var yy = d.getFullYear();
var mm = d.getMonth();
var dd = d.getDate();
var h = d.getHours();
var m = d.getMinutes();
var s = d.getSeconds();
console.log(yy + ‘-’ + (mm + 1) + ‘-’ + dd + ’ ’ + h + ‘:’ + m + ‘:’ + s);
语法: setInterval(callback,delay);
描述: setInterval 将每隔delay的时间执行callback
参数: callback(function) 需要反复执行的函数
delay(number) 延迟/间隔 时间 毫秒值
var i = 0;
setInterval(function() {
console.log(i);
i++;
}, 2000);
window.onload = function() {
var time = document.getElementById('time');
setInterval(function() {
var d = new Date();
var yy = d.getFullYear();
var mm = d.getMonth() + 1;
var dd = d.getDate();
var h = d.getHours() > 12 ? d.getHours() - 12 : d.getHours();
var m = d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes();
var s = d.getSeconds() < 10 ? '0' + d.getSeconds() : d.getSeconds();
time.innerHTML = yy + '-' + mm + '-' + dd + ' ' + h + ':' + m + ':' + s;
}, 1000);
}
// 两个时间
// 当前时间 未来时间
// 未来时间 - 当前时间
window.onload = function() {
var djs = document.getElementById('djs');
setInterval(function() {
var futureTime = new Date(2020, 0, 17, 18, 0, 0); // 未来时间
var now = Date.now(); // 当前时间的时间戳
// JS在做时间对象运算时可以自动将时间对象转成时间戳进行计算
// console.log(futureTime);3
// console.log(now);
var time = futureTime - now; // 需要倒计时的时间 毫秒
var s = time / 1000; // 将毫秒转换成秒
var day = Math.floor(s / (60 * 60 * 24)); // 将秒换算成天
var hour = Math.floor(s % 86400 / 3600); // 计算剩余小时
var min = Math.floor(s % 3600 / 60); // 计算分钟
var sec = Math.floor(s % 60); // 获得秒
djs.innerHTML = '距离春节假期来临 还剩:' + day + '天' + hour + '时' + min + '分' + sec + '秒';
}, 1000);
}
• BOM:Brower Object Model浏览器对象模型,用来访问和操作浏览器窗口,
使JS有能力与浏览器交互
• 通过使用BOM、可移动窗口、更改状态栏文本、执行其它不与页面内容
发生直接联系的操作
• 没有相关标准,但被广泛支持
• DOM:Document Object Model文档对象模型,用来操作当前HTML文档的
内容
• 定义了访问和操作HTML文档的标准方法
• 通过对DOM树的操作,实现对HTML文档树据的操作
• W3C指定了相关标准
• window对象是BOM的根对象,其它对象其实都是window对象的属性,
window对象的属性和方法都可以省略"window."
window对象在浏览器中表示打开的浏览器窗口
window是BOM的根对象
window浏览器环境中的最高级对象(全局对象)
window对象中的属性和方法都可以省略 window.
window下所有子属性和方法全局都可以访问
console.log(window);
console.log(alert === window.alert);
console.log(parseInt === window.parseInt);
所有的全局变量和全局函数 都是window的属性
var a = 10; console.log(a); console.log(window.a); var langth = 1; console.log(length);
文档显示区域宽高
console.log(innerHeight); console.log(innerWidth); var name = 10; // 窗口名 字符串类型 console.log(name + 10); // 拼接字符串
浏览器宽高
console.log(outerHeight); console.log(outerWidth);
window全局函数
// var b = confirm('你确定要关闭吗?'); // 弹出一个带有确定和取消按钮点窗口 用户点击以后获得一个布尔值
// if (b) close(); // 用于关闭页面(如果当前只有一个页面则关闭浏览器)
window.onload = function() {
var pri = document.getElementById('print');
pri.onclick = function() {
print(); // 打印
}
}
<body>
<button id="print">打印当前页面</button>
</body>
浏览器打开窗口
var config = "left=200,top=300,width=500,height=300";
//打开窗口
var openurl = "https://www.baidu.com";
var newWin = open(openurl, 'popwin', config);
对话框
• window对象提供了三种对话框:
• window.alert(msg) //弹出一个警告框
• window.primpt(msg) //弹出一个输入提示框
• window.confirm(msg) //弹出一个确认框
定时器
• 多用于网页动态时钟、制作倒计时效果等
• 周期性时钟
• 以一定的间隔执行代码,循环往复
• 一次性时钟
• 在一个设定的时间间隔之后来执行代码,而不是在函数被调用后立即执行
周期性定时器
• setInterval(exp,time):周期性触发代码exp
• exp:执行语句
• time:时间周期,单位为毫秒
• 返回已经启动的定时器ID
• clearInterval(tID):停止启动的定时器
• tID:启动的定时器对象
一次性定时器
• setTimeout(exp,time):一次性触发代码exp
• exp:执行语句
• time:时间周期,单位为毫秒
• 返回已经启动的定时器ID
• clearTimeout(tID):停止启动的定时器
• tID:启动的定时器对象
JavaScript 提供了两种计时器
周期性计时器
setInterval('console.log(123)', 2000);
返回值: number 返回的是计时器的编号
每间隔一定的时间 执行一次函数
var timer = setInterval(function() { console.log('ok'); }, 1000); console.log(timer);
window.onload = function() { var stop = document.getElementById('stop'); stop.onclick = function() { // 参数: 计时器设置时的编号 clearInterval(timer); // 用于关闭周期性计时器 } };
一次性计时器
var timer = setTimeout(function() { // 只执行一次 延迟代码的执行时间 console.log('ok'); }, 2000); clearTimeout(timer);
setTimeout 是一个异步操作
JS引擎如何执行代码
JS引擎 单线程
线程指的是可以同时执行的任务数量
I/O阻塞 Input/Output
BIOS basic input output system
当出现异步操作时 异步操作会从主线程中移出 将这个操作放入到 事件队列
当主线程内的代码执行完毕后 开始执行事件队列
setTimeout()
for (var i = 0; i < 5; i++) {
// 循环5次
// 5个计时器
setTimeout(function() {
console.log(i);
}, 1000);
}
alert(1);
alert(2);
console.log(1);
setTimeout(function() {
console.log(2)
}, 0);
console.log(3);
/ 如何输出0 1 2 3 4
for (var i = 0; i < 5; i++) {
// 循环5次
// 5个计时器
setTimeout(function() {
console.log(i);
}, 1000);
}
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 0);
})(i);
}
for (let i = 0; i < 5; i++) { // let 用于申明块级变量
setTimeout(function() {
console.log(i);
}, 0);
}
console.log(123);
setTimeout(function() {
console.log('ok');
}, 1000);
console.log(456);
• navigator对象
• location对象
• history对象
• screen对象
• navigator对象包含浏览器URL的信息
• 常用于获取客户端浏览器和操作系统信息
for(var i in navigator){
console.log(i+":"+navigator[i]);
//遍历navigator对象的所有属性
}
console.log(location);
console.log(location.href); // 获得地址内容
location.hash //获得地址从#开始的部分 锚
location.host // 主机名和端口号
location.hostname // 主机名
location.pathname // 路径名 从第一个 /开始获取
location.search // 获得从?开始的部分
console.log(location.pathname);
console.log(location.host);
window.onhashchange = function() {
// onhashchange 是 SPA(单页面应用) 的基础
console.log('hash改变了');
}
window.onload = function() {
var link = document.getElementById('link');
link.onclick = function() {
// location.href 可以修改地址
location.href = "https://www.baidu.com";
}
}
模拟获取数据
var data = location.search.slice(1); // 获取数据
data = data.split('&');
console.log(data);
for (var i = 0; i < data.length; i++) {
console.log(data[i].split('=')[1]);
}
• history对象包含用户(在浏览器窗口中)访问过的URL的历史记录
history.back() 后退
history.forword() 前进
• Screen对象包含有关客户端显示屏幕的信息,方用于获取屏幕的分辨率和色彩
• JavaScript程序将利用这些信息来优化它们的输出,以达到需要显示要求
复习
var data = [{
name: '张三',
age: 18,
sex: 1
}, {
name: '李四',
age: 17,
sex: 1
}, {
name: '小花',
age: 25,
sex: 0
}, {
name: '小汪',
age: 30,
sex: 1
}, {
name: '小闫',
age: 35,
sex: 1
}];
// 男性 女性 成年人 未成年人
var res = data.reduce(function(result, current) {
if (current.age >= 18) {
result.adult++;
} else {
result.nonage++;
}
if (current.sex) {
result.man++;
} else {
result.woman++;
}
return result;
}, {
// 要统计的东西写成对象的属性
adult: 0, // 成年
nonage: 0, // 未成年
man: 0, // 男
woman: 0 // 女
});
console.log(res);
函数、构造函数、回调函数、匿名函数、对象、方法 这些定义的区别
函数其实就是一个完整的功能 包含了多条语句来实现某个功能(子程序)
申明和执行会提前
拥有参数 为了让函数更加的灵活
返回值 获得运行结果
构造函数 用于创建对象的函数(类似于Java中的Class)
回调函数 将函数作为参数来使用
1. 让调用变得简单
2. 改变代码的执行顺序
3. 异步
匿名函数 没有名字的函数
仅在执行时,临时创建作用域链对象 用完即释放 节省内存空间
对象(Object) 一组无序的 数据(属性)和功能(方法)的集合
在JS中 除了关键字 保留字 运算符 操作符以外 所有东西都是对象
方法 方法就是函数
当函数在对象中作为属性存在的时候通常称其为方法
function fn() {
}
window.fn()
var arr = [1, 2, 3, 4, 5];
arr.forEach(function(val, i) {
// 完整遍历数组 不需要写for语句
console.log(val * 2);
})
Array.prototype.fn = function(callback) {
for (var i = 0; i < this.length; i++) { // this 在原型函数中 指向调用者
// 循环调用回调函数
callback(this[i], i);
}
}
var arr = [1, 3, 5, 6];
arr.fn(function(value, index) {
// console.log(value, index);
console.log(value * 2);
})
Array.prototype.map()
arr.map(callback)
var arr = [1, 3, 5, 8];
var arr2 = arr.map(function(val, i) {
return val * 2;
});
console.log(arr2);
console.log(arr);
Array.prototype.abc = function(callback) {
var arr = [];
for (var i = 0; i < this.length; i++) {
arr.push(callback(this[i], i));
}
return arr;
}
var arr = [6, 5756, 14, 86, 11];
var res = arr.abc(function(val, i) {
return val / 2;
});
console.log(res);
4.问 两个数组 如何判断里面的数据相同
解题思路:1. 排序 使用相同的排序算法 结果一定相同
2. == 比较的是地址
3. 转换成字符串 比较字符串
var arr1 = [124, 765, 867, 'bc', true];
var arr2 = [867, 124, 765, true, 'bc'];
arr1.sort();
arr2.sort();
// 数组的toString()是将里面所有的元素都调用 toString() 用,连接
console.log(arr1.toString() === arr2.toString());
// console.log(arr2.toString());
5.隐式转换
console.log([] == ![]); // true
// 数组是引用类型 比较的是地址
// 运算符的优先级
// 逻辑非优先级高于等于
console.log(![]); // false 0
// 0
console.log(Number([])); // 空数组转数字的结果是0
console.log([] == 0);
• DOM是W3C(万维网联盟)的标准,是中立于平台和语言的接口,
它允许程序和脚本动态的访问和更新文档的内容、结构和样式。
• W3C DOM标准被分为3个不同的部分:
• 核心DOM 针对任何结构化文档的标准模型
• XML DOM 针对XML文档的标准模型
• HTML DOM针对HTML文档的标准模型
• HTML DOM:针对HTML文档的对象模型
• 当网页被加载时,浏览器会创建页面的文档对象模型
• 通过DOM,可以访问所有的HTML元素,连同它们所包含的文本
和属性
• 可以对其中的内容进行修改和删除,同时也可以创建新的元素
• 文档中的所有节点组成了一个文档树
• document对象是一颗文档树的根
当浏览器加载一个HTML文件时 会自动创建对应的document对象
在页面中所有的元素(html标签)属性(标签属性)文本 注释 都被看作为是节点
而是document对象是最高级级别的节点(根节点)
一个元素 div元素 从标记开始到标记结束
所有的节点在JS中 都是对象(重要)
document对象
• 浏览器内置的JS解释器会为载入的每个HTML文档创建一个对应的document对象
• 通过使用document对象,可以从脚本中对HTML页面中的所有元素进行访问
var box = document.getElementById('box');
var li4 = document.getElementById('li4');
var list = document.getElementById('list');
console.dir(box);以目录形式打印对象 标签
• 通过可编程的对象模型,JavaScript获得了足够的能力来创建动态的HTML
• 查找节点
• 读取节点信息
• 修改节点信息
• 创建新节点
• 删除节点
• 什么是节点树
• HTML DOM将HTML文档视作树结构。
• 文档中的元素、属性、文本、注释等都被看作一个节点。
• 节点树中的节点彼此拥有层级关系,DOM使用如下属性遍历整个
节点树:
语法:none.parentNode
含义:获得node的父级节点
可以通过parentNode获取父级节点,最高级别的节点是document
document.prentNode是null
console.log(box.parentNode);
console.log(li4.parentNode.parentNode.parentNode.parentNode.parentNode);
语法:node.childNodes
含义:获得node的子节点 集合(多个)
结果为类数组对象
console.log(list.childNodes);
语法:node.firstChild
含义:获得第一个子节点
console.log(list.lastChild);
语法:node.lastChile
含义:获得最后一个子节点
console.log(list.firstElementChild);
语法:node.firstElementChild
含义:获得第一个子元素
console.log(list.firstElementChild);
语法:node.lastElementChild
含义:获得最后一个子元素
console.log(list.lastElementChild);
语法:node.children
含义:获得所有的子元素
结果是类数组
console.log(list.children);
for (var i = 0; i < list.children.length; i++) {
console.log(list.children[i]);
}
• 节点树中使用如下方法访问平行的兄弟节点:
语法:node.previousSibling
含义:获得上一个兄弟节点
console.log(li4.previousSibling);
语法:node.nextSibling
含义:获得下一个兄弟节点
console.log(li4.nextSibling);
语法:node.previousElementSibling
含义:获得上一个兄弟元素
console.log(li4.previousElementSibling);
语法:node.nextElementSibling
含义:获得下一个兄弟元素
console.log(li4.nextElementSibling);
节点名称 nodeName
• nodeName:节点的名称,String类型属性
• nodeName 是只读的
语法:node.nodeName
含义:节点名 只读string
元素节点 返回大写的标签
文本节点 #text
文档节点 #document
注释节点 #comment
属性节点 属性名
var list = document.getElementById('list');
console.log(list.childNodes[1].nodeName);
console.log(document.nodeName);
var box = document.getElementById('box');
// 将所有的div元素放入数组
var arr = [];
for (var i = 0; i < box.children.length; i++) {
if (box.children[i].nodeName === 'DIV') {
arr.push(box.children[i]);
}
}
console.log(arr);
• nodeType:节点类型,Number类型属性
节点类型
语法:node.nodeType
语义:节点类型 number类型
元素节点 1
属性节点 2
文本节点 3
注释节点 8
文档节点 9
文档声明 10
window.onload = function() {
var box = document.getElementById('box');
// console.log(box.childNodes[1].nodeType)
// console.log(document.childNodes[0].nodeType);
var arr = [];
for (var i = 0; i < box.childNodes.length; i++) {
if (box.childNodes[i].nodeType === 1) {
arr.push(box.childNodes[i]);
}
}
console.log(arr);
}
• nodeValue:节点的值,String类型属性
所有的元素节点都用于 innerHTML 属性
用于获取和设置HTML内容
访问该元素里面的HTML内容
文本内容
textContent 用于获取和设置文本内容
无法识别标签
• 元素节点对象的innerHTML属性读取或设置元素节点中的HTML内 容
< div id=“div1”>JavaScript
var div=document.getElementById(‘div1’);
console.log(div.innerHTML);//读取
div.innerHTML = ‘jQuery’;//设置
• 元素节点对象的textContent属性用于读取或设置元素节点中的文
本内容
注:有争议的innerText
标准DOM操作中,并没有innerText属性;
IE8及之前的IE浏览器不支持标准的textContent属性
使用innerText实现类似的功能,目前此属性已被大多数浏览
器所兼容,但Firefox仍不支持此属性
• 元素节点的attributes属性返回节点的属性集合,即一个类数组对
象
< div id=“div1” οnclick=“up()” class=“add”>
var div=document.getElementById(‘div1’);
console.log(div.attributes);//类数组对象
console.log(div.attributes.length);//3
console.log(div.attributes[1]);//属性对象
元素节点用于属性集合
元素节点attributes属性返回属性(节点)集合 类数组对象
读取属性
• 可以使用如下几种方式读取某个属性的值:
(1)element.attributes[下标].value
(2)element.attributes[‘属性名’].value
(3)element.getAttributeNode(‘属性名’).value
(4)element.getAttribute(‘属性名’)
设置属性
• 可以使用如下两种种方式设置元素的属性:
(1)element.setAttribute(name,value);
(2)element.setAttributeNode(attrNode);
移除属性
• 可以使用如下两种种方式删除一个属性:
(1)element.removeAttribute(‘属性名’);
(2)element.removeAttributeNode(attrNode)
判断属性
• 如下方法可用于判定元素是否有指定属性:
(1)element.hasAttribute(‘属性名’);//true或false
(2)element.hasAttributes(); //是否拥有属性、IE8及以下版本不支持此方法
for (var i = 0; i < box.attributes.length; i++) {
// 遍历以后得到的是属性节点
// 节点值
console.dir(box.attributes[i]);
}
获得属性值
语法: element.getAttribute(‘attrName’);
box.setAttribute('data-test', 'abc'); // data-xxx 是html5标准的自定义属性
设置属性值
语法: element.setAttribute(‘attrName’,‘value’);
box.setAttribute('title', 'hello world');
box.setAttribute('data-test', 'abc'); // data-xxx 是html5标准的自定义属性
删除属性
语法: element.removeAttribute(‘attrName’)
box.removeAttribute('class');
判断属性
语法: element.hasAttribute(‘attrName’);
判断属性是否存在 并返回一个布尔值
console.log(box.hasAttribute('class'));
btn.onclick = function() {
// if (box.hasAttribute('class')) { // 判断是否有class属性
// box.removeAttribute('class'); // 删除
// } else {
// box.setAttribute('class', 'red'); // 添加
// }
if (box.getAttribute('class') === 'red') {
box.setAttribute('class', 'green');
} else {
box.setAttribute('class', 'red');
}
}
类名的特点 空格分割
window.onload = function() {
var box = document.getElementById('box');
// 添加类名
function addClass(elm, className) {
elm.setAttribute('class', elm.getAttribute('class') + " " + className);
}
addClass(box, 'center');
addClass(box, 'center2');
addClass(box, 'center3');
// 删除类名
function removeClass(elm, className) {
// 1. 获得类名
var value = elm.getAttribute('class');
// 类名的特点 空格分割
// console.log(value);
var arr = value.split(' '); // 将字符串切割成数组
// console.log(arr);
var index = arr.indexOf(className); // 在数组中查找类名 获得索引
arr.splice(index, 1);
value = arr.join(' ');
// console.log(value);
elm.setAttribute('class', value);
}
removeClass(box, 'a3');
removeClass(box, 'center2');
}
扩展:
HTML5 为元素节点增加了类名接口 classList
window.onload = function() {
var box = document.getElementById('box');
// console.log(box.classList);
box.classList.add('center'); // 添加类名
box.classList.remove('d2'); // 删除类名
}
选项卡
window.onload = function() {
// 1. 事件绑定给谁? li 元素
// 2. 谁要操作类名 li和div
var tabs = document.getElementById('tabs');
var child = tabs.children;
var oUl;
var oDiv = [];
for (var i = 0; i < child.length; i++) {
if (child[i].nodeName === 'UL') {
oUl = child[i]; // 选择UL
} else if (child[i].nodeName === 'DIV') {
oDiv.push(child[i]); //选择DIV
}
}
var oLi = oUl.children; //选择LI
// 3. 绑定事件
for (var j = 0; j < oLi.length; j++) {
// 通过循环给每一个li元素添加点击事件
// oLi[j].setAttribute('data-index', j); // 为每一个元素添加一个索引值
oLi[j].index = j; // index不是html标准属性
oLi[j].onclick = function() {
// // 点击li元素的时候 获得索引值
// var index = this.getAttribute('data-index');
// 删除所有li元素的 actived 类名
// 删除所有Div元素的 show 类名
for (var k = 0; k < oLi.length; k++) {
oLi[k].classList.remove('actived');
oDiv[k].classList.remove('show');
}
// 给被点元素添加 actived 类名
this.classList.add('actived');
// 给被点击的li元素所对应的div元素加 show类名
// oDiv[index].classList.add('show');
oDiv[this.index].classList.add('show');
}
}
}
<body>
<div id="tabs">
<ul>
<li class="actived">选项一</li>
<li>选项二</li>
<li>选项三</li>
</ul>
<div class="show">内容111111</div>
<div>内容22222222222222</div>
<div>内容33333333333333</div>
</div>
</body>
DOM
DOM选取元素、增加、删除和替换节点
• document.getElementById(‘id’)可用于当前DOM树中根据ID选择某
一个子元素
• Node.getElementsByTagName(‘标签名’)可根据标签名返回所有具有指定标签名的元素集合
• document.getElementsByName(‘name属性值’)可以返回DOM数中具有指定那么属性值的所有子元素集合
• node.getElementsByClassName(‘className’)可以根据class名称选
取元素的方法(IE9+、Firfox3+、Safari3.1+、Chrome和Opera9.5+)
语法: node.getElementsByTagName(‘tagName’);
作用: 通过标签名选择元素
返回值: 类数组对象
var oDiv = document.getElementsByTagName('div');
console.log(oDiv);
var oDiv = box.getElementsByTagName('div');
console.log(oDiv);
语法: document.getElementsByName(‘name’);
作用: 通过name属性选择表单元素
返回值: 类数组对象
var oCheck = document.getElementsByName('ck');
var oCheck = document.querySelectorAll('input[type="checkbox"]');
console.log(oCheck);
全选功能
如何让checkbox被选中
checkbox 拥有内部属性 checked 它是一个布尔值
// 遍历其他checkbox 让其他checkbox的checked属性和第一个相同
for (var i = 1; i < oCheck.length; i++) {
oCheck[i].checked = oCheck[0].checked;
}
console.log(document.documentElement); // 返回html元素
console.log(document.body); // 返回body
console.log(document.head); // 返回head
• 通过css选择器选取元素
(1)node.querySelector(‘selector’)//返回第一个匹配的
(2)node.querySelectorAll(‘selector’)//返回全部匹配的
< div id=“div1”>
< p class=“p1”>中国< /p>
< p class=“p2”>澳门< /p>
< p class=“p2”>台湾< /p>
< p class=“p2”>香港< /p>
< /div>
var div= document.getElementById(‘div1’);
var p= div.querySelectorAll(’.p2’);
console.log§;
语法: node.querySelector(‘selector’)
作用: 通过给定的css选择器选择所匹配的第一个元素
id #
class .
element tagName
attribute []
> 子代选择器
空格 后代选择器
var box = document.querySelector('.box');
console.log(box);
var news = document.querySelector('a[href*="news"]');
console.log(news);
var div3 = document.querySelector('div:nth-of-type(3)');
console.log(div3);
语法: node.querySelectorAll(‘selector’);
作用: 根据给定的选择器 选择所有匹配的元素
返回结果是一个类数组对象
var evenDiv = document.querySelectorAll('div:nth-of-type(even)');
console.log(evenDiv);
选项卡
window.onload = function() {
// 1. 选元素
// li元素的类名 div元素的类名
var oLi = document.querySelectorAll('#tabs>ul>li');
var oDiv = document.querySelectorAll('#tabs>div');
// 使用 querySelectAll 选择的元素 可以使用 forEach 函数
// forEach语法和数组一样
oLi.forEach(function(elm, i) {
elm.index = i; // 给li元素添加一个属性 index
// 给li元素加点击事件
elm.onclick = function() {
// forEach 遍历li元素
oLi.forEach(function(el) {
el.classList.remove('actived'); //删除所有li元素的actived类名
});
// 遍历div元素
oDiv.forEach(function(el) {
el.classList.remove('show'); //删除所有div元素的show类名
});
this.classList.add('actived');
oDiv[this.index].classList.add('show'); // li元素所对应的div元素添加类名
// this指向的是被点击的那个li元素
}
})
}
<body>
<div id="tabs">
<ul>
<li class="actived">选项1</li>
<li>选项2</li>
<li>选项3</li>
<li>选项4</li>
<li>选项5</li>
<li>选项6</li>
<li>选项7</li>
</ul>
<div class="show">11111111111111111111</div>
<div>22222222222222</div>
<div>3333333333333</div>
<div>444444444444</div>
<div>5555555555555555555</div>
<div>6666666666</div>
<div>777777777777777</div>
</div>
</body>
• document.documentElement返回整个HTML文档的根元素(即
< html>元素)
• document.head返回HTML文档中< head>元素
• document.body返回HTML文档中< body>元素
• 创建节点使用如下方法创建一个新的元素
• document.createElement(‘元素名’);
• 创建文本节点使用如下方法可以创建一个新的文本节点
• document.createTextNode(‘text’);
• parentNode.appendChild(childNode)可用于将一个父元素追加最
后一个子节点
• parentNode.insertBefore(newChild,existingChild)方法用于在父元素中指定子
节点之前添加一个新的子节点
• 可以使用parentNode.removeChild(childNode);
• 此方法返回被删除的节点的引用
• 可以使用如下方法替换一个已经存在的子节点:
parentNode.replaceChild(newNode,oldNode);
语法:document.createElement(‘tabName’);
作用:用于创建元素节点
返回值:新创建的元素节点
var div = document.createElement('div');
div.textContent = 'abc';
console.log(div);在这里插入代码片
语法: parentNode.appendChild(childNode);
作用: 用于在父节点的结尾添加一个子节点
document.body.appendChild(div);
语法:
parentNode.insertBefore(newChild,existingChild);
作用: 用于在指定节点的前面插入一个新节点
document.body.insertBefore(div, btn);
增加内容
window.onload = function() {
var btn = document.querySelector('button');
var list = document.querySelector('#list');
btn.onclick = function() {
var li = document.createElement('li');
var oLi = document.querySelectorAll('#list>li');
li.innerHTML = '新的li元素';
list.insertBefore(li, oLi[2]);
}
}
语法: parsentNode.removeChild(childNode);
作用: 在父节点中删除一个子节点
返回值: 被删除的元素
window.onload = function() {
var btn = document.querySelector('.btn');
var list = document.querySelector('#list');
btn.onclick = function() {
// 语法: parsentNode.removeChild(childNode);
// 作用: 在父节点中删除一个子节点
// 返回值: 被删除的元素
var lastLi = document.querySelector('li:last-of-type');
console.log(list.removeChild(lastLi));
// if (lastLi) list.removeChild(lastLi);
}
}
元素节点移动
window.onload = function() {
var btns = document.querySelectorAll('.btns>button');
var left = document.querySelector('.left');
var right = document.querySelector('.right');
btns[0].onclick = function() {
// 右移一个
// 左边删除 右边添加
var firstLi = document.querySelector('.left>li:first-of-type');
if (firstLi) {
var del = left.removeChild(firstLi);
right.appendChild(del);
}
}
btns[1].onclick = function() {
// 获得左边所有的li
var oLi = document.querySelectorAll('.left>li');
oLi.forEach(function(elm) {
var del = left.removeChild(elm);
right.appendChild(del);
});
}
}
* {
padding: 0;
margin: 0;
}
button {
padding: 5px 10px;
}
.btns {
text-align: center;
}
.list {
overflow: hidden;
width: 1004px;
margin: 20px auto;
}
.list>ul {
list-style-type: none;
width: 400px;
margin: 0 50px;
height: 210px;
border: 1px solid black;
float: left;
}
.list>ul>li {
text-align: center;
}
<body>
<div class="btns">
<button> 右移一个 button>
<button> 右移全部 button>
<button> 左移一个 button>
<button> 左移全部 button>
div>
<div class="list">
<ul class="left">
<li>第1个lili>
<li>第2个lili>
<li>第3个lili>
<li>第4个lili>
<li>第5个lili>
<li>第6个lili>
<li>第7个lili>
<li>第8个lili>
<li>第9个lili>
<li>第10个lili>
ul>
<ul class="right">ul>
div>
body>
window.onload = function() {
// 使用一个标题元素 替换p元素 并且需要保存其内容和属性
// 语法: parentNode.replaceChild(newNode,oldNode);
// 作用: 使用一个新节点替换一个旧节点
var btn = document.querySelector('button');
var p = document.querySelector('p');
btn.onclick = function() {
var h1 = document.createElement('h1'); // 创建元素
h1.innerHTML = p.innerHTML; //设置内容
var attr = p.attributes; // 获取属性集合
for (var i = 0; i < attr.length; i++) {
h1.setAttribute(attr[i].nodeName, attr[i].nodeValue);
}
document.body.replaceChild(h1, p);
}
}
• HTML DOM定义了用于HTML的一系列标准的对象,以及访问的
处理HTML文档的标准方法
• HTML标签对象化
• 网页中的每个元素都看作一个对象
var div = document.getElementById(‘div’);
//创建一个新的图片对象,加入到div中
var newNode = new Image();
newNode.src=“a.jpg”;
div.appendChild(newNode);//将HTML对象化
• 标准DOM提供了统一的操作接口
createElement
appendChild
setAttribute
removeAttribute
nodeName…
• HTML DOM提供了封装好的各种对象
Image
Select
Option…
• 标准DOM的实现方式
var newNode = document.createElement(‘img’);
• HTML DOM的实现方式
var newNode = new Image();
• 标准DOM操作适合于:
操作节点,创建,删除,查找等
• HTML DOM操作适合于:
操作属性,如读取或者修改属性的值
var url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1578994332712&di=6c47d56f41fbcb2bfb7bf84efac7c6ab&imgtype=0&src=http%3A%2F%2Fn.sinaimg.cn%2Fsinacn10%2F386%2Fw640h546%2F20180812%2F7c68-hhqtawx2011571.jpg";
window.onload = function() {
// var img = document.createElement('img');
// img.setAttribute('src', url);
// document.body.appendChild(img);
// HTML DOM
// HTML DOM将元素对象化
// 对象拥于属性, 所以可以直接通过.操作符访问属性
// var img = new Image(); // 使用构造函数创建图片
// img.src = url;
// document.body.appendChild(img);
// var s = new Option();
// console.log(s);
// var div = new Div();
// console.log(div);
// var a = new A();
// console.log(a);
// 不是所有的元素都进行了封装,不建议使用构造函数创建元素
// 创建元素依旧使用 document.createElement()
var div = document.querySelector('.box');
// div.setAttribute('id','')
// div.id = 'newid';
// console.log(div.title);
// 不是所有的属性都可以使用HTMLDOM操作
// console.log(div.class); // class 在JS中是关键字
// console.log(div.className); // 类名 className
// 获得行内样式 使用 elm.style.cssText
// console.log(div.style.cssText);
// div.style.cssText += 'font-size:2em;';
// div.style.fontSize = '3em';
}
• 获取元素宽高
• offsetWidth/offsetHeight
• 获取定位值
• offsetTop/offsetLeft
• 获得计算后的CSS样式
• getComputedStyle(elm)[‘attr’] // 标准
• elm.currentStyle[‘attr’] // 低版本ie
元素的style属性是一个对象 样式对象
修改单个样式,直接通过style对象的属性进行设置,采用小驼峰命名法
window.onload = function() {
var box = document.querySelector('.box');
// 获得元素的行内样式文本
// elm.style.cssText
// console.log(box.style.cssText);
// 元素的style属性是一个对象 样式对象
for (var i = 0; i < box.style.length; i++) {
// style是对象
console.log(box.style[i]); //属性名
console.log(box.style[box.style[i]]); //属性值
}
// 给元素添加行内样式
// 修改背景色
// 修改单个样式,直接通过style对象的属性进行设置,采用小驼峰命名法
box.style.backgroundColor = 'yellow';
}
获得元素大小
获得盒模型大小
offsetWidth/offsetHeight
标准盒模型 content-box
content+padding+border = 元素大小
IE盒模型/怪异盒模型 border-box
content = 元素大小
console.log(outer.offsetWidth);
console.log(outer.offsetHeight);
offsetTop/offsetLeft
偏移量(定位值)
修改元素的padding值和margin值会影响偏移量
定位值也会影响偏移量
如果父级元素定位了 根据父元素的0,0点计算
如果父元素没有定位 根据body的0,0点计算
console.log(inner.offsetTop);
console.log(inner.offsetLeft);
层叠样式表 CSS
元素最后生效的样式 需要计算的
获取计算后的样式
兼容性问题
getComputedStyle() 标准浏览器
console.log(getComputedStyle(outer)[‘height’]);
elm.currentStyle[‘style’]; // 低版本ie
alert(inner.currentStyle[‘top’]);
解决兼容问题
function getStyle(elm, style) {
if (typeof getComputedStyle === 'function') {
return getComputedStyle(elm)[style];
} else {
return elm.currentStyle[style];
}
}
alert(getStyle(inner, 'height'));
常用HTML DOM对象
• Image对象
• Image对象代表嵌入的图像
• < img>标签每出现一次,一个Image对象就会被创建
• 也可以使用new Image()创建一个新的对象
• 常用属性:
• src
• height
• width
• Table对象代表一个HTML表格
• < table>标签标示一个Table对象
• 常用属性
• rows
• 常用方法
• insertRow(index):返回TableRow对象
• deleteRow(index)
• TableRow对象代表一个HTML表格行
• 标签标示一个TableRow对象
• 常用属性
• cells、innerHTML、rowIndex
• 常用方法
• insertCell(index):返回TableCell对象
• deleteCell(index)
• TableCell对象代表一个Html表格单元格
• < td>标签标示一个TableCell对象
• 常用属性
• cellIndex、innerHTML、colSpan、rowSpan
table 对象
每一个table标签都是一个table对象
table.rows 返回表格中所有的行的集合 类数组对象
console.log(table.rows);
insertRow 创建了一个行 tr
将tr插入到指定索引
tr.cells 返回当前行 所有单元格的集合 类数组对象
insertCell 用于在行中添加单元格
点击按钮添加一行
window.onload = function() {
var table = document.querySelector('table');
var btn = document.querySelector('button');
// table.rows 返回表格中所有的行的集合 类数组对象
// console.log(table.rows);
// insertRow 创建了一个行 tr
// 将tr插入到指定索引
var index = 3;
btn.onclick = function() {
var tr = table.insertRow(table.rows.length); // 返回新创建的行
// tr.cells 返回当前行 所有单元格的集合 类数组对象
// insertCell 用于在行中添加单元格
var td1 = tr.insertCell(0);
td1.innerHTML = index < 10 ? '0' + index : index;
var td2 = tr.insertCell(1);
td2.innerHTML = '小汪';
var td3 = tr.insertCell(2);
td3.innerHTML = '35';
var td4 = tr.insertCell(3);
td4.innerHTML = '男';
var td5 = tr.insertCell(4);
td5.innerHTML = '';
index++;
// 事件添加
var oBtn = document.querySelectorAll('input[type="button"]');
oBtn.forEach(function(elm) {
elm.onclick = function() {
// 通过按钮父级找到td 再找父级tr 获得tr在表格中的索引
var i = this.parentNode.parentNode.rowIndex;
table.deleteRow(i);
}
});
}
}
** "container">
"container">
"table table-bordered table-hover text-center">
编号
姓名
年龄
性别
more
01
张三
20
男
"button" value="删除">
02
李四
25
男
"button" value="删除">
居中问题
vscode中 Lorem+tab键 测试文 假文
外面套一层div使用 vertical-align: middle;
display: table-cell;
不能与float:left一起使用,只能写在外面一层
.outer {
width: 800px;
height: 500px;
margin: 0 auto;
/* float: left; */
border: 1px solid black;
}
.inner {
width: 800px;
height: 500px;
margin: 0 auto;
/* line-height: 500px; */
vertical-align: middle;
display: table-cell;
}
<div class="outer">
<div class="inner">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, eligendi impedit. Veritatis totam alias accusamus, a possimus odio numquam pariatur eveniet, illum consequuntur soluta cupiditate eius fuga ipsum nobis aspernatur. Lorem ipsum dolor sit
</div>
</div>
文档碎片(了解)
• document.createDocumentFragment()
• 用于创建文档碎片 优化DOM操作的频率
document.createDocumentFragment()
文档碎片 性能优化
DOM
操作页面的元素 创建元素 修改元素内容 修改属性 设置属性…
操作样式 类名 style …
选取元素 …
DOM操作 性能非常差
原则 css能实现的功能一律不用JS
window.onload = function() {
var list = document.querySelector('#list');
// var fra = document.createDocumentFragment(); //创建一个文档碎片
// console.time('go');
// for (var i = 0; i < 50000; i++) {
// var tempLi = document.createElement('li');
// tempLi.innerHTML = '第' + i + '个li';
// fra.appendChild(tempLi);
// }
// list.appendChild(fra);
// console.timeEnd('go');
console.time('go');
var str = '';
for (var i = 0; i < 50000; i++) {
str += '第' + i + '个li'
}
list.innerHTML = str;
console.timeEnd('go');
}
事件概述
当用与Web页面进行某些交互时,解释器就会创建相应的eve瀁t对
象以描述事件信息。常见的事件有:
• 用户点击页面上的某个内容
• 鼠标经过特定的元素
• 用户按下键盘上的某个按键
• 用户滚动窗口或改变窗口大小
• 页面元素加载完成
• …
• 1995年IE4浏览器就已经定义了自己的事件模型;而DOM模型
2004年才最终确定标准的事件模型,并被其它浏览器所支持。所
以事件处理需要注意兼容性问题。
事件处理
1.HTML事件处理: 不推荐
直接添加到HTML结构中
2.DOM0级事件处理:(事件绑定)
一个函数只能绑定一个事件处理函数
把一个函数赋值给一个事件处理程序属性
绑定第二个事件处理函数时,第一个函数被覆盖了
btn.onclick = null; // 将onclick属性指向空 释放引用
window.onload = function() {
// DOM 0级事件 将一个事件处理函数赋值给一个事件处理程序
btn.onclick = function() {
// DOM 0级事件
// 叫做 事件绑定
// 一个事件只能绑定一个事件处理函数
alert(1);
}
btn.onclick = function() {
// 绑定第二个事件处理函数时,第一个函数被覆盖了
alert(2);
// 解绑事件
btn.onclick = null; // 将onclick属性指向空 释放引用
}
}
3.DOM2级事件处理:
addEventListener(“事件名”,”事件处理函数”,”布尔值”);
true:事件捕获
false:事件冒泡
removeEventListener (“事件名”,事件处理函数); //移除事件
window.onload = function() {
var box = document.querySelector('.box');
// 为box添加事件
// DOM2级事件
// 语法: elm.addEventListener(eventType,callback,boolean);
// 参数: eventType 事件类型 事件名 string 没有on
// callback 事件处理函数 function
// boolean 事件冒泡/捕获 default=false
// DOM2级事件 事件监听
box.addEventListener('click', function() {
// DOM2级允许给一个元素绑定多个同事件的处理函数
alert('这里是DOM2级事件处理');
});
// function fn() {
// alert('第二个事件');
// box.removeEventListener('click',fn);
// }
box.addEventListener('click', function() {
alert('第二个事件');
box.removeEventListener('click', arguments.callee);
// arguments.callee 返回当前函数的引用
// console.log(this);
});
// DOM2级事件解绑
// 语法: elm.removeEventListener(eventType,fnName);
// 参数: eventType 事件类型
// fnName 函数名
// 按钮
// 点击按钮触发事件 3秒内不能再次触发
}
小例子:限定事件时间
var btn = document.querySelector('#btn');
// 使用disabled 禁用的方式来处理
// btn.addEventListener('click', function() {
// var that = this;
// console.log('我被点击了');
// this.setAttribute('disabled', 'disabled');
// setTimeout(function() {
// // 计时器中的this指向window
// that.removeAttribute('disabled');
// }, 3000);
// })
//2.通过添加和移除事件
function fn() {
var that = this;
console.log('我被点击了');
this.style.color = "#ddd";
btn.removeEventListener('click', fn);
setTimeout(function() {
that.style.color = "#000";
btn.addEventListener('click', fn);
}, 3000);
}
btn.addEventListener('click', fn);
4.IE事件处理程序(IE版本小于等于8)
attachEvent(“事件名”,”事件处理函数”) 事件类型:带有on
detachEvent(“事件名”,”事件处理函数”)
var btn = document.getElementById('btn');
// IE事件处理函数
// 语法: elm.attachEvent(eventType,callback);
// 参数: eventType 事件类型 有on
btn.attachEvent('onclick', function() {
alert('被点了');
// 解绑事件
// 语法: elm.detachEvent(eventType,fnName);
btn.detachEvent('onclick', arguments.callee);
});
事件绑定兼容写法
// 事件绑定
function addEvent(elm, eventType, callback) {
if (elm.addEventListener) { // 判断浏览器是否支持 addEventListener 函数
elm.addEventListener(eventType, callback);
} else if (elm.attachEvent) { // 判断是否支持IE
elm.attachEvent('on' + eventType, callback);
}
}
// 移除事件
function removeEvent(elm, eventType, callback) {
if (elm.removeEventListener) {
elm.removeEventListener(eventType, callback);
} else if (elm.detachEvent) {
elm.detachEvent('on' + eventType, callback);
}
}
window.onload = function() {
var btn = document.getElementById('btn');
addEvent(btn, 'click', function() {
alert(1);
});
}
练习:几秒后按钮恢复点击
window.onload = function() {
var btn = document.querySelector('#btn');
btn.addEventListener('click', function() {
btn.setAttribute('disabled', 'disabled');
var sec = 5;
var timer = setInterval(function() {
if (sec == 0) {
clearInterval(timer); // 时间为0 关闭计时器
btn.innerHTML = '按钮'; //恢复里面内容
btn.removeAttribute('disabled'); // 删除禁用属性
return;
}
btn.innerHTML = '按钮' + sec + '秒后恢复';
sec--;
}, 1000);
});
}
事件的处理周期
• 解释器创建一个event对象后,会按如下过程将其在HTML元素间
进行传播:
• 第一阶段:事件的捕获,事件对象沿DOM树向下传播
• 第二阶段:目标触发,运行事件监听函数
• 第三阶段:事件冒泡,事件沿DOM树向上传播
• 注:IE的事件中没有“捕获”阶段
// 事件处理周期 事件流
// 当一个事件发生时,会按照顺序在HTML元素之间进行传播
// 1. 事件捕获 从最不具体到最具体的事物 事件沿着DOM树向下传播
// 2. 目标触发 运行事件监听函数
// 3. 事件冒泡 从最具体到最不具体的事物 事件沿着DOM树向上传播
// ie没有事件捕获 只有冒泡
// DOM0级默认冒泡 无法设置为事件捕获
// 一般情况使用 事件冒泡
window.onload = function() {
var btn = document.getElementById('btn');
var box = document.getElementById('box');
// elm.addEventListener(eventType,callback,boolean);
// 第三个参数 布尔值
// true 事件捕获
// false 事件冒泡
document.body.addEventListener('click', function() {
alert(3);
});
btn.addEventListener('click', function() {
alert(1);
});
box.addEventListener('click', function() {
alert(2);
});
}
<body>
<div id="box">
<button id="btn">按钮</button>
</div>
</body>
阻止事件冒泡
event.cancelBubble = true; //IE
event.stopPropagation( ); //DOM
window.onload = function() {
var box = document.getElementById('box');
var btn = document.getElementById('btn');
box.onclick = function(ev) {
// 事件处理函数的参数第一个参数 是事件对象
// 依赖注入 自动传入事件对象
// 在标准浏览器下 ev 就是事件对象
// 在ie浏览器下 事件对象 是event event属于window
ev = ev || event; // ie 兼容写法
alert(1);
// ev.stopPropagation(); // 标准浏览器 阻止事件冒泡
if (ev.stopPropagation) {
ev.stopPropagation(); // 标准浏览器阻止冒泡
} else {
ev.cancelBubble = true; // ie浏览器阻止冒泡
}
}
btn.onclick = function() {
alert(2);
}
document.body.onclick = function() {
alert(3);
}
}
事件委托 事件委派
通过事件冒泡的特性将事件处理函数添给 父级或祖先元素
使用事件冒泡的好处
1. 减少事件的绑定次数 优化性能
2. 可以给未来元素添加事件
window.onload = function() {
var btns = document.querySelectorAll('#box>button');
var box = document.querySelector('#box');
// btns[0].onclick = function() {
// alert(1);
// }
// btns[1].onclick = function() {
// alert(2);
// }
// btns[2].onclick = function() {
// alert(3);
// }
// 事件委托 事件委派
// 通过事件冒泡的特性将事件处理函数添给 父级或祖先元素
// event 事件对象
// event.target 事件目标对象 标准DOM属性
// event.srcElement 事件目标对象 IE属性 被大多数浏览器所支持
// 使用事件冒泡的好处
// 1. 减少事件的绑定次数 优化性能
// 2. 可以给未来元素添加事件
addEvent(box, 'click', function(ev) {
// ev = ev || event;
// var target = ev.target || ev.srcElement;
switch (ev.target.className) {
case 'btn1':
alert(1);
break;
case 'btn2':
alert(2);
break;
case 'btn3':
alert(3);
break;
}
});
}
window.onload = function() {
var box = document.querySelector('#box');
// var button = document.querySelectorAll('button');
// button.forEach(function(elm) {
// elm.addEventListener('click', function() {
// // console.log(1);
// // box.innerHTML +=''; // 赋值以后 元素是全新的
// var btn = document.createElement('button');
// btn.innerHTML = '按钮';
// box.appendChild(btn);
// });
// })
// 使用事件委托 给未来元素(使用JS添加的元素)添加事件
box.addEventListener('click', function(ev) {
if (ev.target.nodeName == 'BUTTON') {
box.innerHTML += '';
}
});
}
例子:给表格添加一行数据
// table 对象
// 每一个table标签都是一个table对象
window.onload = function() {
var table = document.querySelector('table');
var btn = document.querySelector('button');
// table.rows 返回表格中所有的行的集合 类数组对象
// console.log(table.rows);
// insertRow 创建了一个行 tr
// 将tr插入到指定索引
var index = 3;
btn.onclick = function() {
var tr = table.insertRow(table.rows.length); // 返回新创建的行
// tr.cells 返回当前行 所有单元格的集合 类数组对象
// insertCell 用于在行中添加单元格
var td1 = tr.insertCell(0);
td1.innerHTML = index < 10 ? '0' + index : index;
var td2 = tr.insertCell(1);
td2.innerHTML = '小汪';
var td3 = tr.insertCell(2);
td3.innerHTML = '35';
var td4 = tr.insertCell(3);
td4.innerHTML = '男';
var td5 = tr.insertCell(4);
td5.innerHTML = '';
index++;
// 事件添加
// var oBtn = document.querySelectorAll('input[type="button"]');
// oBtn.forEach(function(elm) {
// elm.onclick = function() {
// // 通过按钮父级找到td 再找父级tr 获得tr在表格中的索引
// var i = this.parentNode.parentNode.rowIndex;
// table.deleteRow(i);
// }
// });
}
// 减少事件绑定次数 优化性能
// 给未来元素添加事件
table.addEventListener('click', function(ev) {
if (ev.target.nodeName === 'INPUT') {
table.deleteRow(ev.target.parentNode.parentNode.rowIndex);
}
});
}
"container">
"container">
"table table-bordered table-hover text-center">
编号
姓名
年龄
性别
more
01
张三
20
男
"button" value="删除">
02
李四
25
男
"button" value="删除">
事件目标
this在事件中指向绑定的元素 谁调用指向谁
target指向事件触发的目标元素
var box = document.querySelector('.box');
box.addEventListener('click', function(ev) {
console.log(this); // 谁调用指向谁
console.log(ev.target); // 事件目标对象
// this在事件中指向绑定的元素
// target指向事件触发的目标元素
console.log(this === ev.target);
});
event对象
• 任何事件触发后将会产生一个event对象
• event对象记录事件发生时的鼠标位置、键盘按键状态和触发对象
等信息,事件对象的常用属性:
type:事件类型
srcElement(IE)、target:事件源对象
clientX、offsetX、pageX、screenX:事件发生的X坐标
clientY、offsetY、pageY、screenY:事件发生的y坐标
所有的事件触发 都会生成一个event对象 用于纪录事件信息
event.tyep 事件类型
event.target 事件目标 ie下 event.srcElement
event.button 返回按钮编号
鼠标坐标信息
event.clientX //根据浏览器可视区域左上角0,0开始计算
event.clientY
event.pageX // 根据页面左上角0,0点开始计算
event.pageY
event.layerX // 同上 兼容FF
event.layerY
event.screenX // 根据屏幕左上角0,0开始计算
event.screentY
event.offsetX // 根据元素左上角0,0开始计算
event.offsetY
contextmenu 是右键事件
元素拖动
window.onload = function() {
// 元素拖拽
// 改变元素位置 定位
// 1. 鼠标按下 被移动的元素上
// 2. 鼠标移动 页面
// 3. 鼠标弹起 页面
var box = document.querySelector('.box');
box.onmousedown = function(ev) {
var offsetX = ev.offsetX,
offsetY = ev.offsetY;
document.onmousemove = function(ev) {
var pageX = ev.pageX,
pageY = ev.pageY,
// 计算x,y定位的值
x = pageX - offsetX,
y = pageY - offsetY;
// 设置定位置
box.style.top = y + 'px';
box.style.left = x + 'px';
}
document.onmouseup = function() {
document.onmousemove = null; // 移除事件
}
}
}
边界管理
window.onload = function() {
// 元素拖拽
// 改变元素位置 定位
// 1. 鼠标按下 被移动的元素上
// 2. 鼠标移动 页面
// 3. 鼠标弹起 页面
var box = document.querySelector('.box');
box.onmousedown = function(ev) {
var offsetX = ev.offsetX,
offsetY = ev.offsetY;
document.onmousemove = function(ev) {
var pageX = ev.pageX,
pageY = ev.pageY,
// 计算x,y定位的值
x = pageX - offsetX,
y = pageY - offsetY;
// 左右边界
if (x < 0) {
x = 0;
} else if (x > innerWidth - box.offsetWidth) {
x = innerWidth - box.offsetWidth;
}
// 上下边界
if (y < 0) {
y = 0;
} else if (y > innerHeight - box.offsetHeight) {
y = innerHeight - box.offsetHeight;
}
// 设置定位置
box.style.top = y + 'px';
box.style.left = x + 'px';
}
document.onmouseup = function() {
document.onmousemove = null; // 移除事件
}
}
}
轨迹回放
window.onload = function() {
// 元素拖拽
// 改变元素位置 定位
// 1. 鼠标按下 被移动的元素上
// 2. 鼠标移动 页面
// 3. 鼠标弹起 页面
var map = []; // 存放运动轨迹
var timer = null; // 保存计时器id
var box = document.querySelector('.box');
box.onmousedown = function(ev) {
var offsetX = ev.offsetX,
offsetY = ev.offsetY;
map.push({
x: 0,
y: 0
});
document.onmousemove = function(ev) {
var pageX = ev.pageX,
pageY = ev.pageY,
// 计算x,y定位的值
x = pageX - offsetX,
y = pageY - offsetY;
// 左右边界
if (x < 0) {
x = 0;
} else if (x > innerWidth - box.offsetWidth) {
x = innerWidth - box.offsetWidth;
}
// 上下边界
if (y < 0) {
y = 0;
} else if (y > innerHeight - box.offsetHeight) {
y = innerHeight - box.offsetHeight;
}
// 添加span 看见轨迹
// 轨迹回放 应该将所有的轨迹纪录下来
// var span = document.createElement('span');
// span.style.top = y + 'px';
// span.style.left = x + 'px';
// document.body.appendChild(span);
map.push({
x: x,
y: y
});
// 设置定位置
box.style.top = y + 'px';
box.style.left = x + 'px';
}
document.onmouseup = function() {
document.onmousemove = null; // 移除事件
timer = setInterval(function() {
if (map.length === 0) { //数组内没有数据了 就关闭计时器
clearInterval(timer);
return; // 终止函数执行
}
var last = map.pop(); // 删除并返回数组的最后一个元素
box.style.top = last.y + 'px';
box.style.left = last.x + 'px';
}, 20);
}
}
}
鼠标右键事件
// contextmenu 右键事件
document.addEventListener('contextmenu', function(ev) {
// 在页面点击鼠标右键会自动弹出浏览器的右键菜单
// 右键事件的默认行为
// 事件默认行为
// 阻止事件默认行为
console.log(ev);
// ev.returnValue = false; // IE浏览器 阻止默认行为
// ev.preventDefault(); // 标准浏览器
// return false; // 不推荐使用
});
默认行为
阻止事件的默认行为
• 事件的默认的行为:如sub瀀it按钮默认就可以提交表单、i瀁瀃ut只
要键盘一按下默认就会把内容显示在输入框中…
• 可以使用下述方法阻止事件的默认行为:
• event.returnValue = false; //IE retrun false;(放在最后)
• event.preventDefault( ); //DOM
var baidu = document.querySelector('#baidu');
baidu.addEventListener('click', function(ev) {
// 跳转页面是a元素的默认行为
alert('a标签被点击了');
ev.preventDefault();
// return false;
})
HTML5就绪事件
window.onload = function() {
// 当页面资源加载完毕后执行
// 只能有一个
console.log(1);
}
// HTML5 就绪事件
document.addEventListener('DOMContentLoaded', function() {
// DOM Content Loaded
// 当DOM结构加载完毕
// 速度快 比window.onload 要快
console.log(2);
var btn = document.querySelector('button');
console.log(btn);
});
document.addEventListener('DOMContentLoaded', function() {
console.log(3);
})
鼠标中键滚轮事件
有兼容问题
chrome/ie mousewheel ev.whellDelta 用于判断滚轮方向
Fire Fox DOMMouseScroll ev.detail 用于判断滚轮方向
// document.addEventListener('mousewheel', function(ev) {
// // ev.whellDelta 用于判断滚轮方向
// // 如果大于0 向上
// // 如果小于0 向下
// // console.log(ev);
// console.log(ev.wheelDelta > 0 ? '向上' : '向下');
// });
// document.addEventListener('DOMMouseScroll', function(ev) {
// // ev.detail 用于判断滚轮方向
// // 如果大于0 向下
// // 如果小于0 向上
// console.log(ev.detail > 0 ? '向下' : '向上');
// });
function mouseScroll(ev) {
ev = ev || event;
var flag = true; // 向上
if (ev.wheelDelta) {
flag = ev.wheelDelta > 0 ? true : false;
} else {
flag = ev.detail < 0 ? true : false;
}
console.log(flag);
}
addEvent(document, 'mousewheel', mouseScroll);
addEvent(document, 'DOMMouseScroll', mouseScroll);
模拟滚动条
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
width: 300px;
height: 400px;
border: 1px solid black;
float: left;
position: relative;
overflow: hidden;
}
.scroll {
float: left;
width: 20px;
height: 400px;
border: 1px solid black;
margin-left: 5px;
position: relative;
}
.movebox {
width: 18px;
height: 30px;
background-color: red;
position: absolute;
}
.box>p {
position: absolute;
user-select: none;
}
window.onload = function() {
var box = $('.box')[0];
var p = $('.box>p')[0];
var scroll = $('.scroll')[0];
var movebox = $('.movebox')[0];
addEvent(box, 'mousewheel', mouseScroll);
addEvent(box, 'DOMMouseScroll', mouseScroll);
addEvent(scroll, 'mousewheel', mouseScroll);
addEvent(scroll, 'DOMMouseScroll', mouseScroll);
function mouseScroll(ev) {
ev = ev || event;
var flag = true; // 向上
if (ev.wheelDelta) {
flag = ev.wheelDelta > 0 ? true : false;
} else {
flag = ev.detail < 0 ? true : false;
}
// 4. 添加滚轮事件 让元素移动
if (flag) {
move(movebox.offsetTop - 20);
} else {
move(movebox.offsetTop + 20);
}
}
// 1. 移动movebox
movebox.onmousedown = function(ev) {
ev = ev || event;
var offsetY = ev.offsetY;
document.onmousemove = function(ev) {
ev = ev || event;
var y = ev.pageY - offsetY;
move(y);
// if (y < 0) {
// y = 0;
// } else if (y > scroll.offsetHeight - movebox.offsetHeight - 2) {
// y = scroll.offsetHeight - movebox.offsetHeight - 2;
// }
// // 2. 计算比例
// var ratio = y / (scroll.offsetHeight - movebox.offsetHeight - 2);
// // console.log(ratio);
// p.style.top = -ratio * (p.offsetHeight - box.offsetHeight + 2) + 'px';
// movebox.style.top = y + 'px';
}
document.onmouseup = function() {
document.onmousemove = null;
}
}
// 3. 将核心移动代码封装成函数
function move(y) {
if (y < 0) {
y = 0;
} else if (y > scroll.offsetHeight - movebox.offsetHeight - 2) {
y = scroll.offsetHeight - movebox.offsetHeight - 2;
}
// 2. 计算比例
var ratio = y / (scroll.offsetHeight - movebox.offsetHeight - 2);
// console.log(ratio);
p.style.top = -ratio * (p.offsetHeight - box.offsetHeight + 2) + 'px';
movebox.style.top = y + 'px';
}
}
兼容封装代码
// 事件绑定
function addEvent(elm, eventType, callback) {
if (elm.addEventListener) { // 判断浏览器是否支持 addEventListener 函数
elm.addEventListener(eventType, callback);
} else if (elm.attachEvent) { // 判断是否支持IE
elm.attachEvent('on' + eventType, callback);
}
}
// 移除事件
function removeEvent(elm, eventType, callback) {
if (elm.removeEventListener) {
elm.removeEventListener(eventType, callback);
} else if (elm.detachEvent) {
elm.detachEvent('on' + eventType, callback);
}
}
function $(selector) {
return document.querySelectorAll(selector);
}