Javascript总结

Javascript

历史

1995年 5月 网景公司 布兰登·艾奇 用10天 Macha

9月 改名 LiveScript

12月 javascript

java 和 javascript 没有关系 雷锋和雷峰塔

解决表单提交验证

ie: JScript

1997年, 欧洲计算机制造商协会(ECMA) 以JavaScript1.1为蓝本 定义了语法规范 ECMAScript

javascript和ECMAScript的关系

前者(javascript)是后者的体现

后者(ECMAScript)是前者的语法标准

js的组成部分:

ECMAScript 语法标准

DOM: Document Object Modal 文档对象模型

BOM: Browser Object Modal 浏览器对象模型

概念

js: 是基于对象和事件驱动的解释性脚本语言;

特点:

基于对象: 一切皆对象, 可以使用自己创建出来对象

事件驱动: 以事件作为驱动

解释性: 相对编译性来说, 不需要打包编译,直接在浏览器中就可以执行

跨平台: 只要浏览器支持js, 就能执行js, 跟电脑系统没有关系

相对安全: 同源策略限制

引入方式

行内

行内: 基于事件引入 写在起始标签上的 οnclick="alert('Hello World;')"

这是一个div

内嵌

内嵌: script双标签 可以写在页面的任何位置 body的结束标签之前 学习过程

外链

外链: script双标签 src引入js的文件 body的结束标签之前 工作

js文件: 创建后缀为 .js

注意: 外链js文件的script中不能写内嵌代码



注释

块注释: /* 注释 */ ctrl+shift+/

行注释: // 注释 ctrl+/

键盘快捷方式:

首选项 ---> 键盘快捷方式 ---> 搜索: comment ---> 修改

调试

调试: 程序员用来验证代码是否正确

调试方式: 输出 断点

输出调试:

  1. alert: 警告框

    alert('内容')

    数字和变量可以不加引号 其他的都要加

  2. prompt: 带有输入框的对话框 可以与用户做交互

    prompt('提示内容', '默认值'); 默认值: 可写可不写

    具有返回值, 可以接受

    确定: 输入框中的内容 取消: null

  3. 输出在页面: document.write(...data);

    ...data: 可以一次性写多个数据, 用,分隔

    只适合在页面加载过程中使用 如果在页面加载完成后使用 全页面内容都会被覆盖(函数)

    可以识别标签 不覆盖自己添加的内容

  4. 输出在控制台: console.log(...data);

    ...data: 可以一次性写多个数据, 用,分隔

    检查-->Console

// alert(1);
​
// alert(prompt('请输入你的姓名'));
​
document.write('这是一个a标签', '这是一个i标签');
document.write('BBBBBB');
​
console.log(123, 345, 567);

断点调试

断点调试: 浏览器右键 --> source ---> 打开要调试的文件 ---> 行数前点一下 (蓝色箭头、红色圆点) ---> 刷新 --> 点击三角箭头

变量

变量: 用来存储数据的容器;

声明变量: var声明

声明方式

  1. 先声明 后赋值

    var 变量名;

    变量名 = 值;

    var a;
    a = 10;
    console.log(a);
  2. 声明的同时赋值:

    var 变量名 = 值;

    var b = 20;
    console.log(b);
  3. 多个声明:

    var 变量名1 = 值1, 变量名2 = 值2, ..., 变量名n = 值n;

    js中 , 分隔 ;一句代码的结束

    var c = 30, d = 40;
    console.log(c, d); // 30 40
  4. 连等声明

    var 变量名1 = 变量名2 = 值;

    var m = n = 50;
    console.log(m, n);

命名规范

\1. 以数字、字母、_、$组成, 数字不开头

\2. 不能是关键字和保留字 var let const for break continue top(浏览器中存储window对象)

\3. 不能重复, 如果重复后面的就会覆盖前面的

\4. 遵循驼峰命名法 多个单词组成一个变量的时候 第二个往后的单词的首字母需要大写

\5. 具有语义化 userName user login password loginPass

/* 
    5. 验证变量名:

*/
var userName = '迪丽热巴';
console.log(userName);
var user1 = '杨洋';
console.log(user1);
var _a = '下划线';
console.log(_a);
var $ = 'js';
console.log($);
// var 1a = 'a1'; 报错
// 用var声明一个变量名为var的变量
// var var = 'var'; 报错
var let = '124'; // 一般不这么写
console.log(let);
var a = 20;
console.log(a);
var a = 30;
console.log(a); // 30

特殊声明

\1. 只声明 不赋值 变量值为undefined

\2. 不用var 全局变量 不遵循垃圾回收机制

\3. 不用var 也不赋值 报错: is not defined

/* 
    1. 只声明 不赋值 变量值为undefined
*/
var a;
console.log(a);

/* 
    2. 不用var 全局变量 不遵循垃圾回收机制
*/
b = 30;
console.log(b);

/* 
    3. 不用var 也不赋值 报错: is not defined
*/
console.log(c);

数据类型

为什么要进行数据类型分类:

\1. 不同的数据类型在内存中存储占用的内存不同

\2. 不同数据类型做的操作不同的 数值->计算 布尔->判断

数据类型:

五大基础数据类型 复杂(复合、引用)数据类型

五大基础:

number

string

boolean

null

undefined

复杂:

object

array

function

判断数据类型:

typeof 数据

typeof(数据)

var a = 30;
console.log(a);
console.log(typeof a); // number

var b = '迪丽热巴';
console.log(b);
console.log(typeof(b)); // string

number

分类

\1. 整型 整数 0 -1 1

\2. 浮点数 小数点后至少一位非0数字

\3. NaN: Not a Number 不是一个数字

\4. 进制数:

八进制: 以0为开头 没有超过8的数字

十六进制: 以0x为开头 0-9a-f表示0-15

\5. 特殊值:

Infinity: 无穷大

-Infinity: 无穷小

e: 10的幂次

var a = 1.0;
console.log(a);

var b = 1.000001;
console.log(b);

var c = 1.1234567891234567891;
console.log(c);
console.log(typeof c); // number

var n = NaN;
console.log(n);
console.log(typeof n); // number

var m = 10 - 'a';
console.log(m);

// 八进制
var num = 070;
console.log(num);

// 十六进制
var num1 = 0xa;
console.log(num1);

// 无穷大
var num2 = 1 / 0;
console.log(num2);

// e
var num3 = 2e2; // 2 * 10的2次方 = 200
console.log(num3);

NaN出现

\1. 自己声明

\2. 计算错误

NaN特性

\1. NaN属于数值类型 typeof后返回number

\2. NaN和任何数值都不相等 包括自身

\3. NaN与任何数值计算结果都是NaN

var m = 10 - 'a';
console.log(m);

console.log(NaN == NaN); // false
console.log(1 - NaN); // NaN

注意

注意: 当小数做计算, 由于计算机存储精度的问题, 有偏差

console.log(0.2 + 0.3);
console.log(0.1 + 0.2); // 0.30000000000000004

string

字符串: 用成对的引号包裹的内容

var str = 'abcd';
var str1 = '1234';
console.log(typeof str, typeof str1);

当字符足够长的时候, 需要换行显示, 可以使用\转义换行为字符串

var str = '正义虽然会迟到,但永远不会缺席.由孙红雷、张艺兴、刘奕君主演的《扫黑风暴》已经圆满收官,该作品根据真实案件改编而成,一经上线立马成为年度最热门的剧集。\
据统计,该剧首播日在6小时内就实现了播放量破亿,收视率全国同时段第一的好成绩。\
目前累计播放量44亿,弹幕互动量突破1600万、豆瓣高达8.0分,自开播以来20多天稳居收视率第一的宝座,这种成绩可以说创造了一个收视奇迹。';
console.log(str);

length: 字符串.length 可以得到当前字符串中字符的个数

console.log(str.length);

下标: 从左往后, 从0开始的数字

指定下标对应的字符: 字符串.charAt(下标)

指定下标对应的字符: 字符串[下标] ie8+

// 指定下标对应的字符: 字符串.charAt(下标)
console.log(str.charAt(49));
// 指定下标对应的字符: 字符串[下标] ie8+
console.log(str[49]);

变量和字符串: 变量拼接: 1. 删除 2. 加 加一组引号(与最外层引号一致) 和2个+ 3. 在+中间 拼接变量名

var name = 'javascript';
var age = 26;
var str = '' + name + '出现了' + age + '年';
console.log(str);

boolean

boolean: 布尔, 只有 true 和 false

true: 为真

false: 为假

判断条件 或者 判断条件的结果

var bool = true;
console.log(bool);
console.log(typeof bool); // boolean

// 判断条件
if(true){
    console.log(1);
}

// 判断条件
console.log(1 == 1); // true
console.log(1 == 2); // false

null

null: 只有一个值 就是本身 null js中唯一的真正的空

// 一般用作占位
var n = null;
console.log(n);
console.log(typeof n); // object

undefined

undefined: 未定义 当声明未赋值

var a;
console.log(a); // undefined
console.log(typeof a); // undefined

注意

js中规定 null和undefined是相等的

console.log(null == undefined); // true

null与undefined的区别

null: 真正的空

undefined: 未定义 当声明未赋值

强制转换

为什么要强制转换

所有通过输入框得到的数据 都是字符串

字符串加法 实现的是拼接

强制转换-number

Number(数据);

可以null和布尔值以及字符串中的空字符、空格字符、纯数字字符, 其他的都会被转成NaN

console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number('')); // ''中间没有任何字符 0
console.log(Number('      ')); // 0
console.log(Number('9087')); // 9087
console.log(Number('9087a')); // NaN
console.log(Number('a9087')); // NaN

parseInt

parseInt: 从左往右依次转换每一个字符, 遇到不能转换的或者到结尾就会结束转换, 保留整数

当第一个字符就不能转换的时候 返回NaN

console.log(parseInt('200px')); // 200
console.log(parseInt('155.8px')); // 155

parseFloat

parseFloat: 从左往右依次转换每一个字符, 遇到不能转换的或者到结尾就会结束转换, 保留小数

当第一个字符就不能转换的时候 返回NaN

console.log(parseFloat('155.8px')); // 155.8

强制转换-string

toString()

数据.toString()

将其他数据类型,转成字符串 null和undefined不能转换

在js中 .相当于白勺的

var num = 10;
console.log(num);
console.log(num.toString());
// 了解: 数值类型的时候: 小括号写进制
console.log(num.toString(8));

String

String(数据);

可以转换一切数据类型

console.log(String(10));
console.log(String(null));
console.log(String(undefined));

区别

toString 和 String区别

\1. toString: 对象的方法 可以自己修改 不能转换null和undefined

\2. String: 强制转换的方法 能转换null和undefined

强制转换-boolean

了解js的真和假:

假: false 0 NaN 空字符 null undefined

Boolean(数据): true false

console.log(false);
console.log(Boolean(1));
console.log(Boolean(-1));
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('')); // false
console.log(Boolean(' ')); // true
console.log(Boolean('a')); // true
console.log(Boolean(null)); // false
console.log(Boolean(undefined));// false

// 对象: {} 空对象
// 数组: [] 空数组
var obj = {};
console.log(obj);
console.log([]);

隐式转换方法

isNaN

isNaN(数据): 判断数据 是不是 不是一个数字

true: 不是一个数字

false: 是一个数字

隐式调用 Number 方法 如果Number转出来的不是NaN 返回false 是NaN 返回true

console.log(isNaN(true)); // Number(true)-->1  false
console.log(isNaN('true')); // Number('true')-->NaN true
console.log(isNaN(undefined)); // Number(undefined)-->NaN true
console.log(isNaN(parseInt('22.5px'))); // parseInt('22.5px')-->22 Number(22)-->22 false

toFixed

toFixed: 保留几位小数

将数值保留n位小数转化成字符串

数值.toFixed(数字);

数字: 保留的小数的位数

// var num = 2.3333333;
// var num = 2.500001;
var num = 2.499991;
console.log(num.toFixed(2));
console.log(typeof num.toFixed(2));

运算符

概念

运算符: 用来实现程序执行计算的符号 一般操作两个操作数及以上的符号

例: 1 + 2 +: 运算符 1、2: 操作数

表达式

表达式: 由2个或以上的操作数和运算符组成的式子

1 + 2

var a = 10;

分类:

运算符:

算术运算符: + - * / %(模) ++(自加) --(自减)

赋值运算符: = += -= *= /= %=

比较运算符: > >= < <= == === != !==

逻辑运算符: &&(与) ||(或) !(取反)

三目(元)运算符: 条件 ? 条件为真执行的代码 : 条件为假执行的代码;

表达式: 由运算符做决定的

算术表达式

赋值表达式

比较表达式

逻辑表达式

三目表达式

算术运算符

+ - * / % ++ --

基础

console.log(10 + 20); // 30
console.log(10 - 20); // -10
console.log(10 * 20); // 200
console.log(20 / 10); // 2
// %: 取余  模 
console.log(20 % 3); // 2
console.log(20 % 2); // 0

++

++: 在自身基础上加1 可以放在变量的前面 也可以放在后面

++和其他运算放在一起的时候, ++在前, 先自加, 在执行其他运算, ++在后, 先运行其他运算, 在自加

var a = 10;
a++; // 10 + 1 = 11 --> a
console.log(a); // 11
++a; // 11 + 1 --> 12 --> a
console.log(a); // 12

// ++和其他运算放在一起的时候, ++在前, 先自加, 在执行其他运算, ++在后, 先运行其他运算, 在自加
var b = 10;
console.log(b++); // 输出和++放在一起 先输出b=10 在自加10+1=11
console.log(b); // 11

var c = 10;
console.log(++c); // 输出和++放在一起, 先自加10+1=11 在输出c=11
console.log(c); // 11

--

--: 自减 可以放在前面可以放在后面

--和其他运算在一起的时候, --在前, 先自减, 在执行其他运算; --在后, 先执行其他运算, 在自减

// --: 自减 可以放在前面可以放在后面
var d = 10;
d--;
console.log(d); // 9
--d;
console.log(d); // 8

// --和其他运算在一起的时候, --在前, 先自减, 在执行其他运算; --在后, 先执行其他运算, 在自减
var m = 10;
console.log(m--); // 输出和-- 先输出m=10 再自减m=9
console.log(m); // 9


var n = 10;
console.log(--n); // 先自减 m = 9  再输出m=9

隐式转换规则

隐式转换的规则主要发生在算术运算符之间:

\1. 有字符串的加法就是拼接

\2. 没有字符串的加法的其他运算, 尽可能的将数据都转成数值类型后在计算 隐式调用Number方法

\3. 数值之间正常计算

\4. 遇到复杂数据类型, 会先调用数据的toString方法转换成字符串之后, 在参考上述规则

console.log(1 + 'a'); // 1a
console.log('a' + true); // atrue
console.log('a' + null); // anull


console.log('a' - 10); // NaN - 10 = NaN
console.log(true * 100); // 1 * 100 = 100
console.log(100 / null); // 100 / 0 = Infinity


console.log('a' + {}); // a[object Object]
console.log('a' + [1,2]); // a1,2

var a = '10';
a++;
console.log(a); // 11

赋值运算符

赋值: = += -= *= /= %=

将等号右边的赋值给左边

var a = 10; // 将10给了a
// a+=b: a = a + b;
a += 100;
console.log(a); // 110

a -= 20;
console.log(a);

a*=2; // a = a * 2;
console.log(a);

a /= 3;
console.log(a); // 60

a %= 50; // a = a % 50; 
console.log(a); // 10

比较运算符

> >= < <= 用左右两边的数据进行比较判断 如等式成立 返回true 否则返回false

console.log(1 > 2); // false
console.log(2 >= 1); // true
console.log(1 < 2); // true
console.log(1 <= 2); // true

== ===用于数据的比较判断

== 只比较值是否相等

=== 比较值是否相等 比较数据类型是否一致

// == ===用于数据的比较判断
// == 只比较值是否相等
console.log(1 == 1); // true
console.log(1 == '1'); // true
// === 比较值是否相等 比较数据类型是否一致
console.log(1 === '1'); // 值相等 数据类型不等 false

!=: 只比较值是否不相等

!==: 比较值是否不相等 比较数据类型是否不一致

// !=: 只比较值是否不相等 
console.log(1 != '1'); // false
console.log(1 != 2); // true
// !==: 比较值是否不相等 比较数据类型是否不一致
console.log(1 !== 1); // false
console.log(1 !== '1'); // 数值1 !== 字符串1 值相等 数据类型不等 true

字符串的比较: 从左往右依次比较每一个字符的ASCII码

''空字符串--0 '0'--48 '9'--57 'A'--65 'Z'--90 'a'--97 'z'--122

console.log('10000' < '2' ); // true 49 < 50 ? true
console.log('1000' < '1'); // 48 < 0 ? false

逻辑运算符

逻辑: && || !

&&

&&: 左右两边各自有一个判断条件, 如果两个条件都为真, 整个返回true, 如果有一个条件为假, 整个返回false

全真为真 一假为假

console.log(true && false); // false
console.log(1 < 2 && 2 < 3); // true && true true
console.log(1 > 2 && 2 < 3); // false && true false

||

||: 左右两边各自有一个判断条件, 如果两个条件都为假, 整个返回false, 如果有一个条件为真, 整个返回true

全假为假 一真为真

console.log(true || false); // true
console.log(1 < 2 || 2 > 3); // true || false true
console.log(1 > 2 || 2 > 3); // false || false false

!

!: 取反 返回的结果是true false

如果原来的是true 取反返回false 如果原来是false 取反就是true

js中为假: false 0 NaN '' null undefined

console.log(!''); // true
console.log(!1); // false
console.log(!{}); // false

短路运算

短路运算: 取值(两个值选择一个) 判断运算

逻辑与短路

逻辑与短路: 如果&&左边第一个条件为假, 第二个条件不执行 如果第一个为真 执行第二个条件

var a = 1, b = 1;
var c = --a && --b; // --a a = 0 0是假
console.log(c, a, b);


var m = 1, n = 1;
var d = m-- && n--; // 1 1是真 (m--: m =0)  1 && n-- n = 1 d = 1 n-1 = 0
console.log(d, m, n); // 1 0 0

逻辑或短路

逻辑或短路: 如果第一个条件为真, 第二个条件不执行 如果第第一个条件为假 执行第二个条件

var o = 1, p = 1;
var mn = o-- || p--; // o-- --在后 1 || p-- o=0  1 || p-- 1为真 p--不执行
console.log(mn, o, p); // 1 0 1

三目运算符

三目: 条件 ? 条件为真的时候执行的代码 : 条件为假的时候执行的代码;

代码只能有一句代码

1 > 2 ? alert('哇、1你牛了啊') : alert('还是2厉害');

运算优先级

获取元素

通过id获取

通过id: 通过id获取到的是单独的一个元素

语法: document.getElementById('id')

document: 文档

get: 获取

Element: 元素

ById: 通过id

var b = document.getElementById('box');
console.log(b);

通过标签获取

通过标签名: 获取到的是一个集合, 不可以直接做任何操作(添加事件、加样式)

语法: document/父元素.getElementsByTagName('标签名');

集合: 类数组, 有长度 有下标 但是不能使用数组的方法

长度: length

下标: 从左往右从0开始的数字

即使只有一个符合条件的元素, 当前拿到的也是集合

// 获取li
var lis = document.getElementsByTagName('li');
console.log(lis); // HTMLCollection(5) [li, li, li#box, li, li, box: li#box]
console.log(lis.length); // 5个
console.log(lis[0]); // 得到第一个li

// 获取ul
var uls = document.getElementsByTagName('ul');
console.log(uls); // HTMLCollection [ul]
console.log(uls[0]);

var ul = document.getElementsByTagName('ul')[0];
console.log(ul);

// 获取ul中的li
var lis1 = ul.getElementsByTagName('li');
console.log(lis1); // HTMLCollection(5) [li, li, li#box, li, li, box: li#box]

通过类名获取

通过类名: 获取到的是一个集合, 不可以直接做任何操作(添加事件、加样式)

语法: document/父元素.getElementsByClassName('classname');

集合: 类数组, 有长度 有下标 但是不能使用数组的方法

长度: length

下标: 从左往右从0开始的数字

即使只有一个符合条件的元素, 当前拿到的也是集合

ie8+

// 通过one获取元素
var ones = ul.getElementsByClassName('one');
console.log(ones);

鼠标事件

事件三部曲

事件三部曲:

\1. 找到谁 获取元素 获取到鼠标要操作的元素

\2. 加事件 元素.事件 = function (){

\3. 具体要做的操作

}

注意: 集合一定要通过下标获取到具体的元素之后 才能添加事件 否则没有效果

// 1. 获取 div
// 集合一定要通过下标获取到具体的元素之后 才能添加事件 否则没有效果
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 2. 加事件
div.onclick = function () {
    // 3. 具体要做的操作
    console.log('点击');
};

鼠标事件

\1. 单击: onclick

\2. 双击: ondblclick

\3. 划入: onmouseenter onmouseover

\4. 划出: onmouseleave onmouseout

\5. 按下: onmousedown

\6. 抬起: onmouseup

\7. 移动: onmousemove

\8. 右键菜单: oncontextmenu

// 1. 获取 div
// 集合一定要通过下标获取到具体的元素之后 才能添加事件 否则没有效果
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 2. 加事件
div.onclick = function () {
    // 3. 具体要做的操作
    console.log('点击');
};


div.ondblclick = function () {
    console.log('双击');
};

// 划入
div.onmouseenter = function () {
    console.log('enter');
};
div.onmouseover = function () {
    console.log('over');
};

// 划出
div.onmouseleave = function () {
    console.log('leave');
};
div.onmouseout = function () {
    console.log('out');
};

// 按下
div.onmousedown = function () {
    console.log('down');
};
div.onmouseup = function () {
    console.log('up');
};

// 移动
div.onmousemove = function () {
    console.log('move');
};

// 右键
div.oncontextmenu = function () {
    console.log('menu');
};

over与enter的区别

enter: 子元素不会触发父元素身上的事件

over: 子元素会触发父元素身上的事件

// 1. 获取元素
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 2. 加事件 元素.事件 = function(){}
div.onmouseenter = function () {
    console.log('enter');
};

div.onmouseover = function () {
    console.log('over');
};

操作元素内容

操作单标签内容

单标签中只有表单标签有元素的内容, 写在value上

操作表单元素的值:

获取: var 变量 = 元素.value;

设置: 元素.value = 值;

// 1. 获取输入框
var inp = document.getElementsByTagName('input')[0];
console.log(inp);

// 2. 获取:  var 变量 = 元素.value;
var txt = inp.value;
console.log(txt);

// 3. 设置: 元素.value = 值;
inp.value = '张三';

// 4. 操作下拉列表
// 通过select的value直接拿到当前选中值
var sel = document.getElementsByTagName('select')[0];
console.log(sel);
var city = sel.value;
console.log(city);
sel.value = '广州';

操作闭合标签内容

操作闭合标签内容:

获取: var 变量名 = 元素.innerHTML/innerText;

设置: 元素.innerHTML/innerText = 值;

innerHTML与innerText的特性:

\1. innerHTML可以识别标签

\2. innerText不可以识别标签

\3. 都是操作闭合标签, 后面的会覆盖前面的

基于原有内容基础上来设置: 元素.innerHTML/innerText = 原内容 + 新内容;

// 1. 获取div
var div = document.getElementsByTagName('div')[0];
console.log(div);

// 2. 获取内容
var txt = div.innerText;
console.log(txt);

var html = div.innerHTML;
console.log(html);


// 3. 设置内容
// div.innerText = '这是一个斜体标签';
// div.innerHTML = '这是一个斜体标签1111';

// 4. 基于原有内容基础上来设置 元素.innerHTML/innerText = 原内容 + 新内容;
div.innerText = txt + '这是斜体标签';
div.innerHTML = html + '这是斜体标签111';

操作属性

获取: var 变量名 = 元素.属性名;

设置: 元素.属性名 = 值;

所有的属性都可以用上述方式操作, 其中class例外, 由于class关键字, 不能直接使用, 使用className

// 1. 获取元素
var div = document.getElementsByTagName('div')[0];
console.log(div);

// 2. 获取
var id = div.id;
console.log(id);
console.log(div.title); // div
console.log(div.className); // one

// 3. 设置 元素.属性名 = 值;
div.id = 'wrap';

// 4. 在轮播图中 设置当前被选中
div.className = 'active';

// 获取img
var img = document.getElementsByTagName('img')[0];
console.log(img);
// 设置地址
img.src = './img/2.jpg';

操作样式

单个样式设置

只做设置不做获取

设置样式: 通过js都是行内样式

元素.style.属性名 = 值;

在js中, -连字符不能使用, 需要转成驼峰命名法

// 1. 获取div
var div = document.getElementsByTagName('div')[0];
console.log(div);

// 2. 设置样式
div.style.width = '200px';
div.style.height = '200px';
div.style.background = 'pink';
div.style.fontSize = '30px';

批量设置样式:

元素.style.cssText = '属性名: 属性值; 属性名: 属性值;';

cssText直接设置给style属性, 覆盖原来标签上的行内样式

div.style.cssText = 'width: 300px;height: 300px; background: skyblue; font-size: 50px;';

流程控制语句

分类

流程控制语句: 代码按照什么顺序执行的语句

顺序语句: 默认从上到下执行

条件语句(分支语句): 多条(2条以上)分支中选择 if if-else if-else-if switch

循环语句: for while do-while for-in

其他语句: break continue

分支语句

if

if: 判断代码是否执行

if(条件){

条件为真的时候执行的代码;

}

var core = prompt('请输入成绩');
console.log(core);
// 如果core大于60 弹出及格
// if(core > 60){
//     alert('及格');
// }

if-else

if-else:

if(条件){

条件为真的时候执行的代码;

} else {

条件为假的时候执行的代码;

}

// 如果core大于60 弹出及格 否则弹出继续努力
if(core > 60){
    alert('及格');
} else {
    alert('继续努力');
}

if-else-if

if-else-if: 用于多个条件

if(条件1){

条件1为真,执行的代码;

} else if(条件2){

条件2为真, 执行的代码;

} else if(条件3){

条件3为真, 执行的代码;

} else {

以上条件都不符合的时候,执行的代码;

}

if (core >= 80) {
    alert('A');
} else if (core >= 70 && core < 80) {
    alert('B');
} else if (core >= 60 && core < 70) {
    alert('C');
} else {
    alert('D');
}

switch

switch: 适用于条件和结果都单一的时候

条件: 判断某一个变量或者是某一个具体的值

结果: 指向的是具体的一个值 + - * / 100 60

break: 防止穿透, 如果不加, 当条件匹配到一个符合的结果后, 后续的结果都不匹配, 直接执行后面所有的代码;

switch(条件){
    case 结果1:
        当条件符合结果1执行的代码;
        break;
    case 结果2:
        当条件符合结果2执行的代码;
        break;
    case 结果3:
        当条件符合结果3执行的代码;
        break;
    default:
        以上结果都不符合的时候 执行的代码;
        break;
}
switch (str) {
    case '+':
        console.log(10 + 20);
        break;
    case '-':
        console.log(10 - 20);
        break;
    case '*': 
        console.log(10 * 20)
        break;
    case '/': 
        console.log(10 / 20);
        break;
    default: 
        console.log('超出运算范围了');
        break;
}

分支嵌套

两个及以上分支语句嵌套使用

// 弹出输入框 输入成绩 0-100
var core = prompt('请输入成绩');

// 判断成绩的可选范围
if(core >= 0 && core <= 100){
    if (core >= 80) {
        alert('A');
    } else if (core >= 70 && core < 80) {
        alert('B');
    } else if (core >= 60 && core < 70) {
        alert('C');
    } else {
        alert('D');
    }
} else {
    alert('请输入0-100之间的数字');
}

循环语句

for

语法

将一段代码重复执行多次(指定循环次数)

将一段代码执行指定的循环次数的过程

for(表达式1; 表达式2; 表达式3){

循环体;

}

for(初始化变量; 循环结束条件; 变量更新){

重复执行的代码块

}

初始化变量: var 变量 = 起始值; 数字 0 1 循环的次数从几开始的

循环结束的条件: 条件为真 循环执行 条件为假 循环结束

变量更新: 变量++ 变量--

循环结束的条件必须可用的 否则形成死循环

// 1--100
for(var i = 1; i <= 100; i++){
    console.log(i);
}

// 从50输出到0
for(var i = 50; i >= 0; i--){
    console.log(i);
}

// 循环结束的条件必须可用的 否则形成死循环
// for(var i = 5; i < 10; i--){
//     console.log(i);
// }

变异for

初始化变量;

for(;循环条件;){

循环体;

变量更新;

}

var j = 1;
for(;j<=5;){
    console.log(j);
    j++;
}

注意:

\1. 变异格式中两个分号不能省略

\2. 初始化的变量都是全局变量

\3. 循环执行完成后, 变量留在循环结束的数值

var j = 1;
for(;j<=5;){
    console.log(j);
    j++;
}

console.log(j); // 6

使用情况:

连续的数值

每一个

所有

渲染页面

数据一般都是通过数据请求的方式 由后台返回给我们

页面的数据一般都不是固定数据

数组、对象

多个数据的时候一般用数组

var 变量 = [值, 值1, 值2, ... 值n];

有长度有下标 通过下标的方式从数组中取出对应下标的值

取值: 数组[下标]

while

初始化变量;

while(条件){

循环体;

变量更新;

}

var i = 1;
while(i <= 5){
    console.log(i);
    i++;
}

do-while

初始化变量;

do{

循环体;

变量更新;

}whlie(循环条件);

var j = 1;
do{
    console.log(j, 'j');
    j++;
}while(j <= 5);

for和while

for: 明确循环次数 length 5 10 100

while: 不明确循环次数

while和do-while

while: 先判断后执行

do-while: 先执行后判断

其他语句

break: 防止穿透; 结束整个循环;

continue: 结束本次循环;

// 水饺: 20
for(var i = 1; i <= 20; i++){
    if(i == 5){
        // break; // 吃到虫子 1-4
        continue; // 掉到地上 1-4 6-20
    }
    console.log(i);
}

循环嵌套

for(外层初始化变量; 外层判断条件; 外层变量更新){

for(内层初始化变量; 内层判断条件; 内层变量更新){

内层循环体;

}

}

外层循环执行一次 内层循环执行一轮

// 行循环
for (var i = 1; i <= 5; i++) {
    // 列循环
    for (var j = 1; j <= 5; j++) {
        document.write('⭐️');
    }
    // 行结束之前添加换行
    document.write('
'); }

对象

对象: 用来存储无长度、无顺序的数据

一般用来做前后台交互

{键: 值, 键: 值} 键值对

键建议加引号, 不加引号可以使用

也叫做json格式的数据

取值: 对象.键 对象['键'/变量]

存值: 对象.键 = 值; 对象['键'/变量] = 值;

在js中 .相当于白勺的 .后面本身就是字符串 在整个js中都适用

var user = {
    'name': '杨洋',
    age: 33,
    'height': 188
};
console.log(user);

// 取值: 对象.键
console.log(user.name);
// console.log(user.'name'); // .后面不能直接加字符串
// 在js中 .相当于白勺的 .后面本身就是字符串 在整个js中都适用
// 取值: 对象['键'/变量]
console.log(user['name']);

var a = 'name';
console.log(user[a]);

// 存值: 对象.键 = 值; 对象['键'/变量] = 值;
user.girlFriend = '迪丽热巴';
user['gf1'] = '古力娜扎';

console.log(user);

for-in

for(var 变量 in 数据){

变量: 键

数据[变量]: 值

}

for(var key in user){
    console.log(key, user[key]);
}

// forin不仅仅可以遍历对象 也可以遍历数组、集合
var arr = ['a', 'b', 'c'];
for(var i in arr){
    console.log(i, arr[i]);
}

函数

概念

函数: 将具有独立功能的代码块整合命名的代码

作用: 减少页面代码 提高页面执行速度 页面结构更加清晰

使用:

\1. 事件处理函数: 元素.事件 = function(){}

function(){}--->函数

\2. 对象的方法:

var obj = {

abs: function(){} ---> 函数

}

\3. 封装复用

声明

函数: 由事件驱动的或者在有需要的时候被调用的代码块

注意: 函数只声明 没有任何效果

声明函数:

  1. 函数声明:

    1.1 函数:

    语法: function 函数名(){

    函数体;

    }

    1.2 调用函数:

    函数名();

    fn();
    function fn() {
        console.log(1);
    };
    // fn();
    // fn();
    // fn();
    // fn();
    // fn();
    
  2. 字面量声明:

    2.1 函数:

    语法: var 变量名 = function(){

    函数体;

    }

    2.2 调用函数:

    函数名();

    // fn1 is not a function: fn1不是一个函数
    // fn1();
    var fn1 = function () {
      console.log(2);
    };
    // fn1();
    

注意

函数名和变量名在这里是一样, 命名规范一致的

区别: 函数声明的方式调用可以在声明之前或者之后, 字面量声明的方式调用只能在声明之后;

参数

当遇到不确定的值, 就需要抽取成形参, 在调用的时候, 不同数据传进去

形参: 形式参数, 写在函数function后面的()里, 用来接收实际传递过来的数据

类似变量, 命名规范和变量一致

实参: 实际传递过来的数据, 写在函数调用的()里

arguments:存在于每一个函数中, 是实参的集合

一般形参和实参一一对应

单个参数

// 单个参数
function sum(a) {
    // 求和
    var s = 0;
    // 1 + 2 + 3 + 4 + ... + 100
    for(var i = 1; i <= a; i++){
        // s = s + i;
        s += i;
    }
    console.log(s);
};
// 调用
sum(100);
sum(1000);
sum(2000);

多个参数

多个参数: 用,隔开

// 50-80  90-100 1000-10000
// 多个参数: 用,隔开
function sum1(start, end) {
    // 求和
    var s = 0;
    // 1 + 2 + 3 + 4 + ... + 100
    for(var i = start; i <= end; i++){
        // s = s + i;
        s += i;
    }
    console.log(s);
};
sum1(1, 100);
sum1(50, 80);

arguments

如果参数个数不确定, 形参和实参干脆一个都不写, 直接使用arguments

arguments: 存在于每一个函数中, 是实参的集合

function sum2() {
    console.log(arguments);
    // 将arguments中的每个数据加起来
    var s = 0;
    for(var i = 0; i < arguments.length; i++){
        console.log(arguments[i]);
        s += arguments[i];
    }
    console.log(s);
}
sum2(3,4,5,6,7,8);
sum2(40,50,60);

形参和arguments的关系:

两者互相影响

function fn(a) {
    console.log(a, arguments);
    a = 50;
    console.log(a, arguments);
    arguments[0] = 100;
    console.log(a, arguments);

};
fn(30);

函数问题

  1. 形参实参不一一对应:

    形参 > 实参: 多余的形参就是undefined

    实参 > 形参: 多余的实参不能通过形参获取

    function fn(a, b) {
        console.log(a, b);
    };
    fn(10); // a = 10 b = undefined
    fn(10, 20, 30); // a = 10 b = 20
    
  2. 函数重名:

    函数名重名: 后面的覆盖前面的

    函数和变量名重名: 变量覆盖函数

    function a() {
        console.log('a');
    }
    function a() {
        console.log('a1');
    }
    
    a(); // a1
    
    
    var b = 30;
    function b() {
        console.log('b');
    }
    // b(); // b is not a function
    
  3. 函数封装

    \1. 声明空函数

    \2. 实现单个效果

    \3. 调用

    \4. 抽参

    \5. 传参: 把谁抽出来 把谁传进去

    function getOdd(a) {
        // 0--10
        for(var i = 0; i <= a; i++){
            // 偶数: 被2整除 取余等于0
            if(i % 2 == 0){
                console.log(i);
            }
        }
    }
    
    getOdd(10);
    getOdd(66);
    getOdd(100);
    

参数的数据类型

所有数据类型都可以做为参数

一般不用null和undefined作为参数

由于null好undefined不具有实际意义 所以一般不使用

function getType(a) {
    console.log(a, typeof a);
}
getType(10);
getType('中公');
getType(true);
getType(null);
getType(undefined);
var m = {a: 1};
getType(m);
getType([1,2,3,4]);

function fn() {
    console.log(1);
}
getType(fn);

作用域

作用: 读(获取)、写(设置)

域: 区域

作用域: 变量和函数被读写的区域

es5中 作用域通过函数来划分, 又叫做函数作用域

全局作用域: script标签下

全局变量、全局函数, 可以在整个js中被读写

局部作用域: function的{}里

在局部作用域中, 用var\function声明的变量和函数, 叫做局部变量、局部函数, 只在当前作用域起作用, 如果出了{} 会被销毁

// 全局作用域
var n = 10; // 全局变量
function fn() { // 全局函数
    // 局部作用域
    console.log(n); // 10
    var z = 1;
    console.log(z); // 1
}
fn();
console.log(z); // 报错

作用域链

作用域链: js的一种查找机制, 决定了变量和函数向上一级作用域查找的过程

查找过程: 先找自身作用域, 如果自身作用域有,直接返回, 如果自身没有,往上一级作用域查找, 直到到全局作用域,如果全局作用域也没有,报错: is not defined;

var n = 10; // 全局变量
function fn() {
    // 局部作用域
    var z = 20; // 局部变量
    console.log(n, z);  
}
fn();

变量提升

js在解析代码的时候, 不是按照单纯的从上到下的顺序来执行

至少会执行两步:

\1. 预解析: 找var、function, 将var声明的变量的声明提到最前, function声明的函数整个存储在内存中

\2. 逐行解析: 从上到下的顺序一行行执行代码

函数的形参在函数被调用的第一行代码优先执行, 形参接收实参, 执行函数体

函数每调用形成一个新的局部作用域, 代码的解析过程遵循预解析过程

var

console.log(a); // undefined
var a = 10;
/* 
    解析过程:
        var a;
        console.log(a);
        a = 10;
*/

function

// function
function sum() {
    console.log('函数1');
}
console.log(sum);

function sum() {
    console.log('函数2');
};
console.log(sum);
/* 
    解析过程: 
    function sum() {
        console.log('函数1');
    }
    function sum() {
        console.log('函数2');
    };
    console.log(sum); 函数2
    console.log(sum); 函数2
*/

var和function

// var function 函数声明 字面量声明的区别
var fn = 'abc';
function fn() {
    console.log(1);
}
console.log(fn);
/* 
    解析过程:
        var fn;
        function fn() {
            console.log(1);
        }
        fn = 'abc';
        console.log(fn); abc
*/

形参

// 传参
// 函数的形参在函数被调用的第一行代码优先执行, 形参接收实参, 执行函数体
// 函数每调用形成一个新的局部作用域, 代码的解析过程遵循预解析过程
function fun(a) {
    console.log(a);
    var a = 30;
    console.log(a);
};
fun(10);

/* 
    解析过程:
        function fun(a) {
            console.log(a);
            var a = 30;
            console.log(a);
            解析过程:
                var a;-->声明形参 
                var a;
                a = 10; ---> 接收实参
                console.log(a); // 10
                a = 30;
                console.log(a); // 30
        };
        fun(10);
*/

函数返回值

函数在执行的时候 就像一个小黑屋 里面的数据不能直接出来 如果想要出来需要越狱

函数的返回值: 每个函数执行后都会有返回值, 默认返回值 undefined

就是函数调用的结果

接收函数的返回值: var 变量 = 函数();

想要将函数内的数据 在函数外能使用 需要将函数内的数据设置成返回值返回回来

设置函数的返回值:

函数最后: return value;

接收返回值

function a() {
    console.log(1);
}
var b = a();
console.log(b);

设置返回值

// 设置返回值
function fn() {
    var mn = 20;
    return mn;
}
var q = fn();
console.log(q);

return作用

设置函数的返回值: 函数最后: return value;

return: 结束函数 return后面的代码不执行

function fn1() {
    console.log(1);
    return 'abc';
    // 不执行
    console.log(2);
}
var m = fn1();
console.log(m); // 'abc'

返回多个

return设置返回值的时候 一次只能返回一个数据 如果用,返回多个, 只会返回最后一个;

如果想要返回多个数据, 建议 数组 或者 对象, 更推荐用对象

function fn2() {
    // return 10, 20, 30;
    // return [10, 20, 30];
    return {
        a: 10,
        b: 20,
        c: 30
    };
}
var mn = fn2();
console.log(mn);

使用情况:

\1. 封装函数 函数的最后去到的是一个数据

\2. 操作的对象 返回回来

\3. 函数内的数据 要在 函数外面用到的时候

返回值数据类型

返回值的数据类型可以是一切数据类型

function rType() {
    return function () {
        console.log(90);
    };
    return {a: 1, b:2};
    return [1,2,3,4];
    return null;
    return true;
    return 30;
    return 'abc';
}
var a = rType();
console.log(a);

封装步骤

\1. 实现单个效果

\2. 声明空函数

\3. 单个效果放在空函数里

\4. 调用

\5. 分析不确定的项, 抽取参数

\6. 传参

\7. 设置返回值

\8. 接收返回值

function getMax(data) {
    // 1. 假设最大值
    var max = data[0];
    // 2. 用这个值和数组的每一个值进行比较
    for (var i = 1; i < data.length; i++) {
        // 如果比假设值大
        if (max < data[i]) {
            max = data[i];
        }
    }
    // console.log(max);
    return max;
}
var m = getMax(arr);
console.log(m);

获取元素样式

基础获取

标准浏览器(ie9, chrome, ff):

getComputedStyle(元素).属性名

ie(ie8及以下):

元素.currentStyle.属性名

// 获取div
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 获取样式:
// 标准:
// var w = getComputedStyle(div).width;
// console.log(w);

// var h = getComputedStyle(div).height;
// console.log(h);

console.log(getComputedStyle); // 标准: 函数  ie: undefined
console.log(div.currentStyle); // 标准: undefined ie: 对象
// ie:
// Cannot read properties of undefined (reading 'width'): 
// var w = div.currentStyle.width;
// console.log(w);

兼容

getComputedStyle: 函数 currentStyle: 对象

处理兼容: 一个函数 一个是对象/属性 可以用函数是否存在来做判断

如果函数 xx() 来做调用的话 判断的时候 window.xx 是否存在来做判断

console.log(window.getComputedStyle);
if(window.getComputedStyle){
    // 标准
    var w = getComputedStyle(div).width;
} else {
    // ie
    var w = div.currentStyle.width;
}
console.log(w);

封装

function getStyle(ele, attr) {
    // ele: 元素
    // attr: 属性
    if (window.getComputedStyle) {
        // 标准
        var w = getComputedStyle(ele)[attr];
    } else {
        var w = ele.currentStyle[attr];
    }
    // console.log(w);
    return w;
}

使用



this

概念

this: 指代词, 在不同的位置有不同的含义

全局: window

普通函数: window

对象的方法: 当前对象

事件处理函数: 触发源 点谁就指向谁

console.log(this); // window
function fn() {
    console.log(this);
}
fn();

var obj = {
    abs: function () {
        console.log(this);
    }
};
console.log(obj.abs);
obj.abs();

lis[0].onclick = function () {
    console.log(this);
}

使用

在for循环所嵌套的事件中, 得不到正确的对象的时候 用this来指代

// 点击每一个li 输出当前li的内容
// 1. 获取元素
var lis = document.getElementsByTagName('li');
console.log(lis);
// 2. 每一个
for(var i = 0; i < lis.length; i++){
    // 3. 加事件
    lis[i].onclick = function () {
        console.log(this); // 用this指代当前的触发源
        console.log(this.innerHTML);
    };
}

排他

排他: 除了自己有特定效果之外 其他的都是默认样式

实现过程: 1. 所有元素都设置成默认样式

\2. 指定元素添加特定效果

// 1. 获取元素
var lis = document.getElementsByTagName('li');
console.log(lis);
// 2. 每一个
for(var i = 0; i < lis.length; i++){
    // 3. 加事件
    lis[i].onclick = function () {
        // 先去清除所有的li的字体颜色
        for(var j = 0; j < lis.length; j++){
            lis[j].className = '';
        }

        // 4. 让当前的li的颜色变成黑色
        // 找到当前li
        console.log(this);
        this.className = 'active';
    }
}

注意

一般假定初始状态的时候 不会写太复杂的值 一般一个数字、或者 布尔值

假设内容 随意指定

// 获取元素
var img = document.getElementsByTagName('img')[0];
console.log(img);

// 不知道灯是什么状态 可以假设初始状态
// 一般假定初始状态的时候 不会写太复杂的值 一般一个数字、或者 布尔值
// 1--黑 2--亮  true--亮 false--黑
var tag = 'dark'; // 假设内容 随意指定  dark--黑 light--亮

// 点击
img.onclick = function () {
    console.log(this.src); // file:///Users/fushuangyu/Desktop/offcn/0712/day05/images/dark.jpg
    if(tag == 'dark'){
        // 灯是黑的 变亮
        img.src = './images/bright.jpg';
        // 更新状态
        tag = 'light';
    } else {
        img.src = './images/dark.jpg';
        tag = 'dark';
    }
};

自定义属性

属性: 写在起始标签上的 除了标签以外的 都是属性

固有属性: 规定好作用的 class id alt src...

自定义属性: 由程序员自己去设定的属性 tag

操作属性:

\1. 获取属性的值:

var 变量 = 元素.属性;

var 变量 = 元素[属性];

\2. 设置属性的值:

元素.属性名 = 值;

元素[属性名] = 值;

直接写在html页面中的自定义属性通过上述两种方式不能获取

通过js设置给元素的自定义属性,在页面中看不到, 但是在js中可以正常操作

多个元素之间的同名的属性 互相不影响

// 1. 获取属性值
console.log(div.id);
console.log(div.tag); // undefined

// 2. 设置属性
div.t = 'abc123';

console.log(div.t); // abc123


var img = document.getElementsByTagName('img')[0];
img.t = '987654321';

// 多个元素之间的同名的属性 互相不影响
console.log(div.t, img.t);

自定义索引

在自定义属性中 存储下标 的行为 就是自定义索引

// 2. 每一个
for(var i = 0; i < btns.length; i++){

    // 存储自定义索引
    btns[i].index = i;


    // 3. 加事件
    btns[i].onclick = function () {
        // 获取到对应的颜色
        // 颜色和按钮的关系: 5个 
        // 按钮和颜色: 一一对应  下标是一致
        // 获取当前按钮的下标 ---> 当前按钮的index属性的值
        // console.log(i);
        console.log(this.index);
        // 通过下标获取对应的arr中的颜色
        console.log(arr[this.index]);

        // 颜色设置给body  快速获取页面body的方式: document.body
        // console.log(document.body);
        document.body.style.background = arr[this.index];

    };
}

定时器

概念

定时器: 让一段代码等待一段时间或者每隔一段时间就执行一次的代码就是定时器

分类

延迟定时器

延迟: 让一段代码等待一段时间 setTimeout(函数, 时间); 时间单位: ms

等待 只执行一次的效果 使用延迟定时器

效果: 一次性广告 关不掉的广告

/* 
    打开页面 等待3s后 显示img
*/
var img = document.getElementsByTagName('img')[0];
// 等待 只执行一次的效果 使用延迟定时器
setTimeout(auto, 3000);

function auto(){
    img.style.display = 'block';
}

间隔定时器

间隔: 每隔一段时间执行一次 setInterval(函数, 时间); 时间单位: ms

每隔 间隔 不间断重复的效果

效果: 计时器 倒计时 轮播图

1s = 1000ms

var n = 0;
// 每隔一秒 让n自加1 输出
// 每隔  间隔  不间断重复的效果
setInterval(function () {
    n++;
    console.log(n);
}, 1000);

清除定时器

定时器一旦开启 不会自动清除 会造成内存泄漏

需要手动清除定时器

间隔: setInterval clearInterval(唯一标识)

延迟: setTimeout clearTimeout(唯一标识)

唯一标识 开启定时器后的返回值就是定时器的唯一标识

接收唯一标识:var 变量 = setTimeout/setInterval();

var n = 5;
var timer = setInterval(function () {
    n--;
    // 如果n等于0  清除定时器
    if(n == 0){
        clearInterval(timer);
    }
    console.log('这是间隔定时器', n);
}, 1000);
console.log(timer, 'timer');

注意

一般封装定时器的时候 是将定时器的函数抽取成普通的函数

当遇到会频繁开启定时器的时候 先清除定时器

对象

对象: 在js中 万物皆对象 一切皆对象 分为: 本地 内置 自定义 宿主 全局

本地(内部): Number String Boolean Object Array Function RegExp Date Error

内置: 在页面加载完成后 已经实例化的对象 Global Math

宿主: DOM BOM

全局: window

api: application programming Interface 应用程序编程接口

已经封装好的可以直接使用的函数 直接调用实现功能

Math

console.log(Math); // 数学对象

console.log(Math.PI); // π

console.log(Math.floor(3.99999)); // 向下取整
console.log(Math.ceil(3.000001)); // 向上取整
console.log(Math.round(4.50001)); // 四舍五入
console.log(Math.round(4.499999)); // 四舍五入

console.log(Math.max(20, 32, 12, 43, 12, 43, 435, 43)); // 求最大值
console.log(Math.min(20, 32, 12, 43, 12, 43, 435, 43)); // 求最小值

console.log(Math.pow(2, 10)); // 幂次方  
console.log(Math.sqrt(4)); // 开根号
console.log(Math.abs(-1000)); // 绝对值

// 求随机数:
/* 
    Math.random()   0-1的随机数
    Math.random() * 数   0-数之间的随机数  不包含数
    Math.random() * (y - x) + x  x-y之间的随机数 不包含y  y > x
*/
for(var i = 0; i < 5; i++){
    // console.log(Math.random());
    // console.log(Math.random() * 10);
    console.log(Math.random() * (50 - 30) + 30);

}

Date

创建时间

创建当前时间

var date = new Date();
console.log(date);
console.log(typeof date); // object

创建其他时间

1.2.1 用 , 直接分割 月份: 0-11 表示 1-12 月

1.2.2 传 字符串 年月日中间可以用任意特殊英文符号进行分割 空格 , / $ 时分秒 用 时:分: 秒

// 1.2.1 用 , 直接分割   月份: 0-11 表示 1-12 月
var d1 = new Date(2021, 9, 1);
var d1 = new Date(2021, 9, 1, 13, 13, 13);
console.log(d1);

// 1.2.2 传 字符串 年月日中间可以用任意特殊英文符号进行分割 空格 , / $  时分秒 用 时:分: 秒
// 字符串 月份不减
var d2  = new Date('2021, 10, 1');
var d2  = new Date('2021, 10, 1 23:23:23');
var d2  = new Date('2021 10 1 23:23:23');
var d2  = new Date('2021/10/2 23:23:23');
var d2  = new Date('2021-10-3 23:23:23');
var d2  = new Date('2021_10_3 23:23:23'); // Invalid Date 不可用的时间 _中文符号
console.log(d2);

获取特定格式的时间

var dd = new Date();
console.log(dd);
console.log(dd.toString(), typeof dd.toString()); // 字符串
console.log(dd.toLocaleString()); // 本地字符串日期  2021/9/22 上午11:35:10
console.log(dd.toLocaleDateString()); // 年月日 2021/9/22
console.log(dd.toLocaleTimeString()); // 时分秒 12小时 上午11:36:30

获取单个时间

var dd = new Date();
console.log(dd);

// 获取单个时间
var y = dd.getFullYear();
console.log(y); // 2021
console.log(dd.getMonth()); // 月 0-11表示1-12月
console.log(dd.getDate()); // 日期
console.log(dd.getDay()); // 星期  0-6表示周日到周六 3


var w = dd.getDay();
var week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六' ];
console.log(week[w]);

console.log(dd.getHours()); // 小时 11
console.log(dd.getMinutes()); // 分钟
console.log(dd.getSeconds()); // 秒

// 毫秒: 时间戳 距离1970-1-1
console.log(dd.getTime());

moment

moment.js: 专门处理日期的js插件库

\1. 下载 Moment.js 中文网

\2. moment.js : 格式文档 学习

moment.min.js : 压缩文档 工作

YYYY: 年

MM: 月

DD: 日期

d: 星期

HH: 时

mm: 分

ss: 秒

X: 所有的秒 距离1970-1-1的毫秒/1000

前导0 自动添加

// 创建moment时间对象
var dd = moment();
console.log(dd);

// format: 格式日期
/* 
    YYYY: 年
    MM: 月
    DD: 日期
    d: 星期
    HH: 时
    mm: 分
    ss: 秒
    X: 所有的秒 距离1970-1-1的毫秒/1000

    前导0 自动添加
*/
console.log(dd.format('YYYY'));
console.log(dd.format('MM'));
console.log(dd.format('DD'));
console.log(dd.format('d'));
console.log(dd.format('HH'));
console.log(dd.format('mm'));
console.log(dd.format('ss'));
console.log(dd.format('X'));

// 在页面中显示当前是 xxxx年xx月xx日 星期x x:x:x
document.body.innerHTML = dd.format('YYYY年MM月DD日 星期d HH:mm:ss');
// 每隔1s自动更新一次
setInterval(function () {
    var dd = moment();
    console.log(dd);
    document.body.innerHTML = dd.format('YYYY年MM月DD日 星期d HH:mm:ss');
}, 1000);

string

创建

字面量声明

包装类对象 不是真正的对象

var str = '12345a';

new关键字创建

var str1 = new String('asddhj');
console.log(str1);
console.log(typeof str1); // object

长度

console.log(str1.length); // 长度

查找

charAt

charAt: 指定下标对应的字符

var str = 'qwertyuiop';
console.log(str.charAt(2));

charCodeAt

charCodeAt: 指定下标对应的字符的ASCII码

console.log(str.charCodeAt(2));

indexOf

indexOf: 查找指定的字符在字符串中出现的位置 如果有返回下标 如果没有返回-1

惰性查找: 找到一个符合条件的 就会直接返回

语法: 字符串.indexOf(要找的字符[, 起始下标])

不传起始下标: 默认从第一个字符开始查找

起始下标: 表示从起始下标的位置上开始往后进行查找

var str = '012345678900123456123451234123';
console.log(str);
// 1是否在字符串str中出现
console.log(str.indexOf('1'));
console.log(str.indexOf('1', 2));
console.log(str.indexOf('1', 13));
console.log(str.indexOf('a')); // -1

lastIndexOf

lastIndexOf: 查找指定的字符在字符串中最后出现的位置 如果有返回下标 如果没有返回-1

从右往左查找

语法: 字符串.lastIndexOf(要找的字符[, 起始下标])

console.log(str.lastIndexOf('1'));
console.log(str.lastIndexOf('1', 26));
console.log(str.lastIndexOf('a'));

截取

substring

语法: 字符串.substring([起始下标], [结束下标]);

不传参: 返回整个字符串

传一个参数: 从起始下标开始 截取到 字符串的末尾 截止

传2个参数:

起始下标 < 结束下标: 从起始下标开始 截取到结束下标为止 包含起始下标对应的字符 不包含结束下标对应的字符

结束下标 < 起始下标: 互换位置 在参考上述规则

出现负数: 会把负数变成 0 参考上述规则

var str = 'abcdefghijklmn';
console.log(str.substring()); // abcdefghijklmn
console.log(str.substring(2)); // cdefghijklmn
console.log(str.substring(3, 5)); // de
console.log(str.substring(5, 3)); // de
console.log(str.substring(5, -1)); // 0---5  abcde

slice:

语法: 字符串.slice([起始下标], [结束下标]);

不传参: 返回整个字符串

传一个参数: 从起始下标开始 截取到 字符串的末尾 截止

传2个参数:

起始下标 < 结束下标: 从起始下标开始 截取到结束下标为止 包含起始下标对应的字符 不包含结束下标对应的字符

结束下标 < 起始下标: 返回空字符串

负数: 长度 + 负数 之后得到的结果 在参考上述规则

简单: 从右往左有几位不要

console.log(str.slice()); // abcdefghijklmn
console.log(str.slice(2)); // cdefghijklmn
console.log(str.slice(3, 5)); // de
console.log(str.slice(5, 3)); // 
console.log(str.slice(3, -1)); // defghijklm
console.log(str.slice(-10, -1)); // efghijklm

substr:

语法: 字符串.slice([起始下标], [截取长度]);

不传参: 返回整个字符串

传一个参数: 从起始下标开始 截取到 字符串的末尾 截止

console.log(str.substr());// abcdefghijklmn
console.log(str.substr(2)); // cdefghijklmn
console.log(str.substr(2, 5)); // cdefg

replace

语法: 字符串.replace(要被替换的字符/正则, 被替换的新字符/函数);

一次性只能替换一个位置上的字符, 返回新字符串

var str = 'today is Wednesday';
// s-->*
console.log(str.replace('s', '*'));

split:

作用: 将字符串按照指定的分割符进行分割 返回数组

分割符可以是一切字符 空、空格、标签

语法: 字符串.split('分割符');

var  str = 'you are a beautiful girl';
console.log(str);
console.log(str.split('a'));
// 每一个字符做一个数组的项
console.log(str.split(''));
console.log(str.split()); // 整个字符串是数组的一项

转大小写:

转大写: 字符串.toUpperCase()

转小写: 字符串.toLowerCase()

var str = 'aSaSas';
var str1 = 'AsAsas';
console.log(str.toUpperCase());
console.log(str.toLowerCase());

不区分大小写: 将判断的字符都转成小写的或者都转成大写的之后再做判断

console.log(str.toLowerCase() == str1.toLowerCase());

trim

trim: 去除字符串左右空格

var str = '        (you are a girl)       ';
console.log(str);
console.log(str.trim());

数组

数组: 用来存储不定数量不定类型的数据的容器;

创建数组

  1. 字面量创建

  2. new关键字创建

// 1. 字面量创建
var arr = [12, 43, 64];
console.log(arr);
console.log(typeof arr); // object

// 2. new关键字创建
// var 变量 = new Array(...data);
// 注意: 当参数只有一个且是数字, 表示数组的长度
var arr1 = new Array(1, 2, 3, 4);
console.log(arr1);

var arr2 = new Array(7);
console.log(arr2);
console.log(arr2[0]);

length

获取数组长度 数组.length

console.log(arr2.length);

设置数组长度 数组.length = 值; 长度加长 填充undefined 长度减小 多余的项会被删除 永远都找不到

var arr3 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr3.length); // 9
arr3.length = 4;
console.log(arr3);
arr3.length = 100;
console.log(arr3);

为什么要划分成基础数据类型和复杂数据类型:

基础: 数据比较单一, 声明和存储都在栈

复杂: 数据比较复杂, 声明和地址存储在栈, 具体数据存储在堆

深浅拷贝

深浅出现在引用数据类型

浅拷贝: 地址的赋值

var arr = [1,2,3,4,5];
console.log(arr);
var brr = arr;
console.log(brr);

判断引用数据类型是否是同一个地址的数据 用 == 判断

console.log(arr == brr); // true

深拷贝: 在堆中在划一块, 重新存储对应位置的每一个数据

var crr = [];
// 将arr的每一个数据 存到 crr中   对应位置: 下标一致
for(var i = 0; i < arr.length; i++){
    crr[i] = arr[i];
}
console.log(crr);
console.log(crr == arr); // false

添加删除

数组的方法大部分都是在原来数组上进行直接操作, 会改变原数组

栈方法:

push: 在数组的末尾添加一项或者多项, 返回添加数据后的数组的新长度

数组.push(...data);

pop: 在数组的末尾删除一项, 返回被删除的项

数组.pop();

unshift: 在数组的首位添加一项或者多项, 返回添加数据后的数组的新长度

数组.unshift(...data);

shift: 在数组的首位删除一项, 返回被删除的项

数组.shift();

// push
var arr = [1, 2, 3, 4];
var a = arr.push('a', 'b', 'c');
console.log(arr, a);

// pop
var b = arr.pop();
console.log(arr, b);

// unshift:
var c = arr.unshift('小乔', '大乔', '周瑜');
console.log(arr, c);

// shift
var d = arr.shift();
console.log(arr, d);

splice

splice: 增删改, 返回被删除的项组成的新数组

语法: 数组.splice(起始下标, 删除的个数, [....data]);

增:

数组.splice(起始下标, 删除个数, ...data);

删除:

数组.splice(起始下标, 删除个数);

替换:

数组.splice(起始下标, 删除个数, ...data);

var arr = ['小乔', '大乔', '貂蝉', '王昭君', '西施'];
// 小乔后面添加 周瑜
var a = arr.splice(1, 0, '周瑜');
console.log(arr); // ['小乔', '周瑜', '大乔', '貂蝉', '王昭君', '西施']
console.log(a, 'a----');
// 貂蝉 删除
var b = arr.splice(3, 1);
console.log(arr); // ['小乔', '周瑜', '大乔', '王昭君', '西施']
console.log(b, 'b----');
// 替换
var c = arr.splice(3, 2, '潘金莲', '西门庆');
console.log(arr);
console.log(c, 'c----');

数组方法

concat

concat: 拼接数组和项, 返回新数组

数组.concat(...data);

var arr = [1, 2, 3];
var brr = [6, 7, 8];
var crr = arr.concat(4, 5, brr);
console.log(arr, brr);
console.log(crr); // [1, 2, 3, 4, 5, 6, 7, 8]

slice

slice: 截取 用法与字符串一模一样, 返回截取出来的新数组

数组.slice([起始下标], [结束下标]);

console.log(crr.slice()); // [1, 2, 3, 4, 5, 6, 7, 8]
console.log(crr.slice(2)); // [3, 4, 5, 6, 7, 8]
console.log(crr.slice(2, 5)); // [3, 4, 5]

reverse

reverse: 数组翻转, 改变原数组, 具有返回值, 返回翻转以后的数组

数组.reverse();

var arr = [1, 2, 3, 4];
var a = arr.reverse();
console.log(arr, a);

join

join: 将数组按照拼接符连接起来, 返回字符串

数组.join(连接符)

连接符可以是一切字符, 默认以,作为连接符

var arr = ['小乔', '吕布', '貂蝉'];
console.log(arr.join('和')); // 小乔和吕布和貂蝉
console.log(arr.join('+++')); // 小乔+++吕布+++貂蝉
console.log(arr.join()); // 小乔,吕布,貂蝉
console.log(arr.join('')); // 小乔吕布貂蝉

indexOf/lastIndexOf

indexOf/lastIndexOf: 查找对应的项在数组中出现的位置,如果有返回下标,如果没有返回-1

与字符串一致

注意: 查找的项必须和数组的项 全等 才能被找到

var arr = [1, '1', 2];
console.log(arr.indexOf('1')); // 1
console.log(arr.indexOf(1)); // 0

sort

数组.sort([函数]); 默认按照字符串的排序规则进行排序

有2个形参(假设叫a, b):

return a - b; 从小到大

return b - a; 从大到小

var arr = [4, 2, 4, 1, 3, 31, 4, 15, 81, 11];
arr.sort();
console.log(arr);

console.log(arr.sort);

arr.sort(function (a, b) {
    console.log(a, b); // 相邻的两项
    // return a - b; // 从小到大
    return b - a; // 从大到小
});
console.log(arr);

中文比较

localeCompare: 比较字符是否在另一个字符之前或者之后

字符a.localeCompare(字符b);

字符a 在 字符b 之前 返回 -1

字符a 和 字符b 完全一致 返回 0

字符a 在 字符b 之后 返回 1

var a = '张三';
var b = '李四';
console.log(b.localeCompare(a));
console.log(a.localeCompare(b));
console.log(a.localeCompare(a));

// 用姓名升序排序 a---z
arr.sort(function (x, y) {
    console.log(x.name, y.name);
    return x.name.localeCompare(y.name);
});
console.log(arr);

迭代方法

迭代: every some filter map forEach

every

every: 对数组的每一个项做一些判断, 根据函数的返回值, 如果每个项执行函数的返回值都是true, 返回true. 如果有一个是false 返回false

全真为真 一假为假

语法: 数组.every(函数);

函数有3个形参: 项 下标 原数组

var arr = ['a', 'b', 'c', 'd'];
var res = arr.every(function (v, i, a) {
    console.log(i, v, a);
    // return true;
    return 0;
});
console.log(res);

some

some: 对数组的每一个项做一些判断, 根据函数的返回值, 如果每个项执行函数的返回值都是false, 返回false. 如果有一个是true 返回true

全假为假 一真为真

语法: 数组.some(函数);

函数有3个形参: 项 下标 原数组

var res1 = arr.some(function (v, i, a) {
    console.log(i, v, a);
    // return true;
    return undefined;
});
console.log(res1);

filter

filter: 对数组中的做一些过滤, 会将符合条件的(函数的返回值是true)项组成一个新数组返回;

语法: 数组.filter(函数);

函数有3个形参: 项 下标 原数组

常使用: 数据筛选过滤

var arr = ['a', 'b', 'c', 'd'];
var res2 = arr.filter(function (v, i, a) {
    console.log(i, v, a);
    return i > 1;
});
console.log(res2);

map

map\forEach: for循环

map: for循环 将每个函数的返回值组成新数组返回 造成内存浪费

forEach: 纯粹的for循环 没有返回值

数组.map/forEach(函数);

var res3 = arr.map(function (v, i, a) {
    // console.log(i, v, a);
    return v + '1';
});
console.log(res3);

forEach

map\forEach: for循环

map: for循环 将每个函数的返回值组成新数组返回 造成内存浪费

forEach: 纯粹的for循环 没有返回值

数组.map/forEach(函数);

var res4 = arr.forEach(function (v, i, a) {
    console.log(i, v, a);
    return v + '1';
});
console.log(res4);

正则

正则: 用规定好的具有特定含义的字符组成的规则字符串, 用来实现字符串的检索和替换.

创建正则

new关键字创建:

语法: var 变量 = new RegExp(规则字符串, 修饰符);

var reg = new RegExp('web', 'ig');
console.log(reg); // /web/gi
console.log(typeof reg); // object

字面量声明

语法: var 变量 = /规则字符串/修饰符;

var reg1 = /web/ig;
console.log(reg1); // /web/gi

修饰符

没有顺序

i: ignore case 忽略大小写

g: global 全局

检索方法

replace

字符串.replace(要替换的字符/正则, 新字符/函数);

函数的返回值就是替换的新字符

函数有一个形参: 每次匹配到的结果

var str = 'web01web02web03Web04WEB05';
console.log(str);

// web-->***
var reg = /web/gi;
console.log(str.replace(reg, '***'));
console.log(str.replace(reg, function (a) {
    console.log(a);
    return 'aaa';
}));

split

字符串.split(分割符/正则);

var str = 'web0web1web2web0web1';
console.log(str.split('0'));
var reg = /\d/; // 数字\d
console.log(str.split(reg));

search

search: 替换indexOf 使用正则做查找 返回找到的符合正则的第一个位置上的下标

惰性查找

var str = 'web0web1web2web0web1';
var reg = /\d/;
console.log(str.search(reg));

match

字符串.match(正则);

返回一个数组

单个匹配结果: ['web', index: 0, input: 'web0web1web2web0web1', groups: undefined]

多个匹配结果: ['0', '1', '2', '0', '1']

var str = 'web0web1web2web0web1';
var reg = /\d/;
var reg = /\d/ig;
console.log(str.match(reg));

exec

exec: 正则.exec(字符串);

返回值与match的单个返回结果一致

如果有返回数组 如果没有 返回null

惰性查找, 一次只找一个, 如果加了g 会从上一次找到的位置开始找 不加g 每次都从下标0开始找

正则.lastIndex: 返回下一次正则匹配开始的位置

var str = 'webstrweb0123';
var reg = /web/;
console.log(reg.exec(str));

var reg = /web/g;
console.log(reg.lastIndex); // 0
console.log(reg.exec(str));
console.log(reg.lastIndex); // 3
console.log(reg.exec(str));
console.log(reg.lastIndex); // 9
console.log(reg.exec(str)); // null
console.log(reg.lastIndex); // 0
console.log(reg.exec(str));

test

test: 正则.test(字符串);

判断字符串是否有符合正则的字符 如果有 返回true 如果没有 返回false

惰性查找, 一次只找一个, 如果加了g 会从上一次找到的位置开始找 不加g 每次都从下标0开始找

var reg = /web/;
var str = 'web0web1web2';
console.log(reg.lastIndex); // 0
console.log(reg.test(str));
console.log(reg.lastIndex); // 0
console.log(reg.test(str));

var reg = /web/g;
console.log(reg.lastIndex); // 0
console.log(reg.test(str));
console.log(reg.lastIndex); // 3
console.log(reg.test(str));
console.log(reg.lastIndex); // 7
console.log(reg.test(str));
console.log(reg.lastIndex); // 11
console.log(reg.test(str)); // false
console.log(reg.lastIndex); // 0
console.log(reg.test(str));

元字符

一个元字符可以表示一类字符

一个元字符做匹配只能匹配一个字符

.

// 1. . 点: 除换行以外的任意字符
var str = '\n这是一个换行句子\n';
console.log(str);
var reg = /./;
console.log(reg.exec(str));

[] [^]

// 3. []: 字符集 匹配[]里的任意一个字符 [^]: 非字符集 不匹配[^]中的任意一个字符
var str = 'abc123';
var reg = /[1234567890]/;
var reg1 = /[^1234567890]/;
console.log(reg.exec(str), reg1.exec(str)); // 1 a
// 0-9表示:0123456789
// a-z表示: 小写a到小写z之间的所有的字母
// A-Z表示: 大写a到大写Z之间的所有的字母
var reg = /[0-9a-zA-Z]/;
var str = '.!@##$$a1';
console.log(reg.exec(str));

\d \D

// 2. \d:匹配数字 \D:匹配非数字
var str = 'str123';
var reg = /\d/;
var reg1 = /\D/;
console.log(reg.exec(str), reg1.exec(str));

\w \W

// 4. \w: 匹配数字、字母、_中的任意一个  \W: 不匹配数字、字母、_中的任意一个
var str = '!@##$_123qwe';
var reg = /\w/;
var reg1 = /\W/;
console.log(reg.exec(str), reg1.exec(str)); // _   !

\s \S

// 5. \s: 匹配空格  \S: 不匹配空格
var str = 'you are a beautiful girl';
var reg = /\s/;
var reg1 = /\S/;
console.log(reg.exec(str), reg1.exec(str)); // 空格 y

\b \B

// 6. \b: 匹配单词边界  \B: 匹配非单词边界
// 一个字母有2个边界
var str = 'you are a beautiful girl';
var reg = /\ba\b/;
var reg1 = /\ba\B/;
var reg2 = /\Ba\B/;
console.log(reg.exec(str), reg1.exec(str), reg2.exec(str)); // a are beautiful

^ $

// 7. ^a: 开头 以a为开头的a   a$: 以a为结尾的a
// 一起用: 有具体的长度 6-18位 规律性: 银行卡密码  手机号  身份证号
var str = 'we are web0712';
var reg = /^w/;
var reg1 = /\d$/;
console.log(reg.exec(str), reg1.exec(str));


// 银行卡密码正则:
// 6位
var reg = /^\d\d\d\d\d\d$/;
var str = '123456';
console.log(reg.test(str));

量词

a? : 匹配0个或者1个a 只匹配字符串的第一项

var str = 'str123';
var reg = /\d?/;
var reg = /[a-z]?/;
console.log(reg.exec(str));

*

a* : 匹配0个或者 连续 多个a 尽可能多的做匹配 只匹配字符串的第一项

var str = 'wertyuiodfghjk23456789sdfghj44567';
var reg = /\d*/;
var reg = /[a-z]*/;
console.log(reg.exec(str));

+

a+ : 匹配连续多个a 至少匹配1个 尽可能多的做匹配

var str = 'wertyuiodfghjk23456789sdfghj44567';
var reg = /\d+/;
var reg = /[a-z]+/;
console.log(reg.exec(str));

{m,n}

a{m,n} : 匹配至少m次最多n次的a 尽可能多的做匹配

a{m,} : 匹配至少m次

a{n} : 只匹配n次

,后面绝对不能加空格

var str = 'wtyuiosghjkxcvbnmsdxcvb';
var reg = /[a-z]{5,10}/;
console.log(reg.exec(str)); // wtyuiosghj
var reg = /[a-z]{1,}/;
console.log(reg.exec(str)); // wtyuiosghjkxcvbnmsdxcvb
var reg = /[a-z]{10}/;
console.log(reg.exec(str)); // wtyuiosghj

或和分组

|

|: 或 匹配|左边或者右边

var reg = /web1|web2/;
var str = 'web0712web1web2';
console.log(reg.exec(str)); // web1

()

(): 和 提高匹配的层级

()匹配到的结果可以通过其他属性得到 $1$2:获取第几个()匹配到的结果 RegExp.$1

var reg = /web(1|2)/;
var str = 'web2web0712web1';
console.log(reg.exec(str)); // web2  ['web2', '2', index: 0, input: 'web2web0712web1', groups: undefined]
console.log(RegExp.$1);


// 手机号的加密: 13322221111   133****1111
// 写正则分成3
var reg = /^(1[3-9]\d)(\d{4})(\d{4})$/;
var str = '13322221111';
console.log(reg.exec(str));
// 替换 $1  $3 第一个小括号和第三个小括号匹配到的结果
console.log(str.replace(reg, '$1****$3'));

特殊

(?:) : 非获取匹配

var str = 'web1web2';
var reg = /web(?:1|2)/;
console.log(reg.exec(str));

(?=)

a(?=b) : 匹配后面必须跟b的a

var str = 'webabcweb123';
var reg = /web(?=\d)/; // 匹配web后面是数字的web
console.log(reg.exec(str));

(?!)

a(?!b) : 匹配 后面 不是 b 的 a

使用: 排除条件

var str = 'webabcweb123';
var reg = /web(?!\d)/; // 匹配web后面不是数字的web
console.log(reg.exec(str));  // ['web', index: 0, input: 'webabcweb123', groups: undefined]

DOM

DOM:

DOM树 浏览器在渲染页面的时候 会先形成树状结构 就叫做DOM树

DOM由节点组成的

获取节点

获取节点: css选择器: css中选择器怎么写 这里就怎么写 id class tag 父子 层级 交叉...

ie8+ 静态

获取符合选择器的第一个元素: document/父元素.querySelector('css选择器')

var div = document.querySelector('div');
console.log(div); // 直接获取到第一个div

var ul = document.querySelector('ul');
console.log(ul);

获取所有符合选择器的元素: 节点的集合: document/父元素.querySelectorAll('css选择器');

var lis = ul.querySelectorAll('li');
console.log(lis); // NodeList 节点列表

var boxa = ul.querySelector('.box.a');
console.log(boxa);

获取子节点

父元素.children 标准: 标签节点 常用

父元素.childNodes 标准: 标签节点+文本节点+注释+...

// 1. 获取ul
var ul = document.querySelector('ul');
console.log(ul);
/*
    获取子节点:
        父元素.children 标准: 标签节点  常用
        父元素.childNodes 标准: 标签节点+文本节点+注释+...
*/
console.log(ul.children);
console.log(ul.childNodes);

节点属性:

\1. 节点名称: 节点.nodeName 标签名大写

\2. 节点类型: 节点.nodeType 1-12 1--标签 2---属性 3---文本 8--注释 9--document

\3. 节点内容: 节点.nodeValue 只有文本节点(text)才有内容

var cls = ul.childNodes;
for(var i = 0; i < cls.length; i++){
    // console.log(cls[i], cls[i].nodeName, cls[i].nodeType, cls[i].nodeValue);
    // 获取标签的内容
    if(cls[i].nodeType == 1){
        console.log(cls[i].childNodes[0].nodeValue);
        console.log(cls[i].innerHTML);
    }
}

获取父节点

直接父节点: 节点.parentNode

定位父节点: 节点.offsetParent

如果没有定位父节点 获取到的是body

// 1. 获取box
var box = document.querySelector('.box');
console.log(box);

/* 
    直接父节点: 节点.parentNode
    定位父节点: 节点.offsetParent
        如果没有定位父节点 获取到的是body
*/
console.log(box.parentNode);
console.log(box.offsetParent);

查找兄弟节点

获取上一个兄弟节点:

标准: 节点.previousElementSibling

ie: undefined 标准: 专门提供在标准浏览器中获取上一个兄弟节点

ie: 节点.previousSibling

ie8-: 可以获取到上一个兄弟节点 标准: 换行文本节点

两个值中二选一的时候可以选择用逻辑或短路 将可能出现undefined 的这一项放在前面

兼容: 节点.previousElementSibling || 节点.previousSibling

// 1. 获取box
var box = document.querySelector('.box');
console.log(box);

console.log(box.previousElementSibling, box.previousSibling);
console.log(box.previousElementSibling || box.previousSibling);

获取下一个兄弟节点:

标准: 节点.nextElementSibling

ie: undefined 标准: 专门提供在标准浏览器中获取上一个兄弟节点

ie: 节点.nextSibling

ie8-: 可以获取到上一个兄弟节点 标准: 换行文本节点

两个值中二选一的时候可以选择用逻辑或短路 将可能出现undefined 的这一项放在前面

兼容: 节点.nextElementSibling || 节点.nextSibling

console.log(box.nextElementSibling, box.nextSibling);
console.log(box.nextElementSibling || box.nextSibling);

获取首个子节点:

ie: firstChild

标准: firstElementChild

兼容: 节点.firstElementChild || 节点.firstChild

// 获取父节点
var ul = document.querySelector('ul');
console.log(ul);

/* 
    获取首个子节点:
        ie: firstChild
        标准: firstElementChild
    兼容: 节点.firstElementChild || 节点.firstChild
*/
console.log(ul.firstChild, ul.firstElementChild);
console.log(ul.firstElementChild || ul.firstChild);

获取末位子节点:

ie: lastChild

标准: lastElementChild

兼容: 节点.lastElementChild || 节点.lastChild

console.log(ul.lastElementChild || ul.lastChild);

创建节点

1.1 创建标签节点: var 变量 = document.createElement('标签名');

1.2 创建文本节点: var 变量 = document.createTextNode('内容');

1.3 将文本节点添加到标签节点中: 父节点.appendChild(子节点);

创建节点为了解决innerHTML重新赋值会覆盖原来所有元素的问题

为了简化过程, 常用innerHTML代替 1.2 1.3

// 1. 创建节点:
// 1.1 创建标签节点: var 变量 = document.createElement('标签名');
var li = document.createElement('li');
console.log(li);

// // 1.2 创建文本节点: var 变量 = document.createTextNode('内容');
// var txt = document.createTextNode('这是新的li');
// console.log(txt);

// // 1.3 将文本节点添加到标签节点中: 父节点.appendChild(子节点);
// li.appendChild(txt);
// console.log(li);


// 创建节点为了解决innerHTML重新赋值会覆盖原来所有元素的问题
// 为了简化过程, 常用innerHTML代替 1.2 1.3

li.innerHTML = '这是新的li';
console.log(li);

追加节点

追加到父元素的末位:

父节点.appendChild(子节点);

var ul = document.querySelector('ul');
console.log(ul);
ul.appendChild(li);

追加到某个节点之前:

父节点.insertBefore(新节点, 参考节点);

var li1 = document.createElement('li');
li1.innerHTML = '新的li1';
ul.insertBefore(li1, ul.children[0]);

var li2 = document.createElement('li');
li2.innerHTML = '新的li2';
ul.insertBefore(li2, ul.children[0]);

删除节点

  1. 删除自己: 节点.remove(); ie8+

  2. 删除子节点: 父节点.removeChild(子节点) 会把被删除的元素返回回来

// 1. 删除自己: 节点.remove(); ie8+
// 点击div  删除整个ul
var div = document.querySelector('div');
var ul = document.querySelector('ul');
div.onclick = function () {
    ul.remove();
}
// 2. 删除子节点: 父节点.removeChild(子节点)   会把被删除的元素返回回来
// 点击btn 删除整行li
var btns = document.querySelectorAll('button');
console.log(btns);
for(var i = 0; i < btns.length; i++){
    btns[i].onclick = function () {
        // 通过按钮 找到整个 li  li是btn的直接父元素
        console.log(this.parentNode);
        var a = ul.removeChild(this.parentNode);
        console.log(a);
    }
}

克隆节点

节点.cloneNode(布尔);

true: 克隆节点中的内容

false/不传: 不克隆节点中的内容

var nli = this.cloneNode(true);
console.log(nli);
// 追加到ul中
ul.appendChild(nli);

替换节点:

父节点.replaceChild(新节点, 参考节点);

var box = document.querySelector('.box');
console.log(box);

var li = document.createElement('li');
li.innerHTML = '新内容';

var ul = document.querySelector('ul');
ul.replaceChild(li, box);

操作属性

\1. 获取: var 变量 = 元素.属性名; var 变量 = 元素['属性名'];

\2. 设置: 元素.属性名 = 值; 元素['属性名'] = 值; 设置布尔值 读取到的就是布尔

[]里直接写属性名需要加引号 如果是变量不加引号

问题: 获取属性: 不能获取直接写在标签上的自定义属性 设置属性: 通过js设置的自定义属性在标签上看不到, 可以正常获取和设置操作所有属性, class直接使用

\3. 获取: 节点.getAttribute('属性名');

\4. 设置: 节点.setAttribute('属性名', '属性值');

所有的值都是字符串 设置后面的属性会覆盖前面

\5. 移除:

节点.属性名 = null/'';

节点.removeAttribute('属性名');

一般操作属性都可以直接使用以上方式, 如果只设置属性名就起作用的属性(checked\selected\loop\muted..)用点和[]

/* 
    操作属性:
        1. 获取: var 变量 = 元素.属性名;  var 变量 = 元素['属性名'];
        2. 设置: 元素.属性名 = 值; 元素['属性名'] = 值;  设置布尔值 读取到的就是布尔
        []里直接写属性名需要加引号 如果是变量不加引号
        问题: 获取属性: 不能获取直接写在标签上的自定义属性  设置属性: 通过js设置的自定义属性在标签上看不到, 可以正常获取和设置
*/
var div = document.querySelector('div');
console.log(div.id);
console.log(div.className);
console.log(div.tag); // undefined
console.log(div['tag']); // undefined

div.ttt = '1234';

/* 
    操作所有属性, class直接使用
    3. 获取: 节点.getAttribute('属性名');
    4. 设置: 节点.setAttribute('属性名', '属性值');
        所有的值都是字符串 设置后面的属性会覆盖前面
    5. 移除: 
        节点.属性名 = null/'';
        节点.removeAttribute('属性名');

    一般操作属性都可以直接使用以上方式, 如果只设置属性名就起作用的属性(checked\selected\loop\muted\..)用点和[]
*/
console.log(div.getAttribute('class'));
console.log(div.getAttribute('tag')); // abc123
div.setAttribute('txt', '123123');
div.setAttribute('tnt', true);
div.setAttribute('class', 'wrap a b');

div.id = '';
div.removeAttribute('id');

快速获取表格

// 表格
var table = document.querySelector('table');
console.log(table);
// 表格是由行组成, 行是由单元格, 表格不能直接获取单元格
console.log(table.tHead); // 表格头
console.log(table.tFoot); // 表格脚
console.log(table.tBodies); // 表格体 --> 集合
console.log(table.tBodies[0]); // 第一个表格体
console.log(table.rows); // 表格中所有的行 头体脚 集合
console.log(table.tBodies[0].rows); // 第一个表格体所有的行
console.log(table.cells); // undefined
console.log(table.rows[0].cells); // 获取表格中第一个行的所有的单元格
console.log(table.tBodies[0].rows[0].cells);

快速获取表单

快速获取表单元素: form.name值

/* 
    1. 获取表单form
*/
var form = document.querySelector('form');
console.log(form);

// 快速获取表单元素: form.name值
console.log(form.user);
console.log(form.pass);
console.log(form.sex);
console.log(form.sex.value); // 当前单选按钮所选中得项
console.log(form.hobby);
// 复选框由于有多个选中的项 所以不能直接通过value获取

表单事件

form表单的事件:

提交: form元素.onsubmit = 函数;

重置: form元素.onreset = 函数;

在函数中默认返回值都是 return true;

return false: 禁止提交/重置

如果你不想表单发生重置或者提交的时候 在函数中设置return false;

form.onsubmit = function () {
    console.log('是否提交');
    // return true;
    return false;
};

form.onreset = function () {
    console.log('是否重置');
    // return true;
    return false;
};

表单元素事件

输入框(常见):

onblur: 失去焦点

onfocus: 聚集焦点

onchange: 失去焦点且内容发生改变

边输入边触发: oninput(标准)/onpropertychange(ie8)

搜索提示\密码等级校验...

不建议单独使用, 一般需要结合防抖和节流来进行使用, 避免事件的频繁触发

form.user.onfocus = function () {
    this.style.background = 'orange';
};

form.user.onblur = function () {
    this.style.background = 'skyblue';
};

form.pass.onchange = function () {
    this.style.background = 'red';
};

// 事件可以连等
form.pass.oninput = form.onpropertychange = function () {
    console.log(this.value);
};

BOM

BOM: Browser Object Model 浏览器对象模型

js提供给我们用来操作浏览器的信息的接口

iframes

location

history

document

navigator

....

BOM核心: window

可以直接使用变量名或者函数名就能出线效果的(全局变量、全局函数), 所属对象都是window

对话框

  1. 警告框: alert()

  2. 带有确定取消按钮的警告框: confirm('提示内容')

  3. 带有输入框的对话框: prompt('提示内容', '默认值')

// 1. 警告框: alert()
// alert('是否已经了解清除风险');

// 2. 带有确定取消按钮的警告框: confirm('提示内容')
// 接收返回值: 取消: false  确定: true
// var res = confirm('是否已经了解风险');
// console.log(res);

// 3. 带有输入框的对话框: prompt('提示内容', '默认值')
// 接收返回值: 取消: null  确定: 输入框的内容
// var res = prompt('请输入要购买的金额', '10000');
// console.log(res);

open与close

如果页面结构html中使用, window不能省略

open: 打开

语法: open(跳转的网址, target, 描述词, 是否替换当前页面在历史记录中的位置)

target: 打开方式 _blank: 新标签页 _self: 当前

描述词: 当前窗口宽高 属性名=属性值,属性名=属性值 只在打开方式是_blank

返回新页面的window

close: 关闭

window对象.close();

js中关闭自己: close();

// 点击第一个按钮 打开uxue官网
var btns = document.querySelectorAll('button');
console.log(btns);

var nwin = null;
btns[0].onclick = function () {
    // open('https://www.ujiuye.com');
    // open('https://www.ujiuye.com', '_blank');
    // open('https://www.ujiuye.com', '_self');
    // open('https://www.ujiuye.com', '_self');
    nwin = open('https://www.ujiuye.com', '_blank', 'width=500px,height=500px');
    console.log(nwin);
};

btns[2].onclick = function () {
    close();
};
btns[3].onclick = function () {
    nwin.close();
};

location

location是BOM中最有用的对象之一. 既是BOM直接对象, 也是window下的对象

存储相关当前页面的信息: 网址 协议 搜索内容...

// 调试: 打开线上网站 安装插件: live Server
console.log(location);
// https://www.jd.com/
console.log(location.protocol); // 协议 http https file
console.log(location.hostname); // 服务器名称
console.log(location.port); // 端口
console.log(location.host); // 服务器名称 + 端口
console.log(location.pathname); // 文件路径
console.log(location.search); // 搜索内容  ?+后面的内容
console.log(location.hash); // 哈希值 地址后面的散列 #+后面的内容
console.log(location.href); // 完整地址

setTimeout(function () {
    // 给href赋值 可以实现页面跳转
    // location.href = 'https://www.baidu.com';
    // window.location.href = 'https://www.baidu.com';


    // 刷新
    // location.reload();
},3000);

history

history: 历史记录

history.go(数字);

正数: 前进几个页面

负数: 后退几个页面

0: 刷新

history.back(); 回退到上一个页面

history.forward(); 前进到下一个页面

console.log(history);
setTimeout(function () {
    // 前进到02页面
    // history.forward();
    // history.go(2);
    // history.go(0);
}, 3000);

BOM事件

onload

当script标签写在body、页面结构之前的时候 获取元素拿不到正确的元素 去到的是null

原因: 由于代码是从上到下的顺序去执行的 当执行到script的时候页面中还没有元素 所以取不到

解决: 让js代码在页面结构之后

\1. 使用 window.onload 事件: 等待页面和其中的资源(图片、视频...)都加载完成后 在执行其中的代码

window.onload = function () {
    var div = document.querySelector('div');
    console.log(div);
}

onscroll

滚动事件

window.onscroll 事件

window.onscroll = function () {
    console.log('滚了');
};

onresize

窗口大小改变事件

window.onresize = function () {
    console.log('变了');
};

元素三大宽高

client

元素可视宽高 client系列:

clientWidth/clientHeight: 元素的可视宽高 内容 + padding

clientLeft/clientTop: 左/上边框的宽度

屏幕的可视区域的宽高:

document.documentElement.clientWidth/clientHeight

/* 
    元素可视宽高 client系列:
        clientWidth/clientHeight: 元素的可视宽高 内容 + padding
        clientLeft/clientTop: 左/上边框的宽度
*/
console.log(div.clientHeight, div.clientWidth); // 300+20+10=330 200+15+5=220
console.log(div.clientLeft, div.clientTop); // 25  5

/* 
    屏幕的可视区域的宽高:
        document.documentElement.clientWidth/clientHeight
*/
console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);

offset

offset: 元素的占位宽高

offsetWidth/offsetHeight: 元素的占位宽高 内容 + padding + border

offsetLeft/offasetTop: 元素距离具有定位属性的父元素的左侧/顶部的距离 如果没有定位父元素 就是距离body的距离

console.log(div.offsetWidth, div.offsetHeight); // 200+15+5+25+3=248 300+20+10+5+23=358
console.log(div.offsetLeft, div.offsetTop); // 30 1

scroll

scroll: 滚动距离

scrollHeight/scrollWidth: 元素的实际宽高

scrollTop/scrollLeft: 超出当前页面/元素的距离 滚动卷去的距离

获取页面\窗口的滚动距离:

document.documentElement.scrollTop

document.documentElement.scrollLeft

console.log(div.scrollWidth, div.scrollHeight);
// 通过滚动事件
div.onscroll = function () {
    console.log(div.scrollLeft, div.scrollTop);
};

// 获取页面滚动的距离:
window.onscroll = function () {
    console.log(document.documentElement.scrollTop, document.documentElement.scrollLeft);
};

滚动的距离: scrollTop/scrollLeft可以被赋值 其他的只能获取不能设置

btn.onclick = function () {
    document.documentElement.scrollTop = 0;
};

懒加载

  1. 当页面滚动的时候, 判断每一个图片是否在页面的可视范围之内 如果在 img的src被赋值成ntag的值

  2. 一进入页面的时候 判断是否有图片需要显示

  3. 当页面可视区域的大小发生改变的时候 判断

判断思路:

元素的offsetTop <= window的scrollTop + 屏幕的可视区域的高度

// 1.1 获取元素
var imgs = document.querySelectorAll('img');
console.log(imgs);
// 1.2 页面滚动
window.onscroll = function () {
    auto();
};


// 2. 一进入页面的时候  判断是否有图片需要显示
auto();
function auto() {
    // 获取滚动距离 和 屏幕的可视区域的高度
    var st = document.documentElement.scrollTop;
    var ch = document.documentElement.clientHeight;
    // 每一个   
    for (var i = 0; i < imgs.length; i++) {
        // console.log(imgs[i].offsetTop);
        if (imgs[i].offsetTop <= st + ch) {
            // img的src被赋值成ntag的值
            // 获取ntag的值
            // console.log(imgs[i].getAttribute('ntag'));
            imgs[i].src = imgs[i].getAttribute('ntag');
        }
    }
};

// 3. 当页面可视区域的大小发生改变的时候 判断
window.onresize = function () {
    auto();
}

事件对象

当事件发生的时候, 浏览器将相关当前事件的信息都存在一个对象中, 这个对象就是事件对象

普通: event window.event

低版本ff: 事件处理函数的第一个形参的位置

事件对象兼容: var ev = window.event || evs;

document.onclick = function (evs) {
    // console.log(window.event, evs);
    var ev = window.event || evs;
    console.log(ev);

    console.log(ev.type); // 事件类型
    console.log(ev.target || ev.srcElement); // 事件触发源
    console.log(ev.clientX, ev.clientY); // 鼠标距离屏幕可视区域的左上角的距离
    console.log(ev.screenX, ev.screenY); // 鼠标距离屏幕的左上角的距离
    console.log(ev.pageX, ev.pageY); // 鼠标距离页面左上角的距离
}

事件绑定

语法

标准

事件绑定:利用特定的方法可以实现给一个元素的同一个事件添加多个事件处理函数

标准: 元素.addEventListener(事件类型, 事件处理函数, [是否捕获]);

事件类型: 不加on

事件处理函数: 函数名 函数

是否捕获: 默认false冒泡 true: 捕获

ie: 对象不支持“addEventListener”属性或方法

function a() {
    console.log(this);
}
console.log(div.addEventListener); // ie: undefined  标准: 函数
// div.addEventListener('click', a, false);
// div.addEventListener('click', function () {
//     console.log('这是第二个事件绑定的函数');
//     console.log(this);
// }, false);

ie

ie: 元素.attachEvent(on+事件类型, 事件处理函数);

console.log(div.attachEvent); // ie: 函数  标准: undefined
div.attachEvent('onclick', a);
div.attachEvent('onclick', function () {
    console.log('这是添加的第二个');
    console.log(this);
});

ie和标准事件机制的区别:

\1. 是否加on: ie: 加on 标准: 不加

\2. 是否捕获: ie: 没有捕获 标准: 有捕获

\3. 执行顺序: ie: 倒叙执行 标准: 顺序执行

\4. this的指向: ie: window 标准: 触发源

兼容

if (div.addEventListener) {
    // 标准
    div.addEventListener('click', a, false);
    div.addEventListener('click', function () {
        console.log('这是第二个事件绑定的函数');
        console.log(this);
    }, false);
} else {
    // ie
    div.attachEvent('onclick', a);
    div.attachEvent('onclick', function () {
        console.log('这是添加的第二个');
        console.log(this);
    });
}

封装

function bind(ele, type, fn) {
    // ele: 元素
    // type: 事件类型
    if (ele.addEventListener) {
        // 标准
        ele.addEventListener(type, fn, false);
    } else {
        // ie
        ele.attachEvent('on' + type, fn);
    }
}

事件解绑/事件取消:

元素.事件 元素.事件 = null;

addEventListener 元素.removeEventListener(事件类型, 函数名, [是否捕获]);

attachEvent 元素.detachEvent(on+事件类型, 函数名);

var div = document.querySelector('div');
div.onclick = function () {
    console.log(123);
}

div.onclick = null;

function a() {
    console.log(111);
}
bind(div, 'click', a);
console.log(div.removeEventListener); // ie: undefined 标准: 函数
console.log(div.detachEvent); // ie: 函数  标准: undefined 
// div.removeEventListener('click', a, false);
// div.detachEvent('onclick', a);

// if(div.removeEventListener){
//     // 标准
//     div.removeEventListener('click', a, false);
// } else {
//     // ie
//     div.detachEvent('onclick', a);
// }

封装

unbind(div, 'click', a);
function unbind(ele, type, fn ) {
    if (ele.removeEventListener) {
        // 标准
        ele.removeEventListener(type, fn, false);
    } else {
        // ie
        ele.detachEvent('on' + type, fn);
    }
}

事件流

事件流: 当事件发生的时候, 事件在父子节点之间固定的传递顺序。

捕获型事件(标准) 冒泡型事件

捕获阶段: 当事件发生的时候, 事件从window开始往子元素传递

确定目标: 确定鼠标的触发源

冒泡阶段: 触发源接收到事件并且开始处理. 处理完成后, 会将事件从当前往父节点传递,一直到window

所有事件经过的节点, 都会接收并且去触发这个事件

阻止冒泡

标准: 事件对象.stopPropagation();

ie: 事件对象.cancelBubble = true;

兼容: 如果一个方法一个属性 用方法是否存在来做判断

ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;

// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
console.log(btn, div);

// 点击
btn.onclick = function (evs) {
    var ev = window.event || evs;
    // 阻止冒泡
    // console.log(ev.stopPropagation); // ie: undefined 标准: 函数
    // ev.stopPropagation();
    // ev.cancelBubble = true;
    ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true; 


    console.log(1);
    div.style.display = 'block';
}

document.onclick = function () {
    console.log(2);
    div.style.display = 'none';
}

取消默认行为

默认行为:

a标签的跳转

右键菜单

按下拖拽的时候选中文字

图片拖拽保存

取消默认行为:

元素.事件 return false

标准: addEventListener ev.preventDefault();

ie: attachEvent ev.returnValue = false;

兼容:

ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;

var a = document.querySelector('a');
console.log(a);

// a.onclick = function () {
//     console.log('点击');

//     // 取消默认行为
//     return false;
// }

bind(a, 'click', function (evs) {
    var ev = window.event || evs;
    // ev.preventDefault();
    // ev.returnValue = false;
    ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; 
    console.log('点击了');
});

事件委托

事件委托(事件代理): 将子元素要做的事情交给父元素, 通过target或srcElement找到指定的触发源, 将后续代码交给触发源来处理

优点:

\1. 如果现在元素数量过多 执行速度较快

\2. 如果元素发生在未来, 后面的元素也有事件

ul.onclick = function (evs) {
    var ev = window.event || evs;
    console.log(ev.target || ev.srcElement);
    var tar = ev.target || ev.srcElement;
    // 判断触发源是不是li 如果是li 输出内容
    if(tar.nodeName == 'LI'){
        console.log(tar.innerHTML);
    }
}

var li1 = document.createElement('li');
li1.innerHTML = '2222';
ul.appendChild(li1);

键盘事件

document\表单元素

onkeyup 抬起

obkeydown 按下 键盘上任何一个键都可以触发 不区分大小写, 返回大写的编码

特殊键shift + 1 ---> shift + 49 --> ! + 49

obkeypress 按下 键盘上字符可以触发 区分大小分, 返回大写和小写字母的编码

特殊键shift + 1 ---> ! 33

document.onkeydown = function (evs) {
    var ev = window.event || evs;
    // console.log(ev); // KeyboardEvent
    console.log(ev.key); // 标准: 具体的字符 ie: undefined
    console.log(ev.keyCode); // ASCII码
}

// document.onkeypress = function (evs) {
//     var ev = window.event || evs;
//     // console.log(ev); // KeyboardEvent
//     console.log(ev.key); // 标准: 具体的字符 ie: undefined
//     console.log(ev.keyCode); // ASCII码
// }

document.onkeyup = function (evs) {
    var ev = window.event || evs;
    console.log(ev.keyCode);
}

滚轮事件

chrome/ie: onmousewheel

wheelDelta: 120或150的倍数

> 0 向上

< 0 向下

ff: 事件必须通过事件监听的方式 DOMMouseScroll

detail: 3和3的倍数

> 0 向下

< 0 向上

function mouseScroll(ele, upFn, downFn) {
    // ele: 元素
    ele.onmousewheel = scroll;
    if (ele.addEventListener) {
        ele.addEventListener('DOMMouseScroll', scroll);
    }
    // 滚动滚轮触发的事件
    function scroll(evs) {
        var ev = window.event || evs;

        if (ev.wheelDelta) {
            // chrome ie
            var tag = ev.wheelDelta > 0 ? '上' : '下';
        } else {
            // ff
            var tag = ev.detail > 0 ? '下' : '上';
        }   

        // 根据滚轮向上向下执行不同的代码
        if (tag == '上') {
            upFn();
        } else {
            downFn();
        }

    }
}

回调函数

回调函数: 执行完一个动作之后还要继续执行的函数

作为实参传递的函数就是回调函数

function a() {
    console.log(123);
}


function b(fn) {
    // fn: 形参 函数 回调函数
    console.log(fn);
    fn();
}
b(a);

匿名函数

匿名: 没有名字的函数

直接写会报错 将匿名函数转换成函数表达式 外面加() 同样具有函数的特点

立即执行函数: IIFE

  1. 函数自执行

    使用: 团队协作

    注意: 分号必须加 不能省略

    (function () {
        console.log('匿名函数');
    })();
    
    (function () {
        console.log('匿名函数1');
    }());
    
  2. 有参数

    (function (a, b) {
        console.log(a, b);
        console.log(arguments);
    })(10, 20);
    
  3. 有函数返回值

    var res = (function () {
        return true;
    })();
    console.log(res);
    

闭包

概念

闭包: 可以访问其他函数内部变量的函数就是闭包

组成: 函数里面套函数 内部函数访问外部函数的变量

优点: 扩大变量的作用范围 缓存数据

缺点: 如果有大量缓存数据 会造成内存泄漏 不参与垃圾回收机制

调试:

使用断点调试

\1. outer的第一行代码

\2. inner的第一行代码

\3. 刷新 看右侧或者底部的 Scope

local: 当前作用域

Global: 全局

closure: 闭包

注意: 外部函数调用一次就会形成一个新的闭包

function outer() {
    var a = 10;
    function inner() {
        a++;
        console.log(a);
    }
    // 设置返回值
    return inner;
}
var res = outer();
console.log(res); // inner函数
res(); // 11
res(); // 12

// 外部函数调用一次就会形成一个新的闭包
var res1 = outer();
res1();

使用

当当前作用域需要自己的变量值的时候 使用闭包

在for循环所添加的事件中 解决不能通过下标得到正确的元素的问题

var lis = document.querySelectorAll('li');
console.log(lis);
// for(var i = 0; i < lis.length; i++){
//     lis[i].onclick = function () {
//         console.log(i); // 10
//     };
// }

for(var i = 0; i < lis.length; i++){
    (function (s) {
        // console.log(s);
        lis[s].onclick = function () {
            console.log(s);
        };
    })(i);
}

模拟私有变量

// 创建账号
function create(val) {
    var user = val;
    // console.log(user);
    // 如果想要在函数外读取或者设置 必须通过当前函数提供的专用函数来实现效果
    return {
        getUser: function () {
            console.log(user);
        },
        setUser: function (v) {
            user = v;
        }
    };
}
var u = create('小时候超白');
console.log(u);
u.getUser();
u.setUser('长大后超黑');
u.getUser();

// 与上面的user无关
user = '中年时候超胖';
console.log(user);
u.getUser();

面试题

  1. 输出结果

    function fun(n, o) {
        console.log(o);
        return {
            "fun": function (m) {
                return fun(m, n);
            }
        }
    }
    /* 
        var a = fun(n, o)--> fun(0) --> n = 0 o = undefined
        a = {fun: function(m){  }}
            a.fun(1)
                m = 1 fun(m, n)  m = 1  n = 0  fun(1, 0) --> fun(n, o) n = 1 o = 0 log(o) --> 0
            a.fun(2)
                m = 2 fun(m, n) m = 2 n = 0 fun(2, 0) --> fun(n, o) n = 2 o = 0 log(o) --> 0
            a.fun(3)
                m = 3 fun(m, n) m = 3 n = 0 fun(3, 0) --> fun(n, o) n = 3 o = 0 log(o) --> 0
    
    */
    var a = fun(0); // undefined
    a.fun(1);  // 0
    a.fun(2); // 0
    a.fun(3); // 0
    
  2. 输出结果和执行顺序

    for(var i = 0; i < 5; i++){
        setTimeout(function () {
            console.log(i, new Date(), new Date().getTime()); // 5 当前时间+1s
        }, 1000);
    }
    console.log(i, new Date()); // 5 
    /* 
        同步: 当前代码执行的时候 后续的代码等着 alert for
        异步: 当前代码执行的时候 后续代码不等待执行完成 就可以直接执行 定时器
    */
    

代码分类

同步: 当前代码执行的时候 后续的代码等着 alert for

异步: 当前代码执行的时候 后续代码不等待执行完成 就可以直接执行 定时器

递归

递归: 函数里面调用自己的函数

注意: 一定要有函数结束的条件

将大的操作划分小操作重复执行的时候使用

报错: Uncaught RangeError: Maximum call stack size exceeded 栈溢出 ---> 原因: 递归函数没有设置结束条件

// 阶乘: 6! = 6 * 5 * 4 * 3 * 2 * 1
// function jc(n) {
//     return n * jc(n - 1);
// }

function jc(n) {
    // 设置结束条件
    if(n == 1){
        return 1;
    }
    return n * jc(n - 1);
}
var s = jc(6);
console.log(s);
console.log(jc(10));
console.log(jc(100));

斐波那契数列

有名的兔子问题: 出生2个月后每个月都会生产一对新兔子

月份 兔子

1 1 1

2 1 1

3 2 1 1

4 3 1 1 1

5 5 1 1 1 1 1

6 8 1 1 1 1 1 1 1 1

7 13 1 1 1 1 1 1 1 1 1 1 1 1 1

序列: 1 1 2 3 5 8 13 21

当前月的兔子 = 上个月的兔子个数 + 上上个月的兔子个数

第二个月和第一个月的时候 个数都是1

用函数求第n个月的兔子个数

function fib(n) {
    // 设置返回值 结束条件
    if(n == 1 || n == 2){ return 1; }
    return fib(n-1) + fib(n-2);
};

console.log(fib(6));
console.log(fib(12));

/* 
    第6个月的兔子 = 5 + 4
                = 4 + 3 + 3 + 2
                = 3 + 2 + 2 + 1 + 2 + 1 + 2
                = 2 + 1 + 2 + 2 + 1 + 2 + 1 + 2
*/

快速排序

快速排序: 找到中间项 进行左右重复排序的过程

\1. 有一个函数处理排序函数

\2. 找到中间项的下标

\3. 找到中间项

\4. 删除中间项

\5. 创建两个空数组 放置比中间项小 和 大的值

\6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边

\7. 左右数组需要重复排序

\8. 设置每次排序以后的返回结果

\9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回

var arr = [32, 12, 435, 56, 21, 78, 90];
// function qs(array) {
//     // 9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回
//     if(array.length <= 1){
//         return array;
//     }
//     // 2. 找到中间项的下标
//     var num = Math.floor(array.length / 2);
//     // console.log(num);
//     // 3. 找到中间项
//     var val = array[num];
//     // 4. 删除中间项
//     array.splice(num, 1);
//     // 5. 创建两个空数组 放置比中间项小 和 大的值
//     var left = [], right = [];
//     // 6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边
//     for(var i = 0; i < array.length; i++){
//         if(array[i] > val){
//             right.push(array[i]);
//         } else {
//             left.push(array[i]);
//         }
//     }
//     // 7. 左右数组需要重复排序
//     left = qs(left);
//     right = qs(right);
//     // 8. 设置每次排序以后的返回结果
//     return left.concat(val, right);

// };

function qs(array) {
    // 9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回
    if(array.length <= 1){
        return array;
    }
    // 2. 找到中间项的下标
    var num = Math.floor(array.length / 2);
    // 3-4:
    var val = array.splice(num, 1)[0];
    // 5. 创建两个空数组 放置比中间项小 和 大的值
    var left = [], right = [];
    // 6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边
    for(var i = 0; i < array.length; i++){
        if(array[i] > val){
            right.push(array[i]);
        } else {
            left.push(array[i]);
        }
    }
    // 7-8
    return qs(left).concat(val, qs(right));
};

var a =qs(arr);
console.log(a);

事件频繁触发

为了解决事件频繁触发的问题 引申出了防抖和节流

防抖

防抖: 利用闭包, 在用户触发的事件过程中不进行事件的处理 等待用户停止触发多长时间后 再进行事件的处理

只要用户在输入或者是移动 就不触发事件处理函数 等用户停止1s后 在执行事件处理函数

只要用户触发 时间需要重新计时

问题: 太生硬

// 防抖函数
function debounce(fn, wait) {
    // 解决全局变量的问题
    var timer = null;
    return function () {
        // 清除定时器
        clearTimeout(timer);
        // 延迟定时器
        timer = setTimeout(fn, wait);
    };
}
// 获取元素
var div = document.querySelector('div');
var n = 0;
// 添加事件
div.onmousemove = debounce(inner, 3000);

function inner() {
    n++;
    div.innerHTML = n;
};

节流

节流: 在一定的时间内 只能触发一次事件处理函数

利用闭包 为了解决全局变量

// 节流函数
function throttle(fn, wait) {
    // 假设当前可以触发函数
    var tag = true;
    var timer = null;
    return function () {
        // 判断当前是否可以触发函数
        if(tag){
            // 将状态变成不可触发
            tag = false;
            // 开启定时器
            timer = setTimeout(function () {
                fn();
                // 将状态变成可触发
                tag = true;
                clearTimeout(timer);
            }, wait);

        }
    };
}
// 获取元素
var div = document.querySelector('div');
var n = 0;
// 添加事件
div.onmousemove = throttle(inner, 100);

function inner() {
    n++;
    div.innerHTML = n;
};

call和apply

call和apply: 改变this指向

区别:

函数.call(this的新指向, ...data); 参数一个个用,分隔直接写

函数.apply(this的新指向, [...data]); 第二个参数是一个数组

call

var obj = {
    name: '张三',
    sayName: function () {
        console.log(this.name);
    }
};
obj.sayName(); // 张三

var obj1 = {
    name: '李四'
};
obj.sayName.call(obj1); // 李四

function fn() {
    console.log(this);
}
fn(); // window

fn.call(document);
fn.call(undefined);
fn.call(1);
fn.call('a');


function fn1(a, b) {
    console.log(this, a, b);
}
fn1(20, 30); // window 20 30
fn1.call(1, 10, 20); // 1 10 20

// 判断数据的类型
console.log(Object.prototype.toString()); // [object Object]
console.log(Object.prototype.toString.call(1)); // [object Number]
console.log(Object.prototype.toString.call('aaa')); // [object String]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call({}).slice(8, -1)); // Object
console.log(Object.prototype.toString.call([]).slice(8, -1)); // Array

apply

function fn1(a, b) {
    console.log(this, a, b);
}

fn1.apply(document, [44, 33]);
// 数组找最大和最小项
var arr = [32, 43, 546, 56, 32, 534, 234, 65];
console.log(Math.max.apply(this, arr));
console.log(Math.min.apply(this, arr));

面向对象

概念

概念: 基于对象 

面向过程: 一步步分析实现  注重过程
面向对象: 一种编程思想    注重结果

核心: 对象 

组成:
    方法: 函数 行为
    属性: 描述 属性

以类创建模板 实例化对象的过程 
es5中 没有明确的类的概念 用函数去创建模板 实例化对象

实例化: 具象化对象的时候 就是实例化

遵循: 有对象就要用对象 没有对象就创建对象

特点:
    封装 继承 多态

创建对象

字面量

字面量: 只适用于单个对象的创建

var obj = {
    name: '张三',
    age: 33,
    work: function () {
        console.log('为了碎银几两 辛辛苦苦工作');
    }
};
console.log(obj);
console.log(obj.name);
obj.work();

new关键字

new关键字创建: 代码冗余

// 1. 创建空对象
var obj = new Object();

// 2. 添加属性和方法
obj.name = '杨洋';
obj.age = 38;
obj.work = function () {
    console.log('演员');
};

console.log(obj);
console.log(obj.name);
obj.work();

工厂模式创建

问题:

\1. 识别不清

\2. 内存浪费

// 工厂
function createObj(name, age) {
    // 1. 创建空对象
    var obj = new Object();

    // 2. 添加属性和方法
    obj.name = name;
    obj.age = age;
    obj.work = function () {
        console.log('工作去吧');
    };

    // 3. 出厂 设置返回值
    return obj;
};

// 实例化对象
var obj = createObj('张三', 33);
var obj1 = createObj('古力娜扎', 28);
console.log(obj, obj1);
console.log(obj.name, obj1.name);
obj.work();
obj1.work();

// 判断对象是否是由createObj函数创建
// 对象 instanceof 函数  true--是 false--不是
console.log(obj instanceof createObj); // false
console.log(obj.work == obj1.work); // false

构造函数

构造函数:
    1. 构造函数首字母大写 为了和普通函数进行区分 (约定)
    2. 方法和属性直接加给this
    3. 必须使用new进行调用, 否则和普通函数没有区别

new的发生了什么:
    1. 创建一个空对象
    2. 将this指向当前空对象
    3. 将函数prototype 赋值给 对象的__proto__
    4. 添加属性和方法
    5. 隐式返回对象

问题:
    1. 内存浪费
function CreateObj(name, age){
    // // 1. 创建空对象
    // var obj = new Object();

    // 2. 添加属性和方法
    this.name = name;
    this.age = age;
    this.work = function () {
        console.log('工作去吧');
    };

    // // 3. 出厂 设置返回值
    // return obj;
}

// 实例化:
var obj = new CreateObj('迪丽热巴', 38);
var obj1 = new CreateObj('古力娜扎', 38);
console.log(obj, obj1);

console.log(obj instanceof CreateObj); // true
console.log(obj.work == obj1.work); // false

原型创建

问题: 不能传参

// 1. 构造函数
function CreateObj() {  };

// 2. 给原型添加属性和方法
CreateObj.prototype.name = '迪丽热巴';
CreateObj.prototype.age = 39;
CreateObj.prototype.work = function () {
    console.log('工作');
};

// 3. 实例化对象
var obj = new CreateObj();
var obj1 = new CreateObj();
console.log(obj, obj1);
console.log(obj.name, obj1.name);

// 原型链: 在对象或函数被创建的时候所自带的链表关系, 实现继承和查找;
// 找: 先找自身, 在找原型属性  在找object 找到直接返回 找到object都没有 返回undefined
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

混合创建

构造创建(可变的) + 原型创建(不变的)

// 1. 构造函数
function CreateObj(name, age) {
    this.name = name;
    this.age = age;
};

// 2. 给原型添加属性和方法
CreateObj.prototype.work = function () {
    console.log('工作');
};

// 3. 实例化对象
var obj = new CreateObj('张三', 23);
var obj1 = new CreateObj('李四', 33);
console.log(obj, obj1);
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

动态混合创建(了解)

在构造函数中判断原型上的方法和属性是否是期望值 不是的话在进行赋值

// 1. 构造函数
function CreateObj(name, age) {
    this.name = name;
    this.age = age;

    if (typeof this.work == 'function') {
        console.log('已经是函数');
    } else {
        console.log('不是函数');
        // 2. 给原型添加属性和方法
        CreateObj.prototype.work = function () {
            console.log('工作');
        };
    }
};



// 3. 实例化对象
var obj = new CreateObj('张三', 23);
var obj1 = new CreateObj('李四', 33);
console.log(obj, obj1);
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

原型

原型: 用来存储最顶层共享的方法和属性的对象
函数: prototype
对象: __proto__ 
var arr = [1,2,3,4];
arr.push(5);

console.log(arr);
console.log(arr.__proto__);


var brr = new Array(2,3,4,5);
console.log(brr);
console.log(brr.__proto__);
console.log(Array.prototype);

console.log(Array.prototype == brr.__proto__); // true

Array.prototype.push = function () {
    console.log('新方法');
};

brr.push(666);
console.log(brr);

原型链

原型链: 在对象或函数被创建的时候所自带的链表关系, 实现继承和查找;

面向对象的继承

原型链继承

子类构造函数的原型对象 = 父类构造函数的实例化对象;

原型链查找:
    找自身
    自身没有 找自身的原型对象(父类构造函数的实例化对象)
    如果没有 找父类构造函数的原型对象
    找object
    如果没有 返回undefined  如果在哪一步找到了 直接返回结果

constructor:
    当前对象的构造函数

原型链继承: 
    1. 无法识别当前对象真正的构造函数
    2. 一改全改
    3. 不能传参
    4. 子类构造函数身上的原型对象的属性和方法不能继承
// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(){}

Son.prototype.hobby = function () {
    console.log('打游戏');
};

// 3. 设置继承: 子类构造函数的原型对象 = 父类构造函数的实例化对象;
Son.prototype = new Father('韩红', 50);


// 4. 实例化对象
var son1 = new Son();

console.log(son1);
console.log(son1.name);
console.log(son1.name1);

对象冒充继承

在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this

不能继承父类构造函数的原型对象上的方法和属性

// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(name, age){
    // 3. 在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this
    Father.call(this, name, age);
}

Son.prototype.hobby = function () {
    console.log('打游戏');
};

// 4. 实例化对象
var son1 = new Son('张三', 12);
var son2 = new Son('李四', 12);
console.log(son1, son2);
son1.money.push('股票');
console.log(son1.money, son2.money);
/* 
    不能继承父类构造函数的原型对象上的方法和属性
*/
console.log(son1.name1);

组合继承

组合继承: 原型链 + 对象冒充

\1. 子类构造函数的原型对象的方法和属性继承不了

\2. 父类构造函数的属性和方法多次继承

// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(name, age){
    // 3. 在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this
    Father.call(this, name, age);
}

Son.prototype.hobby = function () {
    console.log('打游戏');
};

// 3. 子类构造函数的原型对象 = 父类构造函数的实例化对象
Son.prototype = new Father();

// 4. 实例化对象
var son1 = new Son('张三', 12);
var son2 = new Son('李四', 12);
console.log(son1, son2);
son1.money.push('股票');
console.log(son1.money, son2.money);
/* 
    不能继承父类构造函数的原型对象上的方法和属性
*/
console.log(son1.name1);

寄生式组合继承

Object.create(原型对象): 使用原型对象创建一个对象

/* 
    组合继承: 原型链 + 对象冒充
        1. 子类构造函数的原型对象的方法和属性继承不了
        2. 父类构造函数的属性和方法多次继承
*/
// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(name, age){
    // 3. 在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this
    Father.call(this, name, age);
}

// 3. 子类构造函数的原型对象 = 父类构造函数的实例化对象
// Object.create(原型对象): 使用原型对象创建一个对象
// console.log(Object.create(Father.prototype));
Son.prototype = Object.create(Father.prototype);
// 单独设置
Son.prototype.constructor = Son;

// 后续son的原型对象添加属性和方法
Son.prototype.hobby = function () {
    console.log('打游戏');
};

var son1 = new Son('张三', 12);
console.log(son1);

图示

LESS

简单使用

官网: https://less.bootcss.com/
vscode:
    安装一个插件: easy less 
    koala
在vscode配置插件:
    "out": "../css/",


后续开发:
    less放在less文件夹下
    css放在css下

如果第一个按ctrl+s没有生成css文件  关闭vscode 在尝试保存

html文件中引入还是 .css 文件

注释

// 行注释 不会出现在css中

/*

块注释

会出现在css文件中

*/

// 行注释 不会出现在css中
/* 
    块注释
    会出现在css文件中
*/
*{
    margin: 0;
    padding: 0;
    list-style: none;
}

编译后:

/* 
    块注释
    会出现在css文件中
*/
* {
  margin: 0;
  padding: 0;
  list-style: none;
}

变量

声明变量 @名字: 设置的值;

@w: 200px;
@h: 300px;
@color: orangered;

div{
    width: @w;
    height: @h;
    background: @color;
}

编译后:

div {
  width: 200px;
  height: 300px;
  background: orangered;
}

作用域

作用域用来使用变量 根据就近原则使用

// 全局
@w: 200px;
@h: 300px;
@c: orangered;

*{
    @w: 300px;
    @h: 300px;
    @c: lightblue;

    div{
        @c: green;
        
        width: @w;
        height: @h;
        background: @c;
    }
}

编译后:

* div {
  width: 300px;
  height: 300px;
  background: green;
}

混合

在一个选择器中使用另一个选择器的所有样式

*{
    margin: 0;
    padding: 0;
    list-style: none;
}

.first{
    width: 200px;
    height: 300px;
    background: red;
    margin: 20px;
}

.two{
    .first();
    background: orangered;
    font-size: 30px;
}

编译后:

* {
  margin: 0;
  padding: 0;
  list-style: none;
}
.first {
  width: 200px;
  height: 300px;
  background: red;
  margin: 20px;
}
.two {
  width: 200px;
  height: 300px;
  background: red;
  margin: 20px;
  background: orangered;
  font-size: 30px;
}

嵌套

嵌套的结构与html结构一致

父{

子{}

&表示当前元素, 添加伪类选择器

}

*{
    margin: 0;
    padding: 0;
    list-style: none;

    ul{
        width: 100%;
        // height: 300px;
        background: red;
        li{
            float: left;
            width: 300px;
            // height: 300px;
            overflow: hidden;
            border: 1px solid #000;
            img{
                width: 100%;
                height: 100%;
            }
        }

        &::after{
            content: '';
            display: block;
            clear: both;
            *zoom: 1;
        }
    }
}

编译后:

/* 
    嵌套的结构与html结构一致
    父{
        子{}
        &表示当前元素, 添加伪类选择器
    }

*/
* {
  margin: 0;
  padding: 0;
  list-style: none;
}
* ul {
  width: 100%;
  background: red;
}
* ul li {
  float: left;
  width: 300px;
  overflow: hidden;
  border: 1px solid #000;
}
* ul li img {
  width: 100%;
  height: 100%;
}
* ul::after {
  content: '';
  display: block;
  clear: both;
  *zoom: 1;
}

嵌套规则与冒泡

@ 规则(例如 @media@supports)可以与选择器以相同的方式进行嵌套。@ 规则会被放在前面,同一规则集中的其它元素的相对顺序保持不变。这叫做冒泡(bubbling)。

div{
    width: 800px;
    height: 600px;
    background: red;
    @media screen and (max-width: 992px) {
        background: green;

        @media (min-width: 768px) {
            background: orange;
        }
    }
}

编译后:

div {
  width: 800px;
  height: 600px;
  background: red;
}
@media screen and (max-width: 992px) {
  div {
    background: green;
  }
}
@media screen and (max-width: 992px) and (min-width: 768px) {
  div {
    background: orange;
  }
}

运算

算术运算符 +-*/ 可以对任何数字、颜色或变量进行运算。如果可能的话,算术运算符在加、减或比较之前会进行单位换算。计算的结果以最左侧操作数的单位类型为准。如果单位换算无效或失去意义,则忽略单位。无效的单位换算例如:px 到 cm 或 rad 到 % 的转换。

@w: 200px;
@h: 200px;
div{
    width: @w + 100 + 10em;
    height: @h * 2 + 10pt;
    background: red;
}

编译后:

div {
  width: 310px;
  height: 413.33333333px;
  background: red;
}

转义

转义: ~"字符串" ~'字符串' 新: 字符串

/* 
    转义: ~"字符串" ~'字符串'
    新: 字符串
*/

@max992: ~"(max-width: 992px)";
// @max768: (max-width: 768px);
div{
    width: 1000px;
    height: 400px;
    background: pink;
    @media @max992 {
        background: skyblue;
    }
    // @media @max768{
    //     background: lightcoral;
    // }
}

编译后:

/* 
    转义: ~"字符串" ~'字符串'
    新: 字符串
*/
div {
  width: 1000px;
  height: 400px;
  background: pink;
}
@media (max-width: 992px) {
  div {
    background: skyblue;
  }
}

映射

类似于js中对象的使用,将一组值组合起来使用

#color(){
    normal: #000;
    hl: orangered; 
    ll: lightcoral;
    lg: grey;
}

div{
   
    &:nth-child(1){
        color: #color[normal];
    }
    &:nth-child(2){
        color: #color[hl];
    }
    &:nth-child(3){
        color: #color[ll];
    }
    &:nth-child(4){
        color: #color[lg];
    }
}

编译后:

div:nth-child(1) {
  color: #000;
}
div:nth-child(2) {
  color: orangered;
}
div:nth-child(3) {
  color: lightcoral;
}
div:nth-child(4) {
  color: grey;
}

命名空间

类似于函数 有助于后期重用和重组

/* 
    先定好了一组less
*/
* {
    margin: 0;
    padding: 0;
    list-style: none;
}

#wrap() {
    .box {
        width: 100px;
        line-height: 50px;
        font-size: 30px;
        height: 50px;
        background: red;
    }

    .em{
        color: lightcoral;
    }
}

div {
    width: 200px;
    height: 200px;
    background: pink;

    p {
        #wrap>.box();
    }
}


p {
    #wrap.box();

    em{
        #wrap.em();
    }
}

编译后:

/* 
    先定好了一组less
*/
* {
  margin: 0;
  padding: 0;
  list-style: none;
}
div {
  width: 200px;
  height: 200px;
  background: pink;
}
div p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p em {
  color: lightcoral;
}

导入

在一个less文件中引入其他样式文件

less文件 后缀可以省略

css文件 后缀绝对不能省略

// less文件 后缀可以省略
@import './11';
// css文件 后缀绝对不能省略
@import '../css/07.css';
@import '../css/06.css';

编译后:

/* 
    先定好了一组less
*/
@import '../css/07.css';
@import '../css/06.css';
* {
  margin: 0;
  padding: 0;
  list-style: none;
}
div {
  width: 200px;
  height: 200px;
  background: pink;
}
div p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p em {
  color: lightcoral;
}

本地存储

存储

localStorage.属性名 = 属性值;

localStorage.setItem(属性名, 属性值);

// localStorage.属性名 = 属性值;
localStorage.firstName = '迪丽';

// localStorage.setItem(属性名, 属性值);
localStorage.lastName = '热巴';
console.log(localStorage);

取值

. [] localStorage.属性名 localStorage['属性名']

localStorage.getItem('属性名');

// 取值
// . [] localStorage.属性名  localStorage['属性名']
console.log(localStorage.firstName);
console.log(localStorage['lastName']);

// localStorage.getItem('属性名');
console.log(localStorage.getItem('firstName'));

清除

设置成空字符串

删除: localStorage.removeItem('属性名');

批量清空

// 设置成空字符串
localStorage.firstName = '';

// 删除: localStorage.removeItem('属性名');
localStorage.removeItem('lastName');

// 批量清空 
localStorage.clear();

console.log(localStorage);

json数据与js数据互转

数组包对象

单纯对象

前后端数据交互的时候进行使用

\1. 将json格式的字符串转成js数据:

JSON.parse(数据);

\2. 将js数据转成json格式的字符串

JSON.stringify(数据);

var data = [{
    name: '李四',
    age: 33,
    tip: '提示'
},{
    name: '李四1',
    age: 33,
    tip: '提示'
},{
    name: '李四2',
    age: 33,
    tip: '提示'
}];
localStorage.list = JSON.stringify(data);
console.log(localStorage);

var d = localStorage.list;
console.log(d);
console.log(JSON.parse(d));

audio

属性

src: 播放文件地址

autoplay: 基于用户体验角度 各大浏览器禁止自动播放

controls: 控制器显示

muted: 是否静音

loop: 是否循环播放

currentSrc: 当前播放地址

currentTime: 当前播放时长 单位 s

duration: 音频时长 单位 s

volume: 音乐音量 [0, 1] 最小值 0 最大值 1

paused: 音乐是否暂停播放 true--暂停 false--播放

ended: 音乐是否结束播放 true--结束 false--没有结束 设置了loop 音频重复循环播放 不会结束

playbackRate: 播放速度

// 获取元素
var audio = document.querySelector('audio');

// 获取属性
console.log(audio.src);
audio.autoplay = false;
console.log(audio.autoplay);
// audio.controls = false;
console.log(audio.controls);
// audio.muted = true;
console.log(audio.muted);
audio.loop = true;
console.log(audio.loop);
console.log(audio.currentSrc);
console.log(audio.currentTime);
console.log(audio.duration);
console.log(audio.volume); // 音乐音量 [0, 1]  最小值 0  最大值 1
console.log(audio.paused); // 音乐是否暂停播放 true--暂停 false--播放
console.log(audio.ended); // 音乐是否结束播放 true--结束 false--没有结束 设置了loop 音频重复循环播放 不会结束
console.log(audio.playbackRate); // 播放速度 

btns[0].onclick = function () {
    audio.src = './金玟岐-岁月神偷 (Demo).mp3';
};

btns[1].onclick = function () {
    audio.currentTime = audio.duration / 2;
};

btns[2].onclick = function () {
    audio.volume = 0;
};

btns[3].onclick = function () {
    audio.volume = 0.5;
};

btns[4].onclick = function () {
    audio.volume = 1;
};

btns[5].onclick = function () {
    // 报错: The volume provided (2) is outside the range [0, 1]. 音量只能设置[0,1]之间的值
    audio.volume = 2;
};

btns[8].onclick = function () {
    audio.playbackRate = 0.1;
};

btns[9].onclick = function () {
    audio.playbackRate = 1;
};

btns[10].onclick = function () {
    audio.playbackRate = 10;
};

事件

oncanplay: 音频可以播放事件

ontimeupdate: 播放时间更新的事件

onended: 当音频结束播放事件

onpause: 当音频播放暂停事件

// 音频可以播放事件
audio.oncanplay = function () {
    // console.log(audio.currentSrc);
    // console.log(audio.duration);
};

// 播放时间更新的事件
audio.ontimeupdate = function () {
    // console.log(audio.currentTime);
    // console.log(audio.paused);
};

// 当音频结束播放事件
audio.onended = function () {
    console.log(audio.ended);
};


// 当音频播放暂停事件
audio.onpause = function () {
    // console.log(audio.paused);
};

方法

load: 重新加载音频

pause: 暂停播放

play: 播放音乐

btns[6].onclick = function () {
    audio.load(); // 重新加载音频
    audio.play(); // 播放音乐
};

btns[7].onclick = function () {
    audio.pause(); // 暂停播放
};

video

属性

poster: 图片

src: 播放地址

height: 高

width: 宽

autoplay: 静音下自动播放

muted: 静音状态

controls: 控制器

loop: 循环

currentSrc: 当前播放地址

currentTime: 当前播放时长 单位 s

duration: 音频时长 单位 s

paused: 是否暂停

ended: 结束 loop设置为true 一直false

playbackRate: 当前视频的播放速度

defaultPlaybackRate: 默认视频播放速度

volume: 音量 [0,1]

var video = document.querySelector('video');

console.log(video.src);
console.log(video.poster);
console.log(video.muted);
console.log(video.loop);
console.log(video.controls);
console.log(video.width);
console.log(video.height);
console.log(video.currentSrc);
console.log(video.duration);
console.log(video.currentTime);
console.log(video.paused); // 是否暂停
console.log(video.ended); // 结束 loop设置为true 一直false 
console.log(video.playbackRate); // 当前视频的播放速度
console.log(video.defaultPlaybackRate); // 默认视频播放速度
console.log(video.volume); // 音量 [0,1]
/* 
    芒果: 
        当前播放速度是 2 playbackRate
        下一个视频 播放速度 1 defaultPlaybackRate
    腾讯:
        当前播放速度 2
        下一个视频播放速度 2
*/

事件

oncanplay: 音频可以播放事件

ontimeupdate: 播放时间更新的事件

onended: 当音频结束播放事件

onpause: 当音频播放暂停事件

// 可以播放
video.oncanplay = function () {
    // console.log(video.currentSrc);
    // console.log(video.duration);
};

// 播放时间改变
video.ontimeupdate = function () {
    // console.log(video.currentTime);
};

video.onpause = function () {
    // console.log(video.paused);
};

video.onended = function () {
    // console.log(video.ended); // 结束
};

方法

load: 重新加载音频

pause: 暂停播放

play: 播放音乐

btns[4].onclick = function () {
    video.play();
};

btns[5].onclick = function () {
    video.pause();
};

btns[6].onclick = function () {
    video.load();
};

jQuery

介绍

jquery: js的工具库

事件处理

文档的处理

动画

唯一变量 $ jQuery

强大的选择器

开源

完善的文档

...

jquery:

\1. 官网:

\2. cdn: jquery (v3.6.0) - jQuery 是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器,这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单。 | BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

\3. 文档: jQuery API 中文文档 | jQuery API 中文在线手册 | jquery api 下载 | jquery api chm

版本:

> 2: 不兼容ie

1.xx: 兼容ie

最新版本: 3.6.0

jquery.js: 未压缩 学习

jquery.min.js: 压缩 工作

引入:

\1. 线上

不推荐

\2. 本地



冲突解决

jQuery覆盖其他




其他覆盖jQuery



选择器

基础选择器

基本选择: 标签 类名 id 组合选择器

css选择器怎么写 jq中选择器就怎么写

console.log($('li'));
console.log($('.box'));
console.log($('#six'));
console.log($('#six, .box'));

层级选择器

后代选择器: 父 子

直接子元素: 父 > 子

相邻选择器: 选1 + 选2

兄弟后面的: 选1 ~ 选择2

console.log($('ul li'));
console.log($('ul > li'));
console.log($('.box + div'));
console.log($('li + div'));
console.log($('.box ~ div'));

基础过滤

基础过滤选择器: first last eq gt lt even odd

console.log($('li:first')); // 第一个
console.log($('li:last')); // 最后一个
console.log($('li:eq(0)')); // 获取指定下标的元素
console.log($('li:gt(4)')); // 获取大于指定下标的元素
console.log($('li:lt(4)')); // 获取小于指定下标的元素
console.log($('li:even').css('background', 'red')); // 获取偶数(下标是偶数)
console.log($('li:odd').css('background', 'pink')); // 获取奇数(下标是奇数)
// jq对象.css(属性名, 属性值);
// jq中非语法错误 不会报错

属性过滤

console.log($('li[class]').css('background', 'red')); // 获取带有class属性的li
console.log($('li[class=box]').css('background', 'blue')); // 获取li中class为box的li
console.log($('li[class^=b]').css('background', 'skyblue')); // 获取li中以b字母为开头 
console.log($('li[class$=x]').css('background', 'pink')); // 获取li中以x字母为结尾
console.log($('li[class!=box]').css('background', 'yellow')); // 获取li中class不等于box的li

子元素过滤

子元素过滤: first-child last-child nth-child

$('ul li:first-child').css('background', 'red');
$('ul li:last-child').css('background', 'red');
$('ul li:nth-child(3)').css('background', 'red');

内容过滤

内容过滤: contains empty has parent 了解

console.log($('li:contains(1)').css('background', 'pink'));
console.log($('li:empty').css('background', 'yellow'));
console.log($('li:has(p)').css('background', 'skyblue'));
console.log($('p:parent').css('background', 'red'));

表单过滤

:input 获取所有的表单元素

:type的值

console.log($(':input'));
console.log($(':text'));
console.log($(':password'));
console.log($(':radio'));
console.log($(':checkbox'));
console.log($(':file'));
// console.log($(':date')); // 报错 


// textarea select 直接获取 不需要加:
console.log($('textarea'));

表单属性

console.log($(':enabled'));
console.log($(':disabled'));
console.log($(':checked'));
console.log($(':checkbox:checked')); // 复选框中被选中
console.log($(':selected'));

jq方法特性

\1. 取赋值一体化

既可以获取值 也可以设置值

除了txt 以外 所有方法取值只获取第一个符合选择器条件的元素的值

设置值的时候 迭代设置

\2. 隐式迭代:

每一个方法在设置的时候, 会自动遍历每一个符合选择器的元素并且设置

\3. 链式调用

每个jq方法在执行以后 会将被操作的对象或操作以后的对象返回回来,会了方便下一个方法直接使用

\4. jq对象只能使用jq方法 js对象只能使用js的方法

console.log($('li').css('font-size'));
// console.log($('li').css('font-size', 20));
// var lis = $('li').css('font-size', 20);
// console.log(lis);
// lis.click(function () {
//     console.log(this.innerHTML);
// });

$('li').css('font-size', 20).click(function () {
    // console.log(this.innerHTML);
    console.log(this);
});

查找节点

节点遍历

每个方法都可以接收一个选择器作为筛选条件

console.log($('ul').children()); // 直接子元素
console.log($('ul').children('li')); // 直接li子元素

console.log($('div').parent()); // 直接父元素
console.log($('div').parents()); // 获取到html为止所有的父元素
console.log($('div').parents('body')); 

console.log($('hr').prev()); // 紧跟着hr的上一个元素
console.log($('hr').prevAll()); // hr前面所有的兄弟节点
console.log($('hr').prevAll('li'));

console.log($('hr').next()); // 紧跟着hr的下一个元素
console.log($('hr').nextAll()); // 后面所有的
console.log($('hr').nextAll('div')); // 后面所有的div

console.log($('hr').siblings()); // 获取所有的兄弟节点

节点过滤

console.log($('li').first());
console.log($('li').last());
console.log($('li').eq(3));
$('li').filter('.box').css('background', 'red');
$('li').not('.box').css('background', 'pink');
$('ul').find('.box').css('background', 'skyblue');

操作属性

attr: 可以操作一切属性 不建议属性值为true和false

获取: jq对象.attr('属性名');

设置: jq对象.attr('属性名', '属性值');

移除: jq对象.removeAttr('属性名');

prop: 操作固有属性 建议属性值为true和false

获取: jq对象.prop('属性名');

设置: jq对象.prop('属性名', '属性值');

// console.log($('li').attr('class'));
// console.log($('li').attr('class', 'box abc'));
// $('li').attr('tag', 123);
// console.log($('li').attr('tag'));


console.log($('li').prop('class')); // box a
console.log($('li').prop('class', 'nC'));
console.log($('li').prop('tag', 'aaa'));
console.log($('li').prop('a')); // undefined

// console.log($(':checkbox').attr('checked')); // undefined  checked
// console.log($(':checkbox').prop('checked')); // true
// console.log($(':checkbox').prop('checked', true));

$('li').removeAttr('a');

操作类名

添加: 原有类名的基础上添加

jq对象.addClass('类名 类名');

移除: 原有类名的基础上删除指定

jq对象.removeClass('类名 类名');

切换: 有就删除 没有就添加

jq对象.toggleClass('类名');

判断是否有某个类名: 返回布尔值 true--有 false--没有

jq对象.hasClass('类名');

判断对象是否符合某个选择器:

jq对象.is('选择器');

$('li').addClass('active');
$('li').click(function () {
    // console.log(this); // 触发源
    // $(this).addClass('active');
    // $(this).removeClass('active');
    console.log($(this).hasClass('active'));
    console.log($(this).is('.active'));
    $(this).toggleClass('active');

});

操作样式

jq对象.css();

获取:

jq对象.css(属性名);

设置:

单个: jq对象.css(属性名, 属性值);

多个: jq对象.css({});

{

属性名: 属性值,

属性名: 属性值,

属性名: 属性值

}

属性名: 可以加引号也可以不加 建议加引号

加引号可以使用- 不加引号 使用驼峰命名

属性值:

如果单位是px 省略px 直接写数字

表达式: '+=20' '-=10' 引号必须加

console.log($('div').css('width'));
$('div').css('width', '100px');
$('div').css({
    width: 200,
    height: 300,
    fontSize: 20,
    'font-weight': 800
});

$('div').click(function () {
    $('div').css({
        width: '+=100',
        height: '-=10'
    });
});

元素宽高

client: 可视宽高

innerWidth/innerHeight: 内容+内边距

offset: 占位宽高

outerWidth/outerHeight(布尔值):

false/不传: 内容 + 内边距 + 边框

true: 内容 + 内边距 + 边框 + 外边距

scroll: 滚动距离

console.log($('div').width(), $('div').height()); // 内容宽 内容高
console.log($('div').innerWidth(), $('div').innerHeight()); // 可视宽 可视高
console.log($('div').outerWidth(), $('div').outerHeight()); // 占位宽 占位高
console.log($('div').outerWidth(true), $('div').outerHeight(true)); // 占位宽 占位高

$(window).scroll(function () {
    // console.log($('body,html').scrollTop(), $('body,html').scrollLeft());
    console.log($(window).scrollTop(), $(window).scrollLeft());
});

/* 
    取赋值一体化
*/
console.log($('div').width(500), $('div').height(200));
console.log($('div').innerWidth(500), $('div').innerHeight(200));
console.log($('div').outerWidth(500), $('div').outerHeight(200));
console.log($('div').outerWidth(500, true), $('div').outerHeight(200, true));

$('button').click(function () {
    console.log($(window).scrollTop(500), $(window).scrollLeft(500));
});

元素的位置

position: 获取到的结果是当前元素的定位距离 以对象方式返回

{

left: 0,

top: 0

}

offset: 获取的元素距离body的一个偏移距离

/* 
    position: 获取到的结果是当前元素的定位距离 以对象方式返回
        {
            left: 0,
            top: 0
        }
*/
console.log($('div').position()); // {top: 33, left: 8}
console.log($('div').position().left);

/* 
    offset: 获取的元素距离body的一个偏移距离
*/
console.log($('div').offset());
console.log($('div').offset().left);

添加节点

  1. 创建节点: $('标签节点');

    var li = $('
  2. 12344
  3. '); console.log(li);
  4. 父元素末尾:

    父.append(子);

    子.appendTo('选择器');

    $('ul').append('
  5. a1234
  6. '); $('
  7. b1234
  8. ').appendTo('ul');
  9. 父元素开头:

    父.prepend(子);

    子.prependTo('选择器');

    $('ul').prepend('
  10. c1234
  11. '); $('
  12. d1234
  13. ').prependTo('ul');
  14. 插入某个元素之前:

    参考节点.before(新节点);

    新节点.insertBefore(参考节点);

    $('.box').before('
  15. 新Li1
  16. '); $('
  17. 新Li2
  18. ').insertBefore('.box');
  19. 插入到某个元素之后:

    参考节点.after(新节点);

    新节点.insertAfter(参考节点);

    $('.box').after('
  20. 新Li3
  21. '); $('
  22. 新Li4
  23. ').insertAfter('.box');

删除节点

remove: 删除当前元素 返回被删除掉的元素 不包含原来元素的行为

detach: 删除当前元素 返回被删除掉的元素 包含原来元素的行为

empty: 清空元素 删除当前元素中所有子节点

$('li').click(function () {
    console.log($(this).html());
});

/* 
    remove: 删除当前元素 返回被删除掉的元素 不包含原来元素的行为
    detach: 删除当前元素 返回被删除掉的元素 包含原来元素的行为
    empty: 清空元素 删除当前元素中所有子节点
*/
// $('ul').empty();

$('button').click(function () {
    // var li = $(this).parent().remove();
    var li = $(this).parent().detach();
    console.log(li);

    $('ul').append(li);
});

克隆节点

clone(布尔):

false/不传: 不克隆行为 不保留事件函数

$('li').click(function () {
    console.log($(this).html());
});

/* 
    clone(布尔):
        false/不传: 不克隆行为 不保留事件函数
*/
// var li  = $('li').eq(0).clone().appendTo('ul');
var li  = $('li').eq(0).clone(true).appendTo('ul');
console.log(li);

替换节点

参考节点.replaceWith(新节点);

新节点.replaceAll(参考节点);

/* 
    参考节点.replaceWith(新节点);
    新节点.replaceAll(参考节点);
*/
// $('li').replaceWith('

1234

'); $('
').replaceAll('li');

事件对象

/* 
    以事件处理函数的第一个形参
*/
$(window).click(function (ev) {
    console.log(ev); // jQuery.Event 
    console.log(ev.originalEvent); // js原生事件对象
    console.log(ev.type); // 事件类型
    console.log(ev.target);
    console.log(ev.keyCode); // 键盘编码
    console.log(ev.which); // 跟keyCode一致  比keyCode强大 左中右 123
    console.log(ev.pageX, ev.pageY); // 距离页面
    console.log(ev.clientX, ev.clientY); // 可视区域左上角
    console.log(ev.screenX, ev.screenY); // 屏幕
    console.log(ev.offsetX, ev.offsetY); // 触发源内容左上角 边框会出现负数
});

on

  1. 给一个元素绑定一个事件

    jq对象.on(事件类型, 事件处理函数);

    $('div').on('click', function () {
        console.log(this);
    });
    
  2. 给一个元素的多个事件添加同一处理函数

    jq对象.on('事件 事件 事件...', 事件处理函数)

    $('div').on('click mousedown mouseup', function (ev) {
        console.log(ev.type);
    });
    
  3. 给不同事件添加不同处理函数

    jq对象.on({

    事件: 函数,

    事件: 函数

    });

    $('div').on({
        mousemove: function (ev) {
            console.log(ev.clientX);
        },
        contextmenu: function () {
            console.log('contextmenu');
        }
    });
    
  4. 绑定自定义事件:

    由程序员自己定义的事件

    $('div').on('call', function () {
        console.log('okk');
    });
    
    // 手动触发自定义事件: jq对象.trigger('自定义事件名称');
    setTimeout(function () {
        $('div').trigger('call');
    }, 3000);
    
  5. 事件委托

    jq对象(父).on(事件类型, '子选择器', 事件处理函数);

    this指向的就是每一个子元素

    $('ul').on('click', 'li', function () {
        console.log(this);
    });
    
    $('ul').append('
  6. 1234
  7. ');

one

one: 与on是一样的 只会触发一次

$('div').one('click', function () {
    console.log(1);
});

off

// div添加事件
function aa() {
    console.log(1);
}
$('div').click(aa);
$('div').click(function () {
    console.log(2);
});
$('div').mousedown(function () {
    console.log('down');
});
// $('div').off(); // 取消所有的事件
// $('div').off('click'); // 取消所有的click的事件
// $('div').off('click', aa); // 取消click中名字为aa的事件
// $('div').off('click mousedown'); // 取消所有的click和mousedown所有事件

// jq中事件具有命名空间 事件.名 设置命名空间 避免全局变量的影响
$('div').on('click.cc', function () {
    console.log(3);
});

$('div').off('click.cc mousedown');

合成事件

jq对象.hover()

一个函数: 滑入滑出都触发

两个函数: 第一个滑入 第二个滑出

// $('div').hover(function (ev) {
//     console.log(ev.type);
// });

$('div').hover(function (ev) {
    console.log(ev.type);
}, function (ev) {
    console.log(ev.type, '1-----');
});

阻止冒泡和取消默认行为

$('p').click(function (ev) {
    console.log('p');

    // 阻止冒泡
    // ev.stopPropagation();
    // 取消默认行为
    // ev.preventDefault();

    // 阻止冒泡 + 取消默认行为
    return false;
});
$('div').click(function () {
    console.log('div');
});

动画

show/hide/toggle

show([s,[e],[fn]])

width + height + opacity

不传参: 没有动画效果

传参:

时间: 以ms为单位

运动曲线: 'swing' 'linear'

回调函数: 在动画执行完成后还要执行的操作

$('button').eq(0).click(function () {
    // $('div').show();
    // $('div').show(3000);
    $('div').eq(0).show(3000, 'swing', function () {
        console.log('结束');
    });
    // $('div').eq(1).show(3000, 'linear');
});

$('button').eq(1).click(function () {
    // $('div').hide();
    // $('div').hide(3000);
    $('div').hide(3000, function () {
        console.log('结束');
    });
});

$('button').eq(2).click(function () {
    // $('div').toggle();
    // $('div').toggle(3000);
    $('div').toggle(3000, function () {
        console.log('结束');
    });
});

slideDown/slideUp/slideToggle

slideDown([s,[e],[fn]])

height

不传参: 有动画效果 400ms

$('button').eq(0).click(function () {
    // $('div').slideDown();
    // $('div').slideDown(3000);
    // $('div').slideDown(3000, 'linear');
    $('div').slideDown(3000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(1).click(function () {
    // $('div').slideUp();
    // $('div').slideUp(3000);
    // $('div').slideUp(3000, 'linear');
    $('div').slideUp(3000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(2).click(function () {
    // $('div').slideToggle();
    // $('div').slideToggle(1000);
    // $('div').slideToggle(1000, 'linear');
    $('div').slideToggle(1000, 'linear', function () {
        console.log('结束了');
    });
});

fadeIn/fadeOut/fadeToggle/fadeTo

fadeIn([s,[e],[fn]])

不传参: 有动画效果 400ms

fadeTo(s, to 透明度, e, fn)

$('button').eq(0).click(function () {
    // $('div').fadeIn();
    // $('div').fadeIn(3000);
    // $('div').fadeIn(3000, 'linear');
    $('div').fadeIn(3000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(1).click(function () {
    // $('div').fadeOut();
    // $('div').fadeOut(1000);
    // $('div').fadeOut(1000, 'linear');
    $('div').fadeOut(1000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(2).click(function () {
    // $('div').fadeToggle();
    // $('div').fadeToggle(1000);
    // $('div').fadeToggle(1000, 'linear');
    $('div').fadeToggle(1000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(3).click(function () {
    $('div').fadeTo(400, 0.5);
});

自定义动画

语法一

jq对象.animate({动画参数}, duration, easing, callback)

动画参数: 对象 {width: 300px, height: 500px}

duration: 时长 400ms ms为单位

easing: linear swing

callback: 回调函数 动画完成以后

背景色无法通过jq动画方式实现效果

$('div').click(function () {
    $('div').animate({
        opacity: 0.5,
        width: 500,
        height: 500,
        background: 'black'
        // height: 'toggle'
        // height: 'hide'
    }, 3000, 'linear', function () {
        console.log('结束');
    });

});

语法二

jq对象.animate({动画参数}, {options});

动画参数: 对象 {width: 300px, height: 500px}

options: {

duration: 动画时间,

easing: 运动曲线,

complete: 动画完成后执行的回调函数,

step: 动画每一步执行后的回调函数,

queue: 动画是否进入队列, true--队列中排队 默认值 false--跟随第一个动画一起执行

}

$('div').click(function () {
    $('div').animate({
        width: 500,
        height: 500
    }, {
        duration: 3000,
        easing: 'linear',
        complete: function () {
            console.log('结束');
        },
        step: function () {
            // console.log($(this).width());
        },
        queue: true
    }).animate({
        opacity: 0.3
    }, {
        queue: false,
        duration: 3000
    });
});

动画注意

\1. 动画可以连缀 在连缀的过程中没有特殊设置 默认是进行队列执行

$('div').click(function () {
    $('div').animate({
        left: 500
    }, 1000).animate({
        top: 500
    }, 1000).animate({
        top: 0,
        left: 0
    }, 1000);
});

\2. .css所设置的样式 不会进入动画队列 会跟随第一个动画 在第一时间执行

$('div').click(function () {
    $('div').animate({
        left: 500
    }, 1000).animate({
        top: 500
    }, 1000)
    .css({
        background: 'pink',
        left: '1000px',
        width: 500
    })
    .animate({
        top: 0,
        left: 0
    }, 1000);
});

\3. .queue方法实现插队

jq对象.queue(函数); 函数中写要放进去的代码 函数有一个形参 这个形参是个函数

.queue后面的动画 都不在执行

$('div').click(function () {
    $('div').animate({
            left: 500
        }, 1000).animate({
            top: 500
        }, 1000)
        .queue(function (next) {
            $('div').css({
                background: 'pink',
                // left: '1000px',
                // width: 500
            });
            console.log(next);
            next();
        }).animate({
            top: 0,
            left: 0
        }, 1000);
});

停止动画

jq对象.stop(clearQueue, gotoEnd);

clearQueue: true: 后续的队列中等待执行的动画被清除 false(默认): 执行下一个队列的动画

gotoEnd: true: 当前动画被停止的一瞬间到达目标值 false(默认): 在哪里停止就留在哪个尺寸

finish: 1.8+

jq对象.finish();

将所有的动画一瞬间到达目标值

$('button').eq(1).click(function () {
    // $('div').stop(false, false);
    // $('div').stop(true, false);
    // $('div').stop(true, true);

    $('div').finish();
});

is

is(":animated"):判断是否处于动画中 true--正在动画 false--没有动画

$('div').click(function () {
    console.log(1);
    // 如果当前元素已经在动画中 不允许添加动画
    if(!$('div').is(':animated')){
        console.log(2);
        $('div').animate({
            width: 'toggle',
            height: 'toggle'
        }, {
            duration: 1000,
            step: function () {
                // 判断是否处于动画中 true--正在动画 false--没有动画
                // console.log($('div').is(':animated'));
            },
            complete:function(){
                // console.log($('div').is(':animated'), 'complete');
            }
        });
    }
});

循环

each: 返回原数据

jq对象.each(函数)

$.each(数据, 函数)

map: 返回函数中设置的返回值组成的新数组

jq对象.map(函数)

$.map(数据, 函数)

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// $(arr).each(function (i, v) {
//     console.log(i, v);
// });

// var res = $.each(arr, function (i, v ) {
//     /* 
//         第一个参数: 下标
//         第二个参数: 值
//     */
//    console.log(i, v);
// });
// console.log(res);

var res = $.map(arr, function (v, i ) {
    /* 
        第一个参数: 值
        第二个参数: 下标
    */
   console.log(i, v);
   return v * v;
});
console.log(res);

var obj = {
    name: '迪丽热巴',
    age: 33,
    height: 178
}
// var res = $.each(obj, function (key, val) {
//     console.log(key, val);
// });
// console.log(res);

var res = $.map(obj, function (val, key) {
    console.log(key, val);
    return val;
});
console.log(res);

// var res = $.each($('li'), function (i, ele) {
//     console.log(i, ele);
// });
// console.log(res);

var res = $.map($('li'), function (ele, i) {
    console.log(i, ele);
    return $(ele).html();
});
console.log(res);

extend

$.extend([deep], dist, ....data);

返回拷贝以后的完整数据

deep: 是否进行深拷贝 false/不传: 浅拷贝 true: 深拷贝

浅拷贝: 只对比第一层级的属性名是否相同 如果相同 用后面的覆盖前面的

如果不同 就复制进来

深拷贝: 第一个参数设置成true, 进行的是递归拷贝, 先比较第一册层级的属性名是否重复, 如果重复, 判断属性值是否两边都是object/array, 保证两边数据类型是一样的, 如果不一样直接用后面的覆盖前面的, 如果属性名一样属性值都是object或者都是array, 比较子属性

dist: 默认的目标源 其他数据拷贝到这里

var obj = {
    name: '张三',
    age: 22,
    money: ['电影', '饺子馆', '茶叶蛋', '慈善'],
    gf: {
        name: '迪丽热巴',
        age: 18,
        money: ['衣服', '化妆', '珠宝']
    }
};

var obj1 = {
    name: '李四',
    gf: {
        name: '古力娜扎',
        height: 168,
        money: ['唱歌', "表演", '衣服', '火锅']
    }
}

var obj2 = {
    hobby: {
        h1: '骑马',
        h2: '唱歌'
    }
};

// var res = $.extend(false, obj, obj1, obj2);
// console.log(res);


var res = $.extend(true, obj, obj1, obj2);
console.log(res);

深拷贝合集

  1. JSON.parse(JSON.stringify(数据))

    var res = JSON.parse(JSON.stringify(obj));
    console.log(res);
    console.log(res == obj); // false
    
  2. extend(true, ...data);

    var res1 = $.extend(true, {}, obj);
    console.log(res1);
    console.log(res1 == obj); // false
    
  3. 使用原生js的递归函数实现深拷贝

    深拷贝: Object Array

    在内存中再划分一块内存

    // 获取数据的类型
    function getType(data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    };
    
    // 实现递归拷贝
    function deepClone(data) {
        // data: 需要实现深拷贝的数据
        // 声明对应的数据类型
        // console.log(getType(data));
        if(getType(data) == 'Object'){
            var res = {};
        } else if(getType(data) == 'Array'){
            var res = [];
        } else {
            return data;
        }
    
        // console.log(res);
    
        // 将data数据中的每一个属性名和属性值存储到res中
        for(var key in data){
            // console.log(key, data[key]);
            // 判断要存储的是否是Array或者Object  如果是 调用deepClone
            // console.log(getType(data[key]));
            if(getType(data[key]) == 'Object' || getType(data[key]) == 'Array'){
                res[key] = deepClone(data[key]);
            } else {
                res[key] = data[key];
            }
        }
    
        // console.log(res);
        // 设置返回值
        return res;
    }
    
    var r = deepClone(obj);
    console.log(r);
    console.log(r == obj);
    

ready

onload:

等待页面结构和资源加载完成后在执行的代码

后面的会覆盖前面

ready:

等待页面结构加载完成

叠加执行

可以简写

window.onload = function () {
    console.log(1);
}
$(document).ready(function () {
    console.log(2);
});
$().ready(function () {
    console.log(3);
});

$(function () {
    console.log(4);
});

插件拓展

类级别: $.extend({方法名: 函数, 方法名: 函数})

$.each $.map

$.extend({
    lunbo: function (sel, wait, time) {
        wait = wait ? wait : 5000;
        time = time ? time : 400;
        // console.log($(sel));
        var n = 0;
        var cw = $(sel).find('ul > li').width();
        // console.log(cw);
        function auto() {
            n++;
            if(n == $(sel).find('ul > li').length){
                n = 0;
                $(sel).find('ul').css({
                    left: -n * cw
                });
                n = 1;
            }
            $(sel).find('ul').stop().animate({
                left: -n * cw
            }, time);
            // 设置小圆点
            $(sel).find('p > span').eq(n == $(sel).find('ul > li').length - 1 ? 0 : n).addClass('active').siblings().removeClass('active');
        }
        // 1. 每隔3s换一张图
        $(sel)[0].timer = setInterval(auto, wait);


        // 划上sel清除定时器
        // 划下sel开启定时器
        $(sel).hover(function () {
            console.log(1, $(sel)[0].timer);
            clearInterval($(sel)[0].timer);
        }, function () {
            $(sel)[0].timer = setInterval(auto, 3000);
        });

    }
});

// 调用
// $.lunbo('.wrap');
$.lunbo('.wrap', 3000, 100);

对象级别: $.fn.extend({方法名: 函数, 方法名: 函数})

jq对象.css jq对象.animate

// 轮播图
$.fn.extend({
    lunbo: function (wait, time) {
        console.log(this);
        wait = wait ? wait : 5000;
        time = time ? time : 400;
        var n = 0;
        var cw = $(this).find('ul > li').width();
        // console.log(cw, n);
        // console.log($(this).find('ul'));
        var that = $(this);
        function auto() {
            n++;
            if(n == that.find('ul > li').length){
                n = 0;
                that.find('ul').css({
                    left: -n * cw
                });
                n = 1;
            }
            that.find('ul').stop().animate({
                left: -n * cw
            }, time);
            // 设置小圆点
            that.find('p > span').eq(n == that.find('ul > li').length - 1 ? 0 : n).addClass('active').siblings().removeClass('active');
        }
        // 1. 每隔3s换一张图
        this[0].timer = setInterval(auto, wait);


        // 划上sel清除定时器
        // 划下sel开启定时器
        $(this).hover(function () {
            console.log(1, $(this)[0].timer);
            clearInterval($(this)[0].timer);
        }, function () {
            $(this)[0].timer = setInterval(auto, 3000);
        });

        // 设置返回值
        return $(this);
    }
});

// 调用
var d = $('.wrap').lunbo(3000).css({
    border: '10px solid #aaa'
});
console.log(d);

Zepto

介绍

zepto: 专门给移动端使用的javascript库

核心: $

zepto的方法与jq中是一致的

官网: Zepto.js: 轻量且兼容 jQuery API 的 JavaScript 工具库 | Zepto.js 中文网

\1. 下载zepto文件: 一定通过上面的官网 或者是 cdn服务器下载完整文件

zepto form ie ajax event

\2. 使用zepto




区别

  1. jq有 zepto没有

  2. offset

  3. zepto的宽高直接求得是占位宽高

touch事件

tap: 单击

doubleTap: 双击

longTap: 长按 >750ms

swipe: 滑动

swipeUp swipeDown swipeLeft swipeRight

touch事件只支持移动端使用
下载压缩包后 解压出来的文件夹中只需要使用src 
但是注意: src中的zepto模块不要使用

注释

块注释: /* 注释 */ ctrl+shift+/

行注释: // 注释 ctrl+/

键盘快捷方式:

首选项 ---> 键盘快捷方式 ---> 搜索: comment ---> 修改

调试

调试: 程序员用来验证代码是否正确

调试方式: 输出 断点

输出调试:

  1. alert: 警告框

    alert('内容')

    数字和变量可以不加引号 其他的都要加

  2. prompt: 带有输入框的对话框 可以与用户做交互

    prompt('提示内容', '默认值'); 默认值: 可写可不写

    具有返回值, 可以接受

    确定: 输入框中的内容 取消: null

  3. 输出在页面: document.write(...data);

    ...data: 可以一次性写多个数据, 用,分隔

    只适合在页面加载过程中使用 如果在页面加载完成后使用 全页面内容都会被覆盖(函数)

    可以识别标签 不覆盖自己添加的内容

  4. 输出在控制台: console.log(...data);

    ...data: 可以一次性写多个数据, 用,分隔

    检查-->Console

// alert(1);
​
// alert(prompt('请输入你的姓名'));
​
document.write('这是一个a标签', '这是一个i标签');
document.write('BBBBBB');
​
console.log(123, 345, 567);

断点调试

断点调试: 浏览器右键 --> source ---> 打开要调试的文件 ---> 行数前点一下 (蓝色箭头、红色圆点) ---> 刷新 --> 点击三角箭头

变量

变量: 用来存储数据的容器;

声明变量: var声明

声明方式

  1. 先声明 后赋值

    var 变量名;

    变量名 = 值;

    var a;
    a = 10;
    console.log(a);
  2. 声明的同时赋值:

    var 变量名 = 值;

    var b = 20;
    console.log(b);
  3. 多个声明:

    var 变量名1 = 值1, 变量名2 = 值2, ..., 变量名n = 值n;

    js中 , 分隔 ;一句代码的结束

    var c = 30, d = 40;
    console.log(c, d); // 30 40
  4. 连等声明

    var 变量名1 = 变量名2 = 值;

    var m = n = 50;
    console.log(m, n);

命名规范

\1. 以数字、字母、_、$组成, 数字不开头

\2. 不能是关键字和保留字 var let const for break continue top(浏览器中存储window对象)

\3. 不能重复, 如果重复后面的就会覆盖前面的

\4. 遵循驼峰命名法 多个单词组成一个变量的时候 第二个往后的单词的首字母需要大写

\5. 具有语义化 userName user login password loginPass

/* 
    5. 验证变量名:

*/
var userName = '迪丽热巴';
console.log(userName);
var user1 = '杨洋';
console.log(user1);
var _a = '下划线';
console.log(_a);
var $ = 'js';
console.log($);
// var 1a = 'a1'; 报错
// 用var声明一个变量名为var的变量
// var var = 'var'; 报错
var let = '124'; // 一般不这么写
console.log(let);
var a = 20;
console.log(a);
var a = 30;
console.log(a); // 30

特殊声明

\1. 只声明 不赋值 变量值为undefined

\2. 不用var 全局变量 不遵循垃圾回收机制

\3. 不用var 也不赋值 报错: is not defined

/* 
    1. 只声明 不赋值 变量值为undefined
*/
var a;
console.log(a);

/* 
    2. 不用var 全局变量 不遵循垃圾回收机制
*/
b = 30;
console.log(b);

/* 
    3. 不用var 也不赋值 报错: is not defined
*/
console.log(c);

数据类型

为什么要进行数据类型分类:

\1. 不同的数据类型在内存中存储占用的内存不同

\2. 不同数据类型做的操作不同的 数值->计算 布尔->判断

数据类型:

五大基础数据类型 复杂(复合、引用)数据类型

五大基础:

number

string

boolean

null

undefined

复杂:

object

array

function

判断数据类型:

typeof 数据

typeof(数据)

var a = 30;
console.log(a);
console.log(typeof a); // number

var b = '迪丽热巴';
console.log(b);
console.log(typeof(b)); // string

number

分类

\1. 整型 整数 0 -1 1

\2. 浮点数 小数点后至少一位非0数字

\3. NaN: Not a Number 不是一个数字

\4. 进制数:

八进制: 以0为开头 没有超过8的数字

十六进制: 以0x为开头 0-9a-f表示0-15

\5. 特殊值:

Infinity: 无穷大

-Infinity: 无穷小

e: 10的幂次

var a = 1.0;
console.log(a);

var b = 1.000001;
console.log(b);

var c = 1.1234567891234567891;
console.log(c);
console.log(typeof c); // number

var n = NaN;
console.log(n);
console.log(typeof n); // number

var m = 10 - 'a';
console.log(m);

// 八进制
var num = 070;
console.log(num);

// 十六进制
var num1 = 0xa;
console.log(num1);

// 无穷大
var num2 = 1 / 0;
console.log(num2);

// e
var num3 = 2e2; // 2 * 10的2次方 = 200
console.log(num3);

NaN出现

\1. 自己声明

\2. 计算错误

NaN特性

\1. NaN属于数值类型 typeof后返回number

\2. NaN和任何数值都不相等 包括自身

\3. NaN与任何数值计算结果都是NaN

var m = 10 - 'a';
console.log(m);

console.log(NaN == NaN); // false
console.log(1 - NaN); // NaN

注意

注意: 当小数做计算, 由于计算机存储精度的问题, 有偏差

console.log(0.2 + 0.3);
console.log(0.1 + 0.2); // 0.30000000000000004

string

字符串: 用成对的引号包裹的内容

var str = 'abcd';
var str1 = '1234';
console.log(typeof str, typeof str1);

当字符足够长的时候, 需要换行显示, 可以使用\转义换行为字符串

var str = '正义虽然会迟到,但永远不会缺席.由孙红雷、张艺兴、刘奕君主演的《扫黑风暴》已经圆满收官,该作品根据真实案件改编而成,一经上线立马成为年度最热门的剧集。\
据统计,该剧首播日在6小时内就实现了播放量破亿,收视率全国同时段第一的好成绩。\
目前累计播放量44亿,弹幕互动量突破1600万、豆瓣高达8.0分,自开播以来20多天稳居收视率第一的宝座,这种成绩可以说创造了一个收视奇迹。';
console.log(str);

length: 字符串.length 可以得到当前字符串中字符的个数

console.log(str.length);

下标: 从左往后, 从0开始的数字

指定下标对应的字符: 字符串.charAt(下标)

指定下标对应的字符: 字符串[下标] ie8+

// 指定下标对应的字符: 字符串.charAt(下标)
console.log(str.charAt(49));
// 指定下标对应的字符: 字符串[下标] ie8+
console.log(str[49]);

变量和字符串: 变量拼接: 1. 删除 2. 加 加一组引号(与最外层引号一致) 和2个+ 3. 在+中间 拼接变量名

var name = 'javascript';
var age = 26;
var str = '' + name + '出现了' + age + '年';
console.log(str);

boolean

boolean: 布尔, 只有 true 和 false

true: 为真

false: 为假

判断条件 或者 判断条件的结果

var bool = true;
console.log(bool);
console.log(typeof bool); // boolean

// 判断条件
if(true){
    console.log(1);
}

// 判断条件
console.log(1 == 1); // true
console.log(1 == 2); // false

null

null: 只有一个值 就是本身 null js中唯一的真正的空

// 一般用作占位
var n = null;
console.log(n);
console.log(typeof n); // object

undefined

undefined: 未定义 当声明未赋值

var a;
console.log(a); // undefined
console.log(typeof a); // undefined

注意

js中规定 null和undefined是相等的

console.log(null == undefined); // true

null与undefined的区别

null: 真正的空

undefined: 未定义 当声明未赋值

强制转换

为什么要强制转换

所有通过输入框得到的数据 都是字符串

字符串加法 实现的是拼接

强制转换-number

Number(数据);

可以null和布尔值以及字符串中的空字符、空格字符、纯数字字符, 其他的都会被转成NaN

console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number('')); // ''中间没有任何字符 0
console.log(Number('      ')); // 0
console.log(Number('9087')); // 9087
console.log(Number('9087a')); // NaN
console.log(Number('a9087')); // NaN

parseInt

parseInt: 从左往右依次转换每一个字符, 遇到不能转换的或者到结尾就会结束转换, 保留整数

当第一个字符就不能转换的时候 返回NaN

console.log(parseInt('200px')); // 200
console.log(parseInt('155.8px')); // 155

parseFloat

parseFloat: 从左往右依次转换每一个字符, 遇到不能转换的或者到结尾就会结束转换, 保留小数

当第一个字符就不能转换的时候 返回NaN

console.log(parseFloat('155.8px')); // 155.8

强制转换-string

toString()

数据.toString()

将其他数据类型,转成字符串 null和undefined不能转换

在js中 .相当于白勺的

var num = 10;
console.log(num);
console.log(num.toString());
// 了解: 数值类型的时候: 小括号写进制
console.log(num.toString(8));

String

String(数据);

可以转换一切数据类型

console.log(String(10));
console.log(String(null));
console.log(String(undefined));

区别

toString 和 String区别

\1. toString: 对象的方法 可以自己修改 不能转换null和undefined

\2. String: 强制转换的方法 能转换null和undefined

强制转换-boolean

了解js的真和假:

假: false 0 NaN 空字符 null undefined

Boolean(数据): true false

console.log(false);
console.log(Boolean(1));
console.log(Boolean(-1));
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('')); // false
console.log(Boolean(' ')); // true
console.log(Boolean('a')); // true
console.log(Boolean(null)); // false
console.log(Boolean(undefined));// false

// 对象: {} 空对象
// 数组: [] 空数组
var obj = {};
console.log(obj);
console.log([]);

隐式转换方法

isNaN

isNaN(数据): 判断数据 是不是 不是一个数字

true: 不是一个数字

false: 是一个数字

隐式调用 Number 方法 如果Number转出来的不是NaN 返回false 是NaN 返回true

console.log(isNaN(true)); // Number(true)-->1  false
console.log(isNaN('true')); // Number('true')-->NaN true
console.log(isNaN(undefined)); // Number(undefined)-->NaN true
console.log(isNaN(parseInt('22.5px'))); // parseInt('22.5px')-->22 Number(22)-->22 false

toFixed

toFixed: 保留几位小数

将数值保留n位小数转化成字符串

数值.toFixed(数字);

数字: 保留的小数的位数

// var num = 2.3333333;
// var num = 2.500001;
var num = 2.499991;
console.log(num.toFixed(2));
console.log(typeof num.toFixed(2));

运算符

概念

运算符: 用来实现程序执行计算的符号 一般操作两个操作数及以上的符号

例: 1 + 2 +: 运算符 1、2: 操作数

表达式

表达式: 由2个或以上的操作数和运算符组成的式子

1 + 2

var a = 10;

分类:

运算符:

算术运算符: + - * / %(模) ++(自加) --(自减)

赋值运算符: = += -= *= /= %=

比较运算符: > >= < <= == === != !==

逻辑运算符: &&(与) ||(或) !(取反)

三目(元)运算符: 条件 ? 条件为真执行的代码 : 条件为假执行的代码;

表达式: 由运算符做决定的

算术表达式

赋值表达式

比较表达式

逻辑表达式

三目表达式

算术运算符

+ - * / % ++ --

基础

console.log(10 + 20); // 30
console.log(10 - 20); // -10
console.log(10 * 20); // 200
console.log(20 / 10); // 2
// %: 取余  模 
console.log(20 % 3); // 2
console.log(20 % 2); // 0

++

++: 在自身基础上加1 可以放在变量的前面 也可以放在后面

++和其他运算放在一起的时候, ++在前, 先自加, 在执行其他运算, ++在后, 先运行其他运算, 在自加

var a = 10;
a++; // 10 + 1 = 11 --> a
console.log(a); // 11
++a; // 11 + 1 --> 12 --> a
console.log(a); // 12

// ++和其他运算放在一起的时候, ++在前, 先自加, 在执行其他运算, ++在后, 先运行其他运算, 在自加
var b = 10;
console.log(b++); // 输出和++放在一起 先输出b=10 在自加10+1=11
console.log(b); // 11

var c = 10;
console.log(++c); // 输出和++放在一起, 先自加10+1=11 在输出c=11
console.log(c); // 11

--

--: 自减 可以放在前面可以放在后面

--和其他运算在一起的时候, --在前, 先自减, 在执行其他运算; --在后, 先执行其他运算, 在自减

// --: 自减 可以放在前面可以放在后面
var d = 10;
d--;
console.log(d); // 9
--d;
console.log(d); // 8

// --和其他运算在一起的时候, --在前, 先自减, 在执行其他运算; --在后, 先执行其他运算, 在自减
var m = 10;
console.log(m--); // 输出和-- 先输出m=10 再自减m=9
console.log(m); // 9


var n = 10;
console.log(--n); // 先自减 m = 9  再输出m=9

隐式转换规则

隐式转换的规则主要发生在算术运算符之间:

\1. 有字符串的加法就是拼接

\2. 没有字符串的加法的其他运算, 尽可能的将数据都转成数值类型后在计算 隐式调用Number方法

\3. 数值之间正常计算

\4. 遇到复杂数据类型, 会先调用数据的toString方法转换成字符串之后, 在参考上述规则

console.log(1 + 'a'); // 1a
console.log('a' + true); // atrue
console.log('a' + null); // anull


console.log('a' - 10); // NaN - 10 = NaN
console.log(true * 100); // 1 * 100 = 100
console.log(100 / null); // 100 / 0 = Infinity


console.log('a' + {}); // a[object Object]
console.log('a' + [1,2]); // a1,2

var a = '10';
a++;
console.log(a); // 11

赋值运算符

赋值: = += -= *= /= %=

将等号右边的赋值给左边

var a = 10; // 将10给了a
// a+=b: a = a + b;
a += 100;
console.log(a); // 110

a -= 20;
console.log(a);

a*=2; // a = a * 2;
console.log(a);

a /= 3;
console.log(a); // 60

a %= 50; // a = a % 50; 
console.log(a); // 10

比较运算符

> >= < <= 用左右两边的数据进行比较判断 如等式成立 返回true 否则返回false

console.log(1 > 2); // false
console.log(2 >= 1); // true
console.log(1 < 2); // true
console.log(1 <= 2); // true

== ===用于数据的比较判断

== 只比较值是否相等

=== 比较值是否相等 比较数据类型是否一致

// == ===用于数据的比较判断
// == 只比较值是否相等
console.log(1 == 1); // true
console.log(1 == '1'); // true
// === 比较值是否相等 比较数据类型是否一致
console.log(1 === '1'); // 值相等 数据类型不等 false

!=: 只比较值是否不相等

!==: 比较值是否不相等 比较数据类型是否不一致

// !=: 只比较值是否不相等 
console.log(1 != '1'); // false
console.log(1 != 2); // true
// !==: 比较值是否不相等 比较数据类型是否不一致
console.log(1 !== 1); // false
console.log(1 !== '1'); // 数值1 !== 字符串1 值相等 数据类型不等 true

字符串的比较: 从左往右依次比较每一个字符的ASCII码

''空字符串--0 '0'--48 '9'--57 'A'--65 'Z'--90 'a'--97 'z'--122

console.log('10000' < '2' ); // true 49 < 50 ? true
console.log('1000' < '1'); // 48 < 0 ? false

逻辑运算符

逻辑: && || !

&&

&&: 左右两边各自有一个判断条件, 如果两个条件都为真, 整个返回true, 如果有一个条件为假, 整个返回false

全真为真 一假为假

console.log(true && false); // false
console.log(1 < 2 && 2 < 3); // true && true true
console.log(1 > 2 && 2 < 3); // false && true false

||

||: 左右两边各自有一个判断条件, 如果两个条件都为假, 整个返回false, 如果有一个条件为真, 整个返回true

全假为假 一真为真

console.log(true || false); // true
console.log(1 < 2 || 2 > 3); // true || false true
console.log(1 > 2 || 2 > 3); // false || false false

!

!: 取反 返回的结果是true false

如果原来的是true 取反返回false 如果原来是false 取反就是true

js中为假: false 0 NaN '' null undefined

console.log(!''); // true
console.log(!1); // false
console.log(!{}); // false

短路运算

短路运算: 取值(两个值选择一个) 判断运算

逻辑与短路

逻辑与短路: 如果&&左边第一个条件为假, 第二个条件不执行 如果第一个为真 执行第二个条件

var a = 1, b = 1;
var c = --a && --b; // --a a = 0 0是假
console.log(c, a, b);


var m = 1, n = 1;
var d = m-- && n--; // 1 1是真 (m--: m =0)  1 && n-- n = 1 d = 1 n-1 = 0
console.log(d, m, n); // 1 0 0

逻辑或短路

逻辑或短路: 如果第一个条件为真, 第二个条件不执行 如果第第一个条件为假 执行第二个条件

var o = 1, p = 1;
var mn = o-- || p--; // o-- --在后 1 || p-- o=0  1 || p-- 1为真 p--不执行
console.log(mn, o, p); // 1 0 1

三目运算符

三目: 条件 ? 条件为真的时候执行的代码 : 条件为假的时候执行的代码;

代码只能有一句代码

1 > 2 ? alert('哇、1你牛了啊') : alert('还是2厉害');

运算优先级

获取元素

通过id获取

通过id: 通过id获取到的是单独的一个元素

语法: document.getElementById('id')

document: 文档

get: 获取

Element: 元素

ById: 通过id

var b = document.getElementById('box');
console.log(b);

通过标签获取

通过标签名: 获取到的是一个集合, 不可以直接做任何操作(添加事件、加样式)

语法: document/父元素.getElementsByTagName('标签名');

集合: 类数组, 有长度 有下标 但是不能使用数组的方法

长度: length

下标: 从左往右从0开始的数字

即使只有一个符合条件的元素, 当前拿到的也是集合

// 获取li
var lis = document.getElementsByTagName('li');
console.log(lis); // HTMLCollection(5) [li, li, li#box, li, li, box: li#box]
console.log(lis.length); // 5个
console.log(lis[0]); // 得到第一个li

// 获取ul
var uls = document.getElementsByTagName('ul');
console.log(uls); // HTMLCollection [ul]
console.log(uls[0]);

var ul = document.getElementsByTagName('ul')[0];
console.log(ul);

// 获取ul中的li
var lis1 = ul.getElementsByTagName('li');
console.log(lis1); // HTMLCollection(5) [li, li, li#box, li, li, box: li#box]

通过类名获取

通过类名: 获取到的是一个集合, 不可以直接做任何操作(添加事件、加样式)

语法: document/父元素.getElementsByClassName('classname');

集合: 类数组, 有长度 有下标 但是不能使用数组的方法

长度: length

下标: 从左往右从0开始的数字

即使只有一个符合条件的元素, 当前拿到的也是集合

ie8+

// 通过one获取元素
var ones = ul.getElementsByClassName('one');
console.log(ones);

鼠标事件

事件三部曲

事件三部曲:

\1. 找到谁 获取元素 获取到鼠标要操作的元素

\2. 加事件 元素.事件 = function (){

\3. 具体要做的操作

}

注意: 集合一定要通过下标获取到具体的元素之后 才能添加事件 否则没有效果

// 1. 获取 div
// 集合一定要通过下标获取到具体的元素之后 才能添加事件 否则没有效果
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 2. 加事件
div.onclick = function () {
    // 3. 具体要做的操作
    console.log('点击');
};

鼠标事件

\1. 单击: onclick

\2. 双击: ondblclick

\3. 划入: onmouseenter onmouseover

\4. 划出: onmouseleave onmouseout

\5. 按下: onmousedown

\6. 抬起: onmouseup

\7. 移动: onmousemove

\8. 右键菜单: oncontextmenu

// 1. 获取 div
// 集合一定要通过下标获取到具体的元素之后 才能添加事件 否则没有效果
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 2. 加事件
div.onclick = function () {
    // 3. 具体要做的操作
    console.log('点击');
};


div.ondblclick = function () {
    console.log('双击');
};

// 划入
div.onmouseenter = function () {
    console.log('enter');
};
div.onmouseover = function () {
    console.log('over');
};

// 划出
div.onmouseleave = function () {
    console.log('leave');
};
div.onmouseout = function () {
    console.log('out');
};

// 按下
div.onmousedown = function () {
    console.log('down');
};
div.onmouseup = function () {
    console.log('up');
};

// 移动
div.onmousemove = function () {
    console.log('move');
};

// 右键
div.oncontextmenu = function () {
    console.log('menu');
};

over与enter的区别

enter: 子元素不会触发父元素身上的事件

over: 子元素会触发父元素身上的事件

// 1. 获取元素
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 2. 加事件 元素.事件 = function(){}
div.onmouseenter = function () {
    console.log('enter');
};

div.onmouseover = function () {
    console.log('over');
};

操作元素内容

操作单标签内容

单标签中只有表单标签有元素的内容, 写在value上

操作表单元素的值:

获取: var 变量 = 元素.value;

设置: 元素.value = 值;

// 1. 获取输入框
var inp = document.getElementsByTagName('input')[0];
console.log(inp);

// 2. 获取:  var 变量 = 元素.value;
var txt = inp.value;
console.log(txt);

// 3. 设置: 元素.value = 值;
inp.value = '张三';

// 4. 操作下拉列表
// 通过select的value直接拿到当前选中值
var sel = document.getElementsByTagName('select')[0];
console.log(sel);
var city = sel.value;
console.log(city);
sel.value = '广州';

操作闭合标签内容

操作闭合标签内容:

获取: var 变量名 = 元素.innerHTML/innerText;

设置: 元素.innerHTML/innerText = 值;

innerHTML与innerText的特性:

\1. innerHTML可以识别标签

\2. innerText不可以识别标签

\3. 都是操作闭合标签, 后面的会覆盖前面的

基于原有内容基础上来设置: 元素.innerHTML/innerText = 原内容 + 新内容;

// 1. 获取div
var div = document.getElementsByTagName('div')[0];
console.log(div);

// 2. 获取内容
var txt = div.innerText;
console.log(txt);

var html = div.innerHTML;
console.log(html);


// 3. 设置内容
// div.innerText = '这是一个斜体标签';
// div.innerHTML = '这是一个斜体标签1111';

// 4. 基于原有内容基础上来设置 元素.innerHTML/innerText = 原内容 + 新内容;
div.innerText = txt + '这是斜体标签';
div.innerHTML = html + '这是斜体标签111';

操作属性

获取: var 变量名 = 元素.属性名;

设置: 元素.属性名 = 值;

所有的属性都可以用上述方式操作, 其中class例外, 由于class关键字, 不能直接使用, 使用className

// 1. 获取元素
var div = document.getElementsByTagName('div')[0];
console.log(div);

// 2. 获取
var id = div.id;
console.log(id);
console.log(div.title); // div
console.log(div.className); // one

// 3. 设置 元素.属性名 = 值;
div.id = 'wrap';

// 4. 在轮播图中 设置当前被选中
div.className = 'active';

// 获取img
var img = document.getElementsByTagName('img')[0];
console.log(img);
// 设置地址
img.src = './img/2.jpg';

操作样式

单个样式设置

只做设置不做获取

设置样式: 通过js都是行内样式

元素.style.属性名 = 值;

在js中, -连字符不能使用, 需要转成驼峰命名法

// 1. 获取div
var div = document.getElementsByTagName('div')[0];
console.log(div);

// 2. 设置样式
div.style.width = '200px';
div.style.height = '200px';
div.style.background = 'pink';
div.style.fontSize = '30px';

批量设置样式:

元素.style.cssText = '属性名: 属性值; 属性名: 属性值;';

cssText直接设置给style属性, 覆盖原来标签上的行内样式

div.style.cssText = 'width: 300px;height: 300px; background: skyblue; font-size: 50px;';

流程控制语句

分类

流程控制语句: 代码按照什么顺序执行的语句

顺序语句: 默认从上到下执行

条件语句(分支语句): 多条(2条以上)分支中选择 if if-else if-else-if switch

循环语句: for while do-while for-in

其他语句: break continue

分支语句

if

if: 判断代码是否执行

if(条件){

条件为真的时候执行的代码;

}

var core = prompt('请输入成绩');
console.log(core);
// 如果core大于60 弹出及格
// if(core > 60){
//     alert('及格');
// }

if-else

if-else:

if(条件){

条件为真的时候执行的代码;

} else {

条件为假的时候执行的代码;

}

// 如果core大于60 弹出及格 否则弹出继续努力
if(core > 60){
    alert('及格');
} else {
    alert('继续努力');
}

if-else-if

if-else-if: 用于多个条件

if(条件1){

条件1为真,执行的代码;

} else if(条件2){

条件2为真, 执行的代码;

} else if(条件3){

条件3为真, 执行的代码;

} else {

以上条件都不符合的时候,执行的代码;

}

if (core >= 80) {
    alert('A');
} else if (core >= 70 && core < 80) {
    alert('B');
} else if (core >= 60 && core < 70) {
    alert('C');
} else {
    alert('D');
}

switch

switch: 适用于条件和结果都单一的时候

条件: 判断某一个变量或者是某一个具体的值

结果: 指向的是具体的一个值 + - * / 100 60

break: 防止穿透, 如果不加, 当条件匹配到一个符合的结果后, 后续的结果都不匹配, 直接执行后面所有的代码;

switch(条件){
    case 结果1:
        当条件符合结果1执行的代码;
        break;
    case 结果2:
        当条件符合结果2执行的代码;
        break;
    case 结果3:
        当条件符合结果3执行的代码;
        break;
    default:
        以上结果都不符合的时候 执行的代码;
        break;
}
switch (str) {
    case '+':
        console.log(10 + 20);
        break;
    case '-':
        console.log(10 - 20);
        break;
    case '*': 
        console.log(10 * 20)
        break;
    case '/': 
        console.log(10 / 20);
        break;
    default: 
        console.log('超出运算范围了');
        break;
}

分支嵌套

两个及以上分支语句嵌套使用

// 弹出输入框 输入成绩 0-100
var core = prompt('请输入成绩');

// 判断成绩的可选范围
if(core >= 0 && core <= 100){
    if (core >= 80) {
        alert('A');
    } else if (core >= 70 && core < 80) {
        alert('B');
    } else if (core >= 60 && core < 70) {
        alert('C');
    } else {
        alert('D');
    }
} else {
    alert('请输入0-100之间的数字');
}

循环语句

for

语法

将一段代码重复执行多次(指定循环次数)

将一段代码执行指定的循环次数的过程

for(表达式1; 表达式2; 表达式3){

循环体;

}

for(初始化变量; 循环结束条件; 变量更新){

重复执行的代码块

}

初始化变量: var 变量 = 起始值; 数字 0 1 循环的次数从几开始的

循环结束的条件: 条件为真 循环执行 条件为假 循环结束

变量更新: 变量++ 变量--

循环结束的条件必须可用的 否则形成死循环

// 1--100
for(var i = 1; i <= 100; i++){
    console.log(i);
}

// 从50输出到0
for(var i = 50; i >= 0; i--){
    console.log(i);
}

// 循环结束的条件必须可用的 否则形成死循环
// for(var i = 5; i < 10; i--){
//     console.log(i);
// }

变异for

初始化变量;

for(;循环条件;){

循环体;

变量更新;

}

var j = 1;
for(;j<=5;){
    console.log(j);
    j++;
}

注意:

\1. 变异格式中两个分号不能省略

\2. 初始化的变量都是全局变量

\3. 循环执行完成后, 变量留在循环结束的数值

var j = 1;
for(;j<=5;){
    console.log(j);
    j++;
}

console.log(j); // 6

使用情况:

连续的数值

每一个

所有

渲染页面

数据一般都是通过数据请求的方式 由后台返回给我们

页面的数据一般都不是固定数据

数组、对象

多个数据的时候一般用数组

var 变量 = [值, 值1, 值2, ... 值n];

有长度有下标 通过下标的方式从数组中取出对应下标的值

取值: 数组[下标]

while

初始化变量;

while(条件){

循环体;

变量更新;

}

var i = 1;
while(i <= 5){
    console.log(i);
    i++;
}

do-while

初始化变量;

do{

循环体;

变量更新;

}whlie(循环条件);

var j = 1;
do{
    console.log(j, 'j');
    j++;
}while(j <= 5);

for和while

for: 明确循环次数 length 5 10 100

while: 不明确循环次数

while和do-while

while: 先判断后执行

do-while: 先执行后判断

其他语句

break: 防止穿透; 结束整个循环;

continue: 结束本次循环;

// 水饺: 20
for(var i = 1; i <= 20; i++){
    if(i == 5){
        // break; // 吃到虫子 1-4
        continue; // 掉到地上 1-4 6-20
    }
    console.log(i);
}

循环嵌套

for(外层初始化变量; 外层判断条件; 外层变量更新){

for(内层初始化变量; 内层判断条件; 内层变量更新){

内层循环体;

}

}

外层循环执行一次 内层循环执行一轮

// 行循环
for (var i = 1; i <= 5; i++) {
    // 列循环
    for (var j = 1; j <= 5; j++) {
        document.write('⭐️');
    }
    // 行结束之前添加换行
    document.write('
'); }

对象

对象: 用来存储无长度、无顺序的数据

一般用来做前后台交互

{键: 值, 键: 值} 键值对

键建议加引号, 不加引号可以使用

也叫做json格式的数据

取值: 对象.键 对象['键'/变量]

存值: 对象.键 = 值; 对象['键'/变量] = 值;

在js中 .相当于白勺的 .后面本身就是字符串 在整个js中都适用

var user = {
    'name': '杨洋',
    age: 33,
    'height': 188
};
console.log(user);

// 取值: 对象.键
console.log(user.name);
// console.log(user.'name'); // .后面不能直接加字符串
// 在js中 .相当于白勺的 .后面本身就是字符串 在整个js中都适用
// 取值: 对象['键'/变量]
console.log(user['name']);

var a = 'name';
console.log(user[a]);

// 存值: 对象.键 = 值; 对象['键'/变量] = 值;
user.girlFriend = '迪丽热巴';
user['gf1'] = '古力娜扎';

console.log(user);

for-in

for(var 变量 in 数据){

变量: 键

数据[变量]: 值

}

for(var key in user){
    console.log(key, user[key]);
}

// forin不仅仅可以遍历对象 也可以遍历数组、集合
var arr = ['a', 'b', 'c'];
for(var i in arr){
    console.log(i, arr[i]);
}

函数

概念

函数: 将具有独立功能的代码块整合命名的代码

作用: 减少页面代码 提高页面执行速度 页面结构更加清晰

使用:

\1. 事件处理函数: 元素.事件 = function(){}

function(){}--->函数

\2. 对象的方法:

var obj = {

abs: function(){} ---> 函数

}

\3. 封装复用

声明

函数: 由事件驱动的或者在有需要的时候被调用的代码块

注意: 函数只声明 没有任何效果

声明函数:

  1. 函数声明:

    1.1 函数:

    语法: function 函数名(){

    函数体;

    }

    1.2 调用函数:

    函数名();

    fn();
    function fn() {
        console.log(1);
    };
    // fn();
    // fn();
    // fn();
    // fn();
    // fn();
    
  2. 字面量声明:

    2.1 函数:

    语法: var 变量名 = function(){

    函数体;

    }

    2.2 调用函数:

    函数名();

    // fn1 is not a function: fn1不是一个函数
    // fn1();
    var fn1 = function () {
      console.log(2);
    };
    // fn1();
    

注意

函数名和变量名在这里是一样, 命名规范一致的

区别: 函数声明的方式调用可以在声明之前或者之后, 字面量声明的方式调用只能在声明之后;

参数

当遇到不确定的值, 就需要抽取成形参, 在调用的时候, 不同数据传进去

形参: 形式参数, 写在函数function后面的()里, 用来接收实际传递过来的数据

类似变量, 命名规范和变量一致

实参: 实际传递过来的数据, 写在函数调用的()里

arguments:存在于每一个函数中, 是实参的集合

一般形参和实参一一对应

单个参数

// 单个参数
function sum(a) {
    // 求和
    var s = 0;
    // 1 + 2 + 3 + 4 + ... + 100
    for(var i = 1; i <= a; i++){
        // s = s + i;
        s += i;
    }
    console.log(s);
};
// 调用
sum(100);
sum(1000);
sum(2000);

多个参数

多个参数: 用,隔开

// 50-80  90-100 1000-10000
// 多个参数: 用,隔开
function sum1(start, end) {
    // 求和
    var s = 0;
    // 1 + 2 + 3 + 4 + ... + 100
    for(var i = start; i <= end; i++){
        // s = s + i;
        s += i;
    }
    console.log(s);
};
sum1(1, 100);
sum1(50, 80);

arguments

如果参数个数不确定, 形参和实参干脆一个都不写, 直接使用arguments

arguments: 存在于每一个函数中, 是实参的集合

function sum2() {
    console.log(arguments);
    // 将arguments中的每个数据加起来
    var s = 0;
    for(var i = 0; i < arguments.length; i++){
        console.log(arguments[i]);
        s += arguments[i];
    }
    console.log(s);
}
sum2(3,4,5,6,7,8);
sum2(40,50,60);

形参和arguments的关系:

两者互相影响

function fn(a) {
    console.log(a, arguments);
    a = 50;
    console.log(a, arguments);
    arguments[0] = 100;
    console.log(a, arguments);

};
fn(30);

函数问题

  1. 形参实参不一一对应:

    形参 > 实参: 多余的形参就是undefined

    实参 > 形参: 多余的实参不能通过形参获取

    function fn(a, b) {
        console.log(a, b);
    };
    fn(10); // a = 10 b = undefined
    fn(10, 20, 30); // a = 10 b = 20
    
  2. 函数重名:

    函数名重名: 后面的覆盖前面的

    函数和变量名重名: 变量覆盖函数

    function a() {
        console.log('a');
    }
    function a() {
        console.log('a1');
    }
    
    a(); // a1
    
    
    var b = 30;
    function b() {
        console.log('b');
    }
    // b(); // b is not a function
    
  3. 函数封装

    \1. 声明空函数

    \2. 实现单个效果

    \3. 调用

    \4. 抽参

    \5. 传参: 把谁抽出来 把谁传进去

    function getOdd(a) {
        // 0--10
        for(var i = 0; i <= a; i++){
            // 偶数: 被2整除 取余等于0
            if(i % 2 == 0){
                console.log(i);
            }
        }
    }
    
    getOdd(10);
    getOdd(66);
    getOdd(100);
    

参数的数据类型

所有数据类型都可以做为参数

一般不用null和undefined作为参数

由于null好undefined不具有实际意义 所以一般不使用

function getType(a) {
    console.log(a, typeof a);
}
getType(10);
getType('中公');
getType(true);
getType(null);
getType(undefined);
var m = {a: 1};
getType(m);
getType([1,2,3,4]);

function fn() {
    console.log(1);
}
getType(fn);

作用域

作用: 读(获取)、写(设置)

域: 区域

作用域: 变量和函数被读写的区域

es5中 作用域通过函数来划分, 又叫做函数作用域

全局作用域: script标签下

全局变量、全局函数, 可以在整个js中被读写

局部作用域: function的{}里

在局部作用域中, 用var\function声明的变量和函数, 叫做局部变量、局部函数, 只在当前作用域起作用, 如果出了{} 会被销毁

// 全局作用域
var n = 10; // 全局变量
function fn() { // 全局函数
    // 局部作用域
    console.log(n); // 10
    var z = 1;
    console.log(z); // 1
}
fn();
console.log(z); // 报错

作用域链

作用域链: js的一种查找机制, 决定了变量和函数向上一级作用域查找的过程

查找过程: 先找自身作用域, 如果自身作用域有,直接返回, 如果自身没有,往上一级作用域查找, 直到到全局作用域,如果全局作用域也没有,报错: is not defined;

var n = 10; // 全局变量
function fn() {
    // 局部作用域
    var z = 20; // 局部变量
    console.log(n, z);  
}
fn();

变量提升

js在解析代码的时候, 不是按照单纯的从上到下的顺序来执行

至少会执行两步:

\1. 预解析: 找var、function, 将var声明的变量的声明提到最前, function声明的函数整个存储在内存中

\2. 逐行解析: 从上到下的顺序一行行执行代码

函数的形参在函数被调用的第一行代码优先执行, 形参接收实参, 执行函数体

函数每调用形成一个新的局部作用域, 代码的解析过程遵循预解析过程

var

console.log(a); // undefined
var a = 10;
/* 
    解析过程:
        var a;
        console.log(a);
        a = 10;
*/

function

// function
function sum() {
    console.log('函数1');
}
console.log(sum);

function sum() {
    console.log('函数2');
};
console.log(sum);
/* 
    解析过程: 
    function sum() {
        console.log('函数1');
    }
    function sum() {
        console.log('函数2');
    };
    console.log(sum); 函数2
    console.log(sum); 函数2
*/

var和function

// var function 函数声明 字面量声明的区别
var fn = 'abc';
function fn() {
    console.log(1);
}
console.log(fn);
/* 
    解析过程:
        var fn;
        function fn() {
            console.log(1);
        }
        fn = 'abc';
        console.log(fn); abc
*/

形参

// 传参
// 函数的形参在函数被调用的第一行代码优先执行, 形参接收实参, 执行函数体
// 函数每调用形成一个新的局部作用域, 代码的解析过程遵循预解析过程
function fun(a) {
    console.log(a);
    var a = 30;
    console.log(a);
};
fun(10);

/* 
    解析过程:
        function fun(a) {
            console.log(a);
            var a = 30;
            console.log(a);
            解析过程:
                var a;-->声明形参 
                var a;
                a = 10; ---> 接收实参
                console.log(a); // 10
                a = 30;
                console.log(a); // 30
        };
        fun(10);
*/

函数返回值

函数在执行的时候 就像一个小黑屋 里面的数据不能直接出来 如果想要出来需要越狱

函数的返回值: 每个函数执行后都会有返回值, 默认返回值 undefined

就是函数调用的结果

接收函数的返回值: var 变量 = 函数();

想要将函数内的数据 在函数外能使用 需要将函数内的数据设置成返回值返回回来

设置函数的返回值:

函数最后: return value;

接收返回值

function a() {
    console.log(1);
}
var b = a();
console.log(b);

设置返回值

// 设置返回值
function fn() {
    var mn = 20;
    return mn;
}
var q = fn();
console.log(q);

return作用

设置函数的返回值: 函数最后: return value;

return: 结束函数 return后面的代码不执行

function fn1() {
    console.log(1);
    return 'abc';
    // 不执行
    console.log(2);
}
var m = fn1();
console.log(m); // 'abc'

返回多个

return设置返回值的时候 一次只能返回一个数据 如果用,返回多个, 只会返回最后一个;

如果想要返回多个数据, 建议 数组 或者 对象, 更推荐用对象

function fn2() {
    // return 10, 20, 30;
    // return [10, 20, 30];
    return {
        a: 10,
        b: 20,
        c: 30
    };
}
var mn = fn2();
console.log(mn);

使用情况:

\1. 封装函数 函数的最后去到的是一个数据

\2. 操作的对象 返回回来

\3. 函数内的数据 要在 函数外面用到的时候

返回值数据类型

返回值的数据类型可以是一切数据类型

function rType() {
    return function () {
        console.log(90);
    };
    return {a: 1, b:2};
    return [1,2,3,4];
    return null;
    return true;
    return 30;
    return 'abc';
}
var a = rType();
console.log(a);

封装步骤

\1. 实现单个效果

\2. 声明空函数

\3. 单个效果放在空函数里

\4. 调用

\5. 分析不确定的项, 抽取参数

\6. 传参

\7. 设置返回值

\8. 接收返回值

function getMax(data) {
    // 1. 假设最大值
    var max = data[0];
    // 2. 用这个值和数组的每一个值进行比较
    for (var i = 1; i < data.length; i++) {
        // 如果比假设值大
        if (max < data[i]) {
            max = data[i];
        }
    }
    // console.log(max);
    return max;
}
var m = getMax(arr);
console.log(m);

获取元素样式

基础获取

标准浏览器(ie9, chrome, ff):

getComputedStyle(元素).属性名

ie(ie8及以下):

元素.currentStyle.属性名

// 获取div
var div = document.getElementsByTagName('div')[0];
console.log(div);
// 获取样式:
// 标准:
// var w = getComputedStyle(div).width;
// console.log(w);

// var h = getComputedStyle(div).height;
// console.log(h);

console.log(getComputedStyle); // 标准: 函数  ie: undefined
console.log(div.currentStyle); // 标准: undefined ie: 对象
// ie:
// Cannot read properties of undefined (reading 'width'): 
// var w = div.currentStyle.width;
// console.log(w);

兼容

getComputedStyle: 函数 currentStyle: 对象

处理兼容: 一个函数 一个是对象/属性 可以用函数是否存在来做判断

如果函数 xx() 来做调用的话 判断的时候 window.xx 是否存在来做判断

console.log(window.getComputedStyle);
if(window.getComputedStyle){
    // 标准
    var w = getComputedStyle(div).width;
} else {
    // ie
    var w = div.currentStyle.width;
}
console.log(w);

封装

function getStyle(ele, attr) {
    // ele: 元素
    // attr: 属性
    if (window.getComputedStyle) {
        // 标准
        var w = getComputedStyle(ele)[attr];
    } else {
        var w = ele.currentStyle[attr];
    }
    // console.log(w);
    return w;
}

使用



this

概念

this: 指代词, 在不同的位置有不同的含义

全局: window

普通函数: window

对象的方法: 当前对象

事件处理函数: 触发源 点谁就指向谁

console.log(this); // window
function fn() {
    console.log(this);
}
fn();

var obj = {
    abs: function () {
        console.log(this);
    }
};
console.log(obj.abs);
obj.abs();

lis[0].onclick = function () {
    console.log(this);
}

使用

在for循环所嵌套的事件中, 得不到正确的对象的时候 用this来指代

// 点击每一个li 输出当前li的内容
// 1. 获取元素
var lis = document.getElementsByTagName('li');
console.log(lis);
// 2. 每一个
for(var i = 0; i < lis.length; i++){
    // 3. 加事件
    lis[i].onclick = function () {
        console.log(this); // 用this指代当前的触发源
        console.log(this.innerHTML);
    };
}

排他

排他: 除了自己有特定效果之外 其他的都是默认样式

实现过程: 1. 所有元素都设置成默认样式

\2. 指定元素添加特定效果

// 1. 获取元素
var lis = document.getElementsByTagName('li');
console.log(lis);
// 2. 每一个
for(var i = 0; i < lis.length; i++){
    // 3. 加事件
    lis[i].onclick = function () {
        // 先去清除所有的li的字体颜色
        for(var j = 0; j < lis.length; j++){
            lis[j].className = '';
        }

        // 4. 让当前的li的颜色变成黑色
        // 找到当前li
        console.log(this);
        this.className = 'active';
    }
}

注意

一般假定初始状态的时候 不会写太复杂的值 一般一个数字、或者 布尔值

假设内容 随意指定

// 获取元素
var img = document.getElementsByTagName('img')[0];
console.log(img);

// 不知道灯是什么状态 可以假设初始状态
// 一般假定初始状态的时候 不会写太复杂的值 一般一个数字、或者 布尔值
// 1--黑 2--亮  true--亮 false--黑
var tag = 'dark'; // 假设内容 随意指定  dark--黑 light--亮

// 点击
img.onclick = function () {
    console.log(this.src); // file:///Users/fushuangyu/Desktop/offcn/0712/day05/images/dark.jpg
    if(tag == 'dark'){
        // 灯是黑的 变亮
        img.src = './images/bright.jpg';
        // 更新状态
        tag = 'light';
    } else {
        img.src = './images/dark.jpg';
        tag = 'dark';
    }
};

自定义属性

属性: 写在起始标签上的 除了标签以外的 都是属性

固有属性: 规定好作用的 class id alt src...

自定义属性: 由程序员自己去设定的属性 tag

操作属性:

\1. 获取属性的值:

var 变量 = 元素.属性;

var 变量 = 元素[属性];

\2. 设置属性的值:

元素.属性名 = 值;

元素[属性名] = 值;

直接写在html页面中的自定义属性通过上述两种方式不能获取

通过js设置给元素的自定义属性,在页面中看不到, 但是在js中可以正常操作

多个元素之间的同名的属性 互相不影响

// 1. 获取属性值
console.log(div.id);
console.log(div.tag); // undefined

// 2. 设置属性
div.t = 'abc123';

console.log(div.t); // abc123


var img = document.getElementsByTagName('img')[0];
img.t = '987654321';

// 多个元素之间的同名的属性 互相不影响
console.log(div.t, img.t);

自定义索引

在自定义属性中 存储下标 的行为 就是自定义索引

// 2. 每一个
for(var i = 0; i < btns.length; i++){

    // 存储自定义索引
    btns[i].index = i;


    // 3. 加事件
    btns[i].onclick = function () {
        // 获取到对应的颜色
        // 颜色和按钮的关系: 5个 
        // 按钮和颜色: 一一对应  下标是一致
        // 获取当前按钮的下标 ---> 当前按钮的index属性的值
        // console.log(i);
        console.log(this.index);
        // 通过下标获取对应的arr中的颜色
        console.log(arr[this.index]);

        // 颜色设置给body  快速获取页面body的方式: document.body
        // console.log(document.body);
        document.body.style.background = arr[this.index];

    };
}

定时器

概念

定时器: 让一段代码等待一段时间或者每隔一段时间就执行一次的代码就是定时器

分类

延迟定时器

延迟: 让一段代码等待一段时间 setTimeout(函数, 时间); 时间单位: ms

等待 只执行一次的效果 使用延迟定时器

效果: 一次性广告 关不掉的广告

/* 
    打开页面 等待3s后 显示img
*/
var img = document.getElementsByTagName('img')[0];
// 等待 只执行一次的效果 使用延迟定时器
setTimeout(auto, 3000);

function auto(){
    img.style.display = 'block';
}

间隔定时器

间隔: 每隔一段时间执行一次 setInterval(函数, 时间); 时间单位: ms

每隔 间隔 不间断重复的效果

效果: 计时器 倒计时 轮播图

1s = 1000ms

var n = 0;
// 每隔一秒 让n自加1 输出
// 每隔  间隔  不间断重复的效果
setInterval(function () {
    n++;
    console.log(n);
}, 1000);

清除定时器

定时器一旦开启 不会自动清除 会造成内存泄漏

需要手动清除定时器

间隔: setInterval clearInterval(唯一标识)

延迟: setTimeout clearTimeout(唯一标识)

唯一标识 开启定时器后的返回值就是定时器的唯一标识

接收唯一标识:var 变量 = setTimeout/setInterval();

var n = 5;
var timer = setInterval(function () {
    n--;
    // 如果n等于0  清除定时器
    if(n == 0){
        clearInterval(timer);
    }
    console.log('这是间隔定时器', n);
}, 1000);
console.log(timer, 'timer');

注意

一般封装定时器的时候 是将定时器的函数抽取成普通的函数

当遇到会频繁开启定时器的时候 先清除定时器

对象

对象: 在js中 万物皆对象 一切皆对象 分为: 本地 内置 自定义 宿主 全局

本地(内部): Number String Boolean Object Array Function RegExp Date Error

内置: 在页面加载完成后 已经实例化的对象 Global Math

宿主: DOM BOM

全局: window

api: application programming Interface 应用程序编程接口

已经封装好的可以直接使用的函数 直接调用实现功能

Math

console.log(Math); // 数学对象

console.log(Math.PI); // π

console.log(Math.floor(3.99999)); // 向下取整
console.log(Math.ceil(3.000001)); // 向上取整
console.log(Math.round(4.50001)); // 四舍五入
console.log(Math.round(4.499999)); // 四舍五入

console.log(Math.max(20, 32, 12, 43, 12, 43, 435, 43)); // 求最大值
console.log(Math.min(20, 32, 12, 43, 12, 43, 435, 43)); // 求最小值

console.log(Math.pow(2, 10)); // 幂次方  
console.log(Math.sqrt(4)); // 开根号
console.log(Math.abs(-1000)); // 绝对值

// 求随机数:
/* 
    Math.random()   0-1的随机数
    Math.random() * 数   0-数之间的随机数  不包含数
    Math.random() * (y - x) + x  x-y之间的随机数 不包含y  y > x
*/
for(var i = 0; i < 5; i++){
    // console.log(Math.random());
    // console.log(Math.random() * 10);
    console.log(Math.random() * (50 - 30) + 30);

}

Date

创建时间

创建当前时间

var date = new Date();
console.log(date);
console.log(typeof date); // object

创建其他时间

1.2.1 用 , 直接分割 月份: 0-11 表示 1-12 月

1.2.2 传 字符串 年月日中间可以用任意特殊英文符号进行分割 空格 , / $ 时分秒 用 时:分: 秒

// 1.2.1 用 , 直接分割   月份: 0-11 表示 1-12 月
var d1 = new Date(2021, 9, 1);
var d1 = new Date(2021, 9, 1, 13, 13, 13);
console.log(d1);

// 1.2.2 传 字符串 年月日中间可以用任意特殊英文符号进行分割 空格 , / $  时分秒 用 时:分: 秒
// 字符串 月份不减
var d2  = new Date('2021, 10, 1');
var d2  = new Date('2021, 10, 1 23:23:23');
var d2  = new Date('2021 10 1 23:23:23');
var d2  = new Date('2021/10/2 23:23:23');
var d2  = new Date('2021-10-3 23:23:23');
var d2  = new Date('2021_10_3 23:23:23'); // Invalid Date 不可用的时间 _中文符号
console.log(d2);

获取特定格式的时间

var dd = new Date();
console.log(dd);
console.log(dd.toString(), typeof dd.toString()); // 字符串
console.log(dd.toLocaleString()); // 本地字符串日期  2021/9/22 上午11:35:10
console.log(dd.toLocaleDateString()); // 年月日 2021/9/22
console.log(dd.toLocaleTimeString()); // 时分秒 12小时 上午11:36:30

获取单个时间

var dd = new Date();
console.log(dd);

// 获取单个时间
var y = dd.getFullYear();
console.log(y); // 2021
console.log(dd.getMonth()); // 月 0-11表示1-12月
console.log(dd.getDate()); // 日期
console.log(dd.getDay()); // 星期  0-6表示周日到周六 3


var w = dd.getDay();
var week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六' ];
console.log(week[w]);

console.log(dd.getHours()); // 小时 11
console.log(dd.getMinutes()); // 分钟
console.log(dd.getSeconds()); // 秒

// 毫秒: 时间戳 距离1970-1-1
console.log(dd.getTime());

moment

moment.js: 专门处理日期的js插件库

\1. 下载 Moment.js 中文网

\2. moment.js : 格式文档 学习

moment.min.js : 压缩文档 工作

YYYY: 年

MM: 月

DD: 日期

d: 星期

HH: 时

mm: 分

ss: 秒

X: 所有的秒 距离1970-1-1的毫秒/1000

前导0 自动添加

// 创建moment时间对象
var dd = moment();
console.log(dd);

// format: 格式日期
/* 
    YYYY: 年
    MM: 月
    DD: 日期
    d: 星期
    HH: 时
    mm: 分
    ss: 秒
    X: 所有的秒 距离1970-1-1的毫秒/1000

    前导0 自动添加
*/
console.log(dd.format('YYYY'));
console.log(dd.format('MM'));
console.log(dd.format('DD'));
console.log(dd.format('d'));
console.log(dd.format('HH'));
console.log(dd.format('mm'));
console.log(dd.format('ss'));
console.log(dd.format('X'));

// 在页面中显示当前是 xxxx年xx月xx日 星期x x:x:x
document.body.innerHTML = dd.format('YYYY年MM月DD日 星期d HH:mm:ss');
// 每隔1s自动更新一次
setInterval(function () {
    var dd = moment();
    console.log(dd);
    document.body.innerHTML = dd.format('YYYY年MM月DD日 星期d HH:mm:ss');
}, 1000);

string

创建

字面量声明

包装类对象 不是真正的对象

var str = '12345a';

new关键字创建

var str1 = new String('asddhj');
console.log(str1);
console.log(typeof str1); // object

长度

console.log(str1.length); // 长度

查找

charAt

charAt: 指定下标对应的字符

var str = 'qwertyuiop';
console.log(str.charAt(2));

charCodeAt

charCodeAt: 指定下标对应的字符的ASCII码

console.log(str.charCodeAt(2));

indexOf

indexOf: 查找指定的字符在字符串中出现的位置 如果有返回下标 如果没有返回-1

惰性查找: 找到一个符合条件的 就会直接返回

语法: 字符串.indexOf(要找的字符[, 起始下标])

不传起始下标: 默认从第一个字符开始查找

起始下标: 表示从起始下标的位置上开始往后进行查找

var str = '012345678900123456123451234123';
console.log(str);
// 1是否在字符串str中出现
console.log(str.indexOf('1'));
console.log(str.indexOf('1', 2));
console.log(str.indexOf('1', 13));
console.log(str.indexOf('a')); // -1

lastIndexOf

lastIndexOf: 查找指定的字符在字符串中最后出现的位置 如果有返回下标 如果没有返回-1

从右往左查找

语法: 字符串.lastIndexOf(要找的字符[, 起始下标])

console.log(str.lastIndexOf('1'));
console.log(str.lastIndexOf('1', 26));
console.log(str.lastIndexOf('a'));

截取

substring

语法: 字符串.substring([起始下标], [结束下标]);

不传参: 返回整个字符串

传一个参数: 从起始下标开始 截取到 字符串的末尾 截止

传2个参数:

起始下标 < 结束下标: 从起始下标开始 截取到结束下标为止 包含起始下标对应的字符 不包含结束下标对应的字符

结束下标 < 起始下标: 互换位置 在参考上述规则

出现负数: 会把负数变成 0 参考上述规则

var str = 'abcdefghijklmn';
console.log(str.substring()); // abcdefghijklmn
console.log(str.substring(2)); // cdefghijklmn
console.log(str.substring(3, 5)); // de
console.log(str.substring(5, 3)); // de
console.log(str.substring(5, -1)); // 0---5  abcde

slice:

语法: 字符串.slice([起始下标], [结束下标]);

不传参: 返回整个字符串

传一个参数: 从起始下标开始 截取到 字符串的末尾 截止

传2个参数:

起始下标 < 结束下标: 从起始下标开始 截取到结束下标为止 包含起始下标对应的字符 不包含结束下标对应的字符

结束下标 < 起始下标: 返回空字符串

负数: 长度 + 负数 之后得到的结果 在参考上述规则

简单: 从右往左有几位不要

console.log(str.slice()); // abcdefghijklmn
console.log(str.slice(2)); // cdefghijklmn
console.log(str.slice(3, 5)); // de
console.log(str.slice(5, 3)); // 
console.log(str.slice(3, -1)); // defghijklm
console.log(str.slice(-10, -1)); // efghijklm

substr:

语法: 字符串.slice([起始下标], [截取长度]);

不传参: 返回整个字符串

传一个参数: 从起始下标开始 截取到 字符串的末尾 截止

console.log(str.substr());// abcdefghijklmn
console.log(str.substr(2)); // cdefghijklmn
console.log(str.substr(2, 5)); // cdefg

replace

语法: 字符串.replace(要被替换的字符/正则, 被替换的新字符/函数);

一次性只能替换一个位置上的字符, 返回新字符串

var str = 'today is Wednesday';
// s-->*
console.log(str.replace('s', '*'));

split:

作用: 将字符串按照指定的分割符进行分割 返回数组

分割符可以是一切字符 空、空格、标签

语法: 字符串.split('分割符');

var  str = 'you are a beautiful girl';
console.log(str);
console.log(str.split('a'));
// 每一个字符做一个数组的项
console.log(str.split(''));
console.log(str.split()); // 整个字符串是数组的一项

转大小写:

转大写: 字符串.toUpperCase()

转小写: 字符串.toLowerCase()

var str = 'aSaSas';
var str1 = 'AsAsas';
console.log(str.toUpperCase());
console.log(str.toLowerCase());

不区分大小写: 将判断的字符都转成小写的或者都转成大写的之后再做判断

console.log(str.toLowerCase() == str1.toLowerCase());

trim

trim: 去除字符串左右空格

var str = '        (you are a girl)       ';
console.log(str);
console.log(str.trim());

数组

数组: 用来存储不定数量不定类型的数据的容器;

创建数组

  1. 字面量创建

  2. new关键字创建

// 1. 字面量创建
var arr = [12, 43, 64];
console.log(arr);
console.log(typeof arr); // object

// 2. new关键字创建
// var 变量 = new Array(...data);
// 注意: 当参数只有一个且是数字, 表示数组的长度
var arr1 = new Array(1, 2, 3, 4);
console.log(arr1);

var arr2 = new Array(7);
console.log(arr2);
console.log(arr2[0]);

length

获取数组长度 数组.length

console.log(arr2.length);

设置数组长度 数组.length = 值; 长度加长 填充undefined 长度减小 多余的项会被删除 永远都找不到

var arr3 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr3.length); // 9
arr3.length = 4;
console.log(arr3);
arr3.length = 100;
console.log(arr3);

为什么要划分成基础数据类型和复杂数据类型:

基础: 数据比较单一, 声明和存储都在栈

复杂: 数据比较复杂, 声明和地址存储在栈, 具体数据存储在堆

深浅拷贝

深浅出现在引用数据类型

浅拷贝: 地址的赋值

var arr = [1,2,3,4,5];
console.log(arr);
var brr = arr;
console.log(brr);

判断引用数据类型是否是同一个地址的数据 用 == 判断

console.log(arr == brr); // true

深拷贝: 在堆中在划一块, 重新存储对应位置的每一个数据

var crr = [];
// 将arr的每一个数据 存到 crr中   对应位置: 下标一致
for(var i = 0; i < arr.length; i++){
    crr[i] = arr[i];
}
console.log(crr);
console.log(crr == arr); // false

添加删除

数组的方法大部分都是在原来数组上进行直接操作, 会改变原数组

栈方法:

push: 在数组的末尾添加一项或者多项, 返回添加数据后的数组的新长度

数组.push(...data);

pop: 在数组的末尾删除一项, 返回被删除的项

数组.pop();

unshift: 在数组的首位添加一项或者多项, 返回添加数据后的数组的新长度

数组.unshift(...data);

shift: 在数组的首位删除一项, 返回被删除的项

数组.shift();

// push
var arr = [1, 2, 3, 4];
var a = arr.push('a', 'b', 'c');
console.log(arr, a);

// pop
var b = arr.pop();
console.log(arr, b);

// unshift:
var c = arr.unshift('小乔', '大乔', '周瑜');
console.log(arr, c);

// shift
var d = arr.shift();
console.log(arr, d);

splice

splice: 增删改, 返回被删除的项组成的新数组

语法: 数组.splice(起始下标, 删除的个数, [....data]);

增:

数组.splice(起始下标, 删除个数, ...data);

删除:

数组.splice(起始下标, 删除个数);

替换:

数组.splice(起始下标, 删除个数, ...data);

var arr = ['小乔', '大乔', '貂蝉', '王昭君', '西施'];
// 小乔后面添加 周瑜
var a = arr.splice(1, 0, '周瑜');
console.log(arr); // ['小乔', '周瑜', '大乔', '貂蝉', '王昭君', '西施']
console.log(a, 'a----');
// 貂蝉 删除
var b = arr.splice(3, 1);
console.log(arr); // ['小乔', '周瑜', '大乔', '王昭君', '西施']
console.log(b, 'b----');
// 替换
var c = arr.splice(3, 2, '潘金莲', '西门庆');
console.log(arr);
console.log(c, 'c----');

数组方法

concat

concat: 拼接数组和项, 返回新数组

数组.concat(...data);

var arr = [1, 2, 3];
var brr = [6, 7, 8];
var crr = arr.concat(4, 5, brr);
console.log(arr, brr);
console.log(crr); // [1, 2, 3, 4, 5, 6, 7, 8]

slice

slice: 截取 用法与字符串一模一样, 返回截取出来的新数组

数组.slice([起始下标], [结束下标]);

console.log(crr.slice()); // [1, 2, 3, 4, 5, 6, 7, 8]
console.log(crr.slice(2)); // [3, 4, 5, 6, 7, 8]
console.log(crr.slice(2, 5)); // [3, 4, 5]

reverse

reverse: 数组翻转, 改变原数组, 具有返回值, 返回翻转以后的数组

数组.reverse();

var arr = [1, 2, 3, 4];
var a = arr.reverse();
console.log(arr, a);

join

join: 将数组按照拼接符连接起来, 返回字符串

数组.join(连接符)

连接符可以是一切字符, 默认以,作为连接符

var arr = ['小乔', '吕布', '貂蝉'];
console.log(arr.join('和')); // 小乔和吕布和貂蝉
console.log(arr.join('+++')); // 小乔+++吕布+++貂蝉
console.log(arr.join()); // 小乔,吕布,貂蝉
console.log(arr.join('')); // 小乔吕布貂蝉

indexOf/lastIndexOf

indexOf/lastIndexOf: 查找对应的项在数组中出现的位置,如果有返回下标,如果没有返回-1

与字符串一致

注意: 查找的项必须和数组的项 全等 才能被找到

var arr = [1, '1', 2];
console.log(arr.indexOf('1')); // 1
console.log(arr.indexOf(1)); // 0

sort

数组.sort([函数]); 默认按照字符串的排序规则进行排序

有2个形参(假设叫a, b):

return a - b; 从小到大

return b - a; 从大到小

var arr = [4, 2, 4, 1, 3, 31, 4, 15, 81, 11];
arr.sort();
console.log(arr);

console.log(arr.sort);

arr.sort(function (a, b) {
    console.log(a, b); // 相邻的两项
    // return a - b; // 从小到大
    return b - a; // 从大到小
});
console.log(arr);

中文比较

localeCompare: 比较字符是否在另一个字符之前或者之后

字符a.localeCompare(字符b);

字符a 在 字符b 之前 返回 -1

字符a 和 字符b 完全一致 返回 0

字符a 在 字符b 之后 返回 1

var a = '张三';
var b = '李四';
console.log(b.localeCompare(a));
console.log(a.localeCompare(b));
console.log(a.localeCompare(a));

// 用姓名升序排序 a---z
arr.sort(function (x, y) {
    console.log(x.name, y.name);
    return x.name.localeCompare(y.name);
});
console.log(arr);

迭代方法

迭代: every some filter map forEach

every

every: 对数组的每一个项做一些判断, 根据函数的返回值, 如果每个项执行函数的返回值都是true, 返回true. 如果有一个是false 返回false

全真为真 一假为假

语法: 数组.every(函数);

函数有3个形参: 项 下标 原数组

var arr = ['a', 'b', 'c', 'd'];
var res = arr.every(function (v, i, a) {
    console.log(i, v, a);
    // return true;
    return 0;
});
console.log(res);

some

some: 对数组的每一个项做一些判断, 根据函数的返回值, 如果每个项执行函数的返回值都是false, 返回false. 如果有一个是true 返回true

全假为假 一真为真

语法: 数组.some(函数);

函数有3个形参: 项 下标 原数组

var res1 = arr.some(function (v, i, a) {
    console.log(i, v, a);
    // return true;
    return undefined;
});
console.log(res1);

filter

filter: 对数组中的做一些过滤, 会将符合条件的(函数的返回值是true)项组成一个新数组返回;

语法: 数组.filter(函数);

函数有3个形参: 项 下标 原数组

常使用: 数据筛选过滤

var arr = ['a', 'b', 'c', 'd'];
var res2 = arr.filter(function (v, i, a) {
    console.log(i, v, a);
    return i > 1;
});
console.log(res2);

map

map\forEach: for循环

map: for循环 将每个函数的返回值组成新数组返回 造成内存浪费

forEach: 纯粹的for循环 没有返回值

数组.map/forEach(函数);

var res3 = arr.map(function (v, i, a) {
    // console.log(i, v, a);
    return v + '1';
});
console.log(res3);

forEach

map\forEach: for循环

map: for循环 将每个函数的返回值组成新数组返回 造成内存浪费

forEach: 纯粹的for循环 没有返回值

数组.map/forEach(函数);

var res4 = arr.forEach(function (v, i, a) {
    console.log(i, v, a);
    return v + '1';
});
console.log(res4);

正则

正则: 用规定好的具有特定含义的字符组成的规则字符串, 用来实现字符串的检索和替换.

创建正则

new关键字创建:

语法: var 变量 = new RegExp(规则字符串, 修饰符);

var reg = new RegExp('web', 'ig');
console.log(reg); // /web/gi
console.log(typeof reg); // object

字面量声明

语法: var 变量 = /规则字符串/修饰符;

var reg1 = /web/ig;
console.log(reg1); // /web/gi

修饰符

没有顺序

i: ignore case 忽略大小写

g: global 全局

检索方法

replace

字符串.replace(要替换的字符/正则, 新字符/函数);

函数的返回值就是替换的新字符

函数有一个形参: 每次匹配到的结果

var str = 'web01web02web03Web04WEB05';
console.log(str);

// web-->***
var reg = /web/gi;
console.log(str.replace(reg, '***'));
console.log(str.replace(reg, function (a) {
    console.log(a);
    return 'aaa';
}));

split

字符串.split(分割符/正则);

var str = 'web0web1web2web0web1';
console.log(str.split('0'));
var reg = /\d/; // 数字\d
console.log(str.split(reg));

search

search: 替换indexOf 使用正则做查找 返回找到的符合正则的第一个位置上的下标

惰性查找

var str = 'web0web1web2web0web1';
var reg = /\d/;
console.log(str.search(reg));

match

字符串.match(正则);

返回一个数组

单个匹配结果: ['web', index: 0, input: 'web0web1web2web0web1', groups: undefined]

多个匹配结果: ['0', '1', '2', '0', '1']

var str = 'web0web1web2web0web1';
var reg = /\d/;
var reg = /\d/ig;
console.log(str.match(reg));

exec

exec: 正则.exec(字符串);

返回值与match的单个返回结果一致

如果有返回数组 如果没有 返回null

惰性查找, 一次只找一个, 如果加了g 会从上一次找到的位置开始找 不加g 每次都从下标0开始找

正则.lastIndex: 返回下一次正则匹配开始的位置

var str = 'webstrweb0123';
var reg = /web/;
console.log(reg.exec(str));

var reg = /web/g;
console.log(reg.lastIndex); // 0
console.log(reg.exec(str));
console.log(reg.lastIndex); // 3
console.log(reg.exec(str));
console.log(reg.lastIndex); // 9
console.log(reg.exec(str)); // null
console.log(reg.lastIndex); // 0
console.log(reg.exec(str));

test

test: 正则.test(字符串);

判断字符串是否有符合正则的字符 如果有 返回true 如果没有 返回false

惰性查找, 一次只找一个, 如果加了g 会从上一次找到的位置开始找 不加g 每次都从下标0开始找

var reg = /web/;
var str = 'web0web1web2';
console.log(reg.lastIndex); // 0
console.log(reg.test(str));
console.log(reg.lastIndex); // 0
console.log(reg.test(str));

var reg = /web/g;
console.log(reg.lastIndex); // 0
console.log(reg.test(str));
console.log(reg.lastIndex); // 3
console.log(reg.test(str));
console.log(reg.lastIndex); // 7
console.log(reg.test(str));
console.log(reg.lastIndex); // 11
console.log(reg.test(str)); // false
console.log(reg.lastIndex); // 0
console.log(reg.test(str));

元字符

一个元字符可以表示一类字符

一个元字符做匹配只能匹配一个字符

.

// 1. . 点: 除换行以外的任意字符
var str = '\n这是一个换行句子\n';
console.log(str);
var reg = /./;
console.log(reg.exec(str));

[] [^]

// 3. []: 字符集 匹配[]里的任意一个字符 [^]: 非字符集 不匹配[^]中的任意一个字符
var str = 'abc123';
var reg = /[1234567890]/;
var reg1 = /[^1234567890]/;
console.log(reg.exec(str), reg1.exec(str)); // 1 a
// 0-9表示:0123456789
// a-z表示: 小写a到小写z之间的所有的字母
// A-Z表示: 大写a到大写Z之间的所有的字母
var reg = /[0-9a-zA-Z]/;
var str = '.!@##$$a1';
console.log(reg.exec(str));

\d \D

// 2. \d:匹配数字 \D:匹配非数字
var str = 'str123';
var reg = /\d/;
var reg1 = /\D/;
console.log(reg.exec(str), reg1.exec(str));

\w \W

// 4. \w: 匹配数字、字母、_中的任意一个  \W: 不匹配数字、字母、_中的任意一个
var str = '!@##$_123qwe';
var reg = /\w/;
var reg1 = /\W/;
console.log(reg.exec(str), reg1.exec(str)); // _   !

\s \S

// 5. \s: 匹配空格  \S: 不匹配空格
var str = 'you are a beautiful girl';
var reg = /\s/;
var reg1 = /\S/;
console.log(reg.exec(str), reg1.exec(str)); // 空格 y

\b \B

// 6. \b: 匹配单词边界  \B: 匹配非单词边界
// 一个字母有2个边界
var str = 'you are a beautiful girl';
var reg = /\ba\b/;
var reg1 = /\ba\B/;
var reg2 = /\Ba\B/;
console.log(reg.exec(str), reg1.exec(str), reg2.exec(str)); // a are beautiful

^ $

// 7. ^a: 开头 以a为开头的a   a$: 以a为结尾的a
// 一起用: 有具体的长度 6-18位 规律性: 银行卡密码  手机号  身份证号
var str = 'we are web0712';
var reg = /^w/;
var reg1 = /\d$/;
console.log(reg.exec(str), reg1.exec(str));


// 银行卡密码正则:
// 6位
var reg = /^\d\d\d\d\d\d$/;
var str = '123456';
console.log(reg.test(str));

量词

a? : 匹配0个或者1个a 只匹配字符串的第一项

var str = 'str123';
var reg = /\d?/;
var reg = /[a-z]?/;
console.log(reg.exec(str));

*

a* : 匹配0个或者 连续 多个a 尽可能多的做匹配 只匹配字符串的第一项

var str = 'wertyuiodfghjk23456789sdfghj44567';
var reg = /\d*/;
var reg = /[a-z]*/;
console.log(reg.exec(str));

+

a+ : 匹配连续多个a 至少匹配1个 尽可能多的做匹配

var str = 'wertyuiodfghjk23456789sdfghj44567';
var reg = /\d+/;
var reg = /[a-z]+/;
console.log(reg.exec(str));

{m,n}

a{m,n} : 匹配至少m次最多n次的a 尽可能多的做匹配

a{m,} : 匹配至少m次

a{n} : 只匹配n次

,后面绝对不能加空格

var str = 'wtyuiosghjkxcvbnmsdxcvb';
var reg = /[a-z]{5,10}/;
console.log(reg.exec(str)); // wtyuiosghj
var reg = /[a-z]{1,}/;
console.log(reg.exec(str)); // wtyuiosghjkxcvbnmsdxcvb
var reg = /[a-z]{10}/;
console.log(reg.exec(str)); // wtyuiosghj

或和分组

|

|: 或 匹配|左边或者右边

var reg = /web1|web2/;
var str = 'web0712web1web2';
console.log(reg.exec(str)); // web1

()

(): 和 提高匹配的层级

()匹配到的结果可以通过其他属性得到 $1$2:获取第几个()匹配到的结果 RegExp.$1

var reg = /web(1|2)/;
var str = 'web2web0712web1';
console.log(reg.exec(str)); // web2  ['web2', '2', index: 0, input: 'web2web0712web1', groups: undefined]
console.log(RegExp.$1);


// 手机号的加密: 13322221111   133****1111
// 写正则分成3
var reg = /^(1[3-9]\d)(\d{4})(\d{4})$/;
var str = '13322221111';
console.log(reg.exec(str));
// 替换 $1  $3 第一个小括号和第三个小括号匹配到的结果
console.log(str.replace(reg, '$1****$3'));

特殊

(?:) : 非获取匹配

var str = 'web1web2';
var reg = /web(?:1|2)/;
console.log(reg.exec(str));

(?=)

a(?=b) : 匹配后面必须跟b的a

var str = 'webabcweb123';
var reg = /web(?=\d)/; // 匹配web后面是数字的web
console.log(reg.exec(str));

(?!)

a(?!b) : 匹配 后面 不是 b 的 a

使用: 排除条件

var str = 'webabcweb123';
var reg = /web(?!\d)/; // 匹配web后面不是数字的web
console.log(reg.exec(str));  // ['web', index: 0, input: 'webabcweb123', groups: undefined]

DOM

DOM:

DOM树 浏览器在渲染页面的时候 会先形成树状结构 就叫做DOM树

DOM由节点组成的

获取节点

获取节点: css选择器: css中选择器怎么写 这里就怎么写 id class tag 父子 层级 交叉...

ie8+ 静态

获取符合选择器的第一个元素: document/父元素.querySelector('css选择器')

var div = document.querySelector('div');
console.log(div); // 直接获取到第一个div

var ul = document.querySelector('ul');
console.log(ul);

获取所有符合选择器的元素: 节点的集合: document/父元素.querySelectorAll('css选择器');

var lis = ul.querySelectorAll('li');
console.log(lis); // NodeList 节点列表

var boxa = ul.querySelector('.box.a');
console.log(boxa);

获取子节点

父元素.children 标准: 标签节点 常用

父元素.childNodes 标准: 标签节点+文本节点+注释+...

// 1. 获取ul
var ul = document.querySelector('ul');
console.log(ul);
/*
    获取子节点:
        父元素.children 标准: 标签节点  常用
        父元素.childNodes 标准: 标签节点+文本节点+注释+...
*/
console.log(ul.children);
console.log(ul.childNodes);

节点属性:

\1. 节点名称: 节点.nodeName 标签名大写

\2. 节点类型: 节点.nodeType 1-12 1--标签 2---属性 3---文本 8--注释 9--document

\3. 节点内容: 节点.nodeValue 只有文本节点(text)才有内容

var cls = ul.childNodes;
for(var i = 0; i < cls.length; i++){
    // console.log(cls[i], cls[i].nodeName, cls[i].nodeType, cls[i].nodeValue);
    // 获取标签的内容
    if(cls[i].nodeType == 1){
        console.log(cls[i].childNodes[0].nodeValue);
        console.log(cls[i].innerHTML);
    }
}

获取父节点

直接父节点: 节点.parentNode

定位父节点: 节点.offsetParent

如果没有定位父节点 获取到的是body

// 1. 获取box
var box = document.querySelector('.box');
console.log(box);

/* 
    直接父节点: 节点.parentNode
    定位父节点: 节点.offsetParent
        如果没有定位父节点 获取到的是body
*/
console.log(box.parentNode);
console.log(box.offsetParent);

查找兄弟节点

获取上一个兄弟节点:

标准: 节点.previousElementSibling

ie: undefined 标准: 专门提供在标准浏览器中获取上一个兄弟节点

ie: 节点.previousSibling

ie8-: 可以获取到上一个兄弟节点 标准: 换行文本节点

两个值中二选一的时候可以选择用逻辑或短路 将可能出现undefined 的这一项放在前面

兼容: 节点.previousElementSibling || 节点.previousSibling

// 1. 获取box
var box = document.querySelector('.box');
console.log(box);

console.log(box.previousElementSibling, box.previousSibling);
console.log(box.previousElementSibling || box.previousSibling);

获取下一个兄弟节点:

标准: 节点.nextElementSibling

ie: undefined 标准: 专门提供在标准浏览器中获取上一个兄弟节点

ie: 节点.nextSibling

ie8-: 可以获取到上一个兄弟节点 标准: 换行文本节点

两个值中二选一的时候可以选择用逻辑或短路 将可能出现undefined 的这一项放在前面

兼容: 节点.nextElementSibling || 节点.nextSibling

console.log(box.nextElementSibling, box.nextSibling);
console.log(box.nextElementSibling || box.nextSibling);

获取首个子节点:

ie: firstChild

标准: firstElementChild

兼容: 节点.firstElementChild || 节点.firstChild

// 获取父节点
var ul = document.querySelector('ul');
console.log(ul);

/* 
    获取首个子节点:
        ie: firstChild
        标准: firstElementChild
    兼容: 节点.firstElementChild || 节点.firstChild
*/
console.log(ul.firstChild, ul.firstElementChild);
console.log(ul.firstElementChild || ul.firstChild);

获取末位子节点:

ie: lastChild

标准: lastElementChild

兼容: 节点.lastElementChild || 节点.lastChild

console.log(ul.lastElementChild || ul.lastChild);

创建节点

1.1 创建标签节点: var 变量 = document.createElement('标签名');

1.2 创建文本节点: var 变量 = document.createTextNode('内容');

1.3 将文本节点添加到标签节点中: 父节点.appendChild(子节点);

创建节点为了解决innerHTML重新赋值会覆盖原来所有元素的问题

为了简化过程, 常用innerHTML代替 1.2 1.3

// 1. 创建节点:
// 1.1 创建标签节点: var 变量 = document.createElement('标签名');
var li = document.createElement('li');
console.log(li);

// // 1.2 创建文本节点: var 变量 = document.createTextNode('内容');
// var txt = document.createTextNode('这是新的li');
// console.log(txt);

// // 1.3 将文本节点添加到标签节点中: 父节点.appendChild(子节点);
// li.appendChild(txt);
// console.log(li);


// 创建节点为了解决innerHTML重新赋值会覆盖原来所有元素的问题
// 为了简化过程, 常用innerHTML代替 1.2 1.3

li.innerHTML = '这是新的li';
console.log(li);

追加节点

追加到父元素的末位:

父节点.appendChild(子节点);

var ul = document.querySelector('ul');
console.log(ul);
ul.appendChild(li);

追加到某个节点之前:

父节点.insertBefore(新节点, 参考节点);

var li1 = document.createElement('li');
li1.innerHTML = '新的li1';
ul.insertBefore(li1, ul.children[0]);

var li2 = document.createElement('li');
li2.innerHTML = '新的li2';
ul.insertBefore(li2, ul.children[0]);

删除节点

  1. 删除自己: 节点.remove(); ie8+

  2. 删除子节点: 父节点.removeChild(子节点) 会把被删除的元素返回回来

// 1. 删除自己: 节点.remove(); ie8+
// 点击div  删除整个ul
var div = document.querySelector('div');
var ul = document.querySelector('ul');
div.onclick = function () {
    ul.remove();
}
// 2. 删除子节点: 父节点.removeChild(子节点)   会把被删除的元素返回回来
// 点击btn 删除整行li
var btns = document.querySelectorAll('button');
console.log(btns);
for(var i = 0; i < btns.length; i++){
    btns[i].onclick = function () {
        // 通过按钮 找到整个 li  li是btn的直接父元素
        console.log(this.parentNode);
        var a = ul.removeChild(this.parentNode);
        console.log(a);
    }
}

克隆节点

节点.cloneNode(布尔);

true: 克隆节点中的内容

false/不传: 不克隆节点中的内容

var nli = this.cloneNode(true);
console.log(nli);
// 追加到ul中
ul.appendChild(nli);

替换节点:

父节点.replaceChild(新节点, 参考节点);

var box = document.querySelector('.box');
console.log(box);

var li = document.createElement('li');
li.innerHTML = '新内容';

var ul = document.querySelector('ul');
ul.replaceChild(li, box);

操作属性

\1. 获取: var 变量 = 元素.属性名; var 变量 = 元素['属性名'];

\2. 设置: 元素.属性名 = 值; 元素['属性名'] = 值; 设置布尔值 读取到的就是布尔

[]里直接写属性名需要加引号 如果是变量不加引号

问题: 获取属性: 不能获取直接写在标签上的自定义属性 设置属性: 通过js设置的自定义属性在标签上看不到, 可以正常获取和设置操作所有属性, class直接使用

\3. 获取: 节点.getAttribute('属性名');

\4. 设置: 节点.setAttribute('属性名', '属性值');

所有的值都是字符串 设置后面的属性会覆盖前面

\5. 移除:

节点.属性名 = null/'';

节点.removeAttribute('属性名');

一般操作属性都可以直接使用以上方式, 如果只设置属性名就起作用的属性(checked\selected\loop\muted..)用点和[]

/* 
    操作属性:
        1. 获取: var 变量 = 元素.属性名;  var 变量 = 元素['属性名'];
        2. 设置: 元素.属性名 = 值; 元素['属性名'] = 值;  设置布尔值 读取到的就是布尔
        []里直接写属性名需要加引号 如果是变量不加引号
        问题: 获取属性: 不能获取直接写在标签上的自定义属性  设置属性: 通过js设置的自定义属性在标签上看不到, 可以正常获取和设置
*/
var div = document.querySelector('div');
console.log(div.id);
console.log(div.className);
console.log(div.tag); // undefined
console.log(div['tag']); // undefined

div.ttt = '1234';

/* 
    操作所有属性, class直接使用
    3. 获取: 节点.getAttribute('属性名');
    4. 设置: 节点.setAttribute('属性名', '属性值');
        所有的值都是字符串 设置后面的属性会覆盖前面
    5. 移除: 
        节点.属性名 = null/'';
        节点.removeAttribute('属性名');

    一般操作属性都可以直接使用以上方式, 如果只设置属性名就起作用的属性(checked\selected\loop\muted\..)用点和[]
*/
console.log(div.getAttribute('class'));
console.log(div.getAttribute('tag')); // abc123
div.setAttribute('txt', '123123');
div.setAttribute('tnt', true);
div.setAttribute('class', 'wrap a b');

div.id = '';
div.removeAttribute('id');

快速获取表格

// 表格
var table = document.querySelector('table');
console.log(table);
// 表格是由行组成, 行是由单元格, 表格不能直接获取单元格
console.log(table.tHead); // 表格头
console.log(table.tFoot); // 表格脚
console.log(table.tBodies); // 表格体 --> 集合
console.log(table.tBodies[0]); // 第一个表格体
console.log(table.rows); // 表格中所有的行 头体脚 集合
console.log(table.tBodies[0].rows); // 第一个表格体所有的行
console.log(table.cells); // undefined
console.log(table.rows[0].cells); // 获取表格中第一个行的所有的单元格
console.log(table.tBodies[0].rows[0].cells);

快速获取表单

快速获取表单元素: form.name值

/* 
    1. 获取表单form
*/
var form = document.querySelector('form');
console.log(form);

// 快速获取表单元素: form.name值
console.log(form.user);
console.log(form.pass);
console.log(form.sex);
console.log(form.sex.value); // 当前单选按钮所选中得项
console.log(form.hobby);
// 复选框由于有多个选中的项 所以不能直接通过value获取

表单事件

form表单的事件:

提交: form元素.onsubmit = 函数;

重置: form元素.onreset = 函数;

在函数中默认返回值都是 return true;

return false: 禁止提交/重置

如果你不想表单发生重置或者提交的时候 在函数中设置return false;

form.onsubmit = function () {
    console.log('是否提交');
    // return true;
    return false;
};

form.onreset = function () {
    console.log('是否重置');
    // return true;
    return false;
};

表单元素事件

输入框(常见):

onblur: 失去焦点

onfocus: 聚集焦点

onchange: 失去焦点且内容发生改变

边输入边触发: oninput(标准)/onpropertychange(ie8)

搜索提示\密码等级校验...

不建议单独使用, 一般需要结合防抖和节流来进行使用, 避免事件的频繁触发

form.user.onfocus = function () {
    this.style.background = 'orange';
};

form.user.onblur = function () {
    this.style.background = 'skyblue';
};

form.pass.onchange = function () {
    this.style.background = 'red';
};

// 事件可以连等
form.pass.oninput = form.onpropertychange = function () {
    console.log(this.value);
};

BOM

BOM: Browser Object Model 浏览器对象模型

js提供给我们用来操作浏览器的信息的接口

iframes

location

history

document

navigator

....

BOM核心: window

可以直接使用变量名或者函数名就能出线效果的(全局变量、全局函数), 所属对象都是window

对话框

  1. 警告框: alert()

  2. 带有确定取消按钮的警告框: confirm('提示内容')

  3. 带有输入框的对话框: prompt('提示内容', '默认值')

// 1. 警告框: alert()
// alert('是否已经了解清除风险');

// 2. 带有确定取消按钮的警告框: confirm('提示内容')
// 接收返回值: 取消: false  确定: true
// var res = confirm('是否已经了解风险');
// console.log(res);

// 3. 带有输入框的对话框: prompt('提示内容', '默认值')
// 接收返回值: 取消: null  确定: 输入框的内容
// var res = prompt('请输入要购买的金额', '10000');
// console.log(res);

open与close

如果页面结构html中使用, window不能省略

open: 打开

语法: open(跳转的网址, target, 描述词, 是否替换当前页面在历史记录中的位置)

target: 打开方式 _blank: 新标签页 _self: 当前

描述词: 当前窗口宽高 属性名=属性值,属性名=属性值 只在打开方式是_blank

返回新页面的window

close: 关闭

window对象.close();

js中关闭自己: close();

// 点击第一个按钮 打开uxue官网
var btns = document.querySelectorAll('button');
console.log(btns);

var nwin = null;
btns[0].onclick = function () {
    // open('https://www.ujiuye.com');
    // open('https://www.ujiuye.com', '_blank');
    // open('https://www.ujiuye.com', '_self');
    // open('https://www.ujiuye.com', '_self');
    nwin = open('https://www.ujiuye.com', '_blank', 'width=500px,height=500px');
    console.log(nwin);
};

btns[2].onclick = function () {
    close();
};
btns[3].onclick = function () {
    nwin.close();
};

location

location是BOM中最有用的对象之一. 既是BOM直接对象, 也是window下的对象

存储相关当前页面的信息: 网址 协议 搜索内容...

// 调试: 打开线上网站 安装插件: live Server
console.log(location);
// https://www.jd.com/
console.log(location.protocol); // 协议 http https file
console.log(location.hostname); // 服务器名称
console.log(location.port); // 端口
console.log(location.host); // 服务器名称 + 端口
console.log(location.pathname); // 文件路径
console.log(location.search); // 搜索内容  ?+后面的内容
console.log(location.hash); // 哈希值 地址后面的散列 #+后面的内容
console.log(location.href); // 完整地址

setTimeout(function () {
    // 给href赋值 可以实现页面跳转
    // location.href = 'https://www.baidu.com';
    // window.location.href = 'https://www.baidu.com';


    // 刷新
    // location.reload();
},3000);

history

history: 历史记录

history.go(数字);

正数: 前进几个页面

负数: 后退几个页面

0: 刷新

history.back(); 回退到上一个页面

history.forward(); 前进到下一个页面

console.log(history);
setTimeout(function () {
    // 前进到02页面
    // history.forward();
    // history.go(2);
    // history.go(0);
}, 3000);

BOM事件

onload

当script标签写在body、页面结构之前的时候 获取元素拿不到正确的元素 去到的是null

原因: 由于代码是从上到下的顺序去执行的 当执行到script的时候页面中还没有元素 所以取不到

解决: 让js代码在页面结构之后

\1. 使用 window.onload 事件: 等待页面和其中的资源(图片、视频...)都加载完成后 在执行其中的代码

window.onload = function () {
    var div = document.querySelector('div');
    console.log(div);
}

onscroll

滚动事件

window.onscroll 事件

window.onscroll = function () {
    console.log('滚了');
};

onresize

窗口大小改变事件

window.onresize = function () {
    console.log('变了');
};

元素三大宽高

client

元素可视宽高 client系列:

clientWidth/clientHeight: 元素的可视宽高 内容 + padding

clientLeft/clientTop: 左/上边框的宽度

屏幕的可视区域的宽高:

document.documentElement.clientWidth/clientHeight

/* 
    元素可视宽高 client系列:
        clientWidth/clientHeight: 元素的可视宽高 内容 + padding
        clientLeft/clientTop: 左/上边框的宽度
*/
console.log(div.clientHeight, div.clientWidth); // 300+20+10=330 200+15+5=220
console.log(div.clientLeft, div.clientTop); // 25  5

/* 
    屏幕的可视区域的宽高:
        document.documentElement.clientWidth/clientHeight
*/
console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);

offset

offset: 元素的占位宽高

offsetWidth/offsetHeight: 元素的占位宽高 内容 + padding + border

offsetLeft/offasetTop: 元素距离具有定位属性的父元素的左侧/顶部的距离 如果没有定位父元素 就是距离body的距离

console.log(div.offsetWidth, div.offsetHeight); // 200+15+5+25+3=248 300+20+10+5+23=358
console.log(div.offsetLeft, div.offsetTop); // 30 1

scroll

scroll: 滚动距离

scrollHeight/scrollWidth: 元素的实际宽高

scrollTop/scrollLeft: 超出当前页面/元素的距离 滚动卷去的距离

获取页面\窗口的滚动距离:

document.documentElement.scrollTop

document.documentElement.scrollLeft

console.log(div.scrollWidth, div.scrollHeight);
// 通过滚动事件
div.onscroll = function () {
    console.log(div.scrollLeft, div.scrollTop);
};

// 获取页面滚动的距离:
window.onscroll = function () {
    console.log(document.documentElement.scrollTop, document.documentElement.scrollLeft);
};

滚动的距离: scrollTop/scrollLeft可以被赋值 其他的只能获取不能设置

btn.onclick = function () {
    document.documentElement.scrollTop = 0;
};

懒加载

  1. 当页面滚动的时候, 判断每一个图片是否在页面的可视范围之内 如果在 img的src被赋值成ntag的值

  2. 一进入页面的时候 判断是否有图片需要显示

  3. 当页面可视区域的大小发生改变的时候 判断

判断思路:

元素的offsetTop <= window的scrollTop + 屏幕的可视区域的高度

// 1.1 获取元素
var imgs = document.querySelectorAll('img');
console.log(imgs);
// 1.2 页面滚动
window.onscroll = function () {
    auto();
};


// 2. 一进入页面的时候  判断是否有图片需要显示
auto();
function auto() {
    // 获取滚动距离 和 屏幕的可视区域的高度
    var st = document.documentElement.scrollTop;
    var ch = document.documentElement.clientHeight;
    // 每一个   
    for (var i = 0; i < imgs.length; i++) {
        // console.log(imgs[i].offsetTop);
        if (imgs[i].offsetTop <= st + ch) {
            // img的src被赋值成ntag的值
            // 获取ntag的值
            // console.log(imgs[i].getAttribute('ntag'));
            imgs[i].src = imgs[i].getAttribute('ntag');
        }
    }
};

// 3. 当页面可视区域的大小发生改变的时候 判断
window.onresize = function () {
    auto();
}

事件对象

当事件发生的时候, 浏览器将相关当前事件的信息都存在一个对象中, 这个对象就是事件对象

普通: event window.event

低版本ff: 事件处理函数的第一个形参的位置

事件对象兼容: var ev = window.event || evs;

document.onclick = function (evs) {
    // console.log(window.event, evs);
    var ev = window.event || evs;
    console.log(ev);

    console.log(ev.type); // 事件类型
    console.log(ev.target || ev.srcElement); // 事件触发源
    console.log(ev.clientX, ev.clientY); // 鼠标距离屏幕可视区域的左上角的距离
    console.log(ev.screenX, ev.screenY); // 鼠标距离屏幕的左上角的距离
    console.log(ev.pageX, ev.pageY); // 鼠标距离页面左上角的距离
}

事件绑定

语法

标准

事件绑定:利用特定的方法可以实现给一个元素的同一个事件添加多个事件处理函数

标准: 元素.addEventListener(事件类型, 事件处理函数, [是否捕获]);

事件类型: 不加on

事件处理函数: 函数名 函数

是否捕获: 默认false冒泡 true: 捕获

ie: 对象不支持“addEventListener”属性或方法

function a() {
    console.log(this);
}
console.log(div.addEventListener); // ie: undefined  标准: 函数
// div.addEventListener('click', a, false);
// div.addEventListener('click', function () {
//     console.log('这是第二个事件绑定的函数');
//     console.log(this);
// }, false);

ie

ie: 元素.attachEvent(on+事件类型, 事件处理函数);

console.log(div.attachEvent); // ie: 函数  标准: undefined
div.attachEvent('onclick', a);
div.attachEvent('onclick', function () {
    console.log('这是添加的第二个');
    console.log(this);
});

ie和标准事件机制的区别:

\1. 是否加on: ie: 加on 标准: 不加

\2. 是否捕获: ie: 没有捕获 标准: 有捕获

\3. 执行顺序: ie: 倒叙执行 标准: 顺序执行

\4. this的指向: ie: window 标准: 触发源

兼容

if (div.addEventListener) {
    // 标准
    div.addEventListener('click', a, false);
    div.addEventListener('click', function () {
        console.log('这是第二个事件绑定的函数');
        console.log(this);
    }, false);
} else {
    // ie
    div.attachEvent('onclick', a);
    div.attachEvent('onclick', function () {
        console.log('这是添加的第二个');
        console.log(this);
    });
}

封装

function bind(ele, type, fn) {
    // ele: 元素
    // type: 事件类型
    if (ele.addEventListener) {
        // 标准
        ele.addEventListener(type, fn, false);
    } else {
        // ie
        ele.attachEvent('on' + type, fn);
    }
}

事件解绑/事件取消:

元素.事件 元素.事件 = null;

addEventListener 元素.removeEventListener(事件类型, 函数名, [是否捕获]);

attachEvent 元素.detachEvent(on+事件类型, 函数名);

var div = document.querySelector('div');
div.onclick = function () {
    console.log(123);
}

div.onclick = null;

function a() {
    console.log(111);
}
bind(div, 'click', a);
console.log(div.removeEventListener); // ie: undefined 标准: 函数
console.log(div.detachEvent); // ie: 函数  标准: undefined 
// div.removeEventListener('click', a, false);
// div.detachEvent('onclick', a);

// if(div.removeEventListener){
//     // 标准
//     div.removeEventListener('click', a, false);
// } else {
//     // ie
//     div.detachEvent('onclick', a);
// }

封装

unbind(div, 'click', a);
function unbind(ele, type, fn ) {
    if (ele.removeEventListener) {
        // 标准
        ele.removeEventListener(type, fn, false);
    } else {
        // ie
        ele.detachEvent('on' + type, fn);
    }
}

事件流

事件流: 当事件发生的时候, 事件在父子节点之间固定的传递顺序。

捕获型事件(标准) 冒泡型事件

捕获阶段: 当事件发生的时候, 事件从window开始往子元素传递

确定目标: 确定鼠标的触发源

冒泡阶段: 触发源接收到事件并且开始处理. 处理完成后, 会将事件从当前往父节点传递,一直到window

所有事件经过的节点, 都会接收并且去触发这个事件

阻止冒泡

标准: 事件对象.stopPropagation();

ie: 事件对象.cancelBubble = true;

兼容: 如果一个方法一个属性 用方法是否存在来做判断

ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;

// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
console.log(btn, div);

// 点击
btn.onclick = function (evs) {
    var ev = window.event || evs;
    // 阻止冒泡
    // console.log(ev.stopPropagation); // ie: undefined 标准: 函数
    // ev.stopPropagation();
    // ev.cancelBubble = true;
    ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true; 


    console.log(1);
    div.style.display = 'block';
}

document.onclick = function () {
    console.log(2);
    div.style.display = 'none';
}

取消默认行为

默认行为:

a标签的跳转

右键菜单

按下拖拽的时候选中文字

图片拖拽保存

取消默认行为:

元素.事件 return false

标准: addEventListener ev.preventDefault();

ie: attachEvent ev.returnValue = false;

兼容:

ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;

var a = document.querySelector('a');
console.log(a);

// a.onclick = function () {
//     console.log('点击');

//     // 取消默认行为
//     return false;
// }

bind(a, 'click', function (evs) {
    var ev = window.event || evs;
    // ev.preventDefault();
    // ev.returnValue = false;
    ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; 
    console.log('点击了');
});

事件委托

事件委托(事件代理): 将子元素要做的事情交给父元素, 通过target或srcElement找到指定的触发源, 将后续代码交给触发源来处理

优点:

\1. 如果现在元素数量过多 执行速度较快

\2. 如果元素发生在未来, 后面的元素也有事件

ul.onclick = function (evs) {
    var ev = window.event || evs;
    console.log(ev.target || ev.srcElement);
    var tar = ev.target || ev.srcElement;
    // 判断触发源是不是li 如果是li 输出内容
    if(tar.nodeName == 'LI'){
        console.log(tar.innerHTML);
    }
}

var li1 = document.createElement('li');
li1.innerHTML = '2222';
ul.appendChild(li1);

键盘事件

document\表单元素

onkeyup 抬起

obkeydown 按下 键盘上任何一个键都可以触发 不区分大小写, 返回大写的编码

特殊键shift + 1 ---> shift + 49 --> ! + 49

obkeypress 按下 键盘上字符可以触发 区分大小分, 返回大写和小写字母的编码

特殊键shift + 1 ---> ! 33

document.onkeydown = function (evs) {
    var ev = window.event || evs;
    // console.log(ev); // KeyboardEvent
    console.log(ev.key); // 标准: 具体的字符 ie: undefined
    console.log(ev.keyCode); // ASCII码
}

// document.onkeypress = function (evs) {
//     var ev = window.event || evs;
//     // console.log(ev); // KeyboardEvent
//     console.log(ev.key); // 标准: 具体的字符 ie: undefined
//     console.log(ev.keyCode); // ASCII码
// }

document.onkeyup = function (evs) {
    var ev = window.event || evs;
    console.log(ev.keyCode);
}

滚轮事件

chrome/ie: onmousewheel

wheelDelta: 120或150的倍数

> 0 向上

< 0 向下

ff: 事件必须通过事件监听的方式 DOMMouseScroll

detail: 3和3的倍数

> 0 向下

< 0 向上

function mouseScroll(ele, upFn, downFn) {
    // ele: 元素
    ele.onmousewheel = scroll;
    if (ele.addEventListener) {
        ele.addEventListener('DOMMouseScroll', scroll);
    }
    // 滚动滚轮触发的事件
    function scroll(evs) {
        var ev = window.event || evs;

        if (ev.wheelDelta) {
            // chrome ie
            var tag = ev.wheelDelta > 0 ? '上' : '下';
        } else {
            // ff
            var tag = ev.detail > 0 ? '下' : '上';
        }   

        // 根据滚轮向上向下执行不同的代码
        if (tag == '上') {
            upFn();
        } else {
            downFn();
        }

    }
}

回调函数

回调函数: 执行完一个动作之后还要继续执行的函数

作为实参传递的函数就是回调函数

function a() {
    console.log(123);
}


function b(fn) {
    // fn: 形参 函数 回调函数
    console.log(fn);
    fn();
}
b(a);

匿名函数

匿名: 没有名字的函数

直接写会报错 将匿名函数转换成函数表达式 外面加() 同样具有函数的特点

立即执行函数: IIFE

  1. 函数自执行

    使用: 团队协作

    注意: 分号必须加 不能省略

    (function () {
        console.log('匿名函数');
    })();
    
    (function () {
        console.log('匿名函数1');
    }());
    
  2. 有参数

    (function (a, b) {
        console.log(a, b);
        console.log(arguments);
    })(10, 20);
    
  3. 有函数返回值

    var res = (function () {
        return true;
    })();
    console.log(res);
    

闭包

概念

闭包: 可以访问其他函数内部变量的函数就是闭包

组成: 函数里面套函数 内部函数访问外部函数的变量

优点: 扩大变量的作用范围 缓存数据

缺点: 如果有大量缓存数据 会造成内存泄漏 不参与垃圾回收机制

调试:

使用断点调试

\1. outer的第一行代码

\2. inner的第一行代码

\3. 刷新 看右侧或者底部的 Scope

local: 当前作用域

Global: 全局

closure: 闭包

注意: 外部函数调用一次就会形成一个新的闭包

function outer() {
    var a = 10;
    function inner() {
        a++;
        console.log(a);
    }
    // 设置返回值
    return inner;
}
var res = outer();
console.log(res); // inner函数
res(); // 11
res(); // 12

// 外部函数调用一次就会形成一个新的闭包
var res1 = outer();
res1();

使用

当当前作用域需要自己的变量值的时候 使用闭包

在for循环所添加的事件中 解决不能通过下标得到正确的元素的问题

var lis = document.querySelectorAll('li');
console.log(lis);
// for(var i = 0; i < lis.length; i++){
//     lis[i].onclick = function () {
//         console.log(i); // 10
//     };
// }

for(var i = 0; i < lis.length; i++){
    (function (s) {
        // console.log(s);
        lis[s].onclick = function () {
            console.log(s);
        };
    })(i);
}

模拟私有变量

// 创建账号
function create(val) {
    var user = val;
    // console.log(user);
    // 如果想要在函数外读取或者设置 必须通过当前函数提供的专用函数来实现效果
    return {
        getUser: function () {
            console.log(user);
        },
        setUser: function (v) {
            user = v;
        }
    };
}
var u = create('小时候超白');
console.log(u);
u.getUser();
u.setUser('长大后超黑');
u.getUser();

// 与上面的user无关
user = '中年时候超胖';
console.log(user);
u.getUser();

面试题

  1. 输出结果

    function fun(n, o) {
        console.log(o);
        return {
            "fun": function (m) {
                return fun(m, n);
            }
        }
    }
    /* 
        var a = fun(n, o)--> fun(0) --> n = 0 o = undefined
        a = {fun: function(m){  }}
            a.fun(1)
                m = 1 fun(m, n)  m = 1  n = 0  fun(1, 0) --> fun(n, o) n = 1 o = 0 log(o) --> 0
            a.fun(2)
                m = 2 fun(m, n) m = 2 n = 0 fun(2, 0) --> fun(n, o) n = 2 o = 0 log(o) --> 0
            a.fun(3)
                m = 3 fun(m, n) m = 3 n = 0 fun(3, 0) --> fun(n, o) n = 3 o = 0 log(o) --> 0
    
    */
    var a = fun(0); // undefined
    a.fun(1);  // 0
    a.fun(2); // 0
    a.fun(3); // 0
    
  2. 输出结果和执行顺序

    for(var i = 0; i < 5; i++){
        setTimeout(function () {
            console.log(i, new Date(), new Date().getTime()); // 5 当前时间+1s
        }, 1000);
    }
    console.log(i, new Date()); // 5 
    /* 
        同步: 当前代码执行的时候 后续的代码等着 alert for
        异步: 当前代码执行的时候 后续代码不等待执行完成 就可以直接执行 定时器
    */
    

代码分类

同步: 当前代码执行的时候 后续的代码等着 alert for

异步: 当前代码执行的时候 后续代码不等待执行完成 就可以直接执行 定时器

递归

递归: 函数里面调用自己的函数

注意: 一定要有函数结束的条件

将大的操作划分小操作重复执行的时候使用

报错: Uncaught RangeError: Maximum call stack size exceeded 栈溢出 ---> 原因: 递归函数没有设置结束条件

// 阶乘: 6! = 6 * 5 * 4 * 3 * 2 * 1
// function jc(n) {
//     return n * jc(n - 1);
// }

function jc(n) {
    // 设置结束条件
    if(n == 1){
        return 1;
    }
    return n * jc(n - 1);
}
var s = jc(6);
console.log(s);
console.log(jc(10));
console.log(jc(100));

斐波那契数列

有名的兔子问题: 出生2个月后每个月都会生产一对新兔子

月份 兔子

1 1 1

2 1 1

3 2 1 1

4 3 1 1 1

5 5 1 1 1 1 1

6 8 1 1 1 1 1 1 1 1

7 13 1 1 1 1 1 1 1 1 1 1 1 1 1

序列: 1 1 2 3 5 8 13 21

当前月的兔子 = 上个月的兔子个数 + 上上个月的兔子个数

第二个月和第一个月的时候 个数都是1

用函数求第n个月的兔子个数

function fib(n) {
    // 设置返回值 结束条件
    if(n == 1 || n == 2){ return 1; }
    return fib(n-1) + fib(n-2);
};

console.log(fib(6));
console.log(fib(12));

/* 
    第6个月的兔子 = 5 + 4
                = 4 + 3 + 3 + 2
                = 3 + 2 + 2 + 1 + 2 + 1 + 2
                = 2 + 1 + 2 + 2 + 1 + 2 + 1 + 2
*/

快速排序

快速排序: 找到中间项 进行左右重复排序的过程

\1. 有一个函数处理排序函数

\2. 找到中间项的下标

\3. 找到中间项

\4. 删除中间项

\5. 创建两个空数组 放置比中间项小 和 大的值

\6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边

\7. 左右数组需要重复排序

\8. 设置每次排序以后的返回结果

\9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回

var arr = [32, 12, 435, 56, 21, 78, 90];
// function qs(array) {
//     // 9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回
//     if(array.length <= 1){
//         return array;
//     }
//     // 2. 找到中间项的下标
//     var num = Math.floor(array.length / 2);
//     // console.log(num);
//     // 3. 找到中间项
//     var val = array[num];
//     // 4. 删除中间项
//     array.splice(num, 1);
//     // 5. 创建两个空数组 放置比中间项小 和 大的值
//     var left = [], right = [];
//     // 6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边
//     for(var i = 0; i < array.length; i++){
//         if(array[i] > val){
//             right.push(array[i]);
//         } else {
//             left.push(array[i]);
//         }
//     }
//     // 7. 左右数组需要重复排序
//     left = qs(left);
//     right = qs(right);
//     // 8. 设置每次排序以后的返回结果
//     return left.concat(val, right);

// };

function qs(array) {
    // 9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回
    if(array.length <= 1){
        return array;
    }
    // 2. 找到中间项的下标
    var num = Math.floor(array.length / 2);
    // 3-4:
    var val = array.splice(num, 1)[0];
    // 5. 创建两个空数组 放置比中间项小 和 大的值
    var left = [], right = [];
    // 6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边
    for(var i = 0; i < array.length; i++){
        if(array[i] > val){
            right.push(array[i]);
        } else {
            left.push(array[i]);
        }
    }
    // 7-8
    return qs(left).concat(val, qs(right));
};

var a =qs(arr);
console.log(a);

事件频繁触发

为了解决事件频繁触发的问题 引申出了防抖和节流

防抖

防抖: 利用闭包, 在用户触发的事件过程中不进行事件的处理 等待用户停止触发多长时间后 再进行事件的处理

只要用户在输入或者是移动 就不触发事件处理函数 等用户停止1s后 在执行事件处理函数

只要用户触发 时间需要重新计时

问题: 太生硬

// 防抖函数
function debounce(fn, wait) {
    // 解决全局变量的问题
    var timer = null;
    return function () {
        // 清除定时器
        clearTimeout(timer);
        // 延迟定时器
        timer = setTimeout(fn, wait);
    };
}
// 获取元素
var div = document.querySelector('div');
var n = 0;
// 添加事件
div.onmousemove = debounce(inner, 3000);

function inner() {
    n++;
    div.innerHTML = n;
};

节流

节流: 在一定的时间内 只能触发一次事件处理函数

利用闭包 为了解决全局变量

// 节流函数
function throttle(fn, wait) {
    // 假设当前可以触发函数
    var tag = true;
    var timer = null;
    return function () {
        // 判断当前是否可以触发函数
        if(tag){
            // 将状态变成不可触发
            tag = false;
            // 开启定时器
            timer = setTimeout(function () {
                fn();
                // 将状态变成可触发
                tag = true;
                clearTimeout(timer);
            }, wait);

        }
    };
}
// 获取元素
var div = document.querySelector('div');
var n = 0;
// 添加事件
div.onmousemove = throttle(inner, 100);

function inner() {
    n++;
    div.innerHTML = n;
};

call和apply

call和apply: 改变this指向

区别:

函数.call(this的新指向, ...data); 参数一个个用,分隔直接写

函数.apply(this的新指向, [...data]); 第二个参数是一个数组

call

var obj = {
    name: '张三',
    sayName: function () {
        console.log(this.name);
    }
};
obj.sayName(); // 张三

var obj1 = {
    name: '李四'
};
obj.sayName.call(obj1); // 李四

function fn() {
    console.log(this);
}
fn(); // window

fn.call(document);
fn.call(undefined);
fn.call(1);
fn.call('a');


function fn1(a, b) {
    console.log(this, a, b);
}
fn1(20, 30); // window 20 30
fn1.call(1, 10, 20); // 1 10 20

// 判断数据的类型
console.log(Object.prototype.toString()); // [object Object]
console.log(Object.prototype.toString.call(1)); // [object Number]
console.log(Object.prototype.toString.call('aaa')); // [object String]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call({}).slice(8, -1)); // Object
console.log(Object.prototype.toString.call([]).slice(8, -1)); // Array

apply

function fn1(a, b) {
    console.log(this, a, b);
}

fn1.apply(document, [44, 33]);
// 数组找最大和最小项
var arr = [32, 43, 546, 56, 32, 534, 234, 65];
console.log(Math.max.apply(this, arr));
console.log(Math.min.apply(this, arr));

面向对象

概念

概念: 基于对象 

面向过程: 一步步分析实现  注重过程
面向对象: 一种编程思想    注重结果

核心: 对象 

组成:
    方法: 函数 行为
    属性: 描述 属性

以类创建模板 实例化对象的过程 
es5中 没有明确的类的概念 用函数去创建模板 实例化对象

实例化: 具象化对象的时候 就是实例化

遵循: 有对象就要用对象 没有对象就创建对象

特点:
    封装 继承 多态

创建对象

字面量

字面量: 只适用于单个对象的创建

var obj = {
    name: '张三',
    age: 33,
    work: function () {
        console.log('为了碎银几两 辛辛苦苦工作');
    }
};
console.log(obj);
console.log(obj.name);
obj.work();

new关键字

new关键字创建: 代码冗余

// 1. 创建空对象
var obj = new Object();

// 2. 添加属性和方法
obj.name = '杨洋';
obj.age = 38;
obj.work = function () {
    console.log('演员');
};

console.log(obj);
console.log(obj.name);
obj.work();

工厂模式创建

问题:

\1. 识别不清

\2. 内存浪费

// 工厂
function createObj(name, age) {
    // 1. 创建空对象
    var obj = new Object();

    // 2. 添加属性和方法
    obj.name = name;
    obj.age = age;
    obj.work = function () {
        console.log('工作去吧');
    };

    // 3. 出厂 设置返回值
    return obj;
};

// 实例化对象
var obj = createObj('张三', 33);
var obj1 = createObj('古力娜扎', 28);
console.log(obj, obj1);
console.log(obj.name, obj1.name);
obj.work();
obj1.work();

// 判断对象是否是由createObj函数创建
// 对象 instanceof 函数  true--是 false--不是
console.log(obj instanceof createObj); // false
console.log(obj.work == obj1.work); // false

构造函数

构造函数:
    1. 构造函数首字母大写 为了和普通函数进行区分 (约定)
    2. 方法和属性直接加给this
    3. 必须使用new进行调用, 否则和普通函数没有区别

new的发生了什么:
    1. 创建一个空对象
    2. 将this指向当前空对象
    3. 将函数prototype 赋值给 对象的__proto__
    4. 添加属性和方法
    5. 隐式返回对象

问题:
    1. 内存浪费
function CreateObj(name, age){
    // // 1. 创建空对象
    // var obj = new Object();

    // 2. 添加属性和方法
    this.name = name;
    this.age = age;
    this.work = function () {
        console.log('工作去吧');
    };

    // // 3. 出厂 设置返回值
    // return obj;
}

// 实例化:
var obj = new CreateObj('迪丽热巴', 38);
var obj1 = new CreateObj('古力娜扎', 38);
console.log(obj, obj1);

console.log(obj instanceof CreateObj); // true
console.log(obj.work == obj1.work); // false

原型创建

问题: 不能传参

// 1. 构造函数
function CreateObj() {  };

// 2. 给原型添加属性和方法
CreateObj.prototype.name = '迪丽热巴';
CreateObj.prototype.age = 39;
CreateObj.prototype.work = function () {
    console.log('工作');
};

// 3. 实例化对象
var obj = new CreateObj();
var obj1 = new CreateObj();
console.log(obj, obj1);
console.log(obj.name, obj1.name);

// 原型链: 在对象或函数被创建的时候所自带的链表关系, 实现继承和查找;
// 找: 先找自身, 在找原型属性  在找object 找到直接返回 找到object都没有 返回undefined
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

混合创建

构造创建(可变的) + 原型创建(不变的)

// 1. 构造函数
function CreateObj(name, age) {
    this.name = name;
    this.age = age;
};

// 2. 给原型添加属性和方法
CreateObj.prototype.work = function () {
    console.log('工作');
};

// 3. 实例化对象
var obj = new CreateObj('张三', 23);
var obj1 = new CreateObj('李四', 33);
console.log(obj, obj1);
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

动态混合创建(了解)

在构造函数中判断原型上的方法和属性是否是期望值 不是的话在进行赋值

// 1. 构造函数
function CreateObj(name, age) {
    this.name = name;
    this.age = age;

    if (typeof this.work == 'function') {
        console.log('已经是函数');
    } else {
        console.log('不是函数');
        // 2. 给原型添加属性和方法
        CreateObj.prototype.work = function () {
            console.log('工作');
        };
    }
};



// 3. 实例化对象
var obj = new CreateObj('张三', 23);
var obj1 = new CreateObj('李四', 33);
console.log(obj, obj1);
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

原型

原型: 用来存储最顶层共享的方法和属性的对象
函数: prototype
对象: __proto__ 
var arr = [1,2,3,4];
arr.push(5);

console.log(arr);
console.log(arr.__proto__);


var brr = new Array(2,3,4,5);
console.log(brr);
console.log(brr.__proto__);
console.log(Array.prototype);

console.log(Array.prototype == brr.__proto__); // true

Array.prototype.push = function () {
    console.log('新方法');
};

brr.push(666);
console.log(brr);

原型链

原型链: 在对象或函数被创建的时候所自带的链表关系, 实现继承和查找;

面向对象的继承

原型链继承

子类构造函数的原型对象 = 父类构造函数的实例化对象;

原型链查找:
    找自身
    自身没有 找自身的原型对象(父类构造函数的实例化对象)
    如果没有 找父类构造函数的原型对象
    找object
    如果没有 返回undefined  如果在哪一步找到了 直接返回结果

constructor:
    当前对象的构造函数

原型链继承: 
    1. 无法识别当前对象真正的构造函数
    2. 一改全改
    3. 不能传参
    4. 子类构造函数身上的原型对象的属性和方法不能继承
// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(){}

Son.prototype.hobby = function () {
    console.log('打游戏');
};

// 3. 设置继承: 子类构造函数的原型对象 = 父类构造函数的实例化对象;
Son.prototype = new Father('韩红', 50);


// 4. 实例化对象
var son1 = new Son();

console.log(son1);
console.log(son1.name);
console.log(son1.name1);

对象冒充继承

在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this

不能继承父类构造函数的原型对象上的方法和属性

// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(name, age){
    // 3. 在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this
    Father.call(this, name, age);
}

Son.prototype.hobby = function () {
    console.log('打游戏');
};

// 4. 实例化对象
var son1 = new Son('张三', 12);
var son2 = new Son('李四', 12);
console.log(son1, son2);
son1.money.push('股票');
console.log(son1.money, son2.money);
/* 
    不能继承父类构造函数的原型对象上的方法和属性
*/
console.log(son1.name1);

组合继承

组合继承: 原型链 + 对象冒充

\1. 子类构造函数的原型对象的方法和属性继承不了

\2. 父类构造函数的属性和方法多次继承

// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(name, age){
    // 3. 在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this
    Father.call(this, name, age);
}

Son.prototype.hobby = function () {
    console.log('打游戏');
};

// 3. 子类构造函数的原型对象 = 父类构造函数的实例化对象
Son.prototype = new Father();

// 4. 实例化对象
var son1 = new Son('张三', 12);
var son2 = new Son('李四', 12);
console.log(son1, son2);
son1.money.push('股票');
console.log(son1.money, son2.money);
/* 
    不能继承父类构造函数的原型对象上的方法和属性
*/
console.log(son1.name1);

寄生式组合继承

Object.create(原型对象): 使用原型对象创建一个对象

/* 
    组合继承: 原型链 + 对象冒充
        1. 子类构造函数的原型对象的方法和属性继承不了
        2. 父类构造函数的属性和方法多次继承
*/
// 1. 父类构造函数
function Father(name, age) {
    this.name = name;
    this.age = age;
    this.money = ['交通', '存款', '理财'];
}

Father.prototype.work = function () {
    console.log('工作有收入');
};

// 2. 子类构造函数
function Son(name, age){
    // 3. 在子类构造函数中 调用父类构造函数 将父类构造函数this指向当前的this
    Father.call(this, name, age);
}

// 3. 子类构造函数的原型对象 = 父类构造函数的实例化对象
// Object.create(原型对象): 使用原型对象创建一个对象
// console.log(Object.create(Father.prototype));
Son.prototype = Object.create(Father.prototype);
// 单独设置
Son.prototype.constructor = Son;

// 后续son的原型对象添加属性和方法
Son.prototype.hobby = function () {
    console.log('打游戏');
};

var son1 = new Son('张三', 12);
console.log(son1);

图示

LESS

简单使用

官网: https://less.bootcss.com/
vscode:
    安装一个插件: easy less 
    koala
在vscode配置插件:
    "out": "../css/",


后续开发:
    less放在less文件夹下
    css放在css下

如果第一个按ctrl+s没有生成css文件  关闭vscode 在尝试保存

html文件中引入还是 .css 文件

注释

// 行注释 不会出现在css中

/*

块注释

会出现在css文件中

*/

// 行注释 不会出现在css中
/* 
    块注释
    会出现在css文件中
*/
*{
    margin: 0;
    padding: 0;
    list-style: none;
}

编译后:

/* 
    块注释
    会出现在css文件中
*/
* {
  margin: 0;
  padding: 0;
  list-style: none;
}

变量

声明变量 @名字: 设置的值;

@w: 200px;
@h: 300px;
@color: orangered;

div{
    width: @w;
    height: @h;
    background: @color;
}

编译后:

div {
  width: 200px;
  height: 300px;
  background: orangered;
}

作用域

作用域用来使用变量 根据就近原则使用

// 全局
@w: 200px;
@h: 300px;
@c: orangered;

*{
    @w: 300px;
    @h: 300px;
    @c: lightblue;

    div{
        @c: green;
        
        width: @w;
        height: @h;
        background: @c;
    }
}

编译后:

* div {
  width: 300px;
  height: 300px;
  background: green;
}

混合

在一个选择器中使用另一个选择器的所有样式

*{
    margin: 0;
    padding: 0;
    list-style: none;
}

.first{
    width: 200px;
    height: 300px;
    background: red;
    margin: 20px;
}

.two{
    .first();
    background: orangered;
    font-size: 30px;
}

编译后:

* {
  margin: 0;
  padding: 0;
  list-style: none;
}
.first {
  width: 200px;
  height: 300px;
  background: red;
  margin: 20px;
}
.two {
  width: 200px;
  height: 300px;
  background: red;
  margin: 20px;
  background: orangered;
  font-size: 30px;
}

嵌套

嵌套的结构与html结构一致

父{

子{}

&表示当前元素, 添加伪类选择器

}

*{
    margin: 0;
    padding: 0;
    list-style: none;

    ul{
        width: 100%;
        // height: 300px;
        background: red;
        li{
            float: left;
            width: 300px;
            // height: 300px;
            overflow: hidden;
            border: 1px solid #000;
            img{
                width: 100%;
                height: 100%;
            }
        }

        &::after{
            content: '';
            display: block;
            clear: both;
            *zoom: 1;
        }
    }
}

编译后:

/* 
    嵌套的结构与html结构一致
    父{
        子{}
        &表示当前元素, 添加伪类选择器
    }

*/
* {
  margin: 0;
  padding: 0;
  list-style: none;
}
* ul {
  width: 100%;
  background: red;
}
* ul li {
  float: left;
  width: 300px;
  overflow: hidden;
  border: 1px solid #000;
}
* ul li img {
  width: 100%;
  height: 100%;
}
* ul::after {
  content: '';
  display: block;
  clear: both;
  *zoom: 1;
}

嵌套规则与冒泡

@ 规则(例如 @media@supports)可以与选择器以相同的方式进行嵌套。@ 规则会被放在前面,同一规则集中的其它元素的相对顺序保持不变。这叫做冒泡(bubbling)。

div{
    width: 800px;
    height: 600px;
    background: red;
    @media screen and (max-width: 992px) {
        background: green;

        @media (min-width: 768px) {
            background: orange;
        }
    }
}

编译后:

div {
  width: 800px;
  height: 600px;
  background: red;
}
@media screen and (max-width: 992px) {
  div {
    background: green;
  }
}
@media screen and (max-width: 992px) and (min-width: 768px) {
  div {
    background: orange;
  }
}

运算

算术运算符 +-*/ 可以对任何数字、颜色或变量进行运算。如果可能的话,算术运算符在加、减或比较之前会进行单位换算。计算的结果以最左侧操作数的单位类型为准。如果单位换算无效或失去意义,则忽略单位。无效的单位换算例如:px 到 cm 或 rad 到 % 的转换。

@w: 200px;
@h: 200px;
div{
    width: @w + 100 + 10em;
    height: @h * 2 + 10pt;
    background: red;
}

编译后:

div {
  width: 310px;
  height: 413.33333333px;
  background: red;
}

转义

转义: ~"字符串" ~'字符串' 新: 字符串

/* 
    转义: ~"字符串" ~'字符串'
    新: 字符串
*/

@max992: ~"(max-width: 992px)";
// @max768: (max-width: 768px);
div{
    width: 1000px;
    height: 400px;
    background: pink;
    @media @max992 {
        background: skyblue;
    }
    // @media @max768{
    //     background: lightcoral;
    // }
}

编译后:

/* 
    转义: ~"字符串" ~'字符串'
    新: 字符串
*/
div {
  width: 1000px;
  height: 400px;
  background: pink;
}
@media (max-width: 992px) {
  div {
    background: skyblue;
  }
}

映射

类似于js中对象的使用,将一组值组合起来使用

#color(){
    normal: #000;
    hl: orangered; 
    ll: lightcoral;
    lg: grey;
}

div{
   
    &:nth-child(1){
        color: #color[normal];
    }
    &:nth-child(2){
        color: #color[hl];
    }
    &:nth-child(3){
        color: #color[ll];
    }
    &:nth-child(4){
        color: #color[lg];
    }
}

编译后:

div:nth-child(1) {
  color: #000;
}
div:nth-child(2) {
  color: orangered;
}
div:nth-child(3) {
  color: lightcoral;
}
div:nth-child(4) {
  color: grey;
}

命名空间

类似于函数 有助于后期重用和重组

/* 
    先定好了一组less
*/
* {
    margin: 0;
    padding: 0;
    list-style: none;
}

#wrap() {
    .box {
        width: 100px;
        line-height: 50px;
        font-size: 30px;
        height: 50px;
        background: red;
    }

    .em{
        color: lightcoral;
    }
}

div {
    width: 200px;
    height: 200px;
    background: pink;

    p {
        #wrap>.box();
    }
}


p {
    #wrap.box();

    em{
        #wrap.em();
    }
}

编译后:

/* 
    先定好了一组less
*/
* {
  margin: 0;
  padding: 0;
  list-style: none;
}
div {
  width: 200px;
  height: 200px;
  background: pink;
}
div p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p em {
  color: lightcoral;
}

导入

在一个less文件中引入其他样式文件

less文件 后缀可以省略

css文件 后缀绝对不能省略

// less文件 后缀可以省略
@import './11';
// css文件 后缀绝对不能省略
@import '../css/07.css';
@import '../css/06.css';

编译后:

/* 
    先定好了一组less
*/
@import '../css/07.css';
@import '../css/06.css';
* {
  margin: 0;
  padding: 0;
  list-style: none;
}
div {
  width: 200px;
  height: 200px;
  background: pink;
}
div p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p {
  width: 100px;
  line-height: 50px;
  font-size: 30px;
  height: 50px;
  background: red;
}
p em {
  color: lightcoral;
}

本地存储

存储

localStorage.属性名 = 属性值;

localStorage.setItem(属性名, 属性值);

// localStorage.属性名 = 属性值;
localStorage.firstName = '迪丽';

// localStorage.setItem(属性名, 属性值);
localStorage.lastName = '热巴';
console.log(localStorage);

取值

. [] localStorage.属性名 localStorage['属性名']

localStorage.getItem('属性名');

// 取值
// . [] localStorage.属性名  localStorage['属性名']
console.log(localStorage.firstName);
console.log(localStorage['lastName']);

// localStorage.getItem('属性名');
console.log(localStorage.getItem('firstName'));

清除

设置成空字符串

删除: localStorage.removeItem('属性名');

批量清空

// 设置成空字符串
localStorage.firstName = '';

// 删除: localStorage.removeItem('属性名');
localStorage.removeItem('lastName');

// 批量清空 
localStorage.clear();

console.log(localStorage);

json数据与js数据互转

数组包对象

单纯对象

前后端数据交互的时候进行使用

\1. 将json格式的字符串转成js数据:

JSON.parse(数据);

\2. 将js数据转成json格式的字符串

JSON.stringify(数据);

var data = [{
    name: '李四',
    age: 33,
    tip: '提示'
},{
    name: '李四1',
    age: 33,
    tip: '提示'
},{
    name: '李四2',
    age: 33,
    tip: '提示'
}];
localStorage.list = JSON.stringify(data);
console.log(localStorage);

var d = localStorage.list;
console.log(d);
console.log(JSON.parse(d));

audio

属性

src: 播放文件地址

autoplay: 基于用户体验角度 各大浏览器禁止自动播放

controls: 控制器显示

muted: 是否静音

loop: 是否循环播放

currentSrc: 当前播放地址

currentTime: 当前播放时长 单位 s

duration: 音频时长 单位 s

volume: 音乐音量 [0, 1] 最小值 0 最大值 1

paused: 音乐是否暂停播放 true--暂停 false--播放

ended: 音乐是否结束播放 true--结束 false--没有结束 设置了loop 音频重复循环播放 不会结束

playbackRate: 播放速度

// 获取元素
var audio = document.querySelector('audio');

// 获取属性
console.log(audio.src);
audio.autoplay = false;
console.log(audio.autoplay);
// audio.controls = false;
console.log(audio.controls);
// audio.muted = true;
console.log(audio.muted);
audio.loop = true;
console.log(audio.loop);
console.log(audio.currentSrc);
console.log(audio.currentTime);
console.log(audio.duration);
console.log(audio.volume); // 音乐音量 [0, 1]  最小值 0  最大值 1
console.log(audio.paused); // 音乐是否暂停播放 true--暂停 false--播放
console.log(audio.ended); // 音乐是否结束播放 true--结束 false--没有结束 设置了loop 音频重复循环播放 不会结束
console.log(audio.playbackRate); // 播放速度 

btns[0].onclick = function () {
    audio.src = './金玟岐-岁月神偷 (Demo).mp3';
};

btns[1].onclick = function () {
    audio.currentTime = audio.duration / 2;
};

btns[2].onclick = function () {
    audio.volume = 0;
};

btns[3].onclick = function () {
    audio.volume = 0.5;
};

btns[4].onclick = function () {
    audio.volume = 1;
};

btns[5].onclick = function () {
    // 报错: The volume provided (2) is outside the range [0, 1]. 音量只能设置[0,1]之间的值
    audio.volume = 2;
};

btns[8].onclick = function () {
    audio.playbackRate = 0.1;
};

btns[9].onclick = function () {
    audio.playbackRate = 1;
};

btns[10].onclick = function () {
    audio.playbackRate = 10;
};

事件

oncanplay: 音频可以播放事件

ontimeupdate: 播放时间更新的事件

onended: 当音频结束播放事件

onpause: 当音频播放暂停事件

// 音频可以播放事件
audio.oncanplay = function () {
    // console.log(audio.currentSrc);
    // console.log(audio.duration);
};

// 播放时间更新的事件
audio.ontimeupdate = function () {
    // console.log(audio.currentTime);
    // console.log(audio.paused);
};

// 当音频结束播放事件
audio.onended = function () {
    console.log(audio.ended);
};


// 当音频播放暂停事件
audio.onpause = function () {
    // console.log(audio.paused);
};

方法

load: 重新加载音频

pause: 暂停播放

play: 播放音乐

btns[6].onclick = function () {
    audio.load(); // 重新加载音频
    audio.play(); // 播放音乐
};

btns[7].onclick = function () {
    audio.pause(); // 暂停播放
};

video

属性

poster: 图片

src: 播放地址

height: 高

width: 宽

autoplay: 静音下自动播放

muted: 静音状态

controls: 控制器

loop: 循环

currentSrc: 当前播放地址

currentTime: 当前播放时长 单位 s

duration: 音频时长 单位 s

paused: 是否暂停

ended: 结束 loop设置为true 一直false

playbackRate: 当前视频的播放速度

defaultPlaybackRate: 默认视频播放速度

volume: 音量 [0,1]

var video = document.querySelector('video');

console.log(video.src);
console.log(video.poster);
console.log(video.muted);
console.log(video.loop);
console.log(video.controls);
console.log(video.width);
console.log(video.height);
console.log(video.currentSrc);
console.log(video.duration);
console.log(video.currentTime);
console.log(video.paused); // 是否暂停
console.log(video.ended); // 结束 loop设置为true 一直false 
console.log(video.playbackRate); // 当前视频的播放速度
console.log(video.defaultPlaybackRate); // 默认视频播放速度
console.log(video.volume); // 音量 [0,1]
/* 
    芒果: 
        当前播放速度是 2 playbackRate
        下一个视频 播放速度 1 defaultPlaybackRate
    腾讯:
        当前播放速度 2
        下一个视频播放速度 2
*/

事件

oncanplay: 音频可以播放事件

ontimeupdate: 播放时间更新的事件

onended: 当音频结束播放事件

onpause: 当音频播放暂停事件

// 可以播放
video.oncanplay = function () {
    // console.log(video.currentSrc);
    // console.log(video.duration);
};

// 播放时间改变
video.ontimeupdate = function () {
    // console.log(video.currentTime);
};

video.onpause = function () {
    // console.log(video.paused);
};

video.onended = function () {
    // console.log(video.ended); // 结束
};

方法

load: 重新加载音频

pause: 暂停播放

play: 播放音乐

btns[4].onclick = function () {
    video.play();
};

btns[5].onclick = function () {
    video.pause();
};

btns[6].onclick = function () {
    video.load();
};

jQuery

介绍

jquery: js的工具库

事件处理

文档的处理

动画

唯一变量 $ jQuery

强大的选择器

开源

完善的文档

...

jquery:

\1. 官网:

\2. cdn: jquery (v3.6.0) - jQuery 是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器,这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单。 | BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

\3. 文档: jQuery API 中文文档 | jQuery API 中文在线手册 | jquery api 下载 | jquery api chm

版本:

> 2: 不兼容ie

1.xx: 兼容ie

最新版本: 3.6.0

jquery.js: 未压缩 学习

jquery.min.js: 压缩 工作

引入:

\1. 线上

不推荐

\2. 本地



冲突解决

jQuery覆盖其他




其他覆盖jQuery



选择器

基础选择器

基本选择: 标签 类名 id 组合选择器

css选择器怎么写 jq中选择器就怎么写

console.log($('li'));
console.log($('.box'));
console.log($('#six'));
console.log($('#six, .box'));

层级选择器

后代选择器: 父 子

直接子元素: 父 > 子

相邻选择器: 选1 + 选2

兄弟后面的: 选1 ~ 选择2

console.log($('ul li'));
console.log($('ul > li'));
console.log($('.box + div'));
console.log($('li + div'));
console.log($('.box ~ div'));

基础过滤

基础过滤选择器: first last eq gt lt even odd

console.log($('li:first')); // 第一个
console.log($('li:last')); // 最后一个
console.log($('li:eq(0)')); // 获取指定下标的元素
console.log($('li:gt(4)')); // 获取大于指定下标的元素
console.log($('li:lt(4)')); // 获取小于指定下标的元素
console.log($('li:even').css('background', 'red')); // 获取偶数(下标是偶数)
console.log($('li:odd').css('background', 'pink')); // 获取奇数(下标是奇数)
// jq对象.css(属性名, 属性值);
// jq中非语法错误 不会报错

属性过滤

console.log($('li[class]').css('background', 'red')); // 获取带有class属性的li
console.log($('li[class=box]').css('background', 'blue')); // 获取li中class为box的li
console.log($('li[class^=b]').css('background', 'skyblue')); // 获取li中以b字母为开头 
console.log($('li[class$=x]').css('background', 'pink')); // 获取li中以x字母为结尾
console.log($('li[class!=box]').css('background', 'yellow')); // 获取li中class不等于box的li

子元素过滤

子元素过滤: first-child last-child nth-child

$('ul li:first-child').css('background', 'red');
$('ul li:last-child').css('background', 'red');
$('ul li:nth-child(3)').css('background', 'red');

内容过滤

内容过滤: contains empty has parent 了解

console.log($('li:contains(1)').css('background', 'pink'));
console.log($('li:empty').css('background', 'yellow'));
console.log($('li:has(p)').css('background', 'skyblue'));
console.log($('p:parent').css('background', 'red'));

表单过滤

:input 获取所有的表单元素

:type的值

console.log($(':input'));
console.log($(':text'));
console.log($(':password'));
console.log($(':radio'));
console.log($(':checkbox'));
console.log($(':file'));
// console.log($(':date')); // 报错 


// textarea select 直接获取 不需要加:
console.log($('textarea'));

表单属性

console.log($(':enabled'));
console.log($(':disabled'));
console.log($(':checked'));
console.log($(':checkbox:checked')); // 复选框中被选中
console.log($(':selected'));

jq方法特性

\1. 取赋值一体化

既可以获取值 也可以设置值

除了txt 以外 所有方法取值只获取第一个符合选择器条件的元素的值

设置值的时候 迭代设置

\2. 隐式迭代:

每一个方法在设置的时候, 会自动遍历每一个符合选择器的元素并且设置

\3. 链式调用

每个jq方法在执行以后 会将被操作的对象或操作以后的对象返回回来,会了方便下一个方法直接使用

\4. jq对象只能使用jq方法 js对象只能使用js的方法

console.log($('li').css('font-size'));
// console.log($('li').css('font-size', 20));
// var lis = $('li').css('font-size', 20);
// console.log(lis);
// lis.click(function () {
//     console.log(this.innerHTML);
// });

$('li').css('font-size', 20).click(function () {
    // console.log(this.innerHTML);
    console.log(this);
});

查找节点

节点遍历

每个方法都可以接收一个选择器作为筛选条件

console.log($('ul').children()); // 直接子元素
console.log($('ul').children('li')); // 直接li子元素

console.log($('div').parent()); // 直接父元素
console.log($('div').parents()); // 获取到html为止所有的父元素
console.log($('div').parents('body')); 

console.log($('hr').prev()); // 紧跟着hr的上一个元素
console.log($('hr').prevAll()); // hr前面所有的兄弟节点
console.log($('hr').prevAll('li'));

console.log($('hr').next()); // 紧跟着hr的下一个元素
console.log($('hr').nextAll()); // 后面所有的
console.log($('hr').nextAll('div')); // 后面所有的div

console.log($('hr').siblings()); // 获取所有的兄弟节点

节点过滤

console.log($('li').first());
console.log($('li').last());
console.log($('li').eq(3));
$('li').filter('.box').css('background', 'red');
$('li').not('.box').css('background', 'pink');
$('ul').find('.box').css('background', 'skyblue');

操作属性

attr: 可以操作一切属性 不建议属性值为true和false

获取: jq对象.attr('属性名');

设置: jq对象.attr('属性名', '属性值');

移除: jq对象.removeAttr('属性名');

prop: 操作固有属性 建议属性值为true和false

获取: jq对象.prop('属性名');

设置: jq对象.prop('属性名', '属性值');

// console.log($('li').attr('class'));
// console.log($('li').attr('class', 'box abc'));
// $('li').attr('tag', 123);
// console.log($('li').attr('tag'));


console.log($('li').prop('class')); // box a
console.log($('li').prop('class', 'nC'));
console.log($('li').prop('tag', 'aaa'));
console.log($('li').prop('a')); // undefined

// console.log($(':checkbox').attr('checked')); // undefined  checked
// console.log($(':checkbox').prop('checked')); // true
// console.log($(':checkbox').prop('checked', true));

$('li').removeAttr('a');

操作类名

添加: 原有类名的基础上添加

jq对象.addClass('类名 类名');

移除: 原有类名的基础上删除指定

jq对象.removeClass('类名 类名');

切换: 有就删除 没有就添加

jq对象.toggleClass('类名');

判断是否有某个类名: 返回布尔值 true--有 false--没有

jq对象.hasClass('类名');

判断对象是否符合某个选择器:

jq对象.is('选择器');

$('li').addClass('active');
$('li').click(function () {
    // console.log(this); // 触发源
    // $(this).addClass('active');
    // $(this).removeClass('active');
    console.log($(this).hasClass('active'));
    console.log($(this).is('.active'));
    $(this).toggleClass('active');

});

操作样式

jq对象.css();

获取:

jq对象.css(属性名);

设置:

单个: jq对象.css(属性名, 属性值);

多个: jq对象.css({});

{

属性名: 属性值,

属性名: 属性值,

属性名: 属性值

}

属性名: 可以加引号也可以不加 建议加引号

加引号可以使用- 不加引号 使用驼峰命名

属性值:

如果单位是px 省略px 直接写数字

表达式: '+=20' '-=10' 引号必须加

console.log($('div').css('width'));
$('div').css('width', '100px');
$('div').css({
    width: 200,
    height: 300,
    fontSize: 20,
    'font-weight': 800
});

$('div').click(function () {
    $('div').css({
        width: '+=100',
        height: '-=10'
    });
});

元素宽高

client: 可视宽高

innerWidth/innerHeight: 内容+内边距

offset: 占位宽高

outerWidth/outerHeight(布尔值):

false/不传: 内容 + 内边距 + 边框

true: 内容 + 内边距 + 边框 + 外边距

scroll: 滚动距离

console.log($('div').width(), $('div').height()); // 内容宽 内容高
console.log($('div').innerWidth(), $('div').innerHeight()); // 可视宽 可视高
console.log($('div').outerWidth(), $('div').outerHeight()); // 占位宽 占位高
console.log($('div').outerWidth(true), $('div').outerHeight(true)); // 占位宽 占位高

$(window).scroll(function () {
    // console.log($('body,html').scrollTop(), $('body,html').scrollLeft());
    console.log($(window).scrollTop(), $(window).scrollLeft());
});

/* 
    取赋值一体化
*/
console.log($('div').width(500), $('div').height(200));
console.log($('div').innerWidth(500), $('div').innerHeight(200));
console.log($('div').outerWidth(500), $('div').outerHeight(200));
console.log($('div').outerWidth(500, true), $('div').outerHeight(200, true));

$('button').click(function () {
    console.log($(window).scrollTop(500), $(window).scrollLeft(500));
});

元素的位置

position: 获取到的结果是当前元素的定位距离 以对象方式返回

{

left: 0,

top: 0

}

offset: 获取的元素距离body的一个偏移距离

/* 
    position: 获取到的结果是当前元素的定位距离 以对象方式返回
        {
            left: 0,
            top: 0
        }
*/
console.log($('div').position()); // {top: 33, left: 8}
console.log($('div').position().left);

/* 
    offset: 获取的元素距离body的一个偏移距离
*/
console.log($('div').offset());
console.log($('div').offset().left);

添加节点

  1. 创建节点: $('标签节点');

    var li = $('
  2. 12344
  3. '); console.log(li);
  4. 父元素末尾:

    父.append(子);

    子.appendTo('选择器');

    $('ul').append('
  5. a1234
  6. '); $('
  7. b1234
  8. ').appendTo('ul');
  9. 父元素开头:

    父.prepend(子);

    子.prependTo('选择器');

    $('ul').prepend('
  10. c1234
  11. '); $('
  12. d1234
  13. ').prependTo('ul');
  14. 插入某个元素之前:

    参考节点.before(新节点);

    新节点.insertBefore(参考节点);

    $('.box').before('
  15. 新Li1
  16. '); $('
  17. 新Li2
  18. ').insertBefore('.box');
  19. 插入到某个元素之后:

    参考节点.after(新节点);

    新节点.insertAfter(参考节点);

    $('.box').after('
  20. 新Li3
  21. '); $('
  22. 新Li4
  23. ').insertAfter('.box');

删除节点

remove: 删除当前元素 返回被删除掉的元素 不包含原来元素的行为

detach: 删除当前元素 返回被删除掉的元素 包含原来元素的行为

empty: 清空元素 删除当前元素中所有子节点

$('li').click(function () {
    console.log($(this).html());
});

/* 
    remove: 删除当前元素 返回被删除掉的元素 不包含原来元素的行为
    detach: 删除当前元素 返回被删除掉的元素 包含原来元素的行为
    empty: 清空元素 删除当前元素中所有子节点
*/
// $('ul').empty();

$('button').click(function () {
    // var li = $(this).parent().remove();
    var li = $(this).parent().detach();
    console.log(li);

    $('ul').append(li);
});

克隆节点

clone(布尔):

false/不传: 不克隆行为 不保留事件函数

$('li').click(function () {
    console.log($(this).html());
});

/* 
    clone(布尔):
        false/不传: 不克隆行为 不保留事件函数
*/
// var li  = $('li').eq(0).clone().appendTo('ul');
var li  = $('li').eq(0).clone(true).appendTo('ul');
console.log(li);

替换节点

参考节点.replaceWith(新节点);

新节点.replaceAll(参考节点);

/* 
    参考节点.replaceWith(新节点);
    新节点.replaceAll(参考节点);
*/
// $('li').replaceWith('

1234

'); $('
').replaceAll('li');

事件对象

/* 
    以事件处理函数的第一个形参
*/
$(window).click(function (ev) {
    console.log(ev); // jQuery.Event 
    console.log(ev.originalEvent); // js原生事件对象
    console.log(ev.type); // 事件类型
    console.log(ev.target);
    console.log(ev.keyCode); // 键盘编码
    console.log(ev.which); // 跟keyCode一致  比keyCode强大 左中右 123
    console.log(ev.pageX, ev.pageY); // 距离页面
    console.log(ev.clientX, ev.clientY); // 可视区域左上角
    console.log(ev.screenX, ev.screenY); // 屏幕
    console.log(ev.offsetX, ev.offsetY); // 触发源内容左上角 边框会出现负数
});

on

  1. 给一个元素绑定一个事件

    jq对象.on(事件类型, 事件处理函数);

    $('div').on('click', function () {
        console.log(this);
    });
    
  2. 给一个元素的多个事件添加同一处理函数

    jq对象.on('事件 事件 事件...', 事件处理函数)

    $('div').on('click mousedown mouseup', function (ev) {
        console.log(ev.type);
    });
    
  3. 给不同事件添加不同处理函数

    jq对象.on({

    事件: 函数,

    事件: 函数

    });

    $('div').on({
        mousemove: function (ev) {
            console.log(ev.clientX);
        },
        contextmenu: function () {
            console.log('contextmenu');
        }
    });
    
  4. 绑定自定义事件:

    由程序员自己定义的事件

    $('div').on('call', function () {
        console.log('okk');
    });
    
    // 手动触发自定义事件: jq对象.trigger('自定义事件名称');
    setTimeout(function () {
        $('div').trigger('call');
    }, 3000);
    
  5. 事件委托

    jq对象(父).on(事件类型, '子选择器', 事件处理函数);

    this指向的就是每一个子元素

    $('ul').on('click', 'li', function () {
        console.log(this);
    });
    
    $('ul').append('
  6. 1234
  7. ');

one

one: 与on是一样的 只会触发一次

$('div').one('click', function () {
    console.log(1);
});

off

// div添加事件
function aa() {
    console.log(1);
}
$('div').click(aa);
$('div').click(function () {
    console.log(2);
});
$('div').mousedown(function () {
    console.log('down');
});
// $('div').off(); // 取消所有的事件
// $('div').off('click'); // 取消所有的click的事件
// $('div').off('click', aa); // 取消click中名字为aa的事件
// $('div').off('click mousedown'); // 取消所有的click和mousedown所有事件

// jq中事件具有命名空间 事件.名 设置命名空间 避免全局变量的影响
$('div').on('click.cc', function () {
    console.log(3);
});

$('div').off('click.cc mousedown');

合成事件

jq对象.hover()

一个函数: 滑入滑出都触发

两个函数: 第一个滑入 第二个滑出

// $('div').hover(function (ev) {
//     console.log(ev.type);
// });

$('div').hover(function (ev) {
    console.log(ev.type);
}, function (ev) {
    console.log(ev.type, '1-----');
});

阻止冒泡和取消默认行为

$('p').click(function (ev) {
    console.log('p');

    // 阻止冒泡
    // ev.stopPropagation();
    // 取消默认行为
    // ev.preventDefault();

    // 阻止冒泡 + 取消默认行为
    return false;
});
$('div').click(function () {
    console.log('div');
});

动画

show/hide/toggle

show([s,[e],[fn]])

width + height + opacity

不传参: 没有动画效果

传参:

时间: 以ms为单位

运动曲线: 'swing' 'linear'

回调函数: 在动画执行完成后还要执行的操作

$('button').eq(0).click(function () {
    // $('div').show();
    // $('div').show(3000);
    $('div').eq(0).show(3000, 'swing', function () {
        console.log('结束');
    });
    // $('div').eq(1).show(3000, 'linear');
});

$('button').eq(1).click(function () {
    // $('div').hide();
    // $('div').hide(3000);
    $('div').hide(3000, function () {
        console.log('结束');
    });
});

$('button').eq(2).click(function () {
    // $('div').toggle();
    // $('div').toggle(3000);
    $('div').toggle(3000, function () {
        console.log('结束');
    });
});

slideDown/slideUp/slideToggle

slideDown([s,[e],[fn]])

height

不传参: 有动画效果 400ms

$('button').eq(0).click(function () {
    // $('div').slideDown();
    // $('div').slideDown(3000);
    // $('div').slideDown(3000, 'linear');
    $('div').slideDown(3000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(1).click(function () {
    // $('div').slideUp();
    // $('div').slideUp(3000);
    // $('div').slideUp(3000, 'linear');
    $('div').slideUp(3000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(2).click(function () {
    // $('div').slideToggle();
    // $('div').slideToggle(1000);
    // $('div').slideToggle(1000, 'linear');
    $('div').slideToggle(1000, 'linear', function () {
        console.log('结束了');
    });
});

fadeIn/fadeOut/fadeToggle/fadeTo

fadeIn([s,[e],[fn]])

不传参: 有动画效果 400ms

fadeTo(s, to 透明度, e, fn)

$('button').eq(0).click(function () {
    // $('div').fadeIn();
    // $('div').fadeIn(3000);
    // $('div').fadeIn(3000, 'linear');
    $('div').fadeIn(3000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(1).click(function () {
    // $('div').fadeOut();
    // $('div').fadeOut(1000);
    // $('div').fadeOut(1000, 'linear');
    $('div').fadeOut(1000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(2).click(function () {
    // $('div').fadeToggle();
    // $('div').fadeToggle(1000);
    // $('div').fadeToggle(1000, 'linear');
    $('div').fadeToggle(1000, 'linear', function () {
        console.log('结束了');
    });
});

$('button').eq(3).click(function () {
    $('div').fadeTo(400, 0.5);
});

自定义动画

语法一

jq对象.animate({动画参数}, duration, easing, callback)

动画参数: 对象 {width: 300px, height: 500px}

duration: 时长 400ms ms为单位

easing: linear swing

callback: 回调函数 动画完成以后

背景色无法通过jq动画方式实现效果

$('div').click(function () {
    $('div').animate({
        opacity: 0.5,
        width: 500,
        height: 500,
        background: 'black'
        // height: 'toggle'
        // height: 'hide'
    }, 3000, 'linear', function () {
        console.log('结束');
    });

});

语法二

jq对象.animate({动画参数}, {options});

动画参数: 对象 {width: 300px, height: 500px}

options: {

duration: 动画时间,

easing: 运动曲线,

complete: 动画完成后执行的回调函数,

step: 动画每一步执行后的回调函数,

queue: 动画是否进入队列, true--队列中排队 默认值 false--跟随第一个动画一起执行

}

$('div').click(function () {
    $('div').animate({
        width: 500,
        height: 500
    }, {
        duration: 3000,
        easing: 'linear',
        complete: function () {
            console.log('结束');
        },
        step: function () {
            // console.log($(this).width());
        },
        queue: true
    }).animate({
        opacity: 0.3
    }, {
        queue: false,
        duration: 3000
    });
});

动画注意

\1. 动画可以连缀 在连缀的过程中没有特殊设置 默认是进行队列执行

$('div').click(function () {
    $('div').animate({
        left: 500
    }, 1000).animate({
        top: 500
    }, 1000).animate({
        top: 0,
        left: 0
    }, 1000);
});

\2. .css所设置的样式 不会进入动画队列 会跟随第一个动画 在第一时间执行

$('div').click(function () {
    $('div').animate({
        left: 500
    }, 1000).animate({
        top: 500
    }, 1000)
    .css({
        background: 'pink',
        left: '1000px',
        width: 500
    })
    .animate({
        top: 0,
        left: 0
    }, 1000);
});

\3. .queue方法实现插队

jq对象.queue(函数); 函数中写要放进去的代码 函数有一个形参 这个形参是个函数

.queue后面的动画 都不在执行

$('div').click(function () {
    $('div').animate({
            left: 500
        }, 1000).animate({
            top: 500
        }, 1000)
        .queue(function (next) {
            $('div').css({
                background: 'pink',
                // left: '1000px',
                // width: 500
            });
            console.log(next);
            next();
        }).animate({
            top: 0,
            left: 0
        }, 1000);
});

停止动画

jq对象.stop(clearQueue, gotoEnd);

clearQueue: true: 后续的队列中等待执行的动画被清除 false(默认): 执行下一个队列的动画

gotoEnd: true: 当前动画被停止的一瞬间到达目标值 false(默认): 在哪里停止就留在哪个尺寸

finish: 1.8+

jq对象.finish();

将所有的动画一瞬间到达目标值

$('button').eq(1).click(function () {
    // $('div').stop(false, false);
    // $('div').stop(true, false);
    // $('div').stop(true, true);

    $('div').finish();
});

is

is(":animated"):判断是否处于动画中 true--正在动画 false--没有动画

$('div').click(function () {
    console.log(1);
    // 如果当前元素已经在动画中 不允许添加动画
    if(!$('div').is(':animated')){
        console.log(2);
        $('div').animate({
            width: 'toggle',
            height: 'toggle'
        }, {
            duration: 1000,
            step: function () {
                // 判断是否处于动画中 true--正在动画 false--没有动画
                // console.log($('div').is(':animated'));
            },
            complete:function(){
                // console.log($('div').is(':animated'), 'complete');
            }
        });
    }
});

循环

each: 返回原数据

jq对象.each(函数)

$.each(数据, 函数)

map: 返回函数中设置的返回值组成的新数组

jq对象.map(函数)

$.map(数据, 函数)

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// $(arr).each(function (i, v) {
//     console.log(i, v);
// });

// var res = $.each(arr, function (i, v ) {
//     /* 
//         第一个参数: 下标
//         第二个参数: 值
//     */
//    console.log(i, v);
// });
// console.log(res);

var res = $.map(arr, function (v, i ) {
    /* 
        第一个参数: 值
        第二个参数: 下标
    */
   console.log(i, v);
   return v * v;
});
console.log(res);

var obj = {
    name: '迪丽热巴',
    age: 33,
    height: 178
}
// var res = $.each(obj, function (key, val) {
//     console.log(key, val);
// });
// console.log(res);

var res = $.map(obj, function (val, key) {
    console.log(key, val);
    return val;
});
console.log(res);

// var res = $.each($('li'), function (i, ele) {
//     console.log(i, ele);
// });
// console.log(res);

var res = $.map($('li'), function (ele, i) {
    console.log(i, ele);
    return $(ele).html();
});
console.log(res);

extend

$.extend([deep], dist, ....data);

返回拷贝以后的完整数据

deep: 是否进行深拷贝 false/不传: 浅拷贝 true: 深拷贝

浅拷贝: 只对比第一层级的属性名是否相同 如果相同 用后面的覆盖前面的

如果不同 就复制进来

深拷贝: 第一个参数设置成true, 进行的是递归拷贝, 先比较第一册层级的属性名是否重复, 如果重复, 判断属性值是否两边都是object/array, 保证两边数据类型是一样的, 如果不一样直接用后面的覆盖前面的, 如果属性名一样属性值都是object或者都是array, 比较子属性

dist: 默认的目标源 其他数据拷贝到这里

var obj = {
    name: '张三',
    age: 22,
    money: ['电影', '饺子馆', '茶叶蛋', '慈善'],
    gf: {
        name: '迪丽热巴',
        age: 18,
        money: ['衣服', '化妆', '珠宝']
    }
};

var obj1 = {
    name: '李四',
    gf: {
        name: '古力娜扎',
        height: 168,
        money: ['唱歌', "表演", '衣服', '火锅']
    }
}

var obj2 = {
    hobby: {
        h1: '骑马',
        h2: '唱歌'
    }
};

// var res = $.extend(false, obj, obj1, obj2);
// console.log(res);


var res = $.extend(true, obj, obj1, obj2);
console.log(res);

深拷贝合集

  1. JSON.parse(JSON.stringify(数据))

    var res = JSON.parse(JSON.stringify(obj));
    console.log(res);
    console.log(res == obj); // false
    
  2. extend(true, ...data);

    var res1 = $.extend(true, {}, obj);
    console.log(res1);
    console.log(res1 == obj); // false
    
  3. 使用原生js的递归函数实现深拷贝

    深拷贝: Object Array

    在内存中再划分一块内存

    // 获取数据的类型
    function getType(data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    };
    
    // 实现递归拷贝
    function deepClone(data) {
        // data: 需要实现深拷贝的数据
        // 声明对应的数据类型
        // console.log(getType(data));
        if(getType(data) == 'Object'){
            var res = {};
        } else if(getType(data) == 'Array'){
            var res = [];
        } else {
            return data;
        }
    
        // console.log(res);
    
        // 将data数据中的每一个属性名和属性值存储到res中
        for(var key in data){
            // console.log(key, data[key]);
            // 判断要存储的是否是Array或者Object  如果是 调用deepClone
            // console.log(getType(data[key]));
            if(getType(data[key]) == 'Object' || getType(data[key]) == 'Array'){
                res[key] = deepClone(data[key]);
            } else {
                res[key] = data[key];
            }
        }
    
        // console.log(res);
        // 设置返回值
        return res;
    }
    
    var r = deepClone(obj);
    console.log(r);
    console.log(r == obj);
    

ready

onload:

等待页面结构和资源加载完成后在执行的代码

后面的会覆盖前面

ready:

等待页面结构加载完成

叠加执行

可以简写

window.onload = function () {
    console.log(1);
}
$(document).ready(function () {
    console.log(2);
});
$().ready(function () {
    console.log(3);
});

$(function () {
    console.log(4);
});

插件拓展

类级别: $.extend({方法名: 函数, 方法名: 函数})

$.each $.map

$.extend({
    lunbo: function (sel, wait, time) {
        wait = wait ? wait : 5000;
        time = time ? time : 400;
        // console.log($(sel));
        var n = 0;
        var cw = $(sel).find('ul > li').width();
        // console.log(cw);
        function auto() {
            n++;
            if(n == $(sel).find('ul > li').length){
                n = 0;
                $(sel).find('ul').css({
                    left: -n * cw
                });
                n = 1;
            }
            $(sel).find('ul').stop().animate({
                left: -n * cw
            }, time);
            // 设置小圆点
            $(sel).find('p > span').eq(n == $(sel).find('ul > li').length - 1 ? 0 : n).addClass('active').siblings().removeClass('active');
        }
        // 1. 每隔3s换一张图
        $(sel)[0].timer = setInterval(auto, wait);


        // 划上sel清除定时器
        // 划下sel开启定时器
        $(sel).hover(function () {
            console.log(1, $(sel)[0].timer);
            clearInterval($(sel)[0].timer);
        }, function () {
            $(sel)[0].timer = setInterval(auto, 3000);
        });

    }
});

// 调用
// $.lunbo('.wrap');
$.lunbo('.wrap', 3000, 100);

对象级别: $.fn.extend({方法名: 函数, 方法名: 函数})

jq对象.css jq对象.animate

// 轮播图
$.fn.extend({
    lunbo: function (wait, time) {
        console.log(this);
        wait = wait ? wait : 5000;
        time = time ? time : 400;
        var n = 0;
        var cw = $(this).find('ul > li').width();
        // console.log(cw, n);
        // console.log($(this).find('ul'));
        var that = $(this);
        function auto() {
            n++;
            if(n == that.find('ul > li').length){
                n = 0;
                that.find('ul').css({
                    left: -n * cw
                });
                n = 1;
            }
            that.find('ul').stop().animate({
                left: -n * cw
            }, time);
            // 设置小圆点
            that.find('p > span').eq(n == that.find('ul > li').length - 1 ? 0 : n).addClass('active').siblings().removeClass('active');
        }
        // 1. 每隔3s换一张图
        this[0].timer = setInterval(auto, wait);


        // 划上sel清除定时器
        // 划下sel开启定时器
        $(this).hover(function () {
            console.log(1, $(this)[0].timer);
            clearInterval($(this)[0].timer);
        }, function () {
            $(this)[0].timer = setInterval(auto, 3000);
        });

        // 设置返回值
        return $(this);
    }
});

// 调用
var d = $('.wrap').lunbo(3000).css({
    border: '10px solid #aaa'
});
console.log(d);

Zepto

介绍

zepto: 专门给移动端使用的javascript库

核心: $

zepto的方法与jq中是一致的

官网: Zepto.js: 轻量且兼容 jQuery API 的 JavaScript 工具库 | Zepto.js 中文网

\1. 下载zepto文件: 一定通过上面的官网 或者是 cdn服务器下载完整文件

zepto form ie ajax event

\2. 使用zepto




区别

  1. jq有 zepto没有

  2. offset

  3. zepto的宽高直接求得是占位宽高

touch事件

tap: 单击

doubleTap: 双击

longTap: 长按 >750ms

swipe: 滑动

swipeUp swipeDown swipeLeft swipeRight

touch事件只支持移动端使用
下载压缩包后 解压出来的文件夹中只需要使用src 
但是注意: src中的zepto模块不要使用
  1. 引入zepto -->





你可能感兴趣的:(javascript,javascript,开发语言,ecmascript)