前端三层:
语言 | 功能 | |
---|---|---|
结构层 | HTML | 搭建结构、放置部件、描述语义 |
样式层 | CSS | 美化页面、实现布局 |
行为层 | JavaScript | 实现交互效果、数据收发、表单验证等 |
ECMAScript是JavaScript的标准:
REPL(Read、Eval、Print、Loop)环境:
标识符的命名规则:
// 合法命名举例
str aBc_123 $2 $0o_o0$ $
// 非法命名举例
2a aBc#123 ¥2 true
优秀的变量命名方法:
定义变量:
// 使用 var 关键字定义变量
// = 表示赋值,将右边的数值赋值给左边的变量
var a = 5;
// 使用逗号同时声明和初始化多个变量
var b = 2, c = 3, d = 4;
使用变量:
// 变量使用时不能加引号,加引号就变成字符串了
console.log(a);
改变变量的值:
var a = 10;
a = 12; // 更改变量a的值为12
变量的默认值:
变量定义的常见错误:
console.log(a); // 先使用变量,由于不提升值,所有输出 undefined
var a = 12; // 后定义变量
JS 中两大类数据类型:
typeof 运算符:
var a = 12;
console.log(typeof a); // number
5种基本数据类型的 typeof 检测结果:
类型名 | typeof 检测结果 |
---|---|
数字类型 | number |
字符串类型 | string |
布尔类型 | boolean |
undefined类型 | undefined |
null类型 | object |
科学计数法:
3e8; // 300000000
3e-4; // 0.0003
-3e4; // -30000
.3e5; // 30000
不同进制的数字:
一个特殊的数字型值 NaN:
typeof NaN; // number
console.log(NaN == NaN); // false
typeof 11; //number
typeof '11'; // string
'hello' + ' ' + 'world'; //hello world
var a = 10;
var str = '我有' + a + '元钱';
var str = '';
'JS'.length // 2
''.length // 0
字符串的常用方法:
方法 | 功能 |
---|---|
charAt() | 得到指定位置字符 |
substring() | 提取字符串 |
substr() | 提取字符串 |
slice() | 提取字符串 |
toUpperCase() | 将字符串变为大写 |
toLowerCase() | 将字符串变为小写 |
indexOf() | 检索字符串 |
'我喜欢JS'.charAt(0) // '我'
'我喜欢JS'.charAt(10) // ''
'我喜欢JS'.substring(1,3) // '喜欢'
'我喜欢JS'.charAt(2) // '欢JS'
'我喜欢JS'.substring(3,1) // '喜欢'
'我喜欢JavaScript'.substr(2,3) // '欢Ja'
'我喜欢JavaScript'.substr(3) // ' JavaScript'
'我喜欢JavaScript'.substr(-5,4) // 'crip'
'我喜欢JavaScript'.slice(2,3) // '欢Ja'
'我喜欢JavaScript'.slice(-6,-1) // ' Scrip'
'我喜欢JavaScript'.slice(5,4) // ''
'i like js'.toUpperCase() // 'I LIKE JS'
'HELLO'.toLowerCase() // 'hello'
'abcdefg'.indexOf('b') // 1
'abcdefg'.indexOf('ef') // 4
'abcdefg'.indexOf('h') // -1
3 < 5 // true
5 < 3 // false
typeof undefined; // undefined
console.log(a); // undefined
console.log(typeof a); // undefined
var a = 12;
typeof null; // object
其他值 -> 数字(Number):
Number('123'); // 123
Number('123.4'); // 123.4
Number('12月'); // NaN
Number('2e3'); // 2000
Number(''); // 0
Number(true); // 1
Number(false); // 0
Number(undefined); // NaN
Number(null); // 0
使用 parseInt() 函数:
parseInt('3.14'); // 3
parseInt('3.14圆周率'); // 3
parseInt('圆周率是3.14'); // NaN
parseInt('3.89'); // 3
使用 parseFloat() 函数:
parseFloat('3.14'); // 3.14
parseFloat('3.14圆周率'); // 3.14
parseFloat('圆周率是3.14'); // NaN
parseFloat('3.89'); // 3.89
使用 String() 函数:
String(123); // '123'
String(3.14); // '3.14'
String(2e3); // '2000'
String(NaN); // 'NaN'
String(Infinity); // 'Infinity'
String(0xf); // '15'
String(true); // 'true'
String(false); // 'false'
String(undefined); // 'undefined'
String(null); // 'null'
使用 toString() 方法:
(3).toString(); // "3"
使用 Boolean() 函数:
Boolean(13); // true
Boolean(0); // false
Boolean(NaN); // false
Boolean(Infinity); // true
Boolean(-Infinity); // true
Boolean(''); // false
Boolean('adc'); // true
Boolean('false'); // true
Boolean(undefined); // false
Boolean(null); // false
运算符名称 | 运算符 |
---|---|
加 | + |
减 | - |
乘 | * |
除 | / |
取余 | % |
隐式类型转换:
3 * '4' // 12
true + true // 2
false + 1 // 1
3 * '2天' // NaN
有关IEEE754:(toFixed()方法)
0.1 + 0.2 // 0.30000000000000004
Number((0.1 + 0.2).toFixed(2)); // 0.3
幂和开根号:
Math.pow(2, 3) // 8
Math.pow(3, 2) // 9
Math.sqrt(81) // 9
Math.sqrt(-81) // NaN 负数不能开根号
向上取整和向下取整:
Math.ceil(2.4) // 3
Math.floor(2.4) // 2
Math.ceil(-2.4) // -2
Math.floor(-2.4) // -3
Math.ceil(2) // 2
Math.floor(2) // 2
运算符名称 | 运算符 |
---|---|
大于 | > |
小于 | < |
大于或等于 | >= |
小于或等于 | <= |
等于 | == |
不等于 | != |
全等于 | === |
不全等于 | !== |
5 == '5' // true
5 === '5' // false
1 == true // true
1 === true // false
0 == false // true
0 === false // false
0 == undefined // false
0 === undefined // false
undefined == null // true
undefined === null // false (typeof) undefined object
5 != 6 // true
5 !== 6 // true
5 != '5' // false
5 !== '5' // true
NaN不自等:
NaN == NaN // false
NaN === NaN // false
isNaN(NaN) // true
isNaN(3) // false
isNaN(undefined) // true
isNaN('3年') // true
isNaN(null) // false
运算符名称 | 运算符 |
---|---|
与 | && |
或 | || |
非 | ! |
与运算:
true && true // true
false && true // false
false && false // false
true && false // false
或运算:
true || true // true
false || true // true
false || false // false
true || false // true
非运算:
!true // false
!false // true
!0 // true
!undefined // true
!'' // true
!'hello' // false
!!true // true
!!0 // false
!!'' // false
!!'hello' // true
短路计算:
3 && 6 // 6
undefined && 12 // undefined
null && 2 // null
'' && 13 // ''
NaN && undefined // undefined
逻辑运算的优先顺序:
!true || true // true
3 && 4 || 5 && 6 // 4
运算符名称 | 运算符 |
---|---|
赋值 | = |
快捷赋值 | +=、-=、*=、/=、%= |
自增运算 | ++ |
自减运算 | – |
赋值运算符:
var a;
console.log(a = 3); // 3
var a,b,c;
a = b = c = 12;
console.log(a); // 12
console.log(b); // 12
console.log(c); // 12
++a 和 a++ 的区别:
var a = 3;
var b = a++;
console.log(b); // 3
a = 3;
var c = ++a;
console.log(c); // 4
a = 3;
var m = --a;
console.log(m); // 2
a = 3;
var n = a--;
console.log(n); // 3
5 < 3 + 3 // true
3 > 2 && 8 > 3 + 4 // true
3 > 2 && 8 > 3 + 5 // false
!3 < 5 - 3 // true
!3 < 5 - 5 // false
变量的范围表示:
a >= 3 && a <= 12
闰年判断:
// 弹出输入框
var year = Number(prompt('请输入年份'));
// 根据两个条件判断(满足以下两个条件之一)
// 能被4整除且不能被100整除
// 能被100整出也能被400整除
alert((year / 4 == 0 && year % 100 != 0)||(year % 100 == 0 && year % 400 == 0));
if(条件1) {
// 符合条件1执行
// 语句块1
}else if(条件2) {
// 符合条件2执行
// 语句块2
}
……
else {
// 以上条件都不符合
// 语句块
}
算法题:判断水仙花数
var m = Number(prompt('请输入一个三位数'));
// 对用户输入的数值,进行合法性教验
if(!NaN(m) && m >= 100 && m <= 999) {
var m_str = m.toString();
// 百分位
// Math.floor() 向下取整;Math.ceil() 向上取整
// var a = Math.floor(m / 100);
var a = Number(m_str.charAt(0));
// 十分位
// var b = Math.floor(m / 10) % 10;
var b = Number(m_str.charAt(1));
// 个位
// var c = m % 10;
var c = Number(m_str.charAt(2));
// 根据水仙花条件判断
if(Math.pow(a,3) + Math.pow(b,3) + Math.pow(c,3) == m) {
alert(m + '是水仙花数!');
} else {
alert(m + '不是水仙花数');
}
}else {
alert('您的输入数字不合法!');
}
定义数组:
var arr = ['a','b','c','d'];
var arr = new Array('a','b','c','d');
var arr = new Array(4);
访问数组项:
var arr = ['a','b','c','d'];
console.log(arr[0]); // a
console.log(arr[1]); // b
console.log(arr[2]); // c
console.log(arr[3]); // d
下标越界:
var arr = ['a','b','c','d'];
console.log(arr[4]); // undefined
console.log(arr[-1]); // undefined
console.log(arr[100]); // undefined
数组的长度:
var arr = ['a','b','c','d'];
console.log(arr.length); // 4
更改数组项:
var arr = [1,2,3,4];
arr[0]++;
arr[3] = 5;
console.log(arr); // [2, 2, 3, 5]
var arr = [1,2,3,4];
arr[6] = 5;
console.log(arr); // [1, 2, 3, 4, undefined, undefined, 5]
数组遍历:
var arr = [1,2,3,4];
for(var i = 0; i < arr.length; i++) {
console.log(arr[i]); // [1, 2, 3, 4]
}
数组的头尾操作方法:
方法 | 功能 |
---|---|
push() | 在尾部插入新项 |
pop() | 在尾部删除 |
unshift() | 在头部插入新项 |
shift() | 在头部删除 |
push() 方法:
var arr = [1,2,3];
arr.push(11);
arr.push(21,22,23);
console.log(arr); // [1, 2, 3, 11, 21, 22, 23]
pop() 方法:
var arr = [11, 22, 33, 44, 55];
var item = arr.pop();
console.log(item); // 55
console.log(arr); // [11, 22, 33, 44]
unshift() 方法:
var arr = [1,2,3];
arr.unshift(11);
arr.unshift(21,22,23);
console.log(arr); // [21, 22, 23, 11, 1, 2, 3]
shift() 方法:
var arr = [11, 22, 33, 44, 55];
var item = arr.shift();
console.log(item); // 11
console.log(arr); // [22, 33, 44, 55]
splice() 方法:
var arr = ['a','b','c','d','e','f'];
// 1.表示从下标为3项开始,将后面的 2 项替换为 1,2,3
arr.splice(3,2,1,2,3);
console.log(arr); // ['a','b','c', 1, 2, 3,'f']
// 2.表示在数组下标为 3 的位置插入 1,2,3
arr.splice(3,0,1,2,3);
console.log(arr); // ['a','b','c', 1, 2, 3, ‘d', 'e', 'f']
// 3.表示从数组下标为 3 的位置开始删除 2 项
arr.splice(3,2);
console.log(arr); // ['a','b','c', 'f']
// 4.表示从数组下标为 3 的位置开始删除后面所有项
var items = arr.splice(3);
console.log(arr); // ['a','b','c']
console.log(items); // ['d','e','f']
slice() 方法:
var arr = ['a','b','c','d','e','f'];
var child_arr1 = arr.slice(3,5);
var child_arr2 = arr.slice(3);
var child_arr3 = arr.slice(3,-2);
var child_arr4 = arr.slice(-4, -2);
console.log(child_arr1); // ['d','e']
console.log(child_arr2); // ['d','e','f']
console.log(child_arr3); // ['d']
console.log(child_arr4); // ['c', 'd']
console.log(arr); // ['a','b','c','d','e','f']
join() 和 split() 方法:
var arr = ['a','b','c','d'];
// 不写参数,默认使用“,”分隔
var arr_str = arr.join();
console.log(arr_str); // a,b,c,d
// 使用“-”作为分隔符
var arr_str1 = arr.join('-');
console.log(arr_str1); // a-b-c-d
// 使用空字符串作为分隔符
var arr_str2 = arr.join('');
console.log(arr_str2); // abcd
// 不写参数,会将整个字符串当做一个数组项
var str_arr = arr_str.split();
console.log(str_arr); // ["a,b,c,d"]
// 使用空字符串,会连带将分隔符一起作为数组项
var str_arr = arr_str.split('');
console.log(str_arr); // ["a", ",", "b", ",", "c", ",", "d"]
// 使用分隔符分隔,会将每一个字符作为一项
var str_arr = arr_str.split(',');
console.log(str_arr); // ["a", "b", "c", "d"]
字符串和数组更多相关特性:
var str = "hello world!";
console.log(str[0]); // "h"
console.log(str[2]); // "l"
console.log(str[5]); // " "
console.log(str[11]); // "!"
console.log(charAt(0)); // "h"
console.log(charAt(2)); // "l"
console.log(charAt(5)); // " "
console.log(charAt(11)); // "!"
concat() 方法:
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var arr3 = [7,8,9,10,11];
var arr = arr1.concat(arr2, arr3);
console.log(arr); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
console.log(arr1); // [1, 2, 3]
reverse() 方法:
var arr = ['A','B','C','D','E','F','G'];
arr.reverse();
console.log(arr); // ["G", "F", "E", "D", "C", "B", "A"]
// 将一个字符串置反
var str = "abcdefg";
console.log(str.split('').reverse().join('')); // "gfedcba"
// 逐步拆解如下:
var str_arr = str.split('');
console.log(arr); // ["a", "b", "c", "d", "e", "f", "g"]
arr.reverse();
var arr_str = arr.join('');
console.log(arr_str); // "gfedcba"
indexOf 和 includes() 方法:
var arr = ['a','b','c','d','e','c'];
// 搜索数组中的元素,并返回它所在的位置(下标数)
var index1 = arr.indexOf('a');
console.log(index1); // 0
// 当数组中多次出现某个元素,则返回第一次出现时所在的下标数
var index2 = arr.indexOf('c');
console.log(index2); // 2
// 当搜索的元素不存在,则返回 -1
var index3 = arr.indexOf('g');
console.log(index3); // -1
var arr = ['a','b','c','d','e','c'];
// 数组是否包含一个指定的值,返回布尔值
var flag1 = arr.includes('a');
console.log(flag1); // true
var flag2 = arr.includes('g');
console.log(flag2); // false
var arr = ['a','b','c',11,22];
var flag1 = arr.includes('a');
console.log(flag1); // true
var flag2 = arr.includes(22);
console.log(flag2); // true
var flag3 = arr.includes('11');
console.log(flag3); // false
var flag4 = arr.includes(b);
console.log(flag4); // 报错
var index1 = arr.indexOf('b');
console.log(index1); // 1
var index2 = arr.indexOf(22);
console.log(index2); // 4
var index3 = arr.indexOf('11');
console.log(index3); // -1
数组去重:
var arr = [1,1,3,4,2,3,5,5,7,6,7,3,2,9];
var result = [];
for(var i = 0; i < arr.length; i++) {
if(!result.includes(arr[i])) {
result.push(arr[i]);
}
}
console.log(result); // [1, 3, 4, 2, 5, 7, 6, 9]
随机样本:
var arr = [1,3,2,5,9,3,7,6,4,8,10];
var result = [];
// 3 表示执行三次
for(var i = 0; i < 3; i++) {
// [a,b]区间的随机整数是:parseInt(Math.random() * (b - a + 1)) + a;
var randomIndex = parseInt(Math.random() * arr.length);
// 将随机索引下标项推入结果数组
result.push(arr[randomIndex]);
// 原数组删除这项
// splice(a,b) 表示从 a 位置开始删除 b 项
arr.splice(randomIndex,1);
}
console.log(result);
console.log(arr);
var arr = [1,3,2,5,9,7,6,4,8,10];
for(var i = 0; i < arr.length - 1; i++) {
for(var j = 0; j < arr.length - i - 1; j++) {
if(arr[j] > arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log(arr);
var matrix = [
[11,22,33],
[1,2,3],
[4,5,6,7],
[45,54,66]
];
console.log('数组长度为:' + matrix.length); // 4
// 遍历二维数组中的每一项
for(var i = 0; i < matrix.length; i++) {
for(var j = 0; j < matrix[i].length; j++) {
console.log(matrix[i][j]);
}
}
函数的定义:
// function 表示定义函数
// fun 是函数名,函数名必须符合 JS 标识符命名规则
// () 里面是行参列表,即使没有行参,也必须书写圆括号
// {} 大括号中就是函数体语句
function fun() {
// 函数体语句
}
函数表达式:
// function 是匿名函数
var fun = function() {
// 函数体语句
}
函数的调用:
fun(); // 调用函数
function fun() {
console.log('A')
console.log('B')
console.log('C')
}
console.log('1')
console.log('2')
console.log('3')
fun();
console.log('4')
console.log('5')
console.log('6')
// 在浏览器控制台输出
1 2 3 A B C 4 5 6
fun();
function fun() {
console.log('函数体被执行');
}
fun(); // 引发错误
var fun = function() {
console.log('函数体被执行');
}
函数的优先提升:
fun(); // 打印 B
var fun = function() {
console.log(' A');
}
function fun() {
console.log('B');
}
fun(); // 打印 A
函数的参数:
// 这里的 a 和 b 就是函数的行参
function sum(a, b) {
var add = a + b;
console.log("两个参数之和为:" + add);
}
// 这里的 3 和 5 就是调用函数传入的实参
sum(3,5);
行参和实参个数不同的情况:
function fun(a, b, c) {
var sum = a + b + c;
console.log(sum);
}
fun(1,2);
// 输出结果为
NaN
function fun(a, b) {
var sum = a + b;
console.log(sum);
}
fun(2,3,5); // 控制台报错
arguments:
function fun() {
var sum = 0;
for(var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log(sum);
}
fun(12,23,32,55);
fun(6,7);
fun(3,-2,-5,6);
函数的返回值:
function sum(a,b) {
return a + b;
}
var result = sum(1,2) * sum(5,7);
function fun() {
console.log('A');
return 'B';
console.log('C'); // 不会执行
}
console.log(1)
var ch = fun();
console.log(ch);
console.log(2)
// 输出结果
1 A B 2
// 求一个数的阶乘
// 思路:n! 就是 n*(n-1)!
function factorial(n) {
// 递归的出口
if(n == 1) return 1;
return n * factorial(n - 1);
}
var result = factorial(10);
console.log(result);
// 计算一个数字的阶乘
function factorial(n) {
var result = 1;
for(var i = 1; i <= n; i++) {
result *= i;
}
return result;
}
// 利用穷举法寻找100到999的喇叭花数
for(var i = 100; i <= 999; i++) {
// 把数字变为字符串
var i_str = i.toString();
var a = Number(i_str[0]); // 百分位
var b = Number(i_str[1]); // 十分位
var c = Number(i_str[2]); // 个位
if(i == factorial(a) + factorial(b) + factorial(c)) {
console.log(i);
}
}
var arr = [12,3,1,4,6,2];
// 调用 sort() 方法排序
arr.sort(function(a,b) {
if(a > b) {
return 1;
} else {
return -1;
}
});
console.log(arr);
// 也可以简写为
var arr = [12,3,1,4,6,2];
// 调用 sort() 方法排序
arr.sort(function(a,b) {
return a - b; // 升序
// return b - a; // 降序
});
console.log(arr);
function fib(n) {
// 数列的下标为0的项和下标为1的项的值都是1
if(n == 0 || n == 1) return 1;
// 除了前两项,后面的都是 等于前两项的和
return fib(n - 1) + fib(n - 2);
}
举例 | 当 var a = b 变量传值时 | 当用 == 比较时 | |
---|---|---|---|
基本类型 | 数字、字符串、布尔型、undefined | 内存中产生新的副本 | 比较值是否相等 |
引用类型 | 对象、数组 | 内存中不产生新的副本,而是让新的变量指向同一个对象 | 比较内存地址是否相同,即比较是否是同一个对象 |
浅克隆:
var arr = [11,33,22,55,44];
// 空的数组
var result = [];
// 遍历原数组,将遍历到的项都推入到空数组中
for(var i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
console.log(result); // 11,33,22,55,44
console.log(result == arr); // false
实现深克隆:
// 原数组
var arr = [33,44,22,55,[12,2,31,6],10,[11,32,[9,4,5,7,2]]];
function deepClone(arr) {
// 结果数组
var result = [];
// 遍历数组的每一项
for(var i = 0; i < arr.length; i++) {
// 如果遍历到的项是数组
if(Array.isArray(arr[i])) {
// 递归
result.push(deepClone(arr[i]));
} else {
// 如果不是数组项,而是基本类型值,就直接推入到结果数组中
// 相当于递归的出口
result.push(arr[i]);
}
}
// 返回结果数组
return result;
}
var temp = deepClone(arr);
function fun() {
// 变量 a 是在 fun函数中被定义的,所以变量a只在fun函数内部有定义,
// fun函数就是a的作用域,变量a被称为局部变量
var a = 10;
}
fun();
console.log(a); // 此时会报错:a is not defined
var a = 10;
function fun() {
a++;
console.log(a); // 输出 11
}
fun();
console.log(a); // 输出 11
var a = 10;
function fun() {
var a = 5;
a++;
console.log(a); // 输出 6
}
fun();
console.log(a); // 输出 10
var a = 10;
function fun() {
a++;
var a = 5;
console.log(a); // 输出 5
}
fun();
console.log(a); // 输出 10,局部变量不影响全局变量
function fun() {
function inner() { // 该函数是局部函数
console.log("局部函数");
}
inner(); // 调用内部函数
}
fun(); // 调用外部函数
var a = 10;
var b = 20;
function fun() {
var c = 30;
function inner() { // 该函数是局部函数
var a = 40;
var d = 50;
console.log(a, b, c, d); // 使用变量时,JS 会从当前层开始,逐层向上寻找定义
}
inner();
}
fun(); // 输出 a=40 b=20 c=30 d=50
function fun() {
a = 5;
console.log(a); // 输出 5
}
fun();
console.log(a); // 输出 5
function fun() {
// 定义一个局部变量
var name = "ABC";
// 返回一个局部函数
return function() {
console.log(name);
}; // 别忘了“;”,return 返回的结果要有“;”结尾
// 或者写为下面这种形式
// function innerFun() {
// console.log(name);
// }
// return innerFun;
}
// 调用外部函数,就能得到内部函数,用变量 inn 来接收
var inn = fun();
// 执行 inn 函数,就相当于在 fun 函数的外部,执行了内部函数
inn(); // 内部函数被移动到了外部执行
闭包用途1–记忆性:
// 闭包的记忆性举例
// 创建体温检测函数 checkTemp(n),可以检查体温n是否正常,函数会返回布尔值
// 但是,不同的小区有不同的体温检测标准,比如A小区温度合格线时37.3,而B小区体温合格线是37.1
function checkTemp(standardTemp) {
return function(n) {
if(n <= standardTemp) {
alert("体温正常")
} else {
alert("体温偏高")
}
};
}
var checkTemp_A = checkTemp(37.3);
var checkTemp_B = checkTemp(37.1);
// 输入值测试
checkTemp_A(37.0); // 输出:体温正常
checkTemp_A(37.4); // 输出:体温偏高
checkTemp_B(37.2); // 输出:体温偏高
checkTemp_B(37.0); // 输出:体温正常
闭包用途1–模拟私有变量:
// 题目:请定义一个变量a,要求是能保证这个a 只能被进行指定操作,而不能进行其它操作
// 封装一个函数,这个函数的功能就是私有化变量
function fun {
// 定义一个局部变量
var a = 0;
return {
getA:function() {
return a;
},
add:function() {
return a++;
}
};
}
var obj = fun();
// 想在fun函数外面使用变量a,唯一的方法就是调用getA() 方法
console.log(obj.getA())
使用闭包的注意点:
// 包裹函数的圆括号的功能:将函数变为表达式
// 后面的圆括号的功能:运行函数
(function() {
// 任意语句
})();
// 错误示例
function() {
//语句
}();
// 正确示例
(function() {
// 语句
})();
IIFE 的作用1——为变量赋值:
var age = 23;
var sex = "男";
// 定义变量,变量的值由上面的变量决定
var title = (function() {
if(age < 18) {
return ""小朋友;
} else {
if(sex == "男") {
return '先生';
} else {
return '女士';
}
}
})();
console.log(title);
IIFE 的作用2——将全局变量变为局部变量:
var arr = [];
for(var i = 0; i < 5; i++) {
(function(i) {
arr.push(function() {
alert(i);
});
})(i);
}
arr[2](); // 弹出 2
nodeType常用属性值:
nodeType值 | 节点类型 |
---|---|
1 | 元素节点,例如 p标签 和 div标签 |
3 | 文字节点 |
8 | 注释节点 |
9 | document 节点 |
10 | DTD节点 |
方法 | 功能 | 兼容性 |
---|---|---|
document.getElementById() | 通过 id 得到 元素 | IE6 |
document.getElementsByTagName() | 通过 标签名 得到 元素数组 | IE6 |
document.getElementsByClassName() | 通过 类名 得到 元素数组 | IE9 |
document.querySelector() | 通过 选择器 得到 元素 | IE8部分兼容,IE9完全兼容 |
document.querySelectorAll() | 通过 选择器 得到 元素数组 | IE8部分兼容,IE9完全兼容 |
getElementById():
<div id = "box1">我是第一个</div>
<p id = "box2">我的第二个</p>
// JS 代码:
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
getElementsByTagName():
<div id = "box">
<p>一段文字</p>
<p>一段文字</p>
</div>
<div id = "box1">
<p>一段文字</p>
<p>一段文字</p>
</div>
// JS 代码:
// var ps = document.ElementsByTagName('p'); //获得所有
var box = document.getElementById('box');
var ps_box = box.getElementsByTagName('p'); // 获得box盒子下的p
getElementsByClassName():
<div class = "box">我是一个盒子</div>
<div>我是一个盒子</div>
<div class = "box1">我是一个盒子</div>
<div class = "box">我是一个盒子</div>
// JS 代码:
var box = document.getElementsByClassName('box');
querySelector():
<div id = "box">
<p>我是段落</p>
<p class="spec">我是段落</p>
<p>我是段落</p>
</div>
// JS 代码:
var the_p = document.querySelector('#box .spec');
querySelectorAll():
<div id = "box">
<p>我是段落</p>
<p class="spec">我是段落</p>
<p>我是段落</p>
</div>
// JS 代码:
var ps = document.querySelectorAll('#box p');
关系 | 考虑所有节点 | 只考虑元素节点 |
---|---|---|
子节点 | childNodes | children |
父节点 | parentNodes | parentNodes |
第一个子节点 | firstChild | firstElementChild |
最后一个子节点 | lastChild | lastElementChild |
前一个兄弟节点 | previousSibling | previousElementSibling |
后一个兄弟节点 | nextSibling | nextElementSibling |
封装节点关系函数:
// 封装一个函数,这个函数可以返回元素的所有子元素节点(兼容到IE6),类似children的功能
function getChildren(node) {
// 结果数组
var children = [];
// 遍历node这个节点的所有子节点,判断每一个子节点的nodeType属性是不是1
// 如果是1(nodeType值为 1 表示的是元素节点),就推入结果数组
for(var i = 0; i < node.childNodes.length; i++) {
if(node.childNodes[i].nodeType == 1) {
children.push(node.childNodes[i]);
}
}
return children;
}
// 封装一个函数,这个函数可以返回元素的前一个兄弟节点(兼容到IE6),类似previousElementSibling的功能
function getElementPrevSibling(node) {
var o = node;
// 使用while语句
while(o.previousSibling != null) {
if(o.previousSibling.nodeType == 1) {
// 结束循环
return o.previousSibling;
}
// 让 o 成为它的前一个节点
o = o.previousSibling;
}
// 没有前一个兄弟节点时返回 null
return null;
}
// 封装第三个函数,这个函数可以返回元素的所有元素兄弟节点
function getAllElementSibling(node) {
// 前面的元素兄弟节点
var prevs = [];
// 后面的元素兄弟节点
var nexts = [];
var o = node;
// 遍历node前面的节点
while(o.previousSibling != null) {
if(o.previousSibling.nodeType == 1) {
prevs.unshift(o.previousSibling);
}
o = o.previousSibling;
}
o = node;
// 遍历node后面的节点
while(o.nextsSibling != null) {
if(o.nextsSibling.nodeType == 1) {
nexts.push(o.nextsSibling);
}
o = o.nextsSibling;
}
// 将两个数组进行合并,然后返回
return prevs.concat(nexts);
}
改变元素节点内容:
改变元素节点的CSS样式:
var oBox = document.getElementsByClassName('box');
oBox.style.backgroungColor = 'blue';
oBox.style.backgroungImage = 'url(images/1.jpg)';
var oBox = document.getElementsByClassName('box');
oBox.setAttribute('data-n', 10);
var n = oBox.getAttribute('data-n');
节点的创建:
// 示例:
var cDiv = document.createElement('div');
父节点.appendChild(孤儿节点);
父节点.insertBefore(孤儿节点, 标杆节点);
// html 代码
<table id = "mytable"></table>
// CSS代码:
td {
width: 120px;
height: 20px;
border: 1px solid #000;
}
// JS 代码:
var mytable = document.getElementById('mytable');
for(var i = 1; i <= 9; i++) {
// 创建了新的tr标签
var ctr = document.createElement('tr');
for(var j = 1; j <= i; j++) {
// 创建新的td标签
var ctd = document.createElement('td');
// 设置td内部的文字
ctd.innerText = j + 'x' + i + '=' + (i * j);
// 让tr追加td标签
ctr.appendChild(ctd);
}
// 让mytable追加tr标签
mytable.appendChild(ctr);
}
移动节点:
新父节点.appendChild(已经有的父节点);
新父节点.insertBefore(已经有的父节点, 标杆子节点);
删除节点:
父节点.removeChild(要删除的子节点);
克隆节点:
var 克隆得到的孤儿节点 = 老节点.cloneNode();
var 克隆得到的孤儿节点 = 老节点.cloneNode(true); // 连带后代
var 克隆得到的孤儿节点 = 老节点.cloneNode(false); // 只有自身
oBox.onclick = function() {
// 点击盒子时,执行这里的语句
};
常见的鼠标事件监听:
事件名 | 事件描述 |
---|---|
onclick | 当鼠标 点击 某个对象时触发事件 |
ondblclick | 当鼠标 双击 某个对象时触发事件 |
onmousedown | 当鼠标上某个按键在某个对象上 按下 时触发事件 |
onmouseup | 当鼠标上某个按键在某个对象上 松开 时触发事件 |
onmousemove | 当鼠标上某个按键在某个对象上 移动 时触发事件 |
onmouseenter | 当鼠标 进入 某个对象时触发事件(相似事件 onmouseover 冒泡) |
onmouseleave | 当鼠标 离开 某个对象时触发事件(相似事件 onmouseout 冒泡) |
onmousewheel | 当鼠标 滚轮滚动 时触发事件(它的事件对象e提供deltaY属性表示滚轮滚动方向,向下为正值,向上为负值) |
常见的键盘事件监听:
事件名 | 事件描述 |
---|---|
onkeypress | 当某个键盘的按键被 按下(系统按钮如箭头键和F1-F12功能键无法得到识别)时触发事件 |
onkeydown | 当某个键盘的键被 按下(系统按钮可以识别,并且会优先于 onkeypress 发生)时触发事件 |
onkeyup | 当某个键盘的键被 松开 时触发事件 |
常见的表单事件监听:
事件名 | 事件描述 |
---|---|
onchange | 当 用户改变域的内容 时触发事件 |
oninput | 当 用户在域内输入内容 时触发事件(回退不触发) |
onfocus | 当 某元素获得焦点(比如tab键或鼠标点击)时触发事件 |
onblur | 当 某元素失去焦点 时触发事件 |
onsubmit | 当 表单被提交时 触发事件 |
onreset | 当 表单被重置时 触发事件 |
常见的页面事件监听:
事件名 | 事件描述 |
---|---|
onload | 当 页面或图片被完成加载 时触发事件 |
onunload | 当 用户退出页面 时触发事件 |
addEventListener() 方法:
oBox.onclick = function() {
// 触发事件后的执行语句
};
oBox.addEventListener('click', function() {
// 触发事件后的执行语句
}, true);
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
// JS 代码:
var oBox1 = document.getElementById('box1');
var oBox2 = document.getElementById('box2');
var oBox3 = document.getElementById('box3');
oBox1.addEventListener('click', function() {
console.log('我是box1的捕获阶段');
}, true);
oBox2.addEventListener('click', function() {
console.log('我是box2的捕获阶段');
}, true);
oBox3.addEventListener('click', function() {
console.log('我是box3的捕获阶段');
}, true);
oBox1.addEventListener('click', function() {
console.log('我是box1的冒泡阶段');
}, false);
oBox2.addEventListener('click', function() {
console.log('我是box2的冒泡阶段');
}, false);
oBox3.addEventListener('click', function() {
console.log('我是box3的冒泡阶段');
}, false);
注意事项:
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
// JS 代码:
var oBox1 = document.getElementById('box1');
var oBox2 = document.getElementById('box2');
var oBox3 = document.getElementById('box3');
oBox1.onclick = function() {
console.log('A');
};
oBox1.onclick = function() {
console.log('B');
};
oBox1.addEventListener('click', function() {
console.log('C');
}, false);
oBox1.addEventListener('click', function() {
console.log('D');
}, false);
// 输出结果
B C D
// 对象 e 就是这次事件的“事件对象”
oBox.onclick(e) {
// 事件被触发时执行的语句
}
在鼠标事件当中,描述鼠标位置的一些属性:
属性 | 属性描述 |
---|---|
offsetX | 鼠标指针相对于 事件源元素 的水平坐标 |
offsetY | 鼠标指针相对于 事件源元素 的垂直坐标 |
clientX | 鼠标指针相对于 浏览器 的水平坐标 |
clientY | 鼠标指针相对于 浏览器 的垂直坐标 |
pageX | 鼠标指针相对于 整张网页 的水平坐标 |
pageY | 鼠标指针相对于 整张网页 的垂直坐标 |
<div id = "box"></div>
// JS 代码:
var oBox = document.getElementById('box');
oBox.onmousemove = function(e) {
console.log('offsetX/Y: ' + e.offsetX + ' , ' + e.offsetY);
console.log('clientX/Y: ' + e.clientX + ' , ' + e.clientY);
console.log('pageX/Y: ' + e.pageX + ' , ' + e.pageY);
};
按键的 e.charCode 和 e.keyCode 属性:
charCode 字符码:
字符 | 字符码 |
---|---|
数字 0~9 | 48 ~ 57 |
大写字母 A~Z | 65 ~ 90 |
小写字母 a~z | 97 ~ 122 |
keyCode 键码:
按键 | 键码 |
---|---|
数字 0~9 | 48 ~ 57(与charCode字符码完全相同) |
字母不分大小写 a~z | 65 ~ 90 (与charCode字符码的大写字母A~Z相同,而keyCode不分大小写,一律为65~90) |
四个方向键:左⬅️、上⬆️、右➡️、下⬇️ | 37、38、39、40 |
回车键 | 13 |
空格键 | 32 |
// html
<div id="box"></div>
// CSS
#box {
position: absolute;
top: 200px;
left: 200px;
width: 100px;
height: 100px;
background-color: blue;
}
// JS 代码:
var oBox = document.getElementById('box');
// 定义全局变量 t、l分别表示盒子的 top属性和left属性值
var t = 200;
var l = 200;
// 监听document对象的键盘按下事件监听,表示用户在整个网页上按下按键
document.onkeydown = function(e) {
// 条件是以后按下的方向键左37、上38、右39、下40
switch(e.keyCode) {
case 37:
l -= 10;
break;
case 38:
t -= 10;
break;
case 39:
l += 10;
break;
case 40:
t += 10;
break;
}
// 更改样式
oBox.style.top = t + 'px';
oBox.style.left = l + 'px';
};
e.preventDefault() 方法:
小案例1: 制作一个文本框,只能让用户在其中输入小写字母和数字,其它字符输入没有效果
<div>
<p>只能输入小写字母和数字:</p>
<input type="text" id="field">
</div>
//JS 代码
var oField = document.getElementById('field');
oField.onkeypress = function(e) {
// 根据用户输入字符的字符码(e.charCode)决定是否显示
// 数字0-9字符码为:48-57
// 小写字母a-z字符码为:97-122
if(!(e.charCode >= 48 && e.charCode <= 57 || e.charCode >= 97 && e.cahrCode <= 122)) {
// 阻止浏览器的默认行为:输入一个字符显示一个字符的行为
e.preventDefault();
}
};
小案例2: 制作鼠标滚轮事件:当鼠标在盒子中向下滚动时,数字加1,反之,数字减1
<div id="box"></div>
<h1 id="info">0</h1>
//JS 代码
var oBox = document.getElementById('box');
var oInfo = document.getElementById('info');
// 定义全局变量
var a = 0;
// 给盒子添加鼠标滚轮滚动事件监听
oField.onmousewheel = function(e) {
// 阻止浏览器的默认行为:当用户在盒子里面滚动鼠标滚轮的时候,此时不会引起页面滚动条的滚动
e.preventDefault();
if(e.deltaY > 0) {
a++;
} else {
a--;
}
oInfo.innerText = a;
};
e.stopPropagation() 方法:
<button id="btn">点我弹出弹出层</button>
<div class="model" id="model"></div>
// JS代码
var oBtn = document.getElementById('btn');
var oModel = document.getElementById('model');
// 点击按钮的时候,弹出弹出层
oBtn.onclick = function(e) {
// 阻止事件传播到document 身上
e.stopPropagation();
oModel.style.display = "block";
};
// 点击页面任何地方,关闭弹出层
document.onclick = function() {
oModel.style.display = 'none';
};
// 点击弹出层内部的时候,不能关闭弹出层,所以应该阻止事件继续传播
oModel.onclick = function(e) {
// 阻止事件继续传播到 document 身上
e.stopPropagation();
};
问题1(批量添加): 页面上有一个无序列表 < ul >,它内部有多个< li > 元素,请批量给它们添加点击事件监听,实现效果:点击哪个 < li > 元素,哪个 < li > 元素就变红
<ul id="list">
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
</ul>
// JS 代码
var oList = document.getElementById('list');
var lis = oList.getElementsByTagName('li');
// 书写循环语句,批量给元素添加监听
for(var i = 0; i < lis.length; i++) {
lis[i].onclick = function() {
this.style.color = 'red';
};
}
批量事件监听的性能问题:
问题2(动态绑定): 页面上有一个无序列表 < ul >,它内部没有< li > 元素,请制作一个按钮,点击这个按钮就能增加一个< li >元素,并为每个增加的< li >元素添加点击事件,实现效果是点击哪个< li > 元素,哪个< li > 元素就变红
<button id="btn">点我添加新的li列表项</button>
<ul id="list"></ul>
// JS 代码
var oBtn = document.getElementById('btn');
var oList = document.getElementById('list');
// 按钮点击事件
oBtn.onclick = function() {
// 创建一个新的 li 列表项,孤儿节点
var oLi = document.createElement('li');
oLi.innerHTML = '我是列表项';
// 上树
oList.appendChild(oLi);
// 给新创建的这个 li 节点添加 onclick 事件监听
oLi.onclick = function() {
this.style.color = 'red';
};
};
动态绑定事件的性能问题:
事件委托:
属性 | 属性描述 |
---|---|
target | 触发此事件的最早元素,用户真正触发的那个元素,即“事件源元素” |
currentTarget | 事件处理程序附加到的元素 |
使用事件委托时需要注意的事项:
定时器:
setInterval(function() {
// 这个函数将自动被以固定间隔时间调用
},5000);
setInterval(function(a, b) {
// 函数行参中 a对应33,b对应55
},3000, 33, 55);
function fun() {
// 函数体语句
}
// 具名函数当做第一个参数,注意这里没有圆括号
setInterval(fun, 2000);
清除定时器:
// 设置定时器,并且用变量接收这个定时器
var timer = setInterval(function() {
// 函数体语句
}, 3000);
// 点击按钮时,清除定时器
oBox.onclick = function() {
// 清除定时器时,要传入定时器变量
clearInterval(timer);
};
<h1 id="info"></h1>
<button id="btn1">开始</button>
<button id="btn1">暂停</button>
// JS 代码:
var oInfo = document.getElementById('info');
var oBtn1 = document.getElementById('btn1');
var oBtn2 = document.getElementById('btn2');
// 定义全局变量
var timer;
var a = 0;
// 点击开始,计时器开始运行
oBox1.onclick = function() {
// 为了防止定时器叠加,应该在设置定时器之前先清除定时器
clearInterval(timer);
// 设置定时器
timer = setInterval(function() {
// 函数体语句
oInfo.innerText = ++a;
}, 1000);
};
// 点击按钮时,清除定时器
oBox2.onclick = function() {
// 清除定时器时,要传入定时器变量
clearInterval(timer);
};
延时器:
setTimeout(function() {
// 这个函数会在延迟2秒后执行一次
}, 2000);
<button id="btn1">2秒后弹出你好</button>
<button id="btn1">取消弹出</button>
// JS 代码:
var oBtn1 = document.getElementById('btn1');
var oBtn2 = document.getElementById('btn2');
// 定义全局变量
var timer;
// 点击开始,计时器开始运行
oBox1.onclick = function() {
// 设置定时器
timer = setTimeout(function() {
// 函数体语句
alert('你好');
}, 2000);
};
// 点击按钮时,清除定时器
oBox2.onclick = function() {
// 清除定时器时,要传入定时器变量
clearTimeout(timer);
};
初步认识一步语句:
setTimeout(function() {
console.log('A');
}, 2000);
console.log('B');
// 输出结果
B A
使用定时器实现动画:
<button id="btn">移动</button>
<div id="box"></div>
// CSS
#box {
width: 100px;
height: 100px;
background-color: orange;
position: absolute;
top: 100px;
left: 100px;
}
// JS 代码
var oBtn = document.getElementById('btn');
var oBox = document.getElementById('box');
// 标识量 0:表示在左边,1:表示在右边
var pos = 0;
// 事件监听
oBtn.onclick = function() {
// 加上过度
oBox.style.transition = 'all 2s linear 0s';
if(pos == 0) {
// 瞬间移动,但由于有过渡,所以是动画
oBox.style.left = '1100px';
pos = 1;
} else {
oBox.style.left = '100px';
pos = 0;
}
};
var lock = true;
function 需要节流的函数() {
// 如果锁是关闭状态,则不执行
if(!lock) return;
// 函数核心语句
// 关锁
lock = false;
// 指定毫秒数后将锁打开
setTimeout(function() {
lock = true;
}, 2000);
};
<button id="btn">移动</button>
<div id="box"></div>
// CSS
#box {
width: 100px;
height: 100px;
background-color: orange;
position: absolute;
top: 100px;
left: 100px;
}
// JS 代码
var oBtn = document.getElementById('btn');
var oBox = document.getElementById('box');
// 标识量 0:表示在左边,1:表示在右边
var pos = 0;
// 函数节流锁
var lock = true;
// 事件监听
oBtn.onclick = function() {
// 检查锁是否关闭
if(!lock) return;
// 加上过度
oBox.style.transition = 'all 2s linear 0s';
if(pos == 0) {
// 瞬间移动,但由于有过渡,所以是动画
oBox.style.left = '1100px';
pos = 1;
} else {
oBox.style.left = '100px';
pos = 0;
}
// 关锁
lock = false;
// 设置指定毫秒数打开,一般设置为动画过渡时间
setTimeout(function() {
lock = true;
}, 2000);
};
<div id="box" class="box">
<ul id="list">
<li><img src="/images/number/0.png" alt=""></li>
<li><img src="/images/number/1.png" alt=""></li>
<li><img src="/images/number/2.png" alt=""></li>
<li><img src="/images/number/3.png" alt=""></li>
<li><img src="/images/number/4.png" alt=""></li>
<li><img src="/images/number/5.png" alt=""></li>
</ul>
</div>
// CSS
* {
margin: 0;
padding: 0;
}
.box {
width: 1000px;
height: 130px;
border: 1px solid #000;
margin: 50px auto;
overflow: hidden;
}
.box ul {
list-style: none;
width: 5000px;
position: relative;
}
.box ul li {
float: left;
margin-right: 10px;
}
// JS 代码
var oBox = document.getElementById('box');
var oList = document.getElementById('list');
// 复制一遍所有的 li
oList.innerHTML += oList.innerHTML;
// 全局变量,表示当前 list 的 left 值
var left = 0;
var timer;
move();
function move() {
// 防止动画累积
clearInterval(timer);
// 定时器
timer = setInterval(function() {
left -= 6;
if(left <= -1260) {
left = 0;
}
oList.style.left = left + 'px';
},20);
};
// 添加鼠标进入ul元素,停止定时器
oBox.onmouseenter = function() {
clearInterval(timer);
};
// 鼠标离开继续执行定时器
oBox.onmouseleave = function() {
move();
};
<div class="carousel">
<ul id="list">
<li><img src="/images/0.png" alt=""></li>
<li><img src="/images/1.png" alt=""></li>
<li><img src="/images/2.png" alt=""></li>
<li><img src="/images/3.png" alt=""></li>
<li><img src="/images/4.png" alt=""></li>
</ul>
</div>
<a href="javascript:;" class="leftbtn" id="leftbtn"></a>
<a href="javascript:;" class="rightbtn" id="rightbtn"></a>
// CSS
* {
margin: 0;
padding: 0;
}
.carousel {
width: 650px;
height: 360px;
border: 1px solid #000;
margin: 50px auto;
position: relative;
overflow: hidden;
}
.carousel ul {
list-style: none;
width: 6000px;
position: relative;
left: 0px;
transition: left .5s ease 0s;
}
.carousel ul li {
float: left;
}
.carousel .leftbtn {
position: absolute;
left: 20px;
top: 50%;
margin-top: -25px;
width: 50px;
height: 50px;
background-color: rgb(28,180,226);
border-radius: 50%;
}
.carousel .rightbtn {
position: absolute;
right: 20px;
top: 50%;
margin-top: -25px;
width: 50px;
height: 50px;
background-color: rgb(28,180,226);
border-radius: 50%;
}
// JS 代码
// 得到按钮和ul,ul整体进行运动
var rightbtn = document.getElementById('rightbtn');
var leftbtn = document.getElementById('leftbtn');
var list = document.getElementById('list');
// 克隆第一张图片
var cloneli = list.firstElementChild.cloneNode(true);
// 将克隆的图片追加到最后
list.appendChild(cloneli);
// 定义全局变量,当前ul显示到第几张了,从0开始数
var idx = 0;
// 函数节流锁
var lock = true;
// 右边按钮监听
rightbtn.onclick = function() {
// 判断锁的状态
if(!lock) return;
// 关锁
lock = false;
// 因为最后一张图片会把过渡去掉,所以需要在这给list加过渡
list.style.transition = 'left .5s ease 0s';
idx ++;
if(idx > 4) {
// 设置一个延时器,延时器的功能是将ul瞬间拉回0的位置
setTimeout(function() {
// 取消过渡,因为要瞬间移动到第一张图片
list.style.transition = 'none';
list.style.left = 0;
idx = 0;
},500);
}
list.style.left = -idx * 650 + 'px';
//函数节流
setTimeout(function() {
lock = true;
},500);
};
// 左边按钮监听
leftbtn.onclick = function() {
// 判断锁的状态
if(!lock) return;
// 关锁
lock = false;
// 判断是不是第0张,如果是,就要瞬间用假的替换真的
if(idx == 0) {
// 取消过渡
list.style.transition = 'none';
// 直接瞬间移动到最后的假图片上
list.style.left = -5 * 650 + 'px';
// 设置一个延时器,这个延时器的延时时间可以是0毫秒
// 虽然是0毫秒,但是可以让我们过渡先是瞬间取消过渡,然后再加上
setTimeout(function() {
// 加过渡
list.style.transition = 'left .5s ease 0s';
// idx改为真正的最后一张图片的编号
idx = 4;
list.style.left = -idx * 650 + 'px';
},0);
} else {
idx --;
list.style.left = -idx * 650 + 'px';
}
// 函数节流
setTimeout(function() {
lock = true;
},500);
};
<div class="carousel">
<ul id="list">
<li><img src="/images/0.png" alt=""></li>
<li><img src="/images/1.png" alt=""></li>
<li><img src="/images/2.png" alt=""></li>
<li><img src="/images/3.png" alt=""></li>
<li><img src="/images/4.png" alt=""></li>
</ul>
</div>
<a href="javascript:;" class="leftbtn" id="leftbtn"></a>
<a href="javascript:;" class="rightbtn" id="rightbtn"></a>
// CSS
* {
margin: 0;
padding: 0;
}
.carousel {
width: 650px;
height: 360px;
border: 1px solid #000;
margin: 50px auto;
position: relative;
}
.carousel ul {
list-style: none;
}
.carousel ul li {
position: absolute;
top: 0;
left: 0;
/* 后面图片透明度为0 */
opacity: 0;
transition: opacity 1s ease 0s;
}
.carousel ul li:first-child {
/* 第一张图片透明度为1 */
opacity: 1;
}
.carousel .leftbtn {
position: absolute;
left: 20px;
top: 50%;
margin-top: -25px;
width: 50px;
height: 50px;
background-color: rgb(28,180,226);
border-radius: 50%;
}
.carousel .rightbtn {
position: absolute;
right: 20px;
top: 50%;
margin-top: -25px;
width: 50px;
height: 50px;
background-color: rgb(28,180,226);
border-radius: 50%;
}
// JS 代码
// 得到按钮和ul,ul整体进行运动
var rightbtn = document.getElementById('rightbtn');
var leftbtn = document.getElementById('leftbtn');
var list = document.getElementById('list');
var lis = document.getElementsByTagName('li');
// 当前显示的是第几张图
var idx = 0;
// 节流
var lock = true;
// 右边按钮监听
rightbtn.onclick = function() {
// 判断锁的状态
if(!lock) return;
// 关锁
lock = false;
// 还没有改 idx,此时的idx这个图片就是老图,老图淡出
lis[idx].style.opacity = 0;
idx ++;
if(idx > 4) idx = 0;
// 改了 idx,此时的idx这个图片就是新图,新图淡入
lis[idx].style.opacity = 1;
//函数节流
setTimeout(function() {
lock = true;
},1000);
};
// 左边按钮监听
leftbtn.onclick = function() {
// 判断锁的状态
if(!lock) return;
// 关锁
lock = false;
// 还没有改 idx,此时的idx这个图片就是老图,老图淡出
lis[idx].style.opacity = 0;
idx --;
if(idx < 0) idx = 4;
// 改了 idx,此时的idx这个图片就是新图,新图淡入
lis[idx].style.opacity = 1;
//函数节流
setTimeout(function() {
lock = true;
},1000);
};
var a = 10;
console.log(window.a == a); // 输出 true
console.log(window.alert == alert); // true
console.log(window.setInterval == setInterval); // true
窗口尺寸相关的参数:
属性 | 意义 |
---|---|
innerHeight | 浏览器窗口的内容区域的高度,包含水平滚动条(如果有的话) |
innerWidth | 浏览器窗口的内容区域的宽度,包含垂直滚动条(如果有的话) |
outerHeight | 浏览器窗口的外部高度 |
outerWidth | 浏览器窗口的外部宽度 |
resize 事件:
已卷动高度:
// 为了更好的支持浏览器兼容性,使用下面这种方式
var scrollTop = window.scrollY || document.documentElement.scrollTop;
scroll 事件:
属性 | 意义 |
---|---|
appName | 浏览器官方名称 |
appVersion | 浏览器版本 |
userAgent | 浏览器的用户代理(含有内核信息和封装壳信息) |
platform | 用户操作系统 |
history.back(); // 等同于点击浏览器的回退按钮
history.go(-1); // 等同于 history.back();
// 这是第一个页面
<h1>我是temp网页</h1>
<a href="test.html">点我进入第二个页面</a>
// 我是第二个页面
<h1>我是test.html网页</h1>
<button id="btn">回退</button>
// JS代码
var btn = document.getElementById('btn');
btn.onclick = function() {
// history.back();
history.go(-1);
}
window.location = 'http://www.baidu.com';
window.location.href = 'http://www.baidu.com';
重新加载当前页面:
window.location.reload(true);
GET 请求的查询参数:
比如网址:https://www.baidu.com/?a=1&b=2
console.log(window.location.search); //得到 ?a=1&b=2
body {
height: 5000px;
}
.backtotop {
width: 60px;
height: 60px;
background-color: rgba(233,233,233,.6);
position: fixed;
bottom: 100px;
right: 100px;
/* 小手状 */
cursor: pointer;
}
<div class="backtotop" id="backtotopbtn">返回顶部</div>
var backtotopbtn = document.getElementById('backtotopbtn');
// 设置全局变量
var timer;
backtotopbtn.onclick = function() {
// 设表先关
clearInterval(timer);
// 设置定时器
timer = setInterval(function() {
// 不断让 scrollTop减少
document.documentElement.scrollTop -= 200;
// 停止定时器
if(document.documentElement.scrollTop <= 0) {
clearInterval(timer);
}
},20);
};
* {
margin: 0;
padding: 0;
}
#content-part {
width: 1000px;
margin:0px auto;
margin-bottom: 30px;
background-color: #ccc;
font-size: 50px;
}
.floornav {
position: fixed;
right: 40px;
top: 50%;
margin-top: -100px;
width: 120px;
height: 200px;
background-color: orange;
}
.floornav ul {
list-style: none;
}
.floornav ul li {
width: 120px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 26px;
/* 小手指针 */
cursor: pointer;
}
.floornav ul li.current {
background: purple;
color: white;
}
// html
<div class="floornav">
<ul id="list">
<li data-n="科技" class="current">科技</li>
<li data-n="体育">体育</li>
<li data-n="新闻">新闻</li>
<li data-n="娱乐">娱乐</li>
<li data-n="视频">视频</li>
</ul>
</div>
<section class="content-part" style="height:674px;" data-n="科技">科技栏目</section>
<section class="content-part" style="height:654px;" data-n="体育">体育栏目</section>
<section class="content-part" style="height:622px;" data-n="新闻">新闻栏目</section>
<section class="content-part" style="height:432px;" data-n="娱乐">娱乐栏目</section>
<section class="content-part" style="height:526px;" data-n="视频">视频栏目</section>
// JS 代码
var list = document.getElementById('list');
var contentParts = document.querySelectorAll('.content-part');
var lis = document.querySelectAll('#list li');
// 使用事件委托给 li添加监听
list.onclick = function(e) {
if(e.target.targetName.toLowerCase() == 'li') {
// getAttribute表示得到标签上的某个属性值
var n = e.target.getAttribute('data-n');
// 可以使用属性选择器(就是方括号选择器)来寻找带有相同data-n的content-part
var contentPart = document.querySelector('.content-part[data-n=' + n + ']');
// 让页面的卷动自动成为这个盒子的offsetTop值
docuemnt.documentElement.scrollTop = contentPart.offsetTop;
}
};
// 在页面加载好后,将所有的content-part盒子的offsetTop值推入数组
var offsetTopArr = [];
// 遍历所有的 contentPart,将他们的净位置推入数组
for(var i = 0; i < contentParts.length; i++) {
offsetTopArr.push(contentParts[i].offsetTop);
}
// 为了最后一项可以方便比较,我们可以推入一个无穷大
offsetTopArr.push(Infinity);
// 当前所在楼层
var nowfloor = -1;
// 窗口的卷动
window.onscroll = function() {
var scrollTop = document.documentElement.scrollTop;
// 遍历offsetTopArr数组,看看当前的scrollTop 值在哪两个楼层之间
for(var i = 0; i < offsetTopArr.length; i++) {
if(scrollTop > offsetTopArr[i] && scrollTop < offsetTopArr[i + 1]) {
break;
}
}
// 退出循环的时候,i是几就表示当前楼层是几
// 如果当前所在楼层不是i,表示换楼了
if(nowfloor != i) {
// 让全局变量改变为这个楼层号
nowfloor = i;
// 设置下标为i的项有cur
for(var j= 0; j < lis.length; j++) {
if(j == i) {
lis[j].className = 'current';
} else {
lis[j].className = '';
}
}
}
};
var zhangsan = {
name: '张三',
age: 12,
sex: '男',
hobbies: ['玩游戏','编程','踢足球']
};
var zhangsan = {
name: '张三',
// 属性名中有短横,不符合JS标识符命名规范,属性名必须加引号包裹
'favorite-book': '三体'
};
属性的访问:
var obj = {
a: 1,
b: 3
};
// 属性名用变量存储
var key = 'b';
console.log(obj.key); // undefined
console.log(obj[key]); // 3
属性的更改:
var obj = {
a: 10
};
obj.a = 30;
console.log(obj.a); // 30
属性的新增(创建):
var obj = {
a: 10
};
obj.b = 30;
属性的删除:
var obj = {
a: 10,
b: 20
};
delete obj.b;
var xiaoming = {
name: '小明',
age: 18,
sex: '男',
sayHello: function() {
console.log('小明的sayHello方法!')
}
};
// k:循环变量,它会依次成为对象的每一个键
// obj:要遍历的对象
for(var k in obj) {
console.log('属性' + k + '的值是:' + obj[k]);
}
举例 | 当 var a = b 变量传值时 | 当用 == 比较时 | |
---|---|---|---|
基本类型 | 数字、字符串、布尔型、undefined、null | 内存中产生新的副本 | 比较值是否相等 |
引用类型 | 对象、数组等(还包括函数、正则表达式) | 内存中不产生新的副本,而是让新的变量指向同一个对象 | 比较内存地址是否相同,即比较是否是同一个对象 |
对象是引用类型值,这意味着:
对象浅克隆:
var obj1 ={
a: 1,
b: 2,
c: [11,22,33]
};
var obj2 = {};
// 本质上 obj1 和 obj2 的 c属性还是同一块内存中的数组,并没有实现克隆
for(var k in obj1) {
// 每遍历一个 k 属性,就给 obj2 页添加一个同名的 k属性
// 且每个 k属性对应的值也和 obj1的相同
obj2[k] = obj1[k];
}
console.log(obj1.c == obj2.c); // true
对象的深克隆:
var obj1 ={
a: 1,
b: 2,
c: [11,22,33,{
m: 22,
n:78,
p:[65,23,21]
}]
};
function deepClone(obj) {
var result;
// 要判断 obj 是对象还是数组
// 数组的 typeof 也是 object,所以先检测数组
if(Array.isArray(obj)) {
// 数组
for(var i = 0; i < obj.length; i++) {
result.push(deepClone(obj[i]));
}
} else if(typeof obj == 'object') {
// 对象
for(var k in obj) {
result[k] = deepClone(obj[k]);
}
} else {
// 基本类型值
result = obj;
}
return result;
};
var obj2 = deepClone(obj1);
obj1.c.push(99);
console.log(obj1);
console.log(obj2);
var obj = {
a: 1,
b: 2,
fun: function() {
console.log(this.a + this.b);
}
};
obj.fun(); // 输出结果是 3
var fn = obj.fun; // 将函数提出来单独存为变量
fn(); // 输出结果是 NaN
对象.方法();
例题1:
function fun() {
console.log(this.a + this.b);
};
var obj = {
a: 3,
b: 5,
fn: fun
};
obj.fn(); // 输出 8
例题2:
var obj1 = {
a: 1,
b: 3,
fn: function() {
console.log(this.a + this.b);
}
};
var obj2 = {
a: 2,
b: 5,
fun: obj1.fn();
};
obj2.fun(); // 输出 7
例题3:
function outer() {
var a = 2;
var b = 3;
return {
a: 11,
b: 22,
fun: function() {
console.log(this.a + this.b);
}
};
};
outer.fun(); // 输出 33
例题4:
function fun() {
console.log(this.a + this.b);
};
var obj = {
a: 1,
b: 2,
c: [{
a: 3,
b: 4,
c: fun
}]
};
var a = 5;
obj.c[0].c(); // 输出 7
函数()
例题1:
var obj = {
a: 1,
b: 2,
fun: function() {
console.log(this.a + this.b);
}
};
var a = 5;
var b = 6;
var fn = obj.fun;
fun(); // 输出 11
例题2:
function fun() {
return this.a + this.b;
}
var a = 5;
var b = 6;
var obj = {
a: 3,
b: fun(), // 此处调用时的 this 是 window
fun: fun // 此处调用时的 this 是 obj
};
var result = obj.fun(); // 此处调用时的 this 是 obj
console.log(result); // 输出 14
数组[下标]()
例题1:
var arr = ['A','B','C',function(){
console.log(this[1]);
}];
arr[3](); // 输出 B
例题2:
function fun() {
arguments[3]();
}
// 调用函数
fun('A','B','C',function(){
console.log(this[1]);
}); // 输出 B
(function() {
})();
题目1:
var a = 1;
var obj = {
a: 2,
fun: (function {
var a = this.a; // tnis指代window,变量 a 的值为全局变量赋值的 1
return function() {
console.log(a + this.a); // 此处的this指代 obj
}
})()
};
obj.fun(); // 输出 3
setInterval(函数, 时间);
setTimeout(函数, 时间);
题目1:
var obj = {
a: 2,
b: 3,
fun: function {
console.log(this.a + this.b);
}
};
var a = 5;
var b = 6;
setTimeout(obj.fun, 2000); // 输出 11
题目2:
var obj = {
a: 2,
b: 3,
fun: function {
console.log(this.a + this.b);
}
};
var a = 5;
var b = 6;
setTimeout(function() {
obj.fun(); // 此处适用规则1
}, 2000); // 输出 5
DOM元素.onclick = function() {
};
案例1: 请实现效果:点击哪个盒子,哪个盒子就变红,要求使用同一个事件处理函数实现(不能使用事件委托)
<div id="box1"></div>
<div id="box2"></div>
<div id="box3"></div>
// JS
var box1 = document,getElementById('box1');
var box2 = document,getElementById('box2');
var box3 = document,getElementById('box3');
function setColorToRed() {
this.style.backgroundColor = 'red';
}
box1.onclick = setColorToRed;
box2.onclick = setColorToRed;
box3.onclick = setColorToRed;
案例2: 请实现效果:点击哪个盒子,哪个盒子在2000毫秒后变红,要求使用同一个事件处理函数实现(不能使用事件委托)
<div id="box1"></div>
<div id="box2"></div>
<div id="box3"></div>
// JS
var box1 = document,getElementById('box1');
var box2 = document,getElementById('box2');
var box3 = document,getElementById('box3');
function setColorToRed() {
// 备份上下文
var that = this;
setTimeout(function() {
that.style.backgroundColor = 'red';
}, 2000);
}
box1.onclick = setColorToRed;
box2.onclick = setColorToRed;
box3.onclick = setColorToRed;
二者的区别(体现在有参数时):
// 没有参数
函数.call(指定的上下文);
或者:
函数.apply(指定的上下文);
// 有参数
函数.call(指定的上下文, 参数1, 参数2 ...);
或者:
函数.apply(指定的上下文, [参数1, 参数2 ...]);
示例:
function sum() {
console.log(this.a + this.b + this.c);
};
var obj = {
a: 100,
b: 70,
c: 90,
// sum: sum
};
// 方法1: 可以在obj 中使用 sum: sum 指定上下文
// obj.sum();
// 方法2:可以使用 call 或 apply 的方式指定上下文(将 sum: sum 注释掉)
sum.call(obj);
// 或者 sum.apply(obj);
规则 | 上下文 |
---|---|
对象.函数() | 对象 |
函数() | window |
数组[下标] () | 数组 |
IIFE | window |
定时器 | window |
DOM事件处理函数 | 绑定DOM的元素 |
call 和 apply | 任意指定 |
用 new 调用函数 | 创建出对象 |
new 函数()
JS 规定,使用 new 操作符调用函数会进行“四步走”:
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var xiaoming = new People('小明',12,'男');
var xiaoqiang = new People('小强',12,'男');
var xiaolan = new People('小兰',12,'女');
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
People('小明',12,'男');
People('小强',12,'男');
People('小兰',12,'女');
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayHello = function() {
console.log('我是 '+ this.name + ',我今年 '+ this.age + '岁了');
};
}
var xiaoming = new People('小明',12,'男');
var xiaoqiang = new People('小强',14,'男');
var xiaolan = new People('小兰',18,'女');
xiaoming.sayHello();
xiaoqiang.sayHello();
xiaolan.sayHello();
什么是 prototype:
function sum(a,b) {
return a + b;
}
console.log(sum.prototype); //sum的原型是函数,{constructor: function}
console.log(typeof sum.prototype); // object
console.log(sum.prototype.constructor === sum); //true
原型链查找:
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 在构造函数的 prototype 上添加 nationality 属性
People.prototype.nationality = '中国';
var xiaoming = new People('小明',12,'男');
// 实例可以打点访问原型的属性和方法
console.log(xiaoming.nationality); // 输出:中国
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 在构造函数的 prototype 上添加 nationality 属性
People.prototype.nationality = '中国';
var xiaoming = new People('小明',12,'男');
var tom = new People('汤姆',13,'男');
// 实例可以打点访问原型的属性和方法
console.log(xiaoming.nationality); // 输出:中国
// 这里输出中国的原因是tom实例没有nationality属性,只能到原型上查找
console.log(tom.nationality); // 输出:中国
// tom 实例添加nationality属性
tom.nationality = '美国';
console.log(tom.nationality); // 输出:美国
hasOwnProperty方法:
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 在构造函数的 prototype 上添加 nationality 属性
People.prototype.nationality = '中国';
var xiaoming = new People('小明',12,'男');
console.log(xiaoming.hasOwnProperty('name')); // true
console.log(xiaoming.hasOwnProperty('age')); // true
console.log(xiaoming.hasOwnProperty('sex')); // true
console.log(xiaoming.hasOwnProperty('nationality')); // false
in 运算符:
// 接上例
console.log('name' in xiaoming); // true
console.log('age' in xiaoming); // true
console.log('sex' in xiaoming); // true
console.log('nationality' in xiaoming); // true
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 在构造函数的 prototype 属性上添加 方法
People.prototype.sayHello = function() {
console.log('我是'+ this.name + ',今年' + this.age + '岁了,我是一个' + this.sex + '生');
}
People.prototype.growup = function() {
this.age ++;
}
var xiaoming = new People('小明',12,'男');
var xiaohong = new People('小红',10,'女');
console.log(xiaoming.sayHello === xiaohong.sayHello); // true,表明两个实例调用的是同一个方法
xiaoming.sayHello(); // 我是小明,今年12岁了,我是一个男生
xiaohong.sayHello(); // 我是小红,今年10岁了,我是一个女生
xiaoming.growup();
xiaoming.sayHello(); // 我是小明,今年13岁了,我是一个男生
xiaohong.sayHello(); // 我是小红,今年10岁了,我是一个女生
JavaScript中如何实现继承:
// 父类
function People(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
};
People.prototype.sayHello = function() {
console.log('你好,我是'+ this.name + ',我今年'+ this.age + '岁了');
};
People.prototype.sleep = function() {
console.log(this.name + '正在睡觉,zzzzz');
};
// 子类
function Student(name,age,sex,school,studentNumber) {
this.name = name;
this.age = age;
this.sex = sex;
this.school = school;
this.studentNumber = studentNumber;
};
// 实现继承的关键语句:子类的prototype属性指向父类的实例
// 这句关键语句必须写在子类实例原型之前
Student.prototype = new People();
// 子类的方法
Student.prototype.study = function() {
console.log(this.name + '正在学习');
};
Student.prototype.exam = function() {
console.log(this.name + '在考试');
};
// 实例化
var xiaoming = new Student('小明',10,'男','xxx小学',12306);
xiaoming.study();
xiaoming.sayHello();
xiaoming.sleep(); // 小明正在睡觉,zzzzz
// 重写(override)父类的sleep方法
Student.prototype.sleep = function() {
console.log(this.name + '正在睡觉,zzzzz,请不要打扰!');
};
xiaoming.sleep(); // 小明正在睡觉,zzzzz,请不要打扰!
var a = new Number(123);
var b = new String('Hello');
var c = new Boolean(true);
console.log(a); // 123
console.log(typeof a); // object
console.log(b); // Hello
console.log(typeof b); // object
console.log(c); // true
console.log(typeof c); // object
console.log(5 + a); // 128
var d = 2;
console.log(d.__proto__ == Number.prototype); // true
console.log(Math.max(6,2,3,5)); // 6
console.log(Math.min(6,2,3,5)); // 2
var arr = [3,6,9,2];
var max = Math.max.apply(null,arr);
console.log(max); // 9
parseInt(Math.random()*(b - a + 1)) + a
日期对象的常见方法:
方法 | 功能 |
---|---|
getDate() | 得到日期1~31 |
getDay() | 得到星期0~6 |
getMonth() | 得到月份0~11 |
getFullYear() | 得到年份 |
getHours() | 得到小时数0~23 |
getMinutes() | 得到分钟数0~59 |
getSeconds() | 得到秒数0~59 |
时间戳:
// 日期对象
var date = new Date();
// 显示时间戳。时间戳表示1970年1月1日距离此时的毫秒数
var timestamp1 = date.getTime(); // 精确到毫秒
var timestamp2 = Date.parse(date); //精确到毫秒,也是毫秒数,只不过最后三位一定是000
// 把时间戳变为时间对象,比如:1601536565000
var dd = new Date(1601536565000);
小案例:在页面上实时显示距离2021年高考还有多少天、多少时、多少分、多少秒
<h1>2021年高考倒计时</h1>
<h1 id="info"></h1>
// JS 代码
var info = document.getElementById('info');
setInterval(function() {
// 当前时间
var nowDate = new Date();
// 目标时间,5表示6月
var targetDate = new Date(2021,5,7);
// 毫秒差
var diff = nowDate - targetDate;
// 将毫秒差换算为:天、时、分、秒
// 换算为天:毫秒差除以一天的总毫秒数,就能换算为天
var day = parseIn(diff / (1000 * 60 * 60 * 24));
// 换算为时:毫秒差与一天的毫秒数的余数再除以一小时的毫秒数
var hours = parseIn(diff % (1000 * 60 * 60 * 24) / (1000 * 60 * 60));
// 换算为分:
var minutes = parseIn(diff % (1000 * 60 * 60) / (1000 * 60));
// 换算为秒:
var seconds = parseIn(diff % (1000 * 60 * 60) / (1000 * 60) / 1000);
// 显示内容
info.innerText = day + '天' + hours + '时' + minutes + '分' + seconds + '秒';
},1000);