javaScript

JavaScript基础

什么是JavaScript

  • javaScript是一种基于对象和事件驱动并具有相对安全性并广泛用于客户端网页开发的脚本语言,同时也是一种广泛用于客户端Web开发的脚本语言。
  • JavaScript的核心部分相当精简,只包括两个部分:基本的语法构造(比如操作符、控制结构、语句)和标准库(就是一系列具有各种功能的对象比如Array、Date、Math等)。
  • 1992 年一家称作Nombas的公司为自己的软件开发了一种叫做ScriptEase的脚本语言可以嵌入在网页当中
    1995年,Netscape公司为自己的Navigator2.0浏览器开发了另一种客户端脚本语言livescript为了赶时髦改成了javaScript但是跟Java没有任何关系
    1996年Microsoft公司为了进军浏览器的市场,在IE3.0浏览器发布了一个JavaScript的克隆版,称为JScript
    早期的JavaScript指只能运行于Navigator浏览器中的脚本语言 后来JavaScript被提交给ECMA(European Computer Manufacturers Association),成为ECMAScript标准,由各大浏览器厂家来实现。

JavaScript的实现

完整的JavaScript由三部分组成
	JavaScript的核心(ECMAScript)
	文档对象模型(DOM, Document Object Model)
	浏览器对象模型(BOM, Browser Object Model)

在这里插入图片描述

JavaScript和HTML5的关系

HTML5 “就是” JavaScript
HTML5的威力在于让你能用JavaScript来创建这些标签。如果没有后台代码的支持,来创建一个动画效果、游戏、或是可视化工具,那么,图形画布(Canvas)毫无用处。自从出现支持Canvas的浏览器,我们看到了Asteroids游戏的上百个实现,这些都是开发人员为了熟悉HTM5新特性。有的比较粗糙,而有的则极其精致。这些工作完全归功于JavaScript。

JavaScript的特点

  • 代码可以使用任何文本编辑工具编写
  • 无需编译,由JavaScript引擎解释执行
  • 弱类型语言
  • 基于对象和原型

JavaScript运行环境

  • JavaScript运行在浏览器内核中的JavaScript解释器内
  • 哪些地方可以执行JavaScript
    • 浏览器的控制 台(console)Chrome控制台快捷键 ctrl+shift+J
    • 将js脚本嵌入在html页面中执行
      • html元素事件
      • script元素
      • 外部脚本文件

浏览器内核

  • 浏览器的内核负责页面内容的渲染,主要由两部分组成:
    • 内容排版-----解析HTML/CSS
    • 脚本解释-----解析JavasScript

在这里插入图片描述
绝对路径:盘符的开始
相对路径:相对文件的路径

HTML元素事件

  • 要执行的脚本语句直接编写在body中
<body>
   	<button οnclick="console.log('hello word')>打印< /button>
   	< /body>

不推荐在html结构的事件属性中书写JS代码

< script >元素

  • 内部脚本块中可以执行多条语句
<script>
	document.write('<b>你好</b>');
</script>
  • JS代码可以写在Scirpt元素中

  • 一个页面可以拥有多个script元素
    并且 script元素可以出现在页面的任意位置
    script元素type属性默认是 text/javascript 一般可以省略

      alert('我是在head中的script元素');
    
      JavaScript中所有的符号都是英文符号。
    

外部脚本文件

  • 将JavaScript代码写入一个单独的文件,并保存为后缀名为js的文件
    • 为纯文本文件
    • 文件中,不需要包含
<script src="./eg02.outter.js">
        // 当一个script元素被用于引入外部文件时
        // 该元素内部的代码会被自动忽略
        alert('123');
    </script>

结果不会输出123

JavaScript调试

  • JavaScript的代码错误:解释型语言,若某代码错误,则解释器会终止执行;
  • 使用浏览器的开发者工具查看JavaScript中的错误
  • 代码一旦出现错误 JS解释器就会终止执行
<script>
        console.log(1);
        console.Log(2);
// 代码一旦出现错误 JS解释器就会终止执行
        console.abc(3);
        console.log(4);
    </script>
    <script>
        console.log(5);
        console.log(6);
    </script>

这段代码最后的结果是1 5 6

Javascript的语法规范

  • 语句—会被JavaScript引擎解释执行的代码
    • 由表达式、关键字、运算符组成;
    • 大小写敏感;
    • 使用分号或者换行结束
      注释不会被JavaScript引擎解释执行的代码
    • 单行注释://
    • 多行注释:/* */

JavaScript的大小写敏感

  • 在JavaScript程序中大小写是敏感的
  • unmae、UNAME、uName是不同的
  • 基本输出语句:
    • console.log();//控制台输出 日志输出 用于代码调试
    • document.write();//页面输出
    • alert();//弹出提示框

变量

ECMASJavaScript的变量是松散类型的,所谓松散类型就是可以用来保存任何类型
的数据。定义变量时要使用var(var是一个关键字),后跟变量名(即一个标识符)。
当声明一个变量时,就创建了一个新的对象。
什么是变量
变量是存储信息的容器
例如:
x = 1;
y = 3;
sum = x + y;
在JavaScript中,这些字母被成为变量。

变量的声明
  • 使用关键字var如:
    • var name;
    • 使用"="为变量赋值
    • 它的含义是将符号右边的值赋予给左边的变量
    • var price = 25;
  • 没有初始化的变量自动取值为undefined
    • var date;
    • console.log(date); //‘undefined’
一条语句中声明多个变量
  • 可以在一条语句中声明多个变量,变量名使用’,'隔开
var age1 = 20, // 20
   age2; // undefined
a,b交换位置
1.		var a = 10;
        var b = 8;
        var c;
        c = a;
        a = b;
        b = c;
        console.log(a);
        console.log(b);
        
2.		a = a + b; // a = 18 , b = 8
        b = a - b; // b = 10 , a = 18
        a = a - b; // a = 8 , b = 10
        console.log(a);
        console.log(b);

命名规范

  • 标识符命名规范
    • 1.可以使用数字 字母 下划线(_) 美元符($) 进行变量命名
    • 2.变量名不允许以数字开头
    • 3.命名要有明确含义(语义)
    • 4.命名采用驼峰命名法
    • 5.不允许使用关键字和保留字进行命名
  • 驼峰命名法
    • 小驼峰指的是 首字母小写 后面的每一个单词的首字母大写
    • 大驼峰指的是 首字母大写 后面的每一个单词的首字母大写
    • 变量和函数 使用小驼峰命名法
    • 类和构造函数 使用大驼峰命名法

关键字和保留字

在这里插入图片描述
保留字在某种意义上是为将来的关键字而保留的单词,因此保留字也不能被用作变
量名或函数名。
注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,
该单词将被看做关键字,如此将出现关键字错误。
在这里插入图片描述

变量的使用

  • 变量可以先声明再赋值
var a;
a = 1;
  • 可以对变量中的值进行修改
    • 获取变量的值
var a = "1234";
var b = a;
  • 重新设置变量的值
var age = 1;
age = 2;

JavaScript数据类型

  • ECMAScript中有5种基本数据类型:
  • Undefined
  • Null
  • Boolean
  • String
  • 还有一种复杂的数据类型——Object,Object本质上是由一组无序的名值对组成的。
Undefind类型

UNdefined类型只有一个值就是undefined
该值表示一个变量声明没有赋值的情况

var num;
console.log(num); // undefined
console.log(typeof num); // 'undefined'
var car = undefined; // 无意义 默认值就是undefined
Null类型

Null类型 只有一个值 就是null

var car = null;
console.log(car);//null
console.log(typeof car); // 'object' 因为null是空对象指针 所以返回'object'
console.log(num == car); // true
Number类型

Number类型 表示数值

  • 在js中只有一种表示数值的数据类型
  • 不管是整数还是小数 都是Number类型
var x = 10;
var y = 3.14;
console.log(typeof x); // 'number'
console.log(typeof y); // 'number'
NaN 特殊的数值

Not a Number
表示一个要返回数值的操作没有返回数值的结果

console.log(typeof NaN); // 'number'
console.log(3 + 5);//8
console.log(3 * 5);// 15
console.log(3 * 'a');//NaN
isNaN() 函数

判断是否是无效数字
如果是无效数字(NaN)则返回 true(真)
否则返回false(假)
console.log(isNaN(NaN));//true

String类型

字符串类型 引号中所有内容都叫字符串 无论是单引号 或双引号’’ “”
Java语言中’'是字符 char类型 单个字符 ‘a’
"“是字符串 string类型 多个字符"abc”
在JS中单引号和双引号 都是String类型
一般使用情况 外层使用单引号

  • 在字符串中 \ 叫做转义符
    在这里插入图片描述
console.log('你好世界');//'你好世界'
console.log("<div class=\"box\"></div>");
console.log('你好\\世界'); //'你好\世界'
console.log(typeof 'hello'); // 'string'
console.log(typeof typeof 3); // 'string'
Boolean类型

布尔类型
只有两个值 true和false
在实际运算中 true== 1 false == 0
布尔值可以直接参与运算

console.log(1 + true);//2
console.log(3 - false);//3
console.log(3 / false); // Infinity 无穷 任何数除以0 都会得到  Infinity
console.log(true);//true
console.log('123');//'123'
console.log(123);//123
console.log(undefined);//undefined
console.log(null);//null
认识对象

new关键字用于创建对象 new后面跟随的是构造函数

var o = new Object();
console.log(o);//'object'
console.log(typeof o); // 'object'

为新创建的对象性添加属性我们使用’.'操作符
对象是由无序的名值对组成 属性是没有顺序的
名值对 在编程中通常被称作为键值对key-value

var o = new Object();
o.name = 'zhansgan';
o.age = 18;
console.log(o);//{name: "zhansgan", age: 18}

对象的属性可以直接通过key进行访问
对象中可以保存多个键值对
键可以理解是变量名
console.log(o.name);//'zhansgan'
需求:存储一个用户名字 性别 年龄 身高 4条信息描述的是一个整体 一个个体
var userName = 'zhangsan'; var sex = '男'; var age = 21; var height = '170cm';
为对象赋值不存在的属性叫做添加属性
为对象赋值已存在的属性叫做修改属性值

var user = new Object();
        user.name = '张三';
        user.sex = '男';
        user.age = 21;
        user.height = '170cm';
        user.age = 25;
        console.log(user);//{name: "张三", sex: "男", age: 25, height: "170cm"}
        console.log(user.height);//'170cm'

typeof操作符的总结

由于我们的JavaScript是弱类型语言
在声明变量时不需要指定数据类型
所以需要数据类型检测手段
typeof就是用来满足该需求的

typeof返回的是字符串

  • 检测数值或 NaN 返回 ‘number’
  • 检测字符串 返回 ‘string’
  • 检测布尔类型 返回 ‘boolean’
  • 检测null 返回 ‘object’
  • 检测undefined 返回 ‘undefined’
  • 检测对象 返回 ‘object’
  • 检测函数 返回 ‘function’
console.log(typeof isNaN);//'function'

JavaScript运算符

• 算数运算 + - * / % ++ –
• 关系运算> < >= <= == === != !==
• 逻辑运算 && || !
• 赋值运算 = += -= *= /= %=
• 字符链接 +
• 条件(三目)运算 ? :

算数运算
% 取余运算符 读 模

判断一个数是奇数还是偶数

console.log(3 % 2);//1
console.log(9 % 3);//0
console.log(5 % 2); // 任何整数模2 余数为1的是奇数 否则是偶数
一元运算符 ++/–

自增/自减 运算符
将值自身+1或-1

var num = 3;
num++; // num = num + 1;  4
num--; // num = num - 1;  3

在使用自增和自减 运算符时
++/–在前 先运算后使用
++/–在后 先使用后运算

var a = 5;
 console.log(a++ - --a + a++ + a++ - --a + a - ++a - a); // -3
5   -  5  +  5  +  6  -  6  + 6 -  7  - 7
6      5     6     7     6    6    7    7
console.log(a); // 7
关系运算符
console.log(3 > 5);//false
console.log(5 < 7);//true
console.log(3 >= 3);//true
console.log(0 <= 0);//true

正常比较数字的时候 比较数值大小
但是在出现字符串比较的时候 情况不一样
在第2个字符串比较大小的时候 比较的是字符串的Unicode编码
当第一个字符的编码相同的时 比较第二个字符的Unicode编码
数字的Unicode编码是48-57 表示0-9

console.log('你' < '好');//true
console.log(1 >= true);//true
console.log("11" > "110");//false
console.log("22" > "23");//false
console.log("12" > "13");//false
console.log(1 < "3");//true
相等比较

相等操作符(==) 如果比较两个值相等 则返回true 否则返回false
不相等操作符(!=) 如果比较的两个值不相等 则返回true 否则返回false

相等操作符和不相等操作符 在比较值之前都会进行数据类型的转换(相同类型除外)

如果有布尔值 先将布尔值转成数值进行比较
如果有一个操作数是字符串 另一个操作数是数值 先将字符串转换成数值 再进行比较

console.log(123 == '123'); // 转换后是 123 == 123   true
console.log(25 != '25'); // 转换后是 25 != 25  false
console.log(1 == true); // 转换后是 1 == 1   true
console.log(23 == '23a'); // 转换后是 23 == NaN  false
逻辑非(!)

可以用于JS中的任意值(任意类型)

  • 逻辑非操作符 完成两个任务
    • 任务1 将操作的值转换成布尔值
    • 任务2 将转换后的结果进行求反
  • 任意非0数 转成布尔类型 结果都为true
  • 任意对象转成布尔类型都是true
  • 任意非空字符串转成布尔类型都是true
  • null undefined NaN 转换布尔类型 都为 false
  • 空字符串转布尔类型是false
  • 快速将一个值转换为布尔类型 我们使用 (!!)
console.log(Boolean(-1));//true
console.log(!3);//false
console.log(!0);//true
console.log(!!0);//false

console.log(!null);//true                                                       
console.log(!undefined);//true
console.log(!NaN);//true

var obj = new Object();
console.log(!obj);false

console.log(!'123'); // false
console.log(!'abc'); // false
console.log(!' '); // false
console.log(!''); // true

逻辑与和逻辑或

逻辑与(&&)
逻辑与有两个表达式组成
两个表达式都为布尔表达式
当两个布尔表达式的结果同为true的时候 逻辑与的结果为true
只要有一个结果为false 逻辑与的结果就为false

console.log(5 > 3 && 3 > 2);//true
console.log(3 + 3 == 5 && 2 + 2 == 4);//false
console.log(!123 && !false);//false

短路逻辑(最小化求值)
是计算机的一种求值策略
当逻辑与 左右两边的值
第一个值为true的时候 返回第二个值
第一个值为false的时候 返回第一个值

console.log(2 && 3);//3
console.log(4 && 3);//3
console.log(0 && 3);//0
console.log(-1 && 3);//3
console.log(3 && -1);//-1
console.log('35' && false);//false
console.log(-5 && NaN);//NaN
console.log(null && 123);//null

逻辑或(||)
两个布尔表达式
当两个布尔表达式任意一个结果为true时 逻辑或结果为true
两个布尔表达式结果都为false时 结果为false

console.log(3 > 5 || 5 > 3);//true
console.log(3 + 3 == 7 || 3 % 2 == 0);//false

短路逻辑
逻辑或
第一个值为true时 返回第一个值
第一个值为false时 返回第二个值

console.log(3 || 5);//3
console.log(0 || 3);//3
console.log(null || undefined);//undefined
var obj = new Object();
console.log(obj || 123);//Object
赋值运算符
var num1 = 10;
// num1 = num1 + 5;
num1 += 5;
num1 -= 3; // num1 = num1 - 3;
num1 *= 2; // num1 = num1 * 2;
num1 /= 8; // num1 = num1 / 8;
num1 %= 2;
console.log(num1);
console.log(!3 * 5);//0
字符连接符(+)

用于字符串的连接
如果+左右都是字符串 直接连接
console.log(‘123’ + ‘123’);//‘123123’

console.log(123 + '3'); // '123' + '3'
console.log(undefined + '123'); //undefined 转字符串  'undefined'
console.log(null + '123'); // null 转字符串 'null'
console.log(NaN + 'a'); // NaN 转字符串  'NaN'
 console.log(true + 'abc'); // true转字符串  'true'
console.log(false + '123'); //false 转字符串 'false'
console.log(null + 5); // 5
console.log(NaN + 3); // NaN和任何数值进行任何运算 结果都是NaN
条件运算符

条件运算符(三元运算符 三目运算符)
? :
语法:表达式1?表达式2:表达式3;
条件运算符 共有三个表达式 也可以看作是三个操作数
条件运算符 会先判断表达式1(布尔表达式)的值
如果表达式1的结果为true 则执行表达式2(整个条件运算符的结果是表达式2)
如果表达式1的结果为false 则执行表达式3(整个条件运算符的结果是表达式3)
条件运算符可以配合赋值运算符使用

var age = 18;
// console.log(age >= 18 ? '成年' : '未成年');
var result = age >= 18 ? '成年' : '未成年';
console.log(result);

如果条件运算符的第一个表达式 不是 布尔表达式
它会自动将其转换为布尔值

var num = 67;
console.log(num % 2 ? "奇数" : "偶数");//'偶数'
var num;
console.log(num ? '1' : '2');//'2'
运算符优先级

在这里插入图片描述
在这里插入图片描述

数据类型转换

JS是弱类型语言 不需要指定数据的类型
数据类型是由赋值操作来决定的

console.log(3 + '5'); // '35'

算术运算符 结果一定是number类型
如果算术运算表达式不是number类型 会自动转换为number类型 进行运算

console.log(3 * '5'); // 15
console.log(32 + null); // 32

undefined参数的任何算术运算 结果都是 NaN

console.log(2 + undefined); // NaN
console.log('3' * '2'); // 6
console.log(15 * '1.1a'); // NaN  // Number('1.1a')  NaN

快速转换
快速转number类型
加号和减号可以进行快速转换
如果是减号 转换结果是负数

console.log(+'35');//'35'
console.log(3 + +'2');//5
console.log(-'3');//-3
console.log(+'-123');//-123
console.log(-'-123');//123

快速转字符串
拼接空字符串

console.log(354 + '');//'354'

快速转布尔值
使用双!!进行转换

console.log(!!'123');//true
console.log(true + '');//'true'
强制类型转换

Numebr()
将一个字符串解析为number类型,如果有不可解析的部分则返回NaN

console.log(Number('123'));//'123'
console.log(Number('123.123'));'123.123'
console.log(Number('123.12a')); // NaN

parseFloat()
将一个字符串解析为number类型,保留浮点部分,若字符串不可解析则返回NaN

console.log(parseFloat('123.123'));//123.123
console.log(parseFloat('123.12a')); // 123.12
console.log(parseFloat('12a3.123')); // 12
console.log(parseFloat('a123.123')); // NaN
console.log(parseFloat('.123')); // 0.123
console.log(parseFloat('.12.3')); // 0.12

parseInt()
将一个字符串解析为number类型,保留整数部分,若字符串不可解析则返回NaN

console.log(parseInt('123.12'));//123
console.log(parseInt('12a3')); // 12
console.log(parseInt('0.12a3')); // 0
console.log(parseInt('a13')); // NaN

Boolean()
将操作数转为布尔类型
任意非0数 true
任意非空字符串 true
任意对象 true

console.log(Boolean(null));
console.log(Boolean(NaN));
console.log(Boolean(undefined));
console.log(Boolean(0));
console.log(Boolean(0.0));
console.log(Boolean(""));
//都为false

toString()
将一个值转换字符串 JS中任何数据类型都能转字符串
true false undefined null NaN 原样转换
var PI = 3.14; // 常量命名规范全大写

console.log(PI.toString());//3.14
console.log(true.toString());//true
console.log(NaN.toString());//NaN
	二进制数
    3   11
    9   1001
    2147483647  2^31-1
    var num = 2147483647;
    console.log(num.toString(2));

    八进制
    在JS中以0开头的数为8进制数
    var num = 13;
    console.log(num.toString(8));
    console.log(013);

    十六进制
    在JS中十六进制的数以0x开头
    var num = 255;
    console.log(num.toString(16));
    console.log(0x16)

var o = new Object();
o.a = 123;
console.log(o.toString()); // 所有对象转字符串都是 ‘[object Obejct]’

流程控制分支结构

流程控制简介

  • 程序 = 数据 +算法
  • 任何复杂的程序算法都可以通过"顺序","分支,"循环三种基本的程序逻辑组合实现

if语句

  • if语句的语法
  • if语句不改代码执行顺序
  • if(布尔表达式){
    • 代码段
  • }
  • if语句的执行逻辑
    语句1
    if(逻辑表达式){
    语句2;
    }
    语句3;
    执行语句1;
    判断逻辑表达式的值:若为true则执行if语句块中的语句;
    若为false则不执行if语句块中的语句;
    执行语句3;

if语句用于处理分支逻辑
• if判定中默认必须一个Boolean值。
• 若出现的值不是boolean类型,则会自动转换
• 下列值默认都会自动转换为false
• if(0){}
• if(null){}
• if(undefined){}
• if(NaN){}
• if(’’){}
• if(0.0){}

var age = 18;
console.log(1);
if (age >= 18) { // 当if语句中的小括号内的布尔表达式结果为真
// 执行大括号内的语句
console.log(2);
console.log('成年人');
}
console.log(3);
if ('abc') { // 当if语句中的值不是布尔类型时 会自动将其转换为布尔类型
console.log('ok');
}
由于if语句会自动将括号内的值转成布尔类型 所以经常被用来判断东西是否存在
var a;
if (!a) {
a = 10;
console.log(a);
}

当if语句内只有一条语句时可以省略大括号
如果要省略大括号 将语句和if关键字写在同一行

if (false) console.log('ok');
console.log('no');

else关键字必须和if关键字配合使用 无法单独使用
使用if-else可以实现基本的分支功能
if语句的布尔表达式 如果为true 执行if代码块
if语句的布尔表达式 如果未false 执行else代码块

var age = 17;
if (age >= 18) {
console.log('成年人');
} else {
console.log('未成年人 ');
}
var result = age >= 18 ? "成年人" : "未成年人";
console.log(result);

所有的三目运算都可以使用if-else代替
但是不是所有的if-else都能用三目运算代替

age >= 18 ? console.log('成年人') : console.log('未成年');

prompt() 用于接收用户输入的信息 接收到的输入内容是字符串类型

var num = prompt('请输入一个数字');
console.log(num);
var age = parseInt(prompt('请输入年龄'));
if (age >= 18) {
    alert('成年人,蹦迪');
} else {
    alert('未成年,禁止入内');
}

if语句的嵌套
在else中又写了一个if条件
在第一个条件不满足的情况下 判断第二个条件是否满足情况
照成了if-else的嵌套写法
else-if 语句
用于解决if-else的嵌套问题
else-if允许有多个 从上往下依次判断,只要有任意一个条件为true 则执行代码段 结束

var age = parseInt(prompt('请输入年龄'));
1.if (isNaN(age)) {
    alert('年龄输入错误');
} else {
	if (age >= 18) {
    alert('蹦迪');
	} else {
    alert('禁止入内');
  	}
}


2.if (isNaN(age)) {
      alert('年龄输入错误');
} else if (age >= 18) {
       alert('蹦迪');
} else {
        alert('禁止入内');
}
程序流程图

程序流程图是人们对解决问题的方法、思
路或算法的一种描述。
1.流程图的优点:
(a)采用简单规范的符号,画法简单;
(b)结构清晰,逻辑性强;
(c)便于描述,容易理解。
2.流程图采用的符号
(a)椭圆表示开始和结束
(b)箭头表示的是控制流
(c)菱形表示的是逻辑条件
(d)矩形表示的是加工步骤
在这里插入图片描述
天数判断练习

接收用户输入的 年份 月份
判断用户输入的这个月份有多少天
大月 1 3 5 7 8 10 12    31天
    小月 4 6 9 11           30天
    2月 闰年29天 平年28天
var y = parseInt(prompt('请输入一个年份'));
var m = parseInt(prompt('请输入一个月份'));
console.log('您输入的年份是' + y + ',您输入的月份是' + m);
判断平年还剩闰年
闰年指的是能被4整除且不能被100整除 或者 可以被400整除的
if (m == 2) {
 //判断平年 闰年
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
	  console.log('您输入的' + y + '年,2月有29天');
	} else {
	  console.log('您输入的' + y + '年,2月有28天');
	}
} else if (m == 4 || m == 6 || m == 9 || m == 11) {
console.log('您输入的' + y + '年,' + m + '月有30天');
} else {
console.log('您输入的' + y + '年,' + m + '月有31天');
}

switch-case结构

  • switch-case语句是一种特殊的分支结构,可以根据一个表达式的不同取值,
    从不同的程序入口开始执行

  • switch-case和break联合使用,break语句的作用在于跳出switch结构

  • switch 用于实现分支结构
    switch-case 当case等于某个值的时候开始执行,程序往下继续执行直到遇到break关键字为止
    所有switch能完成的任务都可以使用if-else结构代替
    siwtch-case 的结构更清晰 并且执行效率更高

  • 语法:
    switch(表达式){
    case 值:
    语句1;
    break;
    default:
    语句n;
    }
    switch-case的优势
    • switch-case常常和break语句结合使用实现分支功能
    • switch-case在实现分支功能时和if–else的主要区别在于:
    • if…else…可以判定相等或不等的情况,适用性广
    • switch…case…结构更清晰、效率更高;但是一般只用于指定变量相等于某个范围内的某个特定的值
    常量 值是恒定不可变的 命名规范全大写
    变量 存储信息的容器 值可以改变

    在这里插入图片描述

1.获取系统中的星期

var day = new Date().getDay(); // 获取系统中的星期 取值返回是0-6
switch (day) {
            case 1:
                console.log('星期一');
                break;
            case 2:
                console.log('星期二');
                break;
            case 3:
                console.log('星期三');
                break;
            case 4:
                console.log('星期四');
                console.log('...');
                break;
            case 5:
                console.log('星期五');
                break;
            case 6:
                console.log('星期六');
                break;
            default:
                console.log('星期天');
        }

2.天数判断

var y = parseInt(prompt('请输入一个年份'));
var m = parseInt(prompt('请输入一个月份'));
if (m == 2) {
            if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
                console.log('您输入的' + y + '年,2月有29天');
            } else {
                console.log('您输入的' + y + '年,2月有28天');
            }
        } else {
            switch (m) {
                // switch不写break 
                // 代码会继续往下执行
                // 穿透执行
                case 4:
                case 6:
                case 9:
                case 11:
                    console.log('30天');
                    break;
                default:
                    console.log('31天');
            }
        }

3.用户输入一个 年月日
判断该天是该年的第几天
使用switch的穿透写法 进行数据累加

 var y = parseInt(prompt('请输入年份'));
        var m = parseInt(prompt('请输入月份'));
        var d = parseInt(prompt('请输入日期'));
        // 假设 2019年 3月 22日
        // 31+28+22

        // 使用switch的穿透写法 进行数据累加
        var sum = 0; // 总天数
        switch (m) {
            case 12:
                sum += 30; //加的是11月的天数
            case 11:
                sum += 31; //10月
            case 10:
                sum += 30;
            case 9:
                sum += 31;
            case 8:
                sum += 31;
            case 7:
                sum += 30;
            case 6:
                sum += 31;
            case 5:
                sum += 30;
            case 4:
                sum += 31;
            case 3:
                if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
                    sum += 29;
                } else {
                    sum += 28;
                }
            case 2:
                sum += 31;
            case 1:
                sum += d;
        }

console.log(y + '年' + m + '月' + d + '日,是' + y + '年的第' + sum + '天');

流程控制语句-循环结构

什么是循环结构

  • 如果想要执行类似下列代码:
    console.log(1+”world”);
    console.log(1+”world”);
    console.log(2+”world”);
    console.log(3+”world”);

    console.log(100+”world”);
    上述功能可以使用循环结构来代替
    循环,就是一遍又一遍的重复执行相同的或者相似的代码

while语句

while语句的循环语法格式:
while(boolean表达式){
循环体语句
}
含义:若boolean表达式为true,则执行一遍循环体中的语句;然后再判断
一次boolean表达式,若为true,则再次执行一遍循环体中的语句…直到
boolean表达式的值false 则循环结束

  • 含义:
    while语句是一个循环结构,小括号内放的是循环条件的布尔表达式,如果给定的表达式不是布尔表达式,则会自动转换成布尔值
    JS引擎从上往下执行代码 当执行到while语句时
    1. 需要先判断布尔表达式的结果
    2. 如果结果为真 执行代码段内的代码
    如果结果为假 跳过while代码段 从while之后继续执行
    3. 条件为真 执行完毕代码段以后 会继续判断布尔表达式
    如果结果为真 执行代码段内的代码
    如果结果为假 跳过while代码段 从while之后继续执行
    直到布尔表达式结果为false为止
    如果布尔表达式结果为真切无法变成假的情况 叫做死循环
    while (true) {
    console.log(1);
    }

      写循环时 一定要有出口(条件可以变成false的情况)
    
var i = 1;
console.time('start');
while (i <= 100) {
// console.log(i++);
i++;
}
console.timeEnd('start');

while语句用于处理循环逻辑

var i = 0;
while(i < 10){
console.log(i);
i++; //循环条件每执行一次就改变一次
}

在这里插入图片描述

break

break关键字 出现在循环中 表示跳出最近的一个循环
在执行break关键字以后 后面的语句都不会执行
• break用于循环,可使程序终止循环而执行循环后面的语句,常常与条件语
句一起使用。

var i = 0;
while (i < 10) {
    console.log(i); //0 1 2 3 4 5 6
    if (i > 5) break;
    i++; //1 2 3 4 5 6
}
   console.log(i);

continue

continue在循环结构中,用于单次循环 进入到下一次循环
• continue关键字只能用于循环中
• 作用为跳过本次循环体中剩余语句而执行下一次循环
break和continue可以出现在任何循环结构中

显示100以内 个位数不等于3的数

var i = 0;
    while (i < 100) {
        i++;
	if (i % 10 == 3) {
       continue; // 跳过当前的循环 继续判断布尔表达式
	}
console.log(i);
}

do-while

语法格式:
do{
可执行语句;
}while(boolean表达式);

  • 含义:先执行一次循环体中的语句,然后判定boolean表达式的值,若为true,
    则继续执行循环体中的语句;然后再继续判定boolean表达式的值…直到表达式的值为false退出
  • do英文含义 做
    先执行一遍代码段 然后判断逻辑表达式
  • do-while 和while的区别
    do-while无论什么情况都至少执行一次代码段
    while在条件不满足时 1次都不执行
    其他情况没有区别

• while循环 “先判断再执行”
• do-while循环 “先执行再判断”
• 当初始情况不满足循环条件时,while循环一次都不会执行;do-while循
环不管任何情况至少执行一次。
• while和do-while的不同仅仅体现在第一次循环条件就不满足的循环中;
此外的情形是完全一样的

do {
   console.log('ok');
} while (false)

while (false) {
    console.log('while');
}

猜数字
需要一个随机数 1-100之间
猜数字是多少

var randomNumber = Math.floor(Math.random() * 100) + 1; // 生成一个1-100的随机数
var userInput;
do {
   userInput = parseInt(prompt('请输入一个1-100之间的数字'));
// 判断用户输入是有效输入
	if (isNaN(userInput)) {
        alert('输入的数字有误,请从新输入');
        continue; // 输入错误 继续 
    }
	if (userInput === randomNumber) { // 判断猜对
        alert('恭喜你猜对了');
    } else if (userInput > randomNumber) {
        alert('太大了,请继续猜');
    } else {
         alert('太小了,请继续猜');
     }
	} while (userInput != randomNumber); // 循环条件 不相等

在这里插入图片描述

for语句

语法:
for(表达式1;表达式2;表达式3){
代码段
}

  • for括号内的三个表达式
    • 1.初始化
    • 2.循环条件(布尔表达式)
    • 3.增量(改变循环条件)
      for语句的执行顺序
    • 1.执行初始化(只执行1次)
    • 2.判断条件(表达式2)
    • 3.条件为真执行循环,假结束
    • 4.执行完毕循环体以后 执行 增量(改变循环条件)
    • 5.判断条件(表达式2)
    • 6.条件为真执行循环,假结束
    • 7.执行完毕循环体以后执行增量(改变循环条件)
      在这里插入图片描述
for (var i = 0; i < 10; i++) {
   console.log(i);//0 1 2 3 4 5 6 7 8 9
}
  1. 有一个人入职了一家公司 薪资是10k,薪资涨幅每年5%,50年后这个人的工资是多少?
    思路:10000->10500->11025 求和
 var sum = 10000;
     for (var i = 1; i <= 50; i++) {
        sum *= 1.05;
 }
  console.log(sum);//114673.997857537
  1. 打印100以内所有7的倍数
for (var i = 0; i < 100; i++) {
   if (i % 7 == 0 && i != 0) console.log(i);
}
  1. 打印100以内所有奇数的和
var sum = 0;
for (var i = 0; i < 100; i++) {
    if (i % 2) sum += i;
}
console.log(sum);//2500

for循环嵌套

指的是循环体内还有循环

for (var i = 0; i < 5; i++) {
    for (var j = 0; j < 5; j++) {
       console.log(i, j);//
        0 0
		0 1
		0 2
		0 3
		0 4
		1 0
		1 1
		1 2
		1 3
		1 4
		2 0
		2 1
		2 2
		2 3
		2 4
		3 0
		3 1
		3 2
		3 3
		3 4
		4 0
		4 1
		4 2
		4 3
		4 4
	}
}

以上代码执行顺序
1. var i = 0;
2. 0<5 true
3. var j = 0;
4. 0<5 true
5. 输出 0 0
6. j++ j=1
7. 1<5 true
8. 输出 0 1
9. j++ j=2
10. 2<5 true
11. 输出 0 2
12. j++ j=3

j=5
5<5 false 内层循环结束
i++ i = 1
1<5 true
var j = 0;
在这里插入图片描述

循环问题

• 需要多次重复执行一个或多个任务的问题考虑使用循环来解决;
• for/while/do-while三种循环在很多情况下是可以互换的;一般情况,用for
比较多
1.循环嵌套打印三角形
*
**
***
****
*****

for (var i = 1; i <= 5; i++) {
    for (var j = 1; j <= i; j++) {
        document.write('*');
    }
    document.write('<br>');
}
  1. 九九乘法表
<style>
 span {
 	display: inline-block;
   	width: 68px;
    height: 25px;
    margin: 3px;
}
</style>
<script>
  for (var i = 1; i <= 9; i++) {
     for (var j = 1; j <= i; j++) {
        document.write('<span>' + j + '&times;' + i + '=' + j * i + '</span>');
     }
    document.write('<br>');
  }
</script>
  1. 求阶乘的和
    求1!+2!+3!+4!+5!+…+19!+20!
    1! 1
    2! 2*1
    3! 3 * 2 *1
var sum = 0;
var n = 1;
for (var i = 1; i <= 20; i++) {
    n *= i; // 计算的是n = n * i
    sum += n;
}
console.log(sum);
  1. 求水仙花数 是一个三位数
    它是自幂数的一种
    指的是 这个数的 个位3次方+十位3次方+百位3次方 等于这个数
    153 == 1+125+27
    找出所有的水仙花数
    思路:256 /10 25.6%10 5
    256%100 56/10
for (var i = 100; i <= 999; i++) {
    var digit = i % 10; // 获得个位
    var ten = parseInt(i % 100 / 10); //获得十位
    var hund = parseInt(i / 100); //获得百位
    if (digit * digit * digit + ten * ten * ten + hund * hund * hund == i) {
    console.log('水仙花数:' + i);
    }
}
  1. 打印1000-2000年中 所有的闰年 每行4个
var count = 0; // 用于纪录打印个数
  for (var year = 1000; year <= 2000; year++) {
     if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
       count++;
       document.write(year + '&nbsp;');
       if (count % 4 == 0) { // 计数为4的倍数 打印换行
       document.write('<br>');
      }
 	}
}
  1. 接收用户输入的一个数 判断这个数是否是质数(素数)
    只能被1和自身整除的数就是质数
 var userInput = parseInt(prompt('请输入一个整数'));
        质数只有两个因子
        var count = 0; //用于纪录因子的个数
        for (var i = 2; i <= userInput; i++) {
            if (userInput % i == 0) {
                count++;
            }
        }
        if (count == 1) {
            alert('是质数');
        } else {
            alert('不是质数');
        }
        --------------------------------------
        通过一个开关判断是否是质数
        var flag = true;
        for (var i = 2; i < userInput; i++) {
            if (userInput % i == 0) {
                flag = false;
                break;
            }
        }
        if (flag) {
            alert('是质数');
        } else {
            alert('不是质数')
        }

函数

函数的概念以及作用

  • 函数(function)是一个大型程序中的某部分代码(子程序)由一个或多个语句块组成.它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性
  • 一般会有输入参数并带有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
  • 在面向对象编程语言中,类别或对象的子程序也被称作方法(method)
  • 函数对过程进行封装,对细节进行隐藏
  • function 函数/方法
  • console.log();//方法
  • document.write();方法
  • alert();//函数
  • isNaN();//函数

函数的创建

函数有两种常用的创建方式
关键字 function 用于函数声明

  1. 函数名 函数名称
  2. 小括号 参数列表
  3. 大括号 函数体
  • 函数命名规范和变量相同
  1. 可以使用数字 字母 下划线 美元符
  2. 不能以数字开头
  3. 命名要有含义
  4. 不能使用关键字和保留字
  5. 采用驼峰命名法
    定义好一个函数 不会立即执行 而需要手动调用
    函数有很好的复用性
    调用函数 使用 函数名();
声明式函数

使用function声明一个函数
function 函数名(){
代码段
}

function myFunction() {
   console.log('myfunction');
   console.log('myfunction1');
   console.log('myfunction2');
   console.log('myfunction3');
}
        myFunction();
        myFunction();
        myFunction();
        myFunction();
        myFunction();

结果:
输出5次
myfunction
myfunction1
myfunction2
47 myfunction3

赋值式

将一个函数赋值给一个变量 或者 对象的属性,也称作函数表达式

var fn= function(){
代码段
}

var myFn = function() {
     console.log('test');
 }
myFn();

var obj = new Object();
obj.myFn = function() {
   console.log('obj');
}
   obj.myFn();

变量的声明

• JavaScript中的函数可以带参数也可以不带参数
• 参数的声明写在小括号中,多个参数使用逗号隔开
• 小括号内的参数叫做形(式)参(数),命名规范与变量命名相同
• 函数体内使用的参数叫做实(际)参(数)

JS的函数 可以有参数 也可以没有参数
写在小括号中的叫做形参
形参 类似于变量 只能在函数内使用
当声明的形参没有接收到实参时,形参变量的值为undefined

 function fn(num) {
     console.log(num);//undefined
}
fn();

调用函数时 传入的参数叫做实参
实参会为形参进行赋值
传入的实参 可以是常量也可以是变量

var a = 8;
function fn(num) {
     console.log(num);//8
}
fn()

函数允许拥有多个参数 使用英文逗号隔开

 function plus(a, b, c) {
       console.log(a + b + c);//15 16 '358'
 }

        plus(2, 5, 8);
        plus(3, 5, 8);
        plus("3", 5, 8);

按值传递

  • 调用函数时,可在小括号内传入参数
  • JavaScript函数的参数是按值传递的
var num1 = 10;
var num2 = 8;
function fn(a,b){
a+=b;
console.log(a); //18
}
fn(num1,num2);
console.log(num1,num2); //10 8

上面代码调用fn函数时传入的num1,num2是传入的这两个变量的值(将值复制一份传入函数内),函数内对参数的修改不会影响外部变量的值,

函数时参数是按值传递的
传入的参数 其实传入的是值的复制品
当把变量a,b传入函数中时,传入的是a,b的值
函数的参数的值不会影响外部的变量

 var a = 10;
        var b = 5;
 function fn(a, b) {
         a += b;
         console.log(a);
        }

fn(a, b);
console.log(a);//15

arguments对象

  • 每个函数对象都有一个arguments属性;此属性只能在函数执行体内使用
  • arguments属性中保存这当前函数接收到的所有实际参数,故可以使用arguments属性处理可变数量的参数
  • argument对象具有如下属性:
    • lenght:返回实际传入的参数的个数
    • callee:返回当前函数的引用
      它的本质是一个对象,在调用时被赋值,函数执行结束后被销毁

arguments 是一个ArrayLike(类数组)
arguments 里面的属性通过数字(索引 insex i 下标)来进行访问
所有的ArrayLike 都拥有length属性 用于保存 元素的长度(个数)
所有的ArrayLike 都是通过索引进行访问元素的
并且索引 都是从0开始计算的
0表示第一个元素 1表示第二个元素 …

 function fn() {
            // console.log(arguments[2]);
 var sum = 0;
for (var i = 0; i < arguments.length; i++) {
    sum += arguments[i];
}

 console.log(sum);
}

        fn(1, 2, 3, 4, 5);//15
        fn(2, 6, 8, 1, 55, 1);//73
  1. 封装一个函数 接收用户输入的数字 判断是否是质数
var userInput = parseInt(prompt('请输入一个数字'));
        fn(userInput);

        function fn(num) {
            var flag = true;
            for (var i = 2; i < num; i++) {
                if (num % 2 == 0) {
                    flag = false;
                    break;
                }
            }
            if (flag) alert('是质数');
            else alert('不是质数');
        }
  1. 封装一个函数 打印指定行数的三角形
function fn2(row) {
            for (var i = 1; i <= row; i++) {
                for (var j = 1; j <= i; j++) {
                    document.write('*');
                }
                document.write('<br>');
            }
        }

        fn2(7);
        fn2(5);

  1. 编写一个函数 计算给定2个参数的 和,差,积,商
function fn3(arg1, arg2) {
            console.log('和是:' + (arg1 + arg2));
            console.log('差是:' + (arg1 - arg2));
            console.log('积是:' + (arg1 * arg2));
            console.log('商是:' + (arg1 / arg2));
        }

        fn3(5, 2);
  1. 编写一个函数,接收三个参数,并计算三个参数的大小,从小到大输出
function fn4(num1, num2, num3) {
            var num4;
            if (num1 > num2) { // 如果第一个数大于第二个数  交换位置
                num4 = num1;
                num1 = num2;
                num2 = num4;
            }
            if (num2 > num3) {
                num4 = num2;
                num2 = num3;
                num3 = num4; // num3 最大
            }
            if (num1 > num2) {
                num4 = num2;
                num1 = num2;
                num2 = num4;
            }

            console.log(num1 + '<' + num2 + '<' + num3);
        }
        fn4(56, 5, 11);
arguments应用

我们可以使用arguments处理不同数量的参数
函数重载
相同或相近的功能 使用相同的函数名
参数的不同

function fn() {
            if (arguments.length == 2) {
                console.log(arguments[0] * arguments[1]);
            } else if (arguments.length == 3) {
                console.log(arguments[0] + arguments[1] + arguments[2])
            } else {
                console.log('参数错误');
            }
        }

        fn(1, 2);
        fn(1, 2, 3);
        fn(1, 2, 3, 1);

        function fn() {
            if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
                console.log(arguments[0] * arguments[1]);
            } else if (typeof arguments[0] === 'string' || typeof arguments[1] === 'string') {
                console.log(arguments[0] + arguments[1]);
            }
        }

        fn(3, 2);
        fn(5, 'true');

        function fn() {
            arguments.callee() //arguments.callee === fn
        }
        fn();

返回值的设置和接收

• 函数可以设置返回值也可以没有返回值
• 当函数没有返回值时默认返回undefined
• 使用return语句为函数设置返回值
• 函数的返回值可以是任意数据类型,且只能有一个返回值
• 当return执行时,跳出函数体的执行
• return用来终止或跳出函数执行
• 调用有返回值的函数时,可以使用变量接收返回值

在JS的函数中 可以有返回值的设置 也可以没有
设置返回值 使用的是return关键字
每个函数只有一个返回值,返回值可以是任意数据类型
返回值指的是函数的运行结果
返回值可以使用变量接收

一个函数没有设置返回值时,默认返回undefined

return关键字

  1. 设置返回值
  2. 终止函数执行
    当解释器运行到return时,会跳出函数的执行,return的后面的语句没有意义
function fn() {
            return 123; // 返回123
        }

        var result = fn();
        console.log(result);//1 2

        function fn2() {
            console.log(1);
            console.log(2);
            return;
            console.log(3);
        }

        fn2();

function fn3() {

        }

        var result = fn3();
        console.log(result);//undefined

        console.log(fn3());//undefined

JS的编译和执行

JS的编译和执行分为两个阶段

  1. 编译阶段
    对于常见编译型语言(例如:J濴v濴)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节生成。
    对于解释型语言(例如JavaScript)来说,通过词法分析和语法分析得到语法树后,就可以开始解释执行了。
    (1)词法分析是将字符流(char stream)转换为记号流(token stream),就像英文句子一个个单词独立翻译,举例:
    代码:var result = testNum1 - textNum2;
    词法分析后 :
    NAME “result”
    EQUALS
    NAME “testNum1”
    MINUS
    NAME “testNum2”
    SEMICOLON
    (2)语法分析得到语法树,举例:
    条件语句 if(typeof a == “undefinef” ){ a = 0; } else { a = a; } alert(a);
    当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语法错误,并结束整个代码块的解析。
    在这里插入图片描述
    (3)“预编译”(并非完全的顺序执行)
    “function函数”是一等公民!编译阶段,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率!
    总结:当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理!并且是先预声明变量,再预定义函数!
    二、JavaScript执行过程
    在解释过程中,JavaScript引擎是严格按着作用域机制(scope)来执行的。JavaScript语法采用的是词法作用域(lexcical scope),也就是说JavaScript的变量和函数作用域是在定义时决定的,而不是执行时决定的,由于词法作用域取决于源代码结构,所以 JavaScriptr濼瀃t解释器只需要通过静态分析就能确定每个变量、函数的作用域,这种作用域也称为静态作用域(static scopr)。补充:但需要注意,with和eval的语义无法仅通过静态技术实现,实际上,只能说JS的作用域机制非常接近lexcical scope。
    JavaScript中的变量作用域在函数体内有效,无块作用域;
    JavaScrip引擎在执行每个函数实例时,都会创建一个执行环境(execution context)。执行环境中包含一个调用对象(call object), 调用对象是一个scriptObject结构(“运行期上下文”),用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表upvalue等语法分析 结构(注意:varDecls和funDecls等信息是在语法分析阶段就已经得到,并
    保存在语法树中。函数实例执行时,会将这些信息从语法树复制到 scriptObject上)。scriptObject是与函数相关的一套静态系统,与函数实例的生命周期保持一致,函数执行完
    毕,该对象销毁。
    JavaScript引擎通过作用域链(scope chain)把多个嵌套的作用域串连在一起,并借助这个链条帮助JavaScript解释器检索变量的值。这个作用域链相当于一个索引表,并通过编号来存 储它们的嵌套关系。当JavaScript解释器检索变量的值,会按着这个索引编号进行快速查找,直到找到全局对象(global object)为止,如果没有找到值,则传递一个特
    殊的undefined值。

  2. 预编译阶段
    词法分析
    语法分析

    预编译
    JS引擎会在执行代码之前 优先进行一些优化操作 提高执行效率
    JS引擎会找到所有的var关键字 和function关键字
    对变量和函数的声明进行提前
    var 声明的变量提前了 赋值为undefined
    function 申明的函数 整体 提前执行

  3. 执行阶段
    脚本随解释器进行顺序执行


        console.log(a);//undefined
        var a = 10;
        console.log(a);//10


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

        fn2();
        var fn2 = function() {
            console.log(2);//fn2 is not a function
        }

作用域

又名作用区域 作用范围
JavaScript的作用域分为两种

  1. 函数作用域
    在函数内部定义的变量,它的作用范围仅在函数内有效
  2. 全局作用域
    不在函数内定义的变量,在全局任何位置都有效
var a = 8;

        function fn() {
            console.log(a);//undefined
            var a = 5;
        }
        fn();

        for (var i = 0; i < 10; i++) {
        }
        console.log(i);//10

        if (false) {
            var a = 10;
        } else {
            var b = 5;
        }

        console.log(a);//5
        console.log(b);//undefined

递归

递归指的是函数在执行过程中的自调用
如果递归没有出口(变成非递归情况)那么会造成 栈(内存)溢出
构成递归需具备的条件:

  1. 子问题须与原始问题为同样的事,且更为简单
  2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理
    在数学和计算机科学中,递归指由一种(或多种)简单的基本情况定义的一类对象或方法,并规定其他所有情况都能被还原为其基本情况
1.
function fn() {
   arguments.callee // 返回当前函数的引用 fn
   console.log(arguments.callee);
   //ƒ fn() {
            arguments.callee // 返回当前函数的引用 fn
            console.log(arguments.callee);
            // arguments.callee();
        }
   arguments.callee();//Maximum call stack size exceeded
}
fn();



2.
function fn(n) {
            console.log(n);//5 4 3 2 1 0
            if (n == 0) { // 递归出口
                return 0;
            } else {
                fn(n - 1); // 参数的递减
            }
 }
        fn(5);

点击事件改变元素背景颜色

<style>
   #box {
     width: 200px;
     height: 200px;
     background-color: red;
   }
</style>
<script>
    window.onload = function() {
    	var box = document.getElementById('box');
            // var flag = true;
         var count = 0;
         box.onclick = function() {
                // if (flag) {
                //     box.style = "background-color:blue;";
                //     flag = !flag; // 求反
                // } else {
                //     box.style = "background-color:red;";
                //     flag = !flag;
                // }
                count++;
                box.style = count % 2 ? 'background:blue' : 'background:red';
            }
        }
 </script>
 
<body>
    <div id="box"></div>
</body>

斐波那契数列
斐波那契数列 fibonacci
黄金数列
两个已知数 1 1
数列后每一位数 都是前两位的和
1 1 2 3 5 8 13 21…
求斐波那契数列的第n位
n = fibonacci(n-1) + fibonacci(n-2)

var count = 0;
function fibonacci(n) {
     count++;
     if (n <= 2) { // 递归出口
        return 1;
     } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
     }
}
        console.time('go');//输出运行时间
        console.log(fibonacci(42));
        console.log(count);
        console.timeEnd('go');

辗转相除法
使用辗转相除法计算最大公约数
辗转相除法, 又名欧几里得算法(Euclidean algorithm),
目的是求出两个正整数的最大公约数。它是已知最古老的
算法, 其可追溯至公元前300年前。
这条算法基于一个定理:两个正整数a和b(a>b),它们
的最大公约数等于a除以b的余数c和b之间的最大公约数。
比如10和25,25除以10商2余5,那么10和25的最大公约
数,等同于10和5的最大公约数。
在这里插入图片描述

 function fn(m, n) {
    var r = m % n;
        m = n;
        n = r;
        if (r == 0) {
           return m;
        } else {
           return fn(m, n);
        }
}

        console.log(fn(20, 5));//5
        console.log(fn(7, 21));//7

变量的作用域

变量作用域:
变量作用域是程序中定义这个变量的区域:
全局变量拥有全局作用域
局部变量,其作用域是局部性的
在JavaScript中,变量的作用域分为两种:
1.全局作用域 — 一旦定义在程序任何地方都可以访问
2.函数作用域 — 指在函数中定义的变量只能在函数内部访问

作用域链简介

在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象.函数对象和其他对象一样,拥有可以通过代码访问的属性和一系列仅提供JavaScript引擎访问的内部属性,其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问.
当一个函数创建后,它实际上保存了一个作用域链,并且作用域链会被创建此函数的作用域中可访问的数据对象填充.

在函数fn创建时,它的作用域中会填入一个全局对象,该全局对象包含了所有全局变量
在这里插入图片描述
执行此函数时会创建一个称为“运行期上下文(execution context)”(有人称为运行环境)的
内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。
• 这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。
在这里插入图片描述
函数也是对象

function sayHello() {
}

console.log(sayHello.name);//sayHello

匿名函数

匿名函数,就是定义时未直接指定名称的函数
指的是声明函数时没有指定函数名

function(num1,num2){
console.log(num1+num2);
}
  1. 自执行函数
    函数在定义后自动执行
    一次性函数
    作用:
    1.隔离作用域 避免作用域(全局)污染
    2.函数仅在调用时临时创建作用域链对象
    调用结束立即释放(节约内存空间)

尽量避免使用全局变量
非要用全局变量的时候
在作用域的顶部声明 并且加注释

1. (function() {
      var user = 'zhangsan';
      console.log(user);
	})();
console.log(user);//zhangsan

2. ! function() {
            console.log(2);
   }()

3. ~ function() {
            console.log(3);
   }();


(function(a, b, c) {
            // var a = 10;
            console.log(a + b + c);
        })(3, 5, 6);//14

(function() {
       var a = 5;
       console.log(a);//5
 })();

将匿名函数作为参数使用
函数的参数可以是任意数据类型
JS中的函数是对象

  • 匿名函数的优点
    • 因为非匿名函数在定义时,就已经创建函数对象和作用域链对象.所以,即使未调用,也占内存空间
    • 匿名函数,仅在调用时,才临时创建函数对象和作用域链对象.调用完,立即释放
    • 所以,匿名函数比非匿名函数更节省内存空间
回调函数

– >> 将函数作为参数使用
• 回调函数,将一个函数作为另一个函数的参数叫做回调函数

function isOdd(num, callback) {
      if (num % 2) {
          callback('这个数是奇数');
      } else {
          callback('这个数是偶数');
      }
 }

所有的函数作为参数的使用情况 都叫回调函数

isOdd(5, function(msg) {
      console.log(msg);
});

isOdd(8, function(msg) {
      console.log(msg);
 });

函数名
赋值式的函数 变量名就是函数名

function myFn() {
}
    console.log(myFn.name);//myFn
    var fn = function() {
 }
	console.log(fn.name); // 赋值式的函数 变量名就是函数名
	结果是fn
	console.log(function() {}.name === '');//true匿名函数的函数名为空

编程风格

定义变量名时
1.不推荐
var a = 5;
var b = 3;
var c = 2;
2.尽量使用这种方法
var a = 5,
    b = 3,
    c = 2;
使用循环语句时
1.bad
if (5 > 3) {
   console.log('ok');
 } //bad

2.good
if (5 > 3) console.log('ok'); //good

3.best
5 > 3 && console.log('ok'); //best


做比较时 常量写前面
var flag = true;
 1.
if (flag == 1) {
    console.log('ok');
 }
2.
if (1 == flag) { // 做比较时  常量写前面
    console.log('ok');
}

事件与函数

JavaScript基于 对象和事件驱动的一个web开发脚本语言
• 当用与Web页面进行某些交互时,解释器就会创建相应的event对象以描述事
件信息。常见的事件有:

  • 用户点击页面上的某个内容
  • 鼠标经过特定的元素
  • 用户按下键盘上的某个按键
  • 用户滚动窗口或改变窗口大小
  • 页面元素加载完成
  • 文本框内容改变
  • ……
事件和函数的关系

函数是可以被事件触发执行的

  • 函数的触发需要满足以下条件
  • 1.事件源
  • 2.监听事件
  • 3.事件处理函数
    在这里插入图片描述
    window 指的是浏览器窗口
    当窗口内的资源加载完毕
    执行函数内的代码段
window.onload = function() {
    // window 指的是浏览器窗口
    // 当窗口内的资源加载完毕 
	alert(1);
}

通过id获取元素
通过document.getElementById()获取的到所有元素(标签)都是对象
对象是数据和功能的集合
数据体现 属性

<script>
        window.onload = function() {
            var btn = document.getElementById('btn'); // 通过id获取元素
  // 通过 document.getElementById() 获取的到所有 元素(标签) 都是对象
// alert()会将所有输出的内容进行 toString() 操作
// alert(btn); // [object HTMLButtonElement]
// var o = new Object();
// console.log(o.toString()); // [object Object] 
// console.log(btn.toString());
// 对象是数据和功能的集合
// 数据体现 属性
// console.log(btn.id);
// console.log(btn.title);
// btn.title = 'hello world';
btn.onclick = function() {
    // 事件 onclick  鼠标左键单击事件
    btn.title = "hello";
    alert('我修改自己的title');
  }
}
</script>
<body>

    <button id="btn" title="button element">按钮</button>

</body>

1.随机色块

<style>
#box {
  width: 1200px;
  margin: 0 auto;
  overflow: hidden;
}
        
#box div {//初始化随机色块生成的div样式
   width: 120px;
   height: 30px;
   border: 1px solid black;
   float: left;
   margin: 3px;
   border-radius: 5px;
}
</style>
window.onload = function() {
    var btn = document.getElementById('btn');//获取按钮元素的id
    var box = document.getElementById('box');//获取id名为box元素
	// 随机颜色
     function getColor() {
          var color = '#';//定义一个color拼接生成的随机小数的16进制的颜色值
          var randomNumber = 0;//定义一个随机小数
          //随机生成6个颜色值并拼接成一个16进制的rgb颜色
          for (var i = 0; i < 6; i++) {
            // Math.random()
            // 生成一个0-1之间的随机小数
			randomNumber = parseInt(Math.random() * 16);//生成一个0-15之间的随机小数
            color += randomNumber.toString(16); // 拼接16进制数字
                }
                return color;//返回生成的颜色
            }

    // box里添加元素 innerHTML
    btn.onclick = function() {
    box.innerHTML += '<div style="background-color:' + getColor() + '"></div>';//每点击一次就生成一个随机颜色的色块
            }
        }
<body>
    <div style="text-align: center">
        <input type="button" id="btn" value="按钮">
    </div>
    <div id="box">
    </div>
</body>

2.鼠标事件

 window.onload = function() {
    var box = document.getElementById('box');
    var list1 = document.getElementById('list1');
    // onmouseenter
    // onmouseleave

    box.onmouseover = function() { // 鼠标悬停事件
          list1.style = "background:green";
  }

     box.onmouseout = function() { // 鼠标离开事件
         list1.style = "background:red";
      }
}
<body>
    <div id="box">
    </div>
    <div>
        <ul>
            <li id="list1">第一个li</li>
        </ul>
    </div>
</body>

键盘事件

// onkeydown  键盘按下
        window.onkeydown = function() {
            console.log('你按键了');
        }

        window.onkeyup = function() {
            console.log('按键回弹');
        }
拓展less

具体使用方式请查看:Less中文地址
Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。
Less 可以运行在 Node 或浏览器端。
首先安装easy less
easy less
创建一个文件后缀名为.less,会自动生成一个css文件
支持css语言
要设置编码
@charset “utf-8”;
好处:

  1. 层级
header{
    img{
        width:300px;
    }

    nav{
        .list{
            list-style:none;
            overflow: hidden;
            li{
                float: left;
                margin:5px;

                &:hover{ // & 表示父级选择器 
                    color:@color1;
                }

                >a{
                    color:@color1;
                }
            }
        }
    }
}

以上代码会在css文件中自动生成

header img {
  width: 300px;
}
header nav .list {
  list-style: none;
  overflow: hidden;
}
header nav .list li {
  float: left;
  margin: 5px;
}
header nav .list li:hover {
  color: black;
}
header nav .list li > a {
  color: black;
}
  1. 计算
li{
 float: left;
 width: floor(100%/7);  // floor() 向下取整   ceil()向上取整
}

在css代码中自动生成


.box ul li {
  float: left;
  width: 14%;
}

3.变量的使用

@是声明一个变量

@color1:black;
>a{
   color:@color1;
}

数组

创建对象

ECMAScript中的对象其实就是一组数据和功能的集合.对象可以通过执行new操作符后跟要创建的对象类型的名称来创建.而创建Object类型的实例并为其添加属性和(或)方法,就可以自定义对象:

使用构造函数创建对象
var o = new Object();
使用点操作符设置属性
o.name = 'zhangsan';
为不存在的属性直接赋值 是添加属性
o.age = 25;
为已存在的属性赋值 是修改属性
o.age = 18;
使用语法量 直接量的方式 创建对象
{} 它其实是 new Object()的语法糖

var obj = {}; // 底层依旧执行 new Object()

属性名和属性值之间使用英文冒号隔开
每个属性之间使用逗号隔开

var o2 = {
name: 'zhangsan',
age: 20,
sex: 'nan'
};
console.log(o2);//Objectname: "zhangsan"age: 20sex: "nan"__proto__: Object

对象的属性可以是任意数据类型

var o3 = {
    // 对象的属性可以是任意数据类型
    name: 'lisi',
    fn: function() {
        console.log('hello');//hello
    }
 };
   o3.fn();

对象的属性操作
CRUD Create Read Update Delete
delete关键字用于删除对象的属性

var o4 = {
 name: 'lisi',
 age: 20,
 abc: 123,
 fn: function() {
     console.log('ok');
   }
}
delete o4.abc;
console.log(o4);//{name: "lisi", age: 20, fn: ƒ}
name: "lisi"
age: 20
fn: ƒ ()

delete o4; //{name: "lisi", age: 20, fn: ƒ}

arguments.length不可以被delete删除

function fn() {
 delete arguments.length;
 console.log(arguments);//Arguments {0: 1, 1: 2, 2: 3, 3: 4, callee: ƒ, Symbol(Symbol.iterator): ƒ}
}
fn(1, 2, 3, 4);

对象属性的访问
对象的属性名是字符串类型
JSON 轻量级数据交换格式
JSON 是中立于语言和平台的一种数据交换格式

var o5 = {
            "a": 1,
            "b": 2,
            "c": 3
}
        console.log(o5.b);//2
        console.log(o5['b']);//2

数据结构

使用一个变量保存多个值 (对象 数组)
JavaScript的数组可以保存任意数据类型的值

数据结构
将数据和数据之间的关系按照特定结构进行保存
队伍 堆 栈 数 哈希 字典 列表 散列表…
数组也是一种数据结构
1.所有内容都是有序排列
2.排列顺序 最小值是0 最大值是长度-1
3.数组中的数据类型
Number String Null Undefined Boolean Object Function Array

数组
  1. 什么是数组
    • 多个元素组成的集合 – 在一个变量名中储存多个值。
    • JavaScript数组中元素的数据类型可以相同,也可以不同。
    • 可以通过元素所在位置的顺序号(下标)做标识来访问每一个元素(下标从
    0开始,最大到元素的个数-1)
    • 前面学习的if、if-else、switch、循环解决的都是流程问题、既算法问题。
    数组(Array),就是一种很常用的保存批量数据的数据结构,所谓数据结构,就是把数据与数据间的关系按照特定的结构来保存。
    设计合理的数据结构是解决问题的前提。
  2. 定义一维数组
    可以使用如下四中格式定义一个数组变量:
    var arr1=[];//定义一个不包含元素的数组 语法糖
    var arr2=[1,2,3];//定义一个包含3个元素的数组
    var arr3=new Array();//定义一个不包含元素的数组
    var arr4=new Array(“tom”,”marry”,”john”);
    //定义一个包含三个字符串元素的数组 数组允许有多个元素 每一个元素之间使用,隔开
    数组的长度查看
    数组的本质也是对象
    数组的长度是以属性的方式体现的
    length 属性是不允许删除的
    delete arr4.length; console.log(arr4.length);
    获得数组中的元素 使用 索引值来获取
    console.log(arr4[1]); // 获取数组的元素 通过[index]获取
    // 索引值从0开始 最大索引值是 length-1
    初始化数组
    • 数组中的元素可以在定义时初始化
    var arr1=[1,2,3];
    var arr2=new Array(‘苹果’,‘橘子’,‘西瓜’);
    • 也可以先声明一个空数组,随后在向其添加元素
    var empArray=[]; var 濸empArray =new Array();
    empArray[0]=‘Tom’; empArray[0]=1;
    empArray[1]=‘Marray’; empArray[2]=true;

引用类型

引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。
本教程会讨论大量的 ECMAScript 预定义引用类型。
从现在起,将重点讨论与已经讨论过的原始类型紧密相关的引用类型。
注意:从传统意义上来说,ECMAScript 并不真正具有类。事实上,除了说
明不存在类,在 ECMA-262 中根本没有出现“类”这个词。ECMAScript
定义了“对象定义”,逻辑上等价于其他程序设计语言中的类。

在这里插入图片描述
数组是引用类型的数据

new 关键字

所有使用new关键字创建的对象 都是引用类型
var arr = [1, 2, 3, 4];// []是 new Array()语法糖
var arr2 = arr; // 引用赋值的是地址
arr2[0] = 0;//修改的是同一条数据
console.log(arr);//Array(4)0: 01: 22: 33: 4length: 4__proto__: Array(0)

var obj = {
     x: 1,
     y: 2
};

var obj2 = obj;
	obj2.x = 0;
    console.log(obj.x);//0

引用类型比较的是地址
只有地址相同才相等

var arr = [1, 2, 3, 4]; // new Array()  0x0656347
var arr2 = [1, 2, 3, 4]; // new Array()  0x0674612
console.log(arr == arr2);//false
var arr = [];
var arr2 = arr;
console.log(arr === arr2);//true
var o = {
    x: 1
 }
var o2 = {
     x: 1
 }
  console.log(o == o2);//false
数组是引用类型的对象

• 引用类型:值不保存在变量本地的数据类型
var n=100;
• 值类型:保存在栈中,速度快。
var arr=new Array(‘北京’,‘哈尔滨’);
引用类型作为参数传递时 传递的也是地址

function fn(arr) {
     arr[0] = 0;
}
var a = [1, 2, 3, 4, 5]; // 引用类型的值保存再堆 栈中储存的是地址
    fn(a);
console.log(a);//Array(5)0: 01: 22: 33: 44: 5length: 5__proto__: Array(0)

引用类型:数据保存在堆中,栈中只有内存的编号,要通过此编号到堆中查找真正的数据

基本包装类型

ECMAScript 提供了三种基本包装类型
Boolean Number String
基本包装类型 使用了new关键字
var num2 = new Number(12);
基本包装类型有基本类型的特点
console.log(num + num2);//基本包装类型由于基本类型的特点 输出结果:24
console.log(typeof num2);//object
console.log(num2);//Number

var bool = new Boolean(true);
console.log(bool);//Boolean
console.log(typeof bool);//object
var str = '123';
var str2 = new String('abc');
console.log(str + str2);//123abc
console.log(typeof str2);//object
var num = 123;
console.log(num.toString());//'123'
数据类型检测
   var box = document.getElementById('box');
   var obj = {};
   var arr = [];
   var n = null;
console.log(typeof box);//object
console.log(typeof obj);//object
console.log(typeof arr);//object
console.log(typeof n);//object
  1. ECMAScript 提供了一个关键字用于检测 实例对象
    instanceof 谁的实例
    console.log(obj instanceof Object); // 检测obj是否是 Object的实例
    console.log(obj instanceof Array); // 检测obj是否是 Array的实例
    console.log(arr instanceof Array);
    console.log(arr instanceof Object);
    console.log(box instanceof HTMLDivElement);
    console.log(box instanceof Object);

所有的引用类型 使用 instanceof Object均返回为true 不靠谱

  1. 数据类型检测
    constructor 属性 构造器
    所有的引用类型 都有constructor属性
   console.log(obj.constructor === Object);
   console.log(arr.constructor === Array);
   console.log(arr.constructor === Object);
   console.log(box.constructor === HTMLDivElement);
  1. 自定义函数检测数据类型
function getType(o) {
                return Object.prototype.toString.call(o).slice(8, -1);
            }

            var a = 123;
            var b = true;
            var c = [];
            var d = {};
            var e = 'aaaa';
            var f;
            var g = null;

            console.log(getType(a));
            console.log(getType(b));
            console.log(getType(c));
            console.log(getType(d));
            console.log(getType(e));
            console.log(getType(f));
            console.log(getType(g));
  1. 检测对象是不是数组
var arr = [];
    console.log(Array.isArray(arr));//true
null

• 什么是null?
• null专门表示一个变量不能再指向任何对象的地址。
• null与undefined:
• 共同点:
• 都是原始类型,保存在栈中变量本地
• 不同点:
• undefined:表示变量声明过但未赋值。是所有未赋值变量的默认值。
一般不主动使用。例如 var a; //a被自动赋值为undefined
• null:表示一个变量将来可能指向一个对象,但目前暂时什么都没指
向。一般用于主动释放指向对象的引用。
例如:var emps =[“Tom”,”Marry”];
emps=null;//释放指向数组的引用,清空掉栈中的编号,对中的
数据没人用,被回收
数组操作(GET/SET)
• 设置数组元素的值–SET操作
var arr = [1,2,3];
arr[2] = 100; //将值为3的元素重新赋值为100;
arr[3] = 99; //在数组尾部添加一个新的元素;
• 获取数组元素的值–GET操作
var add = new Array(‘Hello’,‘World’);
console.log(add[0]); //Hello

获取数组的长度

var arr = [‘苹果’, ‘橘子’, ‘芒果’, ‘西瓜’, ‘菠萝’];
arr.length = 8; //数组的长度可以修改
console.log(arr.length);
console.log(arr[5]); // 空的元素被取值为 undefined
arr.length = 0; // 将数组长印度设置为0 清空数组内的元素
console.log(arr);
arr = []; //使用新数组替换老数组
遍历 在编程语言中的含义就是 全部访问一边
正序遍历
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
倒序遍历
for (var j = arr.length - 1; j >= 0; j–) {
console.log(arr[j]);
}

 1. 使用数组 求 斐波那契数列的第50var fibonacci = [1, 1];
        for (var i = 2; i < 50; i++) {
            fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
        }
        console.log(fibonacci);
// 2. 冒泡排序
        // 相邻的两个数进行比较大小 较大的数移到后面
        // 理论最大排序轮数是 数组的长度-1 次
        var arr = [64, 67, 189, 77, 16, 167, 66];
        // [64,67,189,77,16,167,66];
        //  64,67,77,16,167,66,189
        //  64,67,16,77,66,167

        var temp;
        for (var j = 0; j < arr.length - 1; j++) {
            for (var i = 0; i < arr.length - j - 1; i++) {
                if (arr[i] > arr[i + 1]) { // 如果第一个数大于第二个数 交换位置
                    temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp
                }
            }
        }
        console.log(arr);
对象的遍历

for - in 用于遍历对象
for-in访问存在的数组元素
in关键字 可以判断 属性在对象中是否存在
length 属于不可枚举属性

 // var city = ['北京', '上海', '广州', , , '深圳', , '南京', , '杭州', '长沙', '重庆'];
        // console.log(city.length);
        // console.log(city);

        // for (var i = 0; i < city.length; i++) {  //index
        //     console.log(city[i]);
        // }

        // for - in 用于遍历对象
        // for (var i in city) { // item 项
        //     // for-in访问存在的数组元素
        //     console.log(i, city[i]);
        // }


        // -------------------------------
        // for-in 用于遍历对象的可枚举属性
        // length 属于不可枚举属性

        var obj = {
            name: 'zhangsan',
            age: 20,
            sex: '男'
        }

        // for (var key in obj) { // key 属性名
        //     console.log(key + ":" + obj[key]); // obj[key] 属性值
        // }

        // in关键字 可以判断 属性在对象中是否存在
        console.log('name' in obj);
        console.log('age' in obj);
        console.log('abc' in obj);
关联数组

JS的数组有两种数组

  1. 索引数组 通过索引值堆数组的元素进行编号
  2. 关联数组 使用字符串作为数组的索引 无序的
var arr = []; //关联数组长度是0
arr['name'] = 'zhangsan';
arr['age'] = 20;
arr['sex'] = 'nan';
console.log(arr);//Array(0)name: "zhangsan"age: 20sex: "nan"length: 0__proto__: Array(0)

关联数组不计算长度 无法使用for循环遍历
但是数组是对象 可以使用for-in遍历
for (var i in arr) {
console.log(arr[i]);
}

数组API

API 应用程序接口( 函数/方法 )
Array.prototype 里面所有的方法 都可以在数组实例中被访问(所有数组都能访问)

  1. Array.prototype.push()
    语法: arr.push(value[,value2,value3,…,valueN])
    描述: 方法push用于在数组的尾部推入一个或多个值
    参数: value 需要添加到数组尾部的值(any)
    返回值: 返回添加后的数组新长度
    注意点: 该方法直接修改原数组
var arr = [1, 2, 3];
 // var result = arr.push('ok', 4, 5, 6);
 // console.log(arr);//Array(8)0: 11: 22: 33: "ok"4: 45: 56: 67: "ok"length: 8__proto__: Array(0)
 // console.log(result);//7
 arr.push('ok');
 console.log(arr);//Array(8)0: 11: 22: 33: "ok"4: 45: 56: 67: "ok"length: 8__proto__: Array(0)

  1. Array.prototype.pop()
    语法: arr.pop()
    描述: 方法pop用于删除数组中的最后一个元素 将数组的长度-1
    返回值: 被删除的元素
    注意点: 直接修改原数组
    var arr = [1, 2, 3];
    var res = arr.pop();
    console.log(arr);
    console.log(res);
    使用 push 和 pop 可以实现类似于栈的功能
  2. Array.prototype.concat()
    语法: arr.concat(value[,value2,…,valueN]);
    描述: concat将参数依次添加到数组的尾部
    参数: value 需要添加到数组尾部的值(any)
    返回值: 返回添加元素后的新 数组
    注意点: concat不修改原数组 创建新数组
var arr = [1, 2, 3];
var arr2 = arr.concat(4, 5, 6);
console.log(arr2);//
(6) [1, 2, 3, 4, 5, 6]
0: 1
1: 2
2: 3
3: 4
4: 5
5: 6
length: 6
__proto__: Array(0)
console.log(arr);//(3) [1, 2, 3]0: 11: 22: 3length: 3__proto__: Array(0)

concat 可以将数组扁平化 将数组展开后的结果依次倒入新数组中
只展开第一层

var arr = [1, 2, 3];
var arr2 = arr.concat([4, [5, 6]]);
console.log(arr2);//(5) [1, 2, 3, 4, Array(2)]
  1. Array.prototype.join()
    语法: arr.join([string]);
    描述: 该方法会将数组内所有的元素进行toString()操作,并且使用给定的字符串进行连接
    如果没有给定参数字符串 默认使用英文逗号连接
    参数: string 用于连接的字符串
    返回值: 新的字符串 包含了所有数组toString()的结果
var arr = [2, 6, 7, true, , false, null, 123, {
            x: 1
        }];
var str = arr.join();
console.log(str);//2,6,7,true,,false,,123,[object Object]
var arr = [1, 2, 3, 4, 5];
var result = arr.join('----');
console.log(result);//1----2----3----4----5
  1. Array.prototype.reverse()
    语法: arr.reverse()
    描述: 用于颠倒数组中的元素
    注意点: 直接修改原数组
 var arr = [1, 2, 3, 'ok'];
        arr.reverse();
        console.log(arr);//(4) ["ok", 3, 2, 1]
var arr = [1, 2, 3, 4];
        var arr2 = arr.concat(4, 5, 'ok'); // [1,2,3,4,4,5,'ok']
        arr.reverse();
        arr2.push(6);
        arr2.reverse();
        var str = arr2.join();
        console.log(str);//6,ok,5,4,4,3,2,1
  1. Array.prototype.shift()
    语法: arr.shift();
    描述: shift函数用于删除数组的第一个元素
    返回值: 返回被删除的元素
    注意点: 该方法直接修改原数组
    如果数组为空 则不修改数组 返回 undefined
var arr = [3, 6, 8];
        var del = arr.shift();
        console.log(arr);//(2) [6, 8]
        console.log(del);//3
  1. Array.prototype.slice()
    语法: arr.slice([start],[end]);
    描述: 该方法用于截取数组片段
    参数: start(number) 开始索引
    end(number) 结束索引
    end 可以是负数 -1表示最后一个元素 -2表示倒数第二个 以此类推
    返回值: 从start开始到end结束的新数组(包含start 不包含end)
    如果没有end参数 则从start开始到数组结尾
    不带参数时可以用于复制数组
  var arr = [1, 2, 3, 4, 5];
        var arr2 = arr.slice(1, 3);
        var arr3 = arr.slice(1);
        console.log(arr2);//Array(2)0: 21: 3length: 2__proto__: Array(0)
        console.log(arr3);//Array(4)0: 21: 32: 43: 5length: 4__proto__: Array(0)
        var arr2 = arr.slice();
        console.log(arr2);//Array(5)0: 11: 22: 33: 44: 5length: 5__proto__: Array(0)
        console.log(arr);//Array(5)0: 11: 22: 33: 44: 5length: 5__proto__: Array(0)
        console.log(arr === arr2);//false
        var arr4 = arr.slice(1, -2);
        console.log(arr4);//Array(2)0: 21: 3length: 2__proto__: Array(0)
  1. Array.prototype.sort()
    语法: arr.sort([callback])
    描述: 将数组内的元素按照特定的顺序进行排序
    参数: callback(function) 用于设定排序规则的函数
    注意点: 直接修改原数组
var arr = [167, 12, 66, 123, 121, 77, 56, 57, 111];
        console.log(arr.sort(function(a, b) {
            return a - b; // 升序
        }));

        
        console.log(arr.sort(function(a, b) {
            return b - a; // 降序
        }));

        console.log(arr.sort((a, b) => a - b));
        console.log(arr.sort((a, b) => b - a));
  1. Array.prototype.toString()
    语法: arr.toString();
    描述: 将数组内所有的元素都toString(),然后使用英文逗号拼接
    返回值: 拼接后的新字符串
    推荐使用join()
 var arr = [1, 2, 4, 5];
 console.log(arr.toString());//1,2,4,5
  1. Array.prototype.unshift()
    语法: arr.unshift(value,[value2,…,valueN]);
    描述: unshift函数用于在数组的头部添加一到多条数据
    将原数组的内的元素依次向后移动
    返回值: 修改后的新长度
    参数: value 要添加到数组头部的数据(any)
    注意点: 直接修改原数组
var arr = [1, 2, 3];
arr.unshift('ok', 'true');
console.log(arr);//Array(5)0: "ok"1: "true"2: 13: 24: 3length: 5__proto__: Array(0)

  1. Array.prototype.splice()
    语法: arr.splice(start[deleteCount[value,…,valueN]]);
    描述: 该方法可以删除指定索引的元素
    替换数组中的某部分内容
    在指定索引位置插入内容
    参数: start(number) 开始索引
    deleteCount(number) 删除的个数
    value(any) 需要插入到数组中的内容
    返回值: 新数组,被删除元素集合 如果没有删除元素则返回空数组
    注意点: 修改原数组
var arr = [1, 2, 3, 4, 5];
        var result = arr.splice(1, 0);
        console.log(arr);//Array(6)
		0: 5
		1: (2) [6, 7]
		2: 2
		3: 3
		4: 4
		5: 5
		length: 6
		__proto__: Array(0)
        console.log(result);//Array(0)length: 0__proto__: Array(0)
        arr.splice(1, 0, 1);
        console.log(arr);//
        Array(6)
			0: 5
			1: Array(2)
			0: 6
			1: 7
			length: 2
			__proto__: Array(0)
			2: 2
			3: 3
			4: 4
			5: 5
			length: 6
			__proto__: Array(0)	

        arr.splice(0, 2, 5, [6, 7]);
        console.log(arr);//
        Array(6)
			0: 5
			1: Array(2)
			0: 6
			1: 7
			length: 2
			__proto__: Array(0)
			2: 2
			3: 3
			4: 4
			5: 5
			length: 6
			__proto__: Array(0)

练习:

  1. 1-100 每次删除偶数位 直到剩余2个数 其中一个是1 另外一个数是多少
var arr = [];
        for (var i = 1; i <= 100; i++) {
            arr[i] = i;
        }
        console.log(arr);
        do {
            for (var j = arr.length - 1; j > 0; j--) {
                if (j % 2 == 0) {
                    arr.splice(j, 1);
                }
            }
            console.log(arr);
        } while (arr.length > 3);

  1. 数组去重
    var arr = [1, 654, 111, 654, 123, 11, 63, 12, 1, 111, 111];
    // [1,654,111,123,11,63,12]
    比较去重
1. 排序
//首先使用sort将数组内的元素按照顺序排序
arr.sort(function(a, b) {
            return a - b
        });
console.log(arr);
2. 比较
var result = [];//定义一个空数组用于接收比较后得到的数字内的元素
for (var i = 0; i < arr.length; i++) {//循环遍历数组
   if (arr[i] !== arr[i + 1]) {//将数组内的元素和后一个元素作比较,如果不相等就推入result中
       result.push(arr[i]);
   }
}
console.log(result);
var arr = [1, 654, 111, 654, 123, 11, 63, 12, 1, 111, 111];
        // 创建一个新数组,在新数组中查找原数组中的每一个值 如果没有找到 则插入该值
        var result = [];

        function indexOf(arr, value) {
            for (var i = 0; i < arr.length; i++) { // 在传入的数组中查找传入的值
                if (arr[i] === value) return i; // 如果值存在则返回 索引
            }
            return -1; //如果循环结束都没有找到 则返回-1
        }

        for (var i = 0; i < arr.length; i++) {
            if (indexOf(result, arr[i]) === -1) {
                result.push(arr[i]);
            }
        }
        console.log(result);

var arr = [1, 654, 111, 654, 123, 11, 63, 12, 1, 111, 111];
	var result = [...new Set(arr)];
	console.log(result);
二维数组

二维数组:从整体上来看,是一个数组,只是其中的每个元素又是一个数组,既数组的数组;
二维数组指的是在数组内的元素全部都是数组
var arr = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
访问二维数组中的某个元素
var arr = [[1,2,3],[3,4,5],[6,7,8]]; console.log(arr[0][0]); arr[1][2] = 200;
遍历二维数组—循环嵌套

 for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < arr[i].length; j++) {
                console.log(arr[i][j]);
            }
        }
二维数组的应用–二级联动菜单
// 二级联动菜单
        var data = [
            ['北京', '朝阳', '海淀', '丰台', '昌平', '大兴', '顺义'],
            ['上海', '杨浦', '青浦', '徐汇', '浦东', '静安', '宝山'],
            ['广州', '白云', '海珠', '天河', '越秀'],
            ['杭州', '江干', '西湖', '上城', '下城', '萧山', '余杭', '富阳', '临安']
        ];

        window.onload = function() {
            var city = document.getElementById('city');
            var area = document.getElementById('area');

            // 1. 把城市放入city
            // innerHTML += "<option>北京</option><option>上海</option><option>广州</option><option>杭州</option>"
            var cityStr = '';
            for (var i = 0; i < data.length; i++) {
                cityStr += '<option value="' + i + '">' + data[i][0] + '</option>';
            }
            city.innerHTML += cityStr;

            // select 是表单元素
            // change事件
            city.onchange = function() {
                // 获得select的value属性
                // value属性和数据的索引是一一对应的
                // console.log(city.value);
                var _index = this.value; // this在事件处理函数中 指向的是事件触发的对象
                var areaStr = '';
                for (var j = 1; j < data[_index].length; j++) {
                    areaStr += '<option>' + data[_index][j] + '</option>';
                }
                area.innerHTML = areaStr;
            }
        }
<body>
    <select id="city">
        <option>请选择</option>
    </select>
    <select id="area">
        <option>请选择</option>
    </select>
</body>

ES5数组api

es5 ECMAScript5
es6 ECMAScript 不再使用版本号命名 而是使用年份命名 es2015
es7 es8 es9 es10都发布了

  1. Array.prototype.indexOf()
    语法: arr.indexOf(searchElement,[fromIndex]);
    描述: indexOf函数用于在arr中检索某个指定的值(值类型)
    如果找到匹配的值 则返回这个值所对应的索引(index)
    如果没有找到匹配的值 则返回-1
    参数: searchElement 要检索的值
    fromIndex 开始索引
    返回值: 索引或-1
var arr = [54, 65, 11, 76, 11, 74, 62, 65];
console.log(arr.indexOf(12, 3));//-1
  1. Array.prototype.forEach()
    语法: arr.forEach(callback)
    描述: 该函数用于遍历arr ,并将每一个元素和对应的索引值传入到回调函数中
    回调参数:
    value 数组中的每一个元素
    index 元素对应的索引值
var arr = [54, 65, 11, 76, 11, 74, 62, 65];
arr.forEach(function(value, index) {
     console.log(value, index);
})

function forEach(arr, callback) {
     for (var i = 0; i < arr.length; i++) {
        callback(arr[i], i);
    }
 }

 forEach(arr, function(value, index) {
            console.log(value)
        })
  1. Array.prototype.filter()
    语法: arr.filter(callback)
    描述: 该函数用于过滤数组内的数据
    回调参数:
    value 数组中的每一个元素
    index 元素对应的索引值
var arr = [176, 2, 67, 27, 658, 1875, 12347, 134];
1.
var arr2 = [];
for (var i = 0; i < arr.length; i++) {
     if (arr[i] % 2) {
       arr2.push(arr[i]);
     }
}
console.log(arr2);

var arr3 = [];
arr.forEach(function(value) {
     if (value % 2) arr3.push(value);
});
console.log(arr3);

2.
var arr4 = arr.filter(function(value, index) {
            // 1. 遍历数组
            // 2. 使用逻辑表达式检测数组中的每一个元素
            // 3. 将结果为true放入一个新的数组
            // 4. 返回新数组
            // console.log(value, index);
            return value % 2;
        })
        console.log(arr4);
 var users = [{
            username: 'zhangsan',
            age: 25
        }, {
            username: 'lisi',
            age: 15
        }, {
            username: 'lisa',
            age: 18
        }, {
            username: 'wangwu',
            age: 22
        }, {
            username: 'zhaoliu',
            age: 16
        }, {
            username: 'xixi',
            age: 20
        }];

        var result = users.filter(function(value, index) {
            return value.age < 18;
        });

        console.log(result);
  1. Array.prototype.map()
    语法: arr.map(callback)
    描述: map函数用于遍历和操作数组元素
    回调参数:
    value 数组的每一个元素
    index 元素对应索引
    返回值: 新数组
  var arr = [1, 2, 3, 4, 5];
        var result = [];
        arr.forEach(function(value, index) {
            // 1. 遍历数组
            // 2. 做操数组                              
            // 3. 将操作结果放入新数组
            if (value % 2) {
                result.push(value * 2);
            } else {
                result.push(value / 2);
            }
        });
        console.log(result);

 var result = arr.map(function(value) {
            // 1. 遍历数组
            // 2. 操作每个数组的值
            // 3. 将结果返回输出生成一个新数组
            return value % 2 ? value * 2 : value / 2;
        });
        console.log(result);


 var res = arr.map(function(value) {
            return value + 10;
        });
        console.log(res);
  1. Array.prototype.reduce()
    语法: arr.reduce(callback,[object]);
    描述: 归并(归类、合并)
    回调参数:
    pre 上一个
    next 下一个
    返回值: 归并完成后的结果
 var arr = [5, 4, 3, 2, 1];

        var result = arr.reduce(function(pre, next) {
            // 第一次执行reduce回调时 ,pre第一个数组元素
            // next是第二个数组元素

            // 后面每次一遍历执行时 pre都是上一次的返回值
            // next依旧是下一个数组元素
            console.log('pre' + pre + ',next' + next);
            return pre * next;
        });

        console.log(result);

String

String类型是字符串的包装类型
• String类型是字符串的对象包装类型,可以使用构造函数来创建。
• String对象的方法也可以在所有基本的字符串值中访问到。其中,继承的
valueOf() toLocale-String() 和toString()方法,都返回对象所表示的基本字
符串值。
在JavaScript字符串可以使用 单引号 或 双引号

    在Java中'a' char 字符类型 单引号
    "abc" string 字符串类型 双引号

Strring.lenght
• 语法
• string.length
• 描述
• 属性String.length是一个只读整数,它声明了指定字符串string中的字符数。对于任何一个字符串s,
它最后一个字符的下标都是s.lenghth-1。用for/in循环不能枚举出字符串的lenghth属性,用delete运算符也不能删除它。
字符串也拥有长度 length 属性
length属性可以在所有的基本字符串中访问到
length是一个只读的(正)整数

  1. String.prototype.charAt();
    语法: str.charAt(index)
    参数: index(number) str的索引值
    描述: 返回str中指定索引的字符
    返回值: string 字符串
 var str = 'abc';
  console.log(str.charAt(1));  // str[1]
  1. String.prototype.charCodeAt();
    语法: str.charCodeAt(index)
    参数: index(number) str的索引值
    描述: 返回指定索引字符的 Unicode 编码 0-65535
    返回值: number Unicode编码

     常用Unicode编码 
     数字 48-57
     小写字母 97-122
     大写字母 65-90
    
 var str = 'Z';
console.log(str.charCodeAt(0));

        var str = '放学别走,小树林见';
        var arr = [];
        for (var i = 0; i < str.length; i++) {
            arr.push(str.charCodeAt(i) + 520);
        }

        console.log(arr);
        arr.forEach(function(value) {
            // String.fromCharCode() 用于将Unicode编码转换成字符串
            console.log(String.fromCharCode(value - 520));
        })
  1. String.prototype.concat()
    语法: str.concat(value[,…valueN]);
    描述: 方法用于在str后连接多个值
    参数: value 字符串类型
    返回值: 新的字符串

    平时时候+连接
    解决复杂字符串问题
    
 var str = 'hello';
 var str2 = str.concat(' ', 'world');
 console.log(str2);//hello world
 console.log(str);//hello
  1. String.prototype.indexOf()
    str.indexOf(searchElement,[fromIndex])
    描述: indexOf 用于在str中匹配查找 字符串片段(searchElement)
    如果找到字符串片段则返回其对应在str中的索引位置
    如果没有找到则返回-1
    参数: searchElement(string) 需要查找的字符串
    fromIndex(number) 起始检索位置
    返回值: 匹配字符串的首个字符的索引 或 -1
 var str = "JavaScript";
console.log(str.indexOf('a', 2));//3
  1. String.prototype.lastIndexOf()
    语法: str.lastIndexOf(searchElement,[fromIndex])
    描述: lastIndexOf 用于在str中匹配查找 从后往前 字符串片段(searchElement)
    如果找到字符串片段则返回其对应在str中的索引位置
    如果没有找到则返回-1
    参数: searchElement(string) 需要查找的字符串
    fromIndex(number) 起始检索位置
    返回值: 匹配字符串的首个字符的索引 或 -1
var str = 'JavaScript';
console.log(str.lastIndexOf('a'));//3
  1. String.prototype.replace()
    语法: str.replace(regexp,newString)
    描述: 方法用于字符串的替换
    参数: regexp 用于匹配要喜欢字符串的正则表达式
    newString 需要替换的新内容
    返回值: 替换后的新字符串
    replace函数的第一个参数如果不是正则表达式 会被自动转换成正则表达式
var str = 'hello world';
        // replace函数的第一个参数如果不是正则表达式 会被自动转换成正则表达式
var newStr = str.replace('h', 'H');
 console.log(newStr);//Hello world
window.onload = function() {
var btn = document.getElementById('btn');
var text = document.getElementById('text');
var word = ['cnm', 'qnmlgb', 'mmp', '中共'];
var str = word.join('|');
var reg = new RegExp(str, 'g'); // 将字符串转成正则表达式
btn.onclick = function() {
  text.value = text.value.replace(reg, '**');
   }
}
<body>
    <textarea id="text" cols="30" rows="10"></textarea>
    <button id="btn">替换</button>
</body>
  1. String.prototype.slice();
    语法: str.slice(start[,end]);
    参数: start 开始索引
    end 结束索引
    end 如果是负数 表示从后往前计算 -1表示最后一个 -2表示倒数第二个
    描述: 方法slice用于在字符串中截取字符串片段
    返回值: 返回从start开始到end结束的字符串片段
    结果包含start 不包含end
    没有截取成功返回空字符串
var str = 'abcdefg';
console.log(str.slice(2));//cdefg
console.log(str.slice(2, 5));//cde
console.log(str.slice(1, -2));//bcde
console.log(str.slice(10, 15) === ''); //没有截取成功返回空字符串//true
  1. String.prototype.split();
    语法: str.split([string])
    描述: 使用给定的字符串将str进行分割,分割后的结果存入一个数组
    参数: string 用于分割的字符串
    返回值: 新数组
var str = '12-23-34-45';
console.log(str.split('-'));//(4) ["12", "23", "34", "45"]
var str2 = 'abcdefg';
var arr = str2.split(''); // join的反向操作
arr.reverse();
str2 = arr.join('');
console.log(str2)//gfedcba
var email = "zhangsan@163.com";
console.log(email.split('@')[0]);//zhangsan
  1. String.prototype.substr()
    语法: str.substr(start,length)
    描述: substr用于截取指定个数的字符串
    参数: start 开始索引
    length 长度
    返回值: 截取到的新字符串
var str = 'abcdefg';
console.log(str.substr(2, 5));//cdefg
  1. String.prototype.substring()
    语法: str.substring(start,[end]);
    描述: 方法用于截取字符串
    参数: start 开始索引
    end 结束索引
    返回值: start开始到end结束的字符串片段
    如果 indexStart 等于 indexEnd,substring 返回一个空字符串。
    如果省略 indexEnd,substring 提取字符一直到字符串末尾。
    如果任一参数小于 0 或为 NaN,则被当作 0。
    如果任一参数大于 stringName.length,则被当作 stringName.length。
    如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。见下面的例子。
var str = 'abcdefg';
console.log(str.substring(1));//bcdefg
console.log(str.substring(1, 3));//bc
console.log(str.substring(3, 1));//bc
console.log(str.substring(3, -1));//abc
  1. String.prototype.toLowerCase();
    语法: str.toLowerCase();
    描述: 将str转成小写
var str = 'HELLO';
console.log(str.toLowerCase());//hello
  1. String.prototype.toUpperCase();
    语法: str.toUpperCase();
    描述: 将str转成大写
var str = 'hello';
console.log(str.toUpperCase());//HELLO
  1. 字符串处理
var str = 'no zuo no die';
        // No,Zuo,No,Die
        var arr = str.split(' '); // 将字符串拆分成数组
        arr = arr.map(function(value) {
            // 遍历数组
            // 操作数组的每一个元素
            // 返回一个新数组 
            return value.charAt(0).toUpperCase() + value.slice(1);
        });
        str = arr.join();
        console.log(str);
  1. 字符串统计
// 统计大写字母个数 小写字母个数 数字个数
        var big = 0,
            small = 0,
            num = 0;
        var code;
        for (var i = 0; i < str2.length; i++) {
            // 数字 48-57
            // 小写字母 97-122
            // 大写字母 65-90
            code = str2.charCodeAt(i);
            if (code >= 48 && code <= 57) {
                num++;
            } else if (code >= 65 && code <= 90) {
                big++;
            } else if (code >= 97 && code <= 122) {
                small++;
            }
        }

        console.log('数字有' + num + '个', '小写字母有' + small + '个', '大写字母有' + big + '个');
归并做法
var arr = str2.split('');//先将字符串转为数组
 var res = arr.reduce(function(result, current) {
            var code = current.charCodeAt(0);
            if (code >= 48 && code <= 57) {
                result.num++;
            } else if (code >= 65 && code <= 90) {
                result.big++;
            } else if (code >= 97 && code <= 122) {
                result.small++;
            }
            return result;
        }, {
            big: 0,
            small: 0,
            num: 0
        });

        console.log(res);
  1. 字符串压缩
 var str3 = 'aaaaabbbccccccddddeeefffgg';
        // 5a3b6c4d3e3f2g
var count = 1;
        var result = '';
        for (var i = 0; i < str3.length; i++) {
            if (str3[i] === str3[i + 1]) { // 如果相邻的字符相同 计数+1
                count++;
            } else { //不同
                result += count + str3[i]; //将结果拼接
                count = 1; //计数初始化
            }
        }
        console.log(result);
var arr = str3.split('');
        var res = arr.reduce(function(result, current) {
            // reduce回遍历数组
            // 第一次执行回调时,result是传入的对象
            // 判断对象中是否用于某个属性,如果有则+1 没有则赋值为1
            result[current] ? result[current]++ : result[current] = 1;
            return result;
        }, {});
        console.log(res);
        var str4 = '';
        for (var i in res) {
            str4 += res[i] + i;
        }
        console.log(str4);
  1. 统计数组中有多少奇数
var arr = [546, 53, 11, 76, 231, 7671, 5654, 771, 54];
        // 统计数组中有多少奇数

        var result = arr.reduce(function(result, current) {
            // 第一次执行时 传入一个对象作为参数
            // 第二次开始 result是上次执行的返回值
            // console.log(result);
            // console.log(current);
            current % 2 ? result.odd++ : null;
            return result;
        }, {
            odd: 0
        });

        console.log(result);
  1. Array.prototype.every()
    语法: arr.every(callback);
    描述: 用于检测数组中每一个元素是否符合逻辑表达式的条件
    回调参数: value 数组的每一个元素
    index 元素对应的索引
    返回值: 布尔值
var arr = [65, 11, 63, 11, 77, 23];
        var res = arr.every(function(value) {
            return value % 2;
        });
        console.log(res);
  1. Array.prototype.some()
    语法: arr.some(callback);
    描述: 用于检测数组中是否有元素符合逻辑表达式的条件
    回调参数: value 数组中的每一个元素
    index 元素对应的索引
    返回值: 布尔值
var arr = [65, 11, 63, 12, 77, 23];
        var res = arr.some(function(value) {
            return value % 2 == 0;
        });
        console.log(res);
var arr = [344, 674, 65, 98, 96, 3456, 344];
var output = arr.find(function(value, index) {
            // return value === 123;
            return value < 100 && value % 2 == 0;
        });
        console.log(output);

Math

•Math对象是ECMAScript提供的一个全局对象,它主要封装了一些常用的数学
函数和常数
•Math对象没有构造函数,无法创建它的实例;调用其属性和方法时,直接使用Math对象名即可。
//Math对象不能实例化
var m1 = new Math(); //type Error
console.log(Math.PI); //直接使用对象名调用属性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Math 是 ECMAScript的全局对象
没有构造函数 无法进行实例(不能new)
直接使用对象名访问其成员(属性、方法)

    console.log(Math.PI); //圆周率
    console.log(Math.E); // 自然对数

    console.log(Math.abs(-3)); // 绝对值
    console.log(Math.ceil(3.00000000000000001)); // 向上取整
    console.log(Math.log(2)); // 自然对数 
    console.log(Math.floor(-3.14)); // 向下取整
    console.log(Math.max(3, 5)); // 返回较大的值
    console.log(Math.min(3, 5)); // 返回较小的值
    console.log(Math.pow(2, 31) - 1); // x的y次幂
    console.log(Math.round(-3.51)); // 四舍五入
    console.log(Math.sqrt(9)); // 平方根

    三角函数
    Math.sin() = 对边/斜边
    Math.cos() = 邻边/斜边

    勾股定理
    a^2+b^2=c^2
var a = 3;
        var b = 4;
        var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
        console.log(c);

随机数

Math.random();
Math.random()函数返回一个0-1之间的小数,伪随机数

    0.00000000000001
    0.99999999999999

    0-100之间的数
    random * 100 四舍五入
    0-99 向下取整
    1-100 向上取整
function getNumber(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
        }
 // 10,20
        function getNumber(min, max) {
            // return Math.round(Math.random() * (max - min) + min);
            return Math.floor(Math.random() * (max - min + 1) + min);
        }

        for (var i = 0; i < 100; i++) {
            console.log(getNumber(10, 20));
        }
  1. 随机生成一个6位的验证码
    要求包含 数字 大写字母 小写字母
function getCode() {
            var checkCode = '';
            var codeType;
            // 随机出6组Unicode编码
            for (var i = 0; i < 6; i++) {
                codeType = getNumber(1, 3);
                switch (codeType) {
                    case 1:
                        // 生成指定范围的随机数
                        // 将随机的Unicode编码转成 字符串
                        // 拼接字符串
                        checkCode += String.fromCharCode(getNumber(48, 57));
                        break;
                    case 2:
                        checkCode += String.fromCharCode(getNumber(97, 122));
                        break;
                    case 3:
                        checkCode += String.fromCharCode(getNumber(65, 90));
                        break;
                }
            }
            return checkCode;
        }
        console.log(getCode());
  1. 编写一个函数 随机获取一个 rgba的颜色 透明度不允许为0
 function getColor(opa) {
            // 使用短路逻辑解决 默认参数问题
            opa = opa || 1; // 断路逻辑
            var color = 'rgba(';
            for (var i = 0; i < 3; i++) {
                color += getNumber(0, 255) + ',';
            }
            return color + opa + ')';
        }

        console.log(getColor());
  1. 在页面随机生成一组双色球彩票
    红色球 32 个 6个
    蓝色球 16 个 1个
<style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        #list {
            list-style: none;
            overflow: hidden;
        }
        
        #list>li {
            width: 60px;
            height: 60px;
            border: 2px solid red;
            border-radius: 50%;
            text-align: center;
            line-height: 60px;
            margin: 5px;
            font-size: 25px;
            float: left;
            color: red;
            user-select: none;
        }
        
        #list>li:last-child {
            border-color: aqua;
            color: aqua;
        }
    </style>
 window.onload = function() {
            // 双色球 
            // 红色球 1-32
            // 蓝色球 1-16

            var list = document.getElementById('list');
            var btn = document.getElementById('btn');

            function getNumber(min, max) {
                return Math.floor(Math.random() * (max - min + 1) + min);
            }

            btn.onclick = doubleColorBall; //给事件赋值实名函数

            function doubleColorBall() {
                // 初始化
                list.innerHTML = '';


                var redBall = [];
                // var redBallResult = [];
                var temp; //临时变量
                for (var i = 0; i < 32; i++) {
                    redBall.push(i + 1);
                }

                // 从抽奖箱(数组中)获取6个红色球
                for (var j = 0; j < 6; j++) {
                    // 循环6次获得6个红色球
                    temp = getNumber(0, redBall.length - 1); // 从数组中随机一个索引值
                    // redBallResult.push(redBall.splice(temp, 1)[0]); // 删除的数组元素  存入数组
                    list.innerHTML += '<li>' + redBall.splice(temp, 1)[0] + '</li>';
                }
                // console.log(redBallResult);
                // console.log(redBall);

                // 随机出一个蓝色球
                list.innerHTML += '<li>' + getNumber(1, 16) + '</li>';
            }
        }
<body>
    <button id="btn">按钮</button>
    <ul id="list">

    </ul>
</body>

Date对象

• Date对象用于对时期和时间进行存储和计算
//使用指定的年月日[时分秒]进行初始化
var d1 = new Date(2008,7,8); //月份是从0~11
var d2 = new Date(2008,7,8,21,31,42);
var d3 = new Date(‘2008,2,8’) ;//把String转换为Date
//初始化为系统时间
var d = new Date();
var d1 = newDate;
// var d3 = Date(); 构建一个string,值为当前系统时间
//初始化为距离计算机元年指定毫秒数的时间
var dd = new Date(0); var d2 = new Date(1000360024*365)

获取时间信息

在这里插入图片描述

修改时间信息

在这里插入图片描述

时间格式转换

在这里插入图片描述
Date 是ECMAScript的内置对象
拥有构造函数 可以 new

    创建时间对象
    var d = new Date(); // 获得当前系统时间
    console.log(d);

    创建时间对象 带参数
    指定一个时间 年,月,日,时,分,秒
    var d2 = new Date(2008, 0, 10);
    console.log(d2);

    var d3 = new Date('2020,5,1 15:12:00');
    console.log(d3);


    var d4 = new Date();
    console.log(d4.getDate()); // 获得日期部分  1-31
    console.log(d4.getDay()); // 获得星期  0-6
    console.log(d4.getFullYear()); // 获得年份
    console.log(d4.getHours()); // 获得小时 0-23
    console.log(d4.getMinutes()); // 获得分钟 0-59
    console.log(d4.getSeconds()); // 获得秒  0-59
    console.log(d4.getMilliseconds()); // 获得毫秒 0-999
    console.log(d4.getMonth() + 1 + '月'); // 获得月份 0-11  需要使用月份时+1
    getTime() 时间戳 它是编程中唯一不重复的数
    电商网站订单号
    20200110094352+用户id 10002354378 + 时间戳
    console.log(d4.getTime()); // 获得当前时间距离UTC时间1970年1月1日12点的毫秒差

    console.log(d4.getTimezoneOffset() / 60); // 时区

设置时间
var d = new Date();
d.setHours(8);
console.log(d.getHours());

    JS的时间容错
    如果在设置时间时超出取值范围 自动计算到下一个运算周期
    d.setTime(65);
    d.setDate(d.getDate() + 22);
    console.log(d);

    console.log(Date.now()); // 快速获得时间戳

时间格式
var d = new Date();
// console.log(d);
// console.log(d.toString());
// console.log(d.toLocaleString());
var yy = d.getFullYear();
var mm = d.getMonth();
var dd = d.getDate();
var h = d.getHours();
var m = d.getMinutes();
var s = d.getSeconds();
console.log(yy + ‘-’ + (mm + 1) + ‘-’ + dd + ’ ’ + h + ‘:’ + m + ‘:’ + s);

setInterval()
    语法: setInterval(callback,delay);
    描述: setInterval 将每隔delay的时间执行callback
    参数: callback(function) 需要反复执行的函数
          delay(number) 延迟/间隔 时间  毫秒值

    var i = 0;
    setInterval(function() {
        console.log(i);
        i++;
    }, 2000);
window.onload = function() {
            var time = document.getElementById('time');
            setInterval(function() {
                var d = new Date();
                var yy = d.getFullYear();
                var mm = d.getMonth() + 1;
                var dd = d.getDate();
                var h = d.getHours() > 12 ? d.getHours() - 12 : d.getHours();
                var m = d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes();
                var s = d.getSeconds() < 10 ? '0' + d.getSeconds() : d.getSeconds();

                time.innerHTML = yy + '-' + mm + '-' + dd + ' ' + h + ':' + m + ':' + s;
            }, 1000);
        }
  1. 倒计时
 // 两个时间
        // 当前时间   未来时间
        // 未来时间 - 当前时间
        window.onload = function() {
            var djs = document.getElementById('djs');

            setInterval(function() {
                var futureTime = new Date(2020, 0, 17, 18, 0, 0); // 未来时间
                var now = Date.now(); // 当前时间的时间戳
                // JS在做时间对象运算时可以自动将时间对象转成时间戳进行计算
                // console.log(futureTime);3
                // console.log(now);
                var time = futureTime - now; // 需要倒计时的时间 毫秒
                var s = time / 1000; // 将毫秒转换成秒
                var day = Math.floor(s / (60 * 60 * 24)); // 将秒换算成天
                var hour = Math.floor(s % 86400 / 3600); // 计算剩余小时
                var min = Math.floor(s % 3600 / 60); // 计算分钟
                var sec = Math.floor(s % 60); // 获得秒
                djs.innerHTML = '距离春节假期来临 还剩:' + day + '天' + hour + '时' + min + '分' + sec + '秒';
            }, 1000);

        }

BOM

BOM与DOM

• BOM:Brower Object Model浏览器对象模型,用来访问和操作浏览器窗口,
使JS有能力与浏览器交互
• 通过使用BOM、可移动窗口、更改状态栏文本、执行其它不与页面内容
发生直接联系的操作
• 没有相关标准,但被广泛支持
• DOM:Document Object Model文档对象模型,用来操作当前HTML文档的
内容
• 定义了访问和操作HTML文档的标准方法
• 通过对DOM树的操作,实现对HTML文档树据的操作
• W3C指定了相关标准

BOM模型

• window对象是BOM的根对象,其它对象其实都是window对象的属性,
window对象的属性和方法都可以省略"window."

window对象在浏览器中表示打开的浏览器窗口
window是BOM的根对象
window浏览器环境中的最高级对象(全局对象)
window对象中的属性和方法都可以省略 window.
window下所有子属性和方法全局都可以访问
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

console.log(window);
console.log(alert === window.alert);
console.log(parseInt === window.parseInt);

所有的全局变量和全局函数 都是window的属性
var a = 10; console.log(a); console.log(window.a); var langth = 1; console.log(length);
文档显示区域宽高
console.log(innerHeight); console.log(innerWidth); var name = 10; // 窗口名 字符串类型 console.log(name + 10); // 拼接字符串
浏览器宽高
console.log(outerHeight); console.log(outerWidth);
window全局函数

// var b = confirm('你确定要关闭吗?'); // 弹出一个带有确定和取消按钮点窗口 用户点击以后获得一个布尔值
        // if (b) close(); // 用于关闭页面(如果当前只有一个页面则关闭浏览器)

        window.onload = function() {
            var pri = document.getElementById('print');
            pri.onclick = function() {
                print(); // 打印
            }
        }
<body>
    <button id="print">打印当前页面</button>
</body>

浏览器打开窗口

var config = "left=200,top=300,width=500,height=300";

        //打开窗口

        var openurl = "https://www.baidu.com";

        var newWin = open(openurl, 'popwin', config);

对话框
• window对象提供了三种对话框:
• window.alert(msg) //弹出一个警告框
• window.primpt(msg) //弹出一个输入提示框
• window.confirm(msg) //弹出一个确认框
定时器
• 多用于网页动态时钟、制作倒计时效果等
• 周期性时钟
• 以一定的间隔执行代码,循环往复
• 一次性时钟
• 在一个设定的时间间隔之后来执行代码,而不是在函数被调用后立即执行

周期性定时器
• setInterval(exp,time):周期性触发代码exp
• exp:执行语句
• time:时间周期,单位为毫秒
• 返回已经启动的定时器ID
• clearInterval(tID):停止启动的定时器
• tID:启动的定时器对象

一次性定时器
• setTimeout(exp,time):一次性触发代码exp
• exp:执行语句
• time:时间周期,单位为毫秒
• 返回已经启动的定时器ID
• clearTimeout(tID):停止启动的定时器
• tID:启动的定时器对象

JavaScript 提供了两种计时器
周期性计时器
setInterval('console.log(123)', 2000);
返回值: number 返回的是计时器的编号
每间隔一定的时间 执行一次函数
var timer = setInterval(function() { console.log('ok'); }, 1000); console.log(timer);
window.onload = function() { var stop = document.getElementById('stop'); stop.onclick = function() { // 参数: 计时器设置时的编号 clearInterval(timer); // 用于关闭周期性计时器 } };
一次性计时器
var timer = setTimeout(function() { // 只执行一次 延迟代码的执行时间 console.log('ok'); }, 2000); clearTimeout(timer);
setTimeout 是一个异步操作
JS引擎如何执行代码
JS引擎 单线程
线程指的是可以同时执行的任务数量
I/O阻塞 Input/Output
BIOS basic input output system

    当出现异步操作时 异步操作会从主线程中移出 将这个操作放入到 事件队列
    当主线程内的代码执行完毕后 开始执行事件队列
setTimeout()
        for (var i = 0; i < 5; i++) {
            // 循环5次
            // 5个计时器
            setTimeout(function() {
                console.log(i);
            }, 1000);
        }

        alert(1);
        alert(2);

        console.log(1);
        setTimeout(function() {
            console.log(2)
        }, 0);
        console.log(3);


        / 如何输出0 1 2 3 4
        for (var i = 0; i < 5; i++) {
            // 循环5次
            // 5个计时器
            setTimeout(function() {
                console.log(i);
            }, 1000);
        }

        for (var i = 0; i < 5; i++) {
            (function(i) {
                setTimeout(function() {
                    console.log(i);
                }, 0);
            })(i);
        }

        for (let i = 0; i < 5; i++) { // let 用于申明块级变量
            setTimeout(function() {
                console.log(i);
            }, 0);
        }

        console.log(123);
        setTimeout(function() {
            console.log('ok');
        }, 1000);
        console.log(456);

Window常用子对象

• navigator对象
• location对象
• history对象
• screen对象

navigator对象的作用

• navigator对象包含浏览器URL的信息
• 常用于获取客户端浏览器和操作系统信息
for(var i in navigator){
console.log(i+":"+navigator[i]);
//遍历navigator对象的所有属性
}
在这里插入图片描述
在这里插入图片描述

  console.log(location);
        console.log(location.href); // 获得地址内容

        location.hash    //获得地址从#开始的部分  锚
        location.host    // 主机名和端口号
        location.hostname  // 主机名
        location.pathname  // 路径名  从第一个 /开始获取
        location.search   // 获得从?开始的部分

        console.log(location.pathname);


        console.log(location.host);


 window.onhashchange = function() {
            // onhashchange 是 SPA(单页面应用) 的基础
            console.log('hash改变了');
        }


  window.onload = function() {
            var link = document.getElementById('link');

            link.onclick = function() {
                // location.href 可以修改地址
                location.href = "https://www.baidu.com";
            }
        }

模拟获取数据

 var data = location.search.slice(1); // 获取数据
        data = data.split('&');
        console.log(data);
        for (var i = 0; i < data.length; i++) {
            console.log(data[i].split('=')[1]);
        }
history对象

• history对象包含用户(在浏览器窗口中)访问过的URL的历史记录
在这里插入图片描述
history.back() 后退
history.forword() 前进

screen对象

• Screen对象包含有关客户端显示屏幕的信息,方用于获取屏幕的分辨率和色彩
• JavaScript程序将利用这些信息来优化它们的输出,以达到需要显示要求
在这里插入图片描述
复习

  1. 归并
    Array.prototype.reduce();
    一般使用情况 用来做 统计
    arr.reduce(callback,object)
    首先 reduce 是数组的函数
    如果是统计字符串的内容 需要转数组
    var arr = [654, 651, 771, 764, 12, 5];
    var res = arr.reduce(function(result, current) {
    // reduce 会 遍历数组
    // 将数组里的每一个元素传入到 current
    // result 是 传入的对象
    // 从遍历第二次开始 result 是上一次回调函数的返回值
    // 如果上次回调没有返回值 则为 undefined
    current % 2 ? result.odd++ : result.even++;
    console.log(result, current);
    return result;
    }, {
    odd: 0,
    even: 0
    })
    console.log(res);
var data = [{
            name: '张三',
            age: 18,
            sex: 1
        }, {
            name: '李四',
            age: 17,
            sex: 1
        }, {
            name: '小花',
            age: 25,
            sex: 0
        }, {
            name: '小汪',
            age: 30,
            sex: 1
        }, {
            name: '小闫',
            age: 35,
            sex: 1
        }];

        // 男性  女性  成年人  未成年人
        var res = data.reduce(function(result, current) {
            if (current.age >= 18) {
                result.adult++;
            } else {
                result.nonage++;
            }

            if (current.sex) {
                result.man++;
            } else {
                result.woman++;
            }

            return result;
        }, {
            // 要统计的东西写成对象的属性
            adult: 0, // 成年
            nonage: 0, // 未成年
            man: 0, // 男
            woman: 0 // 女
        });

        console.log(res);
  1. 函数、构造函数、回调函数、匿名函数、对象、方法 这些定义的区别

     函数其实就是一个完整的功能 包含了多条语句来实现某个功能(子程序)
     申明和执行会提前 
     拥有参数 为了让函数更加的灵活
     返回值 获得运行结果
    
     构造函数  用于创建对象的函数(类似于Java中的Class)
    
    
     回调函数 将函数作为参数来使用 
     1. 让调用变得简单
     2. 改变代码的执行顺序
     3. 异步
    
     匿名函数 没有名字的函数
     仅在执行时,临时创建作用域链对象 用完即释放 节省内存空间
    
     对象(Object) 一组无序的 数据(属性)和功能(方法)的集合
     在JS中 除了关键字 保留字  运算符  操作符以外  所有东西都是对象
    
     方法  方法就是函数 
     当函数在对象中作为属性存在的时候通常称其为方法
    
function fn() {

        }
        window.fn()
  1. Array.prototype.forEach()
    arr.forEach(function(value,index){})
    遍历数组 将数组的每一个元素和它对应的索引值放入回调的参数中
  var arr = [1, 2, 3, 4, 5];
        arr.forEach(function(val, i) {
            // 完整遍历数组 不需要写for语句
            console.log(val * 2);
        })

        Array.prototype.fn = function(callback) {
            for (var i = 0; i < this.length; i++) { // this 在原型函数中 指向调用者
                // 循环调用回调函数
                callback(this[i], i);
            }
        }

        var arr = [1, 3, 5, 6];
        arr.fn(function(value, index) {
            // console.log(value, index);
            console.log(value * 2);
        })
 Array.prototype.map()
        arr.map(callback)
        var arr = [1, 3, 5, 8];
        var arr2 = arr.map(function(val, i) {
            return val * 2;
        });
        console.log(arr2);
        console.log(arr);
Array.prototype.abc = function(callback) {
            var arr = [];
            for (var i = 0; i < this.length; i++) {
                arr.push(callback(this[i], i));
            }
            return arr;
        }

        var arr = [6, 5756, 14, 86, 11];
        var res = arr.abc(function(val, i) {
            return val / 2;
        });
        console.log(res);

4.问 两个数组 如何判断里面的数据相同

解题思路:1. 排序 使用相同的排序算法 结果一定相同
2. == 比较的是地址
3. 转换成字符串 比较字符串

 var arr1 = [124, 765, 867, 'bc', true];
        var arr2 = [867, 124, 765, true, 'bc'];

        arr1.sort();
        arr2.sort();

        // 数组的toString()是将里面所有的元素都调用 toString() 用,连接
        console.log(arr1.toString() === arr2.toString());
        // console.log(arr2.toString());

5.隐式转换

 console.log([] == ![]); // true
        // 数组是引用类型  比较的是地址
        // 运算符的优先级 
        // 逻辑非优先级高于等于

        console.log(![]); // false 0

        // 0
        console.log(Number([])); // 空数组转数字的结果是0
        console.log([] == 0);

DOM

DOM概述

• DOM是W3C(万维网联盟)的标准,是中立于平台和语言的接口,
它允许程序和脚本动态的访问和更新文档的内容、结构和样式。
• W3C DOM标准被分为3个不同的部分:
• 核心DOM 针对任何结构化文档的标准模型
• XML DOM 针对XML文档的标准模型
• HTML DOM针对HTML文档的标准模型

DOM树理解

• HTML DOM:针对HTML文档的对象模型
• 当网页被加载时,浏览器会创建页面的文档对象模型
• 通过DOM,可以访问所有的HTML元素,连同它们所包含的文本
和属性
• 可以对其中的内容进行修改和删除,同时也可以创建新的元素
• 文档中的所有节点组成了一个文档树
• document对象是一颗文档树的根
当浏览器加载一个HTML文件时 会自动创建对应的document对象
在页面中所有的元素(html标签)属性(标签属性)文本 注释 都被看作为是节点
而是document对象是最高级级别的节点(根节点)
一个元素 div元素 从标记开始到标记结束
所有的节点在JS中 都是对象(重要)
document对象
• 浏览器内置的JS解释器会为载入的每个HTML文档创建一个对应的document对象
• 通过使用document对象,可以从脚本中对HTML页面中的所有元素进行访问

var box = document.getElementById('box');
var li4 = document.getElementById('li4');
var list = document.getElementById('list');

console.dir(box);以目录形式打印对象 标签

DOM操作

• 通过可编程的对象模型,JavaScript获得了足够的能力来创建动态的HTML
• 查找节点
• 读取节点信息
• 修改节点信息
• 创建新节点
• 删除节点
在这里插入图片描述

节点树

• 什么是节点树
• HTML DOM将HTML文档视作树结构。
• 文档中的元素、属性、文本、注释等都被看作一个节点。

上下层节点

• 节点树中的节点彼此拥有层级关系,DOM使用如下属性遍历整个
节点树:
在这里插入图片描述
语法:none.parentNode
含义:获得node的父级节点
可以通过parentNode获取父级节点,最高级别的节点是document
document.prentNode是null

console.log(box.parentNode);
console.log(li4.parentNode.parentNode.parentNode.parentNode.parentNode);

语法:node.childNodes
含义:获得node的子节点 集合(多个)
结果为类数组对象

console.log(list.childNodes);

语法:node.firstChild
含义:获得第一个子节点

console.log(list.lastChild);

语法:node.lastChile
含义:获得最后一个子节点

console.log(list.firstElementChild);

语法:node.firstElementChild
含义:获得第一个子元素

console.log(list.firstElementChild);

语法:node.lastElementChild
含义:获得最后一个子元素

console.log(list.lastElementChild);

语法:node.children
含义:获得所有的子元素
结果是类数组

console.log(list.children);            
for (var i = 0; i < list.children.length; i++) {
     console.log(list.children[i]);
}

平行的节点

• 节点树中使用如下方法访问平行的兄弟节点:
在这里插入图片描述
语法:node.previousSibling
含义:获得上一个兄弟节点

console.log(li4.previousSibling);

语法:node.nextSibling
含义:获得下一个兄弟节点

 console.log(li4.nextSibling);

语法:node.previousElementSibling
含义:获得上一个兄弟元素

console.log(li4.previousElementSibling);

语法:node.nextElementSibling
含义:获得下一个兄弟元素

console.log(li4.nextElementSibling);

节点名称 nodeName
• nodeName:节点的名称,String类型属性
• nodeName 是只读的
在这里插入图片描述
语法:node.nodeName
含义:节点名 只读string
元素节点 返回大写的标签
文本节点 #text
文档节点 #document
注释节点 #comment
属性节点 属性名

var list = document.getElementById('list');
console.log(list.childNodes[1].nodeName);
console.log(document.nodeName);
var box = document.getElementById('box');
    // 将所有的div元素放入数组
var arr = [];
for (var i = 0; i < box.children.length; i++) {
    if (box.children[i].nodeName === 'DIV') {
          arr.push(box.children[i]);
    }
}
	console.log(arr);

节点类型 nodeType

• nodeType:节点类型,Number类型属性
在这里插入图片描述
节点类型
语法:node.nodeType
语义:节点类型 number类型
元素节点 1
属性节点 2
文本节点 3
注释节点 8
文档节点 9
文档声明 10

window.onload = function() {
            var box = document.getElementById('box');
            // console.log(box.childNodes[1].nodeType)
            // console.log(document.childNodes[0].nodeType);

            var arr = [];
            for (var i = 0; i < box.childNodes.length; i++) {
                if (box.childNodes[i].nodeType === 1) {
                    arr.push(box.childNodes[i]);
                }
            }

            console.log(arr);
        }

节点值 nodeValue

• nodeValue:节点的值,String类型属性
在这里插入图片描述
所有的元素节点都用于 innerHTML 属性
用于获取和设置HTML内容
访问该元素里面的HTML内容
文本内容
textContent 用于获取和设置文本内容
无法识别标签

HTML内容

• 元素节点对象的innerHTML属性读取或设置元素节点中的HTML内 容
< div id=“div1”>JavaScript
var div=document.getElementById(‘div1’);
console.log(div.innerHTML);//读取
div.innerHTML = ‘jQuery’;//设置

文本内容

• 元素节点对象的textContent属性用于读取或设置元素节点中的文
本内容
注:有争议的innerText
标准DOM操作中,并没有innerText属性;
IE8及之前的IE浏览器不支持标准的textContent属性
使用innerText实现类似的功能,目前此属性已被大多数浏览
器所兼容,但Firefox仍不支持此属性

属性集合

• 元素节点的attributes属性返回节点的属性集合,即一个类数组对

< div id=“div1” οnclick=“up()” class=“add”>
var div=document.getElementById(‘div1’);
console.log(div.attributes);//类数组对象
console.log(div.attributes.length);//3
console.log(div.attributes[1]);//属性对象
元素节点用于属性集合
元素节点attributes属性返回属性(节点)集合 类数组对象
读取属性
• 可以使用如下几种方式读取某个属性的值:
(1)element.attributes[下标].value
(2)element.attributes[‘属性名’].value
(3)element.getAttributeNode(‘属性名’).value
(4)element.getAttribute(‘属性名’)

设置属性
• 可以使用如下两种种方式设置元素的属性:
(1)element.setAttribute(name,value);
(2)element.setAttributeNode(attrNode);

var div=document.getElementById('div1'); var atr=document.createAttribute('class') atr.nodeValue="className"; div.setAttributeNode(atr)

移除属性
• 可以使用如下两种种方式删除一个属性:
(1)element.removeAttribute(‘属性名’);
(2)element.removeAttributeNode(attrNode)

判断属性
• 如下方法可用于判定元素是否有指定属性:
(1)element.hasAttribute(‘属性名’);//true或false
(2)element.hasAttributes(); //是否拥有属性、IE8及以下版本不支持此方法

for (var i = 0; i < box.attributes.length; i++) {
                // 遍历以后得到的是属性节点 
                // 节点值
                console.dir(box.attributes[i]);
            }

获得属性值
语法: element.getAttribute(‘attrName’);

box.setAttribute('data-test', 'abc'); //  data-xxx  是html5标准的自定义属性

设置属性值
语法: element.setAttribute(‘attrName’,‘value’);

box.setAttribute('title', 'hello world');
box.setAttribute('data-test', 'abc'); //  data-xxx  是html5标准的自定义属性

删除属性
语法: element.removeAttribute(‘attrName’)

box.removeAttribute('class');

判断属性
语法: element.hasAttribute(‘attrName’);
判断属性是否存在 并返回一个布尔值

console.log(box.hasAttribute('class'));

            btn.onclick = function() {
                // if (box.hasAttribute('class')) { // 判断是否有class属性
                //     box.removeAttribute('class'); // 删除
                // } else {
                //     box.setAttribute('class', 'red'); // 添加
                // }

                if (box.getAttribute('class') === 'red') {
                    box.setAttribute('class', 'green');
                } else {
                    box.setAttribute('class', 'red');
                }
            }

类名的特点 空格分割

window.onload = function() {
            var box = document.getElementById('box');
            // 添加类名 
            function addClass(elm, className) {
                elm.setAttribute('class', elm.getAttribute('class') + " " + className);
            }

            addClass(box, 'center');
            addClass(box, 'center2');
            addClass(box, 'center3');

            // 删除类名
            function removeClass(elm, className) {
                // 1. 获得类名
                var value = elm.getAttribute('class');
                // 类名的特点 空格分割
                // console.log(value);
                var arr = value.split(' '); //  将字符串切割成数组
                // console.log(arr);
                var index = arr.indexOf(className); // 在数组中查找类名  获得索引
                arr.splice(index, 1);
                value = arr.join(' ');
                // console.log(value);
                elm.setAttribute('class', value);
            }

            removeClass(box, 'a3');
            removeClass(box, 'center2');
        }

扩展:
HTML5 为元素节点增加了类名接口 classList

window.onload = function() {
var box = document.getElementById('box');
// console.log(box.classList);
box.classList.add('center'); // 添加类名
box.classList.remove('d2'); // 删除类名
        }

选项卡

window.onload = function() {
            // 1. 事件绑定给谁?  li 元素
            // 2. 谁要操作类名  li和div

            var tabs = document.getElementById('tabs');
            var child = tabs.children;
            var oUl;
            var oDiv = [];
            for (var i = 0; i < child.length; i++) {
                if (child[i].nodeName === 'UL') {
                    oUl = child[i]; // 选择UL
                } else if (child[i].nodeName === 'DIV') {
                    oDiv.push(child[i]); //选择DIV
                }
            }
            var oLi = oUl.children; //选择LI

            // 3. 绑定事件
            for (var j = 0; j < oLi.length; j++) {
                // 通过循环给每一个li元素添加点击事件
                // oLi[j].setAttribute('data-index', j); // 为每一个元素添加一个索引值
                oLi[j].index = j; // index不是html标准属性

                oLi[j].onclick = function() {
                    // // 点击li元素的时候 获得索引值
                    // var index = this.getAttribute('data-index');

                    // 删除所有li元素的 actived 类名
                    // 删除所有Div元素的 show 类名
                    for (var k = 0; k < oLi.length; k++) {
                        oLi[k].classList.remove('actived');
                        oDiv[k].classList.remove('show');
                    }
                    // 给被点元素添加 actived 类名
                    this.classList.add('actived');
                    // 给被点击的li元素所对应的div元素加 show类名

                    // oDiv[index].classList.add('show');
                    oDiv[this.index].classList.add('show');
                }
            }
        }
<body>
    <div id="tabs">
        <ul>
            <li class="actived">选项一</li>
            <li>选项二</li>
            <li>选项三</li>
        </ul>
        <div class="show">内容111111</div>
        <div>内容22222222222222</div>
        <div>内容33333333333333</div>
    </div>
</body>

DOM
DOM选取元素、增加、删除和替换节点

选取元素

• document.getElementById(‘id’)可用于当前DOM树中根据ID选择某
一个子元素
• Node.getElementsByTagName(‘标签名’)可根据标签名返回所有具有指定标签名的元素集合
• document.getElementsByName(‘name属性值’)可以返回DOM数中具有指定那么属性值的所有子元素集合
• node.getElementsByClassName(‘className’)可以根据class名称选
取元素的方法(IE9+、Firfox3+、Safari3.1+、Chrome和Opera9.5+)

语法: node.getElementsByTagName(‘tagName’);
作用: 通过标签名选择元素
返回值: 类数组对象

var oDiv = document.getElementsByTagName('div');
    console.log(oDiv);
var oDiv = box.getElementsByTagName('div');
    console.log(oDiv);

语法: document.getElementsByName(‘name’);
作用: 通过name属性选择表单元素
返回值: 类数组对象

var oCheck = document.getElementsByName('ck');
var oCheck = document.querySelectorAll('input[type="checkbox"]');
    console.log(oCheck);

全选功能
如何让checkbox被选中
checkbox 拥有内部属性 checked 它是一个布尔值

// 遍历其他checkbox 让其他checkbox的checked属性和第一个相同
   for (var i = 1; i < oCheck.length; i++) {
        oCheck[i].checked = oCheck[0].checked;
   }

console.log(document.documentElement); // 返回html元素
console.log(document.body); // 返回body
console.log(document.head); // 返回head

• 通过css选择器选取元素
(1)node.querySelector(‘selector’)//返回第一个匹配的
(2)node.querySelectorAll(‘selector’)//返回全部匹配的
< div id=“div1”>
< p class=“p1”>中国< /p>
< p class=“p2”>澳门< /p>
< p class=“p2”>台湾< /p>
< p class=“p2”>香港< /p>
< /div>
var div= document.getElementById(‘div1’);
var p= div.querySelectorAll(’.p2’);
console.log§;

语法: node.querySelector(‘selector’)
作用: 通过给定的css选择器选择所匹配的第一个元素

        id #
        class .
        element tagName
        attribute []
        >    子代选择器
        空格  后代选择器
var box = document.querySelector('.box');
            console.log(box);
	var news = document.querySelector('a[href*="news"]');
            console.log(news);

var div3 = document.querySelector('div:nth-of-type(3)');
            console.log(div3);

语法: node.querySelectorAll(‘selector’);
作用: 根据给定的选择器 选择所有匹配的元素
返回结果是一个类数组对象

var evenDiv = document.querySelectorAll('div:nth-of-type(even)');
            console.log(evenDiv);

选项卡

window.onload = function() {
            // 1. 选元素
            // li元素的类名  div元素的类名

            var oLi = document.querySelectorAll('#tabs>ul>li');
            var oDiv = document.querySelectorAll('#tabs>div');
            // 使用 querySelectAll 选择的元素 可以使用 forEach 函数
            // forEach语法和数组一样

            oLi.forEach(function(elm, i) {
                elm.index = i; // 给li元素添加一个属性 index

                // 给li元素加点击事件
                elm.onclick = function() {
                    // forEach 遍历li元素 
                    oLi.forEach(function(el) {
                        el.classList.remove('actived'); //删除所有li元素的actived类名
                    });

                    // 遍历div元素
                    oDiv.forEach(function(el) {
                        el.classList.remove('show'); //删除所有div元素的show类名
                    });

                    this.classList.add('actived');
                    oDiv[this.index].classList.add('show'); // li元素所对应的div元素添加类名
                    // this指向的是被点击的那个li元素
                }
            })

        }
<body>
    <div id="tabs">
        <ul>
            <li class="actived">选项1</li>
            <li>选项2</li>
            <li>选项3</li>
            <li>选项4</li>
            <li>选项5</li>
            <li>选项6</li>
            <li>选项7</li>
        </ul>
        <div class="show">11111111111111111111</div>
        <div>22222222222222</div>
        <div>3333333333333</div>
        <div>444444444444</div>
        <div>5555555555555555555</div>
        <div>6666666666</div>
        <div>777777777777777</div>
    </div>
</body>

其它选取

• document.documentElement返回整个HTML文档的根元素(即
< html>元素)
• document.head返回HTML文档中< head>元素
• document.body返回HTML文档中< body>元素

创建节点

• 创建节点使用如下方法创建一个新的元素
• document.createElement(‘元素名’);
• 创建文本节点使用如下方法可以创建一个新的文本节点
• document.createTextNode(‘text’);

插入节点

• parentNode.appendChild(childNode)可用于将一个父元素追加最
后一个子节点
• parentNode.insertBefore(newChild,existingChild)方法用于在父元素中指定子
节点之前添加一个新的子节点

删除节点

• 可以使用parentNode.removeChild(childNode);
• 此方法返回被删除的节点的引用

替换节点

• 可以使用如下方法替换一个已经存在的子节点:
parentNode.replaceChild(newNode,oldNode);

语法:document.createElement(‘tabName’);
作用:用于创建元素节点
返回值:新创建的元素节点

var div = document.createElement('div');
  div.textContent = 'abc';
  console.log(div);在这里插入代码片

语法: parentNode.appendChild(childNode);
作用: 用于在父节点的结尾添加一个子节点
document.body.appendChild(div);

语法:
parentNode.insertBefore(newChild,existingChild);
作用: 用于在指定节点的前面插入一个新节点

document.body.insertBefore(div, btn);

增加内容

window.onload = function() {
    var btn = document.querySelector('button');
    var list = document.querySelector('#list');
    btn.onclick = function() {
var li = document.createElement('li');
var oLi = document.querySelectorAll('#list>li');
     li.innerHTML = '新的li元素';
     list.insertBefore(li, oLi[2]);
	}
}

语法: parsentNode.removeChild(childNode);
作用: 在父节点中删除一个子节点
返回值: 被删除的元素

 window.onload = function() {
 var btn = document.querySelector('.btn');
 var list = document.querySelector('#list');
            btn.onclick = function() {
                // 语法: parsentNode.removeChild(childNode);
                // 作用: 在父节点中删除一个子节点
                // 返回值: 被删除的元素

  var lastLi = document.querySelector('li:last-of-type');
                console.log(list.removeChild(lastLi));
                // if (lastLi) list.removeChild(lastLi);
            }
        }

元素节点移动

 window.onload = function() {
            var btns = document.querySelectorAll('.btns>button');
            var left = document.querySelector('.left');
            var right = document.querySelector('.right');

            btns[0].onclick = function() {
                // 右移一个
                // 左边删除 右边添加
                var firstLi = document.querySelector('.left>li:first-of-type');
                if (firstLi) {
                    var del = left.removeChild(firstLi);
                    right.appendChild(del);
                }
            }

            btns[1].onclick = function() {
                // 获得左边所有的li
                var oLi = document.querySelectorAll('.left>li');
                oLi.forEach(function(elm) {
                    var del = left.removeChild(elm);
                    right.appendChild(del);
                });
            }
        }
 * {
            padding: 0;
            margin: 0;
        }
        
        button {
            padding: 5px 10px;
        }
        
        .btns {
            text-align: center;
        }
        
        .list {
            overflow: hidden;
            width: 1004px;
            margin: 20px auto;
        }
        
        .list>ul {
            list-style-type: none;
            width: 400px;
            margin: 0 50px;
            height: 210px;
            border: 1px solid black;
            float: left;
        }
        
        .list>ul>li {
            text-align: center;
        }
<body>
    <div class="btns">
        <button> 右移一个 </button>
        <button> 右移全部 </button>
        <button> 左移一个 </button>
        <button> 左移全部 </button>
    </div>
    <div class="list">
        <ul class="left">
            <li>第1个li</li>
            <li>第2个li</li>
            <li>第3个li</li>
            <li>第4个li</li>
            <li>第5个li</li>
            <li>第6个li</li>
            <li>第7个li</li>
            <li>第8个li</li>
            <li>第9个li</li>
            <li>第10个li</li>
        </ul>

        <ul class="right"></ul>
    </div>
</body>
 window.onload = function() {
            // 使用一个标题元素 替换p元素 并且需要保存其内容和属性

            // 语法: parentNode.replaceChild(newNode,oldNode);
            // 作用: 使用一个新节点替换一个旧节点

            var btn = document.querySelector('button');
            var p = document.querySelector('p');
            btn.onclick = function() {
                var h1 = document.createElement('h1'); // 创建元素
                h1.innerHTML = p.innerHTML; //设置内容
                var attr = p.attributes; // 获取属性集合
                for (var i = 0; i < attr.length; i++) {
                    h1.setAttribute(attr[i].nodeName, attr[i].nodeValue);
                }

                document.body.replaceChild(h1, p);

            }
        }

节点树VS元素树

在这里插入图片描述

HTML DOM概述

• HTML DOM定义了用于HTML的一系列标准的对象,以及访问的
处理HTML文档的标准方法
• HTML标签对象化
• 网页中的每个元素都看作一个对象

常用HTML DOM对象

var div = document.getElementById(‘div’);
//创建一个新的图片对象,加入到div中
var newNode = new Image();
newNode.src=“a.jpg”;
div.appendChild(newNode);//将HTML对象化

标准DOM与HTML DOM

• 标准DOM提供了统一的操作接口
createElement
appendChild
setAttribute
removeAttribute
nodeName…
• HTML DOM提供了封装好的各种对象
Image
Select
Option…

• 标准DOM的实现方式
var newNode = document.createElement(‘img’);
• HTML DOM的实现方式
var newNode = new Image();

• 标准DOM操作适合于:
操作节点,创建,删除,查找等
• HTML DOM操作适合于:
操作属性,如读取或者修改属性的值

var url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1578994332712&di=6c47d56f41fbcb2bfb7bf84efac7c6ab&imgtype=0&src=http%3A%2F%2Fn.sinaimg.cn%2Fsinacn10%2F386%2Fw640h546%2F20180812%2F7c68-hhqtawx2011571.jpg";
        window.onload = function() {
            // var img = document.createElement('img');
            // img.setAttribute('src', url);
            // document.body.appendChild(img);

            // HTML DOM
            // HTML DOM将元素对象化  
            // 对象拥于属性, 所以可以直接通过.操作符访问属性
            // var img = new Image(); // 使用构造函数创建图片
            // img.src = url;
            // document.body.appendChild(img);

            // var s = new Option();
            // console.log(s);

            // var div = new Div();
            // console.log(div);

            // var a = new A();
            // console.log(a);


            // 不是所有的元素都进行了封装,不建议使用构造函数创建元素
            // 创建元素依旧使用 document.createElement()

            var div = document.querySelector('.box');
            // div.setAttribute('id','')
            // div.id = 'newid';
            // console.log(div.title);
            // 不是所有的属性都可以使用HTMLDOM操作

            // console.log(div.class); // class 在JS中是关键字
            // console.log(div.className); // 类名 className

            // 获得行内样式 使用  elm.style.cssText
            // console.log(div.style.cssText);
            // div.style.cssText += 'font-size:2em;';
            // div.style.fontSize = '3em';

        }
CSS属性

• 获取元素宽高
• offsetWidth/offsetHeight
• 获取定位值
• offsetTop/offsetLeft
• 获得计算后的CSS样式
• getComputedStyle(elm)[‘attr’] // 标准
• elm.currentStyle[‘attr’] // 低版本ie

元素的style属性是一个对象 样式对象
修改单个样式,直接通过style对象的属性进行设置,采用小驼峰命名法

 window.onload = function() {
            var box = document.querySelector('.box');

            // 获得元素的行内样式文本
            // elm.style.cssText
            // console.log(box.style.cssText);

            // 元素的style属性是一个对象  样式对象
            for (var i = 0; i < box.style.length; i++) {
                // style是对象  
                console.log(box.style[i]); //属性名
                console.log(box.style[box.style[i]]); //属性值
            }

            // 给元素添加行内样式
            // 修改背景色
            // 修改单个样式,直接通过style对象的属性进行设置,采用小驼峰命名法
            box.style.backgroundColor = 'yellow';
        }

获得元素大小
获得盒模型大小
offsetWidth/offsetHeight

        标准盒模型 content-box 
        content+padding+border = 元素大小
        IE盒模型/怪异盒模型 border-box
        content = 元素大小 
console.log(outer.offsetWidth);
console.log(outer.offsetHeight);

offsetTop/offsetLeft
偏移量(定位值)
修改元素的padding值和margin值会影响偏移量
定位值也会影响偏移量
如果父级元素定位了 根据父元素的0,0点计算
如果父元素没有定位 根据body的0,0点计算

console.log(inner.offsetTop);
console.log(inner.offsetLeft);

层叠样式表 CSS
元素最后生效的样式 需要计算的
获取计算后的样式
兼容性问题

getComputedStyle() 标准浏览器
console.log(getComputedStyle(outer)[‘height’]);

elm.currentStyle[‘style’]; // 低版本ie
alert(inner.currentStyle[‘top’]);
解决兼容问题

function getStyle(elm, style) {
      if (typeof getComputedStyle === 'function') {
        return getComputedStyle(elm)[style];
    } else {
        return elm.currentStyle[style];
   }
}

     alert(getStyle(inner, 'height'));

常用HTML DOM对象
• Image对象
• Image对象代表嵌入的图像
• < img>标签每出现一次,一个Image对象就会被创建
• 也可以使用new Image()创建一个新的对象
• 常用属性:
• src
• height
• width

Table对象

• Table对象代表一个HTML表格
• < table>标签标示一个Table对象
• 常用属性
• rows
• 常用方法
• insertRow(index):返回TableRow对象
• deleteRow(index)

TableRow对象

• TableRow对象代表一个HTML表格行
• 标签标示一个TableRow对象
• 常用属性
• cells、innerHTML、rowIndex
• 常用方法
• insertCell(index):返回TableCell对象
• deleteCell(index)

TableCell对象

• TableCell对象代表一个Html表格单元格
• < td>标签标示一个TableCell对象
• 常用属性
• cellIndex、innerHTML、colSpan、rowSpan
table 对象
每一个table标签都是一个table对象
table.rows 返回表格中所有的行的集合 类数组对象
console.log(table.rows);
insertRow 创建了一个行 tr
将tr插入到指定索引
tr.cells 返回当前行 所有单元格的集合 类数组对象
insertCell 用于在行中添加单元格

点击按钮添加一行

 window.onload = function() {
 var table = document.querySelector('table');
 var btn = document.querySelector('button');
            // table.rows 返回表格中所有的行的集合  类数组对象
            // console.log(table.rows);
            // insertRow 创建了一个行 tr
            //           将tr插入到指定索引

            var index = 3;

            btn.onclick = function() {
                var tr = table.insertRow(table.rows.length); // 返回新创建的行

                // tr.cells 返回当前行 所有单元格的集合   类数组对象

                // insertCell 用于在行中添加单元格
                var td1 = tr.insertCell(0);
                td1.innerHTML = index < 10 ? '0' + index : index;
                var td2 = tr.insertCell(1);
                td2.innerHTML = '小汪';
                var td3 = tr.insertCell(2);
                td3.innerHTML = '35';
                var td4 = tr.insertCell(3);
                td4.innerHTML = '男';
                var td5 = tr.insertCell(4);
                td5.innerHTML = '<input type="button" value="删除">';
                index++;

                // 事件添加
                var oBtn = document.querySelectorAll('input[type="button"]');
                oBtn.forEach(function(elm) {
                    elm.onclick = function() {
                        // 通过按钮父级找到td 再找父级tr 获得tr在表格中的索引 
                        var i = this.parentNode.parentNode.rowIndex;
                        table.deleteRow(i);
                    }
                });
            }
        }
** <div class="container">
        <button class="btn btn-success btn-block">添加一行数据</button>
    </div>
    <div class="container">
        <table class="table table-bordered table-hover text-center">
            <tr>
                <td>编号</td>
                <td>姓名</td>
                <td>年龄</td>
                <td>性别</td>
                <td>more</td>
            </tr>
            <tr>
                <td>01</td>
                <td>张三</td>
                <td>20</td>
                <td>男</td>
                <td><input type="button" value="删除"></td>
            </tr>
            <tr>
                <td>02</td>
                <td>李四</td>
                <td>25</td>
                <td>男</td>
                <td><input type="button" value="删除"></td>
            </tr>

        </table>
    </div>

居中问题
vscode中 Lorem+tab键 测试文 假文
外面套一层div使用 vertical-align: middle;
display: table-cell;
不能与float:left一起使用,只能写在外面一层

.outer {
            width: 800px;
            height: 500px;
            margin: 0 auto;
            /* float: left; */
            border: 1px solid black;
        }
        
        .inner {
            width: 800px;
            height: 500px;
            margin: 0 auto;
            /* line-height: 500px; */
            vertical-align: middle;
            display: table-cell;
        }
<div class="outer">
        <div class="inner">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, eligendi impedit. Veritatis totam alias accusamus, a possimus odio numquam pariatur eveniet, illum consequuntur soluta cupiditate eius fuga ipsum nobis aspernatur. Lorem ipsum dolor sit
        </div>
    </div>

文档碎片(了解)

• document.createDocumentFragment()
• 用于创建文档碎片 优化DOM操作的频率
document.createDocumentFragment()
文档碎片 性能优化

DOM
操作页面的元素 创建元素 修改元素内容 修改属性 设置属性…
操作样式 类名 style …
选取元素 …
DOM操作 性能非常差
原则 css能实现的功能一律不用JS

  window.onload = function() {
            var list = document.querySelector('#list');

            // var fra = document.createDocumentFragment(); //创建一个文档碎片
            // console.time('go');
            // for (var i = 0; i < 50000; i++) {
            //     var tempLi = document.createElement('li');
            //     tempLi.innerHTML = '第' + i + '个li';
            //     fra.appendChild(tempLi);
            // }
            // list.appendChild(fra);
            // console.timeEnd('go');


            console.time('go');
            var str = '';
            for (var i = 0; i < 50000; i++) {
                str += '<li>第' + i + '个li</li>'
            }
            list.innerHTML = str;
            console.timeEnd('go');
        }

event

事件概述

当用与Web页面进行某些交互时,解释器就会创建相应的eve瀁t对
象以描述事件信息。常见的事件有:
• 用户点击页面上的某个内容
• 鼠标经过特定的元素
• 用户按下键盘上的某个按键
• 用户滚动窗口或改变窗口大小
• 页面元素加载完成
• …
• 1995年IE4浏览器就已经定义了自己的事件模型;而DOM模型
2004年才最终确定标准的事件模型,并被其它浏览器所支持。所
以事件处理需要注意兼容性问题。

事件处理

1.HTML事件处理: 不推荐
直接添加到HTML结构中

2.DOM0级事件处理:(事件绑定)
一个函数只能绑定一个事件处理函数
把一个函数赋值给一个事件处理程序属性
绑定第二个事件处理函数时,第一个函数被覆盖了
btn.onclick = null; // 将onclick属性指向空 释放引用

window.onload = function() {
            // DOM 0级事件  将一个事件处理函数赋值给一个事件处理程序

            btn.onclick = function() {
                // DOM 0级事件 
                // 叫做 事件绑定
                // 一个事件只能绑定一个事件处理函数
                alert(1);
            }

            btn.onclick = function() {
                // 绑定第二个事件处理函数时,第一个函数被覆盖了
                alert(2);

                // 解绑事件
                btn.onclick = null; // 将onclick属性指向空 释放引用
            }
        }

3.DOM2级事件处理:
addEventListener(“事件名”,”事件处理函数”,”布尔值”);
true:事件捕获
false:事件冒泡
removeEventListener (“事件名”,事件处理函数); //移除事件

window.onload = function() {
            var box = document.querySelector('.box');

            // 为box添加事件
            // DOM2级事件
            // 语法: elm.addEventListener(eventType,callback,boolean);
            // 参数: eventType 事件类型 事件名 string 没有on
            //      callback 事件处理函数  function
            //      boolean  事件冒泡/捕获   default=false

            // DOM2级事件 事件监听
            box.addEventListener('click', function() {
                // DOM2级允许给一个元素绑定多个同事件的处理函数
                alert('这里是DOM2级事件处理');
            });

            // function fn() {
            //     alert('第二个事件');
            //     box.removeEventListener('click',fn);
            // }
            box.addEventListener('click', function() {
                alert('第二个事件');
                box.removeEventListener('click', arguments.callee);
                // arguments.callee  返回当前函数的引用
                // console.log(this);
            });


            // DOM2级事件解绑
            // 语法: elm.removeEventListener(eventType,fnName);
            // 参数: eventType  事件类型
            //       fnName     函数名



            // 按钮
            // 点击按钮触发事件 3秒内不能再次触发
        }

小例子:限定事件时间

var btn = document.querySelector('#btn');

        // 使用disabled 禁用的方式来处理

        // btn.addEventListener('click', function() {
        //     var that = this;
        //     console.log('我被点击了');
        //     this.setAttribute('disabled', 'disabled');
        //     setTimeout(function() {
        //         // 计时器中的this指向window
        //         that.removeAttribute('disabled');
        //     }, 3000);
        // })
		//2.通过添加和移除事件
        function fn() {
            var that = this;
            console.log('我被点击了');
            this.style.color = "#ddd";
            btn.removeEventListener('click', fn);
            setTimeout(function() {
                that.style.color = "#000";
                btn.addEventListener('click', fn);
            }, 3000);
        }
        btn.addEventListener('click', fn);

4.IE事件处理程序(IE版本小于等于8)
attachEvent(“事件名”,”事件处理函数”) 事件类型:带有on
detachEvent(“事件名”,”事件处理函数”)

var btn = document.getElementById('btn');

        // IE事件处理函数
        // 语法: elm.attachEvent(eventType,callback);
        // 参数: eventType 事件类型   有on

        btn.attachEvent('onclick', function() {
            alert('被点了');

            // 解绑事件
            // 语法: elm.detachEvent(eventType,fnName);
            btn.detachEvent('onclick', arguments.callee);
        });

事件绑定兼容写法

// 事件绑定
        function addEvent(elm, eventType, callback) {
            if (elm.addEventListener) { // 判断浏览器是否支持 addEventListener 函数
                elm.addEventListener(eventType, callback);
            } else if (elm.attachEvent) { // 判断是否支持IE
                elm.attachEvent('on' + eventType, callback);
            }
        }

        // 移除事件
        function removeEvent(elm, eventType, callback) {
            if (elm.removeEventListener) {
                elm.removeEventListener(eventType, callback);
            } else if (elm.detachEvent) {
                elm.detachEvent('on' + eventType, callback);
            }
        }

        window.onload = function() {
            var btn = document.getElementById('btn');

            addEvent(btn, 'click', function() {
                alert(1);
            });
        }

练习:几秒后按钮恢复点击

window.onload = function() {
            var btn = document.querySelector('#btn');

            btn.addEventListener('click', function() {
                btn.setAttribute('disabled', 'disabled');
                var sec = 5;
                var timer = setInterval(function() {
                    if (sec == 0) {
                        clearInterval(timer); // 时间为0 关闭计时器
                        btn.innerHTML = '按钮'; //恢复里面内容
                        btn.removeAttribute('disabled'); // 删除禁用属性
                        return;
                    }
                    btn.innerHTML = '按钮' + sec + '秒后恢复';
                    sec--;
                }, 1000);
            });
        }

事件的处理周期
• 解释器创建一个event对象后,会按如下过程将其在HTML元素间
进行传播:
• 第一阶段:事件的捕获,事件对象沿DOM树向下传播
• 第二阶段:目标触发,运行事件监听函数
• 第三阶段:事件冒泡,事件沿DOM树向上传播
• 注:IE的事件中没有“捕获”阶段

// 事件处理周期 事件流
        // 当一个事件发生时,会按照顺序在HTML元素之间进行传播
        // 1. 事件捕获  从最不具体到最具体的事物  事件沿着DOM树向下传播
        // 2. 目标触发  运行事件监听函数
        // 3. 事件冒泡  从最具体到最不具体的事物  事件沿着DOM树向上传播

        // ie没有事件捕获  只有冒泡

        // DOM0级默认冒泡 无法设置为事件捕获

        // 一般情况使用 事件冒泡

        window.onload = function() {
            var btn = document.getElementById('btn');
            var box = document.getElementById('box');

            // elm.addEventListener(eventType,callback,boolean);
            // 第三个参数 布尔值
            // true   事件捕获
            // false  事件冒泡

            document.body.addEventListener('click', function() {
                alert(3);
            });

            btn.addEventListener('click', function() {
                alert(1);
            });

            box.addEventListener('click', function() {
                alert(2);
            });

        }
<body>
    <div id="box">
        <button id="btn">按钮</button>
    </div>
</body>

阻止事件冒泡
event.cancelBubble = true; //IE
event.stopPropagation( ); //DOM

window.onload = function() {
            var box = document.getElementById('box');
            var btn = document.getElementById('btn');

            box.onclick = function(ev) {
                // 事件处理函数的参数第一个参数 是事件对象
                // 依赖注入 自动传入事件对象
                // 在标准浏览器下 ev 就是事件对象
                // 在ie浏览器下 事件对象 是event  event属于window
                ev = ev || event; //  ie 兼容写法
                alert(1);
                // ev.stopPropagation(); // 标准浏览器 阻止事件冒泡

                if (ev.stopPropagation) {
                    ev.stopPropagation(); // 标准浏览器阻止冒泡
                } else {
                    ev.cancelBubble = true; // ie浏览器阻止冒泡
                }
            }

            btn.onclick = function() {
                alert(2);
            }

            document.body.onclick = function() {
                alert(3);
            }
        }

事件委托 事件委派
通过事件冒泡的特性将事件处理函数添给 父级或祖先元素
使用事件冒泡的好处
1. 减少事件的绑定次数 优化性能
2. 可以给未来元素添加事件

window.onload = function() {
            var btns = document.querySelectorAll('#box>button');
            var box = document.querySelector('#box');

            // btns[0].onclick = function() {
            //     alert(1);
            // }
            // btns[1].onclick = function() {
            //     alert(2);
            // }
            // btns[2].onclick = function() {
            //     alert(3);
            // }

            // 事件委托 事件委派
            // 通过事件冒泡的特性将事件处理函数添给 父级或祖先元素
            // event 事件对象
            // event.target  事件目标对象  标准DOM属性
            // event.srcElement  事件目标对象  IE属性 被大多数浏览器所支持


            // 使用事件冒泡的好处
            // 1. 减少事件的绑定次数  优化性能
            // 2. 可以给未来元素添加事件


            addEvent(box, 'click', function(ev) {
                // ev = ev || event;
                // var target = ev.target || ev.srcElement;

                switch (ev.target.className) {
                    case 'btn1':
                        alert(1);
                        break;
                    case 'btn2':
                        alert(2);
                        break;
                    case 'btn3':
                        alert(3);
                        break;
                }
            });

        }
window.onload = function() {
            var box = document.querySelector('#box');
            // var button = document.querySelectorAll('button');
            // button.forEach(function(elm) {
            //     elm.addEventListener('click', function() {
            //         // console.log(1);
            //         // box.innerHTML +='<button>按钮</button>'; // 赋值以后 元素是全新的
            //         var btn = document.createElement('button');
            //         btn.innerHTML = '按钮';
            //         box.appendChild(btn);
            //     });
            // })


            // 使用事件委托 给未来元素(使用JS添加的元素)添加事件
            box.addEventListener('click', function(ev) {
                if (ev.target.nodeName == 'BUTTON') {
                    box.innerHTML += '<button>按钮</button>';
                }
            });
        }

例子:给表格添加一行数据

 // table 对象
        // 每一个table标签都是一个table对象
        window.onload = function() {
            var table = document.querySelector('table');
            var btn = document.querySelector('button');
            // table.rows 返回表格中所有的行的集合  类数组对象
            // console.log(table.rows);
            // insertRow 创建了一个行 tr
            //           将tr插入到指定索引

            var index = 3;

            btn.onclick = function() {
                var tr = table.insertRow(table.rows.length); // 返回新创建的行

                // tr.cells 返回当前行 所有单元格的集合   类数组对象

                // insertCell 用于在行中添加单元格
                var td1 = tr.insertCell(0);
                td1.innerHTML = index < 10 ? '0' + index : index;
                var td2 = tr.insertCell(1);
                td2.innerHTML = '小汪';
                var td3 = tr.insertCell(2);
                td3.innerHTML = '35';
                var td4 = tr.insertCell(3);
                td4.innerHTML = '男';
                var td5 = tr.insertCell(4);
                td5.innerHTML = '<input type="button" value="删除">';
                index++;

                // 事件添加
                // var oBtn = document.querySelectorAll('input[type="button"]');
                // oBtn.forEach(function(elm) {
                //     elm.onclick = function() {
                //         // 通过按钮父级找到td 再找父级tr 获得tr在表格中的索引 
                //         var i = this.parentNode.parentNode.rowIndex;
                //         table.deleteRow(i);
                //     }
                // });
            }

            // 减少事件绑定次数  优化性能
            // 给未来元素添加事件
            table.addEventListener('click', function(ev) {
                if (ev.target.nodeName === 'INPUT') {
                    table.deleteRow(ev.target.parentNode.parentNode.rowIndex);
                }
            });
        }
<div class="container">
        <button class="btn btn-success btn-block">添加一行数据</button>
    </div>
    <div class="container">
        <table class="table table-bordered table-hover text-center">
            <tr>
                <td>编号</td>
                <td>姓名</td>
                <td>年龄</td>
                <td>性别</td>
                <td>more</td>
            </tr>
            <tr>
                <td>01</td>
                <td>张三</td>
                <td>20</td>
                <td>男</td>
                <td><input type="button" value="删除"></td>
            </tr>
            <tr>
                <td>02</td>
                <td>李四</td>
                <td>25</td>
                <td>男</td>
                <td><input type="button" value="删除"></td>
            </tr>

        </table>
    </div>

事件目标

this在事件中指向绑定的元素 谁调用指向谁
target指向事件触发的目标元素

var box = document.querySelector('.box');
        box.addEventListener('click', function(ev) {
            console.log(this); // 谁调用指向谁
            console.log(ev.target); // 事件目标对象

            // this在事件中指向绑定的元素

            // target指向事件触发的目标元素

            console.log(this === ev.target);
        });

event对象

• 任何事件触发后将会产生一个event对象
• event对象记录事件发生时的鼠标位置、键盘按键状态和触发对象
等信息,事件对象的常用属性:
type:事件类型
srcElement(IE)、target:事件源对象
clientX、offsetX、pageX、screenX:事件发生的X坐标
clientY、offsetY、pageY、screenY:事件发生的y坐标

所有的事件触发 都会生成一个event对象 用于纪录事件信息
event.tyep 事件类型
event.target 事件目标 ie下 event.srcElement
event.button 返回按钮编号

    鼠标坐标信息
    event.clientX  //根据浏览器可视区域左上角0,0开始计算
    event.clientY
    event.pageX    // 根据页面左上角0,0点开始计算
    event.pageY
    event.layerX   // 同上 兼容FF
    event.layerY
    event.screenX  // 根据屏幕左上角0,0开始计算
    event.screentY
    event.offsetX  // 根据元素左上角0,0开始计算
    event.offsetY
    
    contextmenu 是右键事件

元素拖动

window.onload = function() {
            // 元素拖拽
            // 改变元素位置 定位

            // 1. 鼠标按下   被移动的元素上 
            // 2. 鼠标移动   页面
            // 3. 鼠标弹起   页面

            var box = document.querySelector('.box');
            box.onmousedown = function(ev) {
                var offsetX = ev.offsetX,
                    offsetY = ev.offsetY;

                document.onmousemove = function(ev) {
                    var pageX = ev.pageX,
                        pageY = ev.pageY,
                        // 计算x,y定位的值
                        x = pageX - offsetX,
                        y = pageY - offsetY;

                    // 设置定位置
                    box.style.top = y + 'px';
                    box.style.left = x + 'px';
                }
                document.onmouseup = function() {
                    document.onmousemove = null; // 移除事件
                }
            }
        }

边界管理

window.onload = function() {
            // 元素拖拽
            // 改变元素位置 定位

            // 1. 鼠标按下   被移动的元素上 
            // 2. 鼠标移动   页面
            // 3. 鼠标弹起   页面

            var box = document.querySelector('.box');
            box.onmousedown = function(ev) {
                var offsetX = ev.offsetX,
                    offsetY = ev.offsetY;

                document.onmousemove = function(ev) {
                    var pageX = ev.pageX,
                        pageY = ev.pageY,
                        // 计算x,y定位的值
                        x = pageX - offsetX,
                        y = pageY - offsetY;

                    // 左右边界
                    if (x < 0) {
                        x = 0;
                    } else if (x > innerWidth - box.offsetWidth) {
                        x = innerWidth - box.offsetWidth;
                    }

                    // 上下边界
                    if (y < 0) {
                        y = 0;
                    } else if (y > innerHeight - box.offsetHeight) {
                        y = innerHeight - box.offsetHeight;
                    }

                    // 设置定位置
                    box.style.top = y + 'px';
                    box.style.left = x + 'px';
                }
                document.onmouseup = function() {
                    document.onmousemove = null; // 移除事件
                }
            }
        }

轨迹回放

window.onload = function() {
            // 元素拖拽
            // 改变元素位置 定位

            // 1. 鼠标按下   被移动的元素上 
            // 2. 鼠标移动   页面
            // 3. 鼠标弹起   页面

            var map = []; // 存放运动轨迹
            var timer = null; // 保存计时器id

            var box = document.querySelector('.box');
            box.onmousedown = function(ev) {
                var offsetX = ev.offsetX,
                    offsetY = ev.offsetY;

                map.push({
                    x: 0,
                    y: 0
                });

                document.onmousemove = function(ev) {
                    var pageX = ev.pageX,
                        pageY = ev.pageY,
                        // 计算x,y定位的值
                        x = pageX - offsetX,
                        y = pageY - offsetY;

                    // 左右边界
                    if (x < 0) {
                        x = 0;
                    } else if (x > innerWidth - box.offsetWidth) {
                        x = innerWidth - box.offsetWidth;
                    }

                    // 上下边界
                    if (y < 0) {
                        y = 0;
                    } else if (y > innerHeight - box.offsetHeight) {
                        y = innerHeight - box.offsetHeight;
                    }

                    // 添加span 看见轨迹
                    // 轨迹回放 应该将所有的轨迹纪录下来
                    // var span = document.createElement('span');
                    // span.style.top = y + 'px';
                    // span.style.left = x + 'px';
                    // document.body.appendChild(span);
                    map.push({
                        x: x,
                        y: y
                    });

                    // 设置定位置
                    box.style.top = y + 'px';
                    box.style.left = x + 'px';
                }
                document.onmouseup = function() {
                    document.onmousemove = null; // 移除事件
                    timer = setInterval(function() {
                        if (map.length === 0) { //数组内没有数据了 就关闭计时器
                            clearInterval(timer);
                            return; // 终止函数执行
                        }

                        var last = map.pop(); // 删除并返回数组的最后一个元素
                        box.style.top = last.y + 'px';
                        box.style.left = last.x + 'px';
                    }, 20);
                }
            }
        }

鼠标右键事件

// contextmenu 右键事件
        document.addEventListener('contextmenu', function(ev) {
            // 在页面点击鼠标右键会自动弹出浏览器的右键菜单
            // 右键事件的默认行为
            // 事件默认行为 
            // 阻止事件默认行为
            console.log(ev);
            // ev.returnValue = false; // IE浏览器 阻止默认行为
            // ev.preventDefault(); // 标准浏览器
            // return false; // 不推荐使用
        });

默认行为

阻止事件的默认行为
• 事件的默认的行为:如sub瀀it按钮默认就可以提交表单、i瀁瀃ut只
要键盘一按下默认就会把内容显示在输入框中…
• 可以使用下述方法阻止事件的默认行为:
• event.returnValue = false; //IE retrun false;(放在最后)
• event.preventDefault( ); //DOM

var baidu = document.querySelector('#baidu');
        baidu.addEventListener('click', function(ev) {
            // 跳转页面是a元素的默认行为
            alert('a标签被点击了');
            ev.preventDefault();
            // return false;
        })

HTML5就绪事件

window.onload = function() {
            // 当页面资源加载完毕后执行
            // 只能有一个

            console.log(1);
        }


        // HTML5 就绪事件
        document.addEventListener('DOMContentLoaded', function() {
            // DOM Content Loaded
            // 当DOM结构加载完毕
            // 速度快 比window.onload 要快
            console.log(2);
            var btn = document.querySelector('button');
            console.log(btn);
        });

        document.addEventListener('DOMContentLoaded', function() {
            console.log(3);
        })

鼠标中键滚轮事件

有兼容问题
chrome/ie mousewheel ev.whellDelta 用于判断滚轮方向
Fire Fox DOMMouseScroll ev.detail 用于判断滚轮方向

// document.addEventListener('mousewheel', function(ev) {
        //     // ev.whellDelta 用于判断滚轮方向
        //     // 如果大于0 向上
        //     // 如果小于0 向下
        //     // console.log(ev);
        //     console.log(ev.wheelDelta > 0 ? '向上' : '向下');
        // });

        // document.addEventListener('DOMMouseScroll', function(ev) {
        //     // ev.detail 用于判断滚轮方向
        //     // 如果大于0 向下
        //     // 如果小于0 向上
        //     console.log(ev.detail > 0 ? '向下' : '向上');
        // });
function mouseScroll(ev) {
            ev = ev || event;
            var flag = true; // 向上
            if (ev.wheelDelta) {
                flag = ev.wheelDelta > 0 ? true : false;
            } else {
                flag = ev.detail < 0 ? true : false;
            }
            console.log(flag);
        }

        addEvent(document, 'mousewheel', mouseScroll);
        addEvent(document, 'DOMMouseScroll', mouseScroll);

模拟滚动条

* {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        .box {
            width: 300px;
            height: 400px;
            border: 1px solid black;
            float: left;
            position: relative;
            overflow: hidden;
        }
        
        .scroll {
            float: left;
            width: 20px;
            height: 400px;
            border: 1px solid black;
            margin-left: 5px;
            position: relative;
        }
        
        .movebox {
            width: 18px;
            height: 30px;
            background-color: red;
            position: absolute;
        }
        
        .box>p {
            position: absolute;
            user-select: none;
        }
window.onload = function() {
            var box = $('.box')[0];
            var p = $('.box>p')[0];
            var scroll = $('.scroll')[0];
            var movebox = $('.movebox')[0];

            addEvent(box, 'mousewheel', mouseScroll);
            addEvent(box, 'DOMMouseScroll', mouseScroll);
            addEvent(scroll, 'mousewheel', mouseScroll);
            addEvent(scroll, 'DOMMouseScroll', mouseScroll);


            function mouseScroll(ev) {
                ev = ev || event;
                var flag = true; // 向上
                if (ev.wheelDelta) {
                    flag = ev.wheelDelta > 0 ? true : false;
                } else {
                    flag = ev.detail < 0 ? true : false;
                }

                // 4. 添加滚轮事件 让元素移动
                if (flag) {
                    move(movebox.offsetTop - 20);
                } else {
                    move(movebox.offsetTop + 20);
                }
            }


            // 1. 移动movebox
            movebox.onmousedown = function(ev) {
                ev = ev || event;
                var offsetY = ev.offsetY;

                document.onmousemove = function(ev) {
                    ev = ev || event;

                    var y = ev.pageY - offsetY;

                    move(y);

                    // if (y < 0) {
                    //     y = 0;
                    // } else if (y > scroll.offsetHeight - movebox.offsetHeight - 2) {
                    //     y = scroll.offsetHeight - movebox.offsetHeight - 2;
                    // }

                    // // 2. 计算比例
                    // var ratio = y / (scroll.offsetHeight - movebox.offsetHeight - 2);
                    // // console.log(ratio);


                    // p.style.top = -ratio * (p.offsetHeight - box.offsetHeight + 2) + 'px';

                    // movebox.style.top = y + 'px';
                }

                document.onmouseup = function() {
                    document.onmousemove = null;
                }
            }

            // 3. 将核心移动代码封装成函数
            function move(y) {
                if (y < 0) {
                    y = 0;
                } else if (y > scroll.offsetHeight - movebox.offsetHeight - 2) {
                    y = scroll.offsetHeight - movebox.offsetHeight - 2;
                }

                // 2. 计算比例
                var ratio = y / (scroll.offsetHeight - movebox.offsetHeight - 2);
                // console.log(ratio);


                p.style.top = -ratio * (p.offsetHeight - box.offsetHeight + 2) + 'px';

                movebox.style.top = y + 'px';
            }
        }

兼容封装代码

// 事件绑定
function addEvent(elm, eventType, callback) {
    if (elm.addEventListener) { // 判断浏览器是否支持 addEventListener 函数
        elm.addEventListener(eventType, callback);
    } else if (elm.attachEvent) { // 判断是否支持IE
        elm.attachEvent('on' + eventType, callback);
    }
}

// 移除事件
function removeEvent(elm, eventType, callback) {
    if (elm.removeEventListener) {
        elm.removeEventListener(eventType, callback);
    } else if (elm.detachEvent) {
        elm.detachEvent('on' + eventType, callback);
    }
}

function $(selector) {
    return document.querySelectorAll(selector);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值