Javascript基础
- javascript是什么
是一种运行在客户端浏览器的编程语言,实现人机交互。 - 作用
网页特效
(监听用户的行为并作出反馈)、表单验证
(针对表单数据的合法性进行判断)、数据交互
(获取后端数据,渲染到前端)
注:js是一种边解释边执行的脚本语言;翻译器(解释器)是将编程代码转化成二进制的机器语言的工具
书写位置
- 内部JavaScript
直接写在html文件里,用script标签包住
规范:script标签写在</body>
上面
拓展:alert(‘你好,js’)页面弹出警告对话框
js代码放在html文档底部的原因是:浏览器会按照代码在文件中的顺序加载HTML;如果放在前面加载,有可能因为js中要操作HTML下方的元素还未加载导致出错
- 外部引入js文件
<body>
<script src="a.js"><!--注意:这里插入js代码会被忽略--></script>
</body>
- 内联js使用
<button onclick="alert('你好')">点击</button>
- 任何地方引入都可以,但是必须要写在window.load(){} 里面,资源全部加载完毕时触发的事件
<script>
window.onload = function(){
// 添加javascript代码
// 入口函数
}
</script>
js注释与结束符
单行注释 //
右边这一行的代码会被忽略
多行注释 /* */
包裹在至之间的内容会被忽略
结束符:代码结束的符号,是分号 (;)
,可以写可以不写;约定:为了风格统一,要么都写,要么都不写
js的输入输出语法
语法:人与计算机进行交互的规则约定
输出语法:
document.write('<h1>输出的内容</h1>')
,注意这个输出会导致页面重绘。alert('弹出内容')
,弹出框console.log('控制台打印输出')
输入语法:
prompt('请输入你的名字')
变量
计算机中存储数据的容器,js是弱类型语言会自动推断变量类型。
变量的类型
- string(字符串)用于表示文本数据。在js中,字符串是不可变的,这意味着一旦创建了一个字符串,就不能更改它。如果你尝试更改一个字符串,实际上会创建一个新的字符串。
- number(数字) 用于表示数字,包括整数和浮点数。
- boolean(布尔)用于表示真或假。
- null(空值)表示没有值或没有对象。它是一个特殊的值,表示变量没有值。
- undefined(未定义)表示变量未定义,即已声明未赋值。
- symbol(符号,这是一种新的基本数据类型,JavaScript ES6 中引入的)Symbol是一个唯一的标识符,它可以用于表示对象的一个唯一属性。
- object(对象)Symbol是一个唯一的标识符,它可以用于表示对象的一个唯一属性。
- array(数组)
- function(函数)
//声明了一个变量,同时保存18这个数据
let age = 18
//修改变量的值为19
age = 19
//注意:如果这里是let age = 20会报错
//var可以声明多个同名变量,let不行
NaN代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果
console.log('老师'-2) //NaN
NaN是粘性的。任何对NaN的操作都会返回NaN , console.log(NaN + 2) //NaN
注意:
null ==null //true
null,undefined,NaN instanceof object //false
undefined===undefined //true
null == undefined //true
null === undefined //false
NaN == NaN //false
isNaN() 函数判断是否是非数字
null+1=2
undefined+1=NaN
字符串,使用单引号、双引号、反引号包裹的数据就是字符串;
字符串的拼接使用+号拼接,以及使用反引号拼接 我的年纪${age}
let和var的区别
let和var都可以声明变量,在js旧的版本时用var,es6中新提出了let。let是为了解决var的一些问题。
var声明:
- 可以先使用在声明(变量提升,不合理)
- var可以重复声明变量(不合理)
- var是全局变量,没有块级作用域
作用域: - var 声明的变量是函数作用域,在函数内部声明的变量在整个函数内都是可见的。
- let 声明的变量是块级作用域,在 {} 内声明的变量只在该块中可见。
function example() {
if (true) {
var x = 1; // 函数作用域
let y = 2; // 块级作用域
}
console.log(x); // 可见
console.log(y); // 不可见,引发错误
}
变量提升:
- 使用 var 声明的变量存在变量提升,即在代码执行前会被提升到函数或全局作用域的顶部。这意味着可以在声明之前访问变量。
推荐使用 let 而不是 var,因为 let 提供了块级作用域,减少了变量提升的问题,并且在重复声明时会产生错误,有助于减少潜在的错误和提高代码的可读性。
使用const修饰的变量是常量,不可修改
数据类型转化
使用表单、prompt获取过来的数据默认是字符串类型的,如果是数字就不能进行数字的基本操作,需要转换数据类型。
- 转换为字符串类型
- toString()方法
- String()强制类型转换
- +号转换
let n1 = 10;
n1.toString(); //将n1转换为string
String(n1); //强制转换
n1+''; //字符串拼接,隐式转换
可以使用typeof()函数判断数据类型
- 转化为数字型
- parseInt(string)函数
- parseFloat(string)函数
- Number(string) 强制转化
- ±*/隐式转化
let a='14'
parseInt(a); //转换为整数型
parseInt(3.4); //结果为3
parseInt('120px'); //结果为120
'12'-0; //隐式转换
- 布尔类型的转化
- Boolean()强制转换
代表空、否定的值会被转换为false,如"、0、NaN、null、undefined
其余值都会被转换为true
console.log(Boolean(''));//false
console.log(Boolean(0));//false
console.log(Boolean(NaN));//false
console.log(Boolean(null));//false
console.log(Boolean(undefined));//false
console.1og(Boolean('小白'));//true
console.log(Boolean(12));//true
数组的基本使用
JavaScript中的数组(Array)是一种特殊的对象,用于存储一系列有序的元素。数组可以通过索引(从0开始)访问其元素,并且可以包含任何数据类型,包括其他数组(作为嵌套元素)。
数组的声明:let arr = []
比如: let names = [ ‘a’, ‘b’, ‘c’ ]
以下是一些关于JavaScript数组的基本操作:
创建数组
- 使用字面量方式创建数组:
var array = [];
- 使用Array构造函数创建数组:
var array = new Array();
- 指定数组长度创建数组:
var array = new Array(length);
- 添加元素
push()方法:将一个或多个元素添加到数组的末尾,并返回新的长度:
array.push(element1, ..., elementN);
unshift()方法:将一个或多个元素添加到数组的开头,并返回新的长度:
array.unshift(element1, ..., elementN);
删除元素
pop()方法:删除并返回数组的最后一个元素:
var lastElement = array.pop();
shift()方法:删除并返回数组的第一个元素:
var firstElement = array.shift();
访问元素
[]:通过索引访问数组元素。例如:var element = array[index]; index 属于[0,arr.length-1]
length属性:获取数组的长度。例如:var length = array.length;
数组的高级使用
- 数组的遍历
let arr = [1,2,3,4,'你好']
// 方法一:for循环
for(let i=0;i<arr.length;i++){
console.log(arr[i])
}
// 方法二:使用forEach函数
arr.forEach(item =>{
console.log(item) // item表示数组中每一个元素
})
//该方法是数组对象的一个内置方法,它会对数组中的每个元素执行一次提供的函数
//方法三:for...of循环:该循环是ES6新引入的,它用来遍历可迭代对象(如数组,字符串等)。
for (let element of arr) {
console.log(element);
}
使用for...of遍历字符串:与数组类似,for...of也可以用于遍历字符串。
let str = 'Hello World';
for (let character of str) {
console.log(character);
}
- splice():更改数组的内容,通过删除或替换现有元素或添加新元素。
-
array.splice(index, deleteCount, item1, …, itemX)
参数说明:- index:必需。一个整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
- deleteCount:必需。要删除的项目数量。如果设置为 0,则不会删除项目,而是添加新项目。
- item1, …, itemX:可选。向数组添加的新项目。
-
let arr = [1, 2, 3, 4, 5];
arr.splice(2, 1, 'a'); //表示在arr[2]后面删除1个元素并添加'a'数据
console.log(arr); // [1, 2, 'a', 4, 5]
- slice():返回一个新的数组对象,包含从开始到结束(不包括结束)选择的数组的一部分浅拷贝。原始数组不会被改变。
let arr = [1, 2, 3, 4, 5];
console.log(arr.slice(2)); // [3, 4, 5]
- map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
let arr = [1, 2, 3, 4, 5];
let newArr = arr.map(function(element) {
return element * 2;
});
console.log(newArr); // [2, 4, 6, 8, 10]
- filter():创建一个新数组,过滤出符合条件的所有元素。
let arr = [1, 2, 3, 4, 5];
let newArr = arr.filter(function(element) {
return element % 2 === 0;
});
console.log(newArr); // [2, 4]
- reduce():接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
let arr = [1, 2, 3, 4, 5];
let sum = arr.reduce(function(accumulator, currentValue) {
return accumulator + currentValue;
}, 0);
console.log(sum); // 15
- find():返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined。
let arr = [1, 2, 3, 4, 5];
console.log(arr.find(function(element) {
return element > 3;
})); // 3
- findIndex():返回数组中满足提供的测试函数的第一个元素的索引值。否则返回-1。
let arr = [1, 2, 3, 4, 5];
console.log(arr.findIndex(function(element) {
return element > 3;
})); // 3
- includes():检测数组中是否包含一个指定的项。返回true或false。
let arr = [1, 2, 3, 4, 5];
console.log(arr.includes(2)); // true
console.log(arr.includes(6)); // false
- join():将数组(或一个类数组对象)的所有元素连接到一个字符串中。元素通过指定的分隔符进行分隔。
let arr = [1, 2, 3, 4, 5];
console.log(arr.join('-')); // '1-2-3-4-5'
- sort():对数组的元素进行排序,然后返回数组。
let arr = [3, 1, 4, 1, 5, 9];
arr.sort();
console.log(arr); // [1, 1, 3, 4, 5, 9]
//如果需要逆序排序:
arr.sort(function(a,b){
return b-a;
})
- reverse(): 对数组元素翻转
let arr = [9, 5, 4, 3, 1, 1]
arr.reverse()
// [1, 1, 3, 4, 5, 9]
函数
函数:封装的一组可被重复使用的代码块。
定义函数的基本用法:
function functionName(parameters) {
// 方法体
// return 表达式
}
其中:
- function是关键字,用于声明函数。
- functionName是函数的名称。函数名称应该以字母或下划线开头,并遵循驼峰命名法。
- parameters是传递给函数的参数列表。参数之间用逗号分隔。当没有参数时,括号可以省略。
- return 返回值,如果不需要返回值则可以省略。
注意:函数必须先声明,才能调用
//创建一个函数:输入n,实现1+2+3+...+n功能
function sum(n){
var s=0;
for(let i=1;i<=n;i++){
s += i;
}
return s;
}
sum(100); //返回5050
匿名函数
是一种没有名字的函数,可以作为表达式的一部分,例如作为回调函数或者作为参数传递给其他函数。也可以赋值给一个变量或者作为属性值。
箭头函数
是ES6中新增的一种定义函数的格式,用于简化定义函数的代码。箭头函数没有自己的this上下文,而是继承了包含它的函数的this上下文。箭头函数不能用作构造函数,也就是说不能使用new操作符。
(parameter) => { 方法体 }
// 如果方法体只有一行可以省略 {}括号
以下是匿名函数和箭头函数的详细使用:
匿名函数:
定义一个匿名函数并立即执行:
(function() {
console.log("这是一个匿名函数");
})();
将匿名函数赋值给一个变量:
var func = function(param) {
console.log(param);
};
func('Hello World'); // 输出 "Hello World"
将匿名函数作为属性值:
var obj = {
func: function(param) {
console.log(param);
}
};
obj.func('Hello World'); // 输出 "Hello World"
箭头函数:
定义一个箭头函数并立即执行:
(() => {
console.log("这是一个箭头函数");
})();
将箭头函数赋值给一个变量:
var func = (param) => { console.log(param); };
func('Hello World'); // 输出 "Hello World"
将箭头函数作为属性值:
var obj = {
func: (param) => { console.log(param); }
};
obj.func('Hello World'); // 输出 "Hello World"
作用域
通常来说,一段代码中的变量不总是有效可用的,这个变量的可用性的代码范围就是的作用域。
-
全局作用域:
- 全局作用域是指在代码的任何位置都可以访问的标识符。
- 使用var关键字声明的变量会自动成为全局变量。
-
局部作用域:
- 局部作用域是指在代码中特定的区域或函数内部可访问的标识符。
- 在函数内部声明的变量只能在函数内部使用,无法在函数外部访问。
-
块级作用域
- 是指在代码块(由一对花括号{}包裹的代码)中定义的变量只在该代码块内部可见和访问,超出该代码块就无法访问。常见的代码块包括if语句、for循环和函数。
function example() {
if (true) {
let x = 10; // 块级作用域中的变量
console.log(x); // 输出:10
}
console.log(x); // 抛出引用错误
}
example();
作用域链本质上是底层的变量查找机制。
- 在函数被执行时,会优先查找当前函数作用域中的变量
- 如果当前作用域查找不到则会依次查找父级作用域直到全局作用域
- 这种嵌套关系的作用域串联就形成了作用域链
对象
是对一类事物的抽象,定义了事物的属性和方法。
- 对象声明方式
let 对象名={} ; let 对象名=new Object()
var person = {
name: "Jian",
age: 30,
city: "Shanghai",
seyhello: function(){
console.log(`你好,我是${this.name}`)
}
}
在这个例子中,person是一个对象,它有三个属性:name、age和city。这些属性对应于特定的值。
对象的访问和属性的访问基本类似,可以使用点符号或者方括号来访问对象的属性。例如:
console.log(person.name); // 输出 "Jian"
console.log(person['age']); // 输出 30
其中this是一个特殊的关键字,它表示当前执行代码的上下文对象,比如上面的this.name中的this表示person对象。
删除对象属性:delete 对象名.属性名
添加对象属性:对象名.新的属性名=值
遍历对象:使用for in循环
var person = {
name: "Jian",
age: 30,
city: "Shanghai",
seyhello: function(){
console.log(`你好,我是${this.name}`)
}
}
for(let item in person){ // item是person中的key
console.log(person[item])
// 注意:这里console.log(person.item)会报错
//因为item默认是string类型,比如person.'name' 没有这个顺序ing
}
自定义创建对象
通过构造函数创建对象,构造函数是一种特殊的函数,主要用来初始化对象; 可以通过构造函数来创建多个类似的对象
function Person(name,age,gender){ //构造函数
this.name = name
this.age = age
this.gender = gender
}
let jian = new Person('jian',25,'男')
let liu = new Person('liu',22, '女')
原型对象
在JavaScript中,每个对象的构造函数都有一个prototype属性,指向另一个对象,这个对象就是原型对象
当试图访问一个对象的某个属性时,如果该对象本身不具有该属性,那么JavaScript就会在该对象的原型上查找该属性。
function Person(name,age,gender){ //构造函数
this.name = name
this.age = age
this.gender = gender
this.seyHello = function(){
console.log(`你好,我是: ${this.name}`)
}
}
-----------
let p1 = new Person('jian',25,'男')
let p2 = new Person('liu',22,'女')
多次创建Person对象,seyHello方法就会创建多次,可以使用一个公用的函数来替代多个seyHello,
节省内存,这个公用的函数就可以提升为原型函数
构造函数通过原型分配的函数是所有对象所共享的。
- 这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存
- 可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。
- 构造函数和原型对象中的this都指向实例化的对象。
原型对象挂载函数:
function Person(name,age,gender){ //构造函数
this.name = name
this.age = age
this.gender = gender
// this.seyHello = function(){
// console.log(`你好,我是: ${this.name}`)
// }
}
Person.prototype.seyHello = function(){ //共享函数,节约内存
console.log(`你好,我的名字是:${this.name}`)
}
公共属性写在构造函数里面;公共方法写在原型对象上面
demo: 在Array对象上添加求最大值的方法
let arr= [1,3,2,4]
Array.prototype.max = function(){
return Math.max(...this) //此时this指向arr
}
console.log(arr.max())
constructor属性
该属性指向该原型对象的构造函数
function Star(name,sex){
this.name = name
this.sex = sex
}
console.log(Star.prototype.constructor === Star)
// 结果为true
作用:在对原型对象赋值时会被覆盖,导致找不到原型所属的对象,这时可以用constructor指回原来对象
function Star(name,sex){ //构造函数
this.name = name
this.sex = sex
Star.prototype = {
constructor: Star, //如果没有这句,会导致prototype被覆盖
sing: function(){
console.log('唱歌')
}
dance: function(){
console.log('跳舞')
}
}
}
对象原型
“对象里面的原型”,每个实例对象都有一个属性__proto__ 指向构造函数的prototype原型对象,对象可以使用构造函数中的原型对象的属性和方法就是因为对象有__proto__属性的存在。
(new Star('a',23,'男')).__proto__ === Star.prototype
// true
原型继承
将同一类事物具有的共同特征抽象成一个类,每一个具体的类可以通过继承的方式创建,这样就可以不用为各个类都去定义共同的属性和方法,实现代码的复用和维护。在js中通过原型对象来实现继承:
// 定义一个父类
function Person(name) {
this.name = name;
}
// 在父类原型上添加方法
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name);
};
// 定义一个子类
function Student(name, grade) {
// 调用父类的构造函数
Person.call(this, name);
this.grade = grade;
}
// 将子类的原型指向父类的实例
Student.prototype = Object.create(Person.prototype);
// 修复构造函数引用
Student.prototype.constructor = Student;
// 创建子类的实例
var john = new Student("John", 12);
// 调用父类的方法
john.sayHello(); // 输出: "Hello, my name is John"
原型链
基于原型对象的继承使得不同的构造函数的原型对象关联在一起形成链状结构,这就是原型链
原型链的查找规则
- 当访问一个对象的属性时,首先查找这个对象自身有没有该属性。
- 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
- 如果还没有就查找原型对象的原型(Object的原型对象)
- 依次类推,直到object为止(null)
- 可以使用
instanceof
运算符检测构造函数的prototype属性是否出现在某个对象的原型链上
注:null instanceof Object // false ; 因为null是一个值,表示对象为空,instanceof 是判断对象是否在某个原型链上
内置对象
- Math类对象
- random 生成0-1之间的随机数
- ceil 向上取整
- floor 向上取整
- min , max 取最小,最大值
- sqrt 取算术平方根
- pow(a,b) 取a的b次方的值
- round 四舍五入的方法
生成[m,n]之间的随机数:Math.floor(Math.random()*(max-min+1)+min)
- String:String对象用于处理字符串。它提供了许多方法来操作字符串,如charAt()、concat()、indexOf()、lastIndexOf()、match()、replace()、slice()、split()、substr()、substring()等。
var str = new String("Hello World");
console.log(str); // 输出 "Hello World"
console.log(typeof str); // 输出 "string"
- Array:Array对象用于处理数组。它提供了许多方法来操作数组元素,如push()、pop()、shift()、unshift()、splice()、slice()、join()等。此外,Array还包含了一系列静态方法,如indexOf()、lastIndexOf()等。
var arr = new Array("apple", "banana", "orange");
console.log(arr); // 输出 ["apple", "banana", "orange"]
- Date:Date对象用于处理日期和时间。它可以用于获取当前日期和时间,或者创建特定日期和时间的对象。Date对象提供了一系列方法来获取日期的各个部分,如getFullYear()、getMonth()、getDate()、getHours()、getMinutes()、getSeconds()、获取当前的日期时间toLocalString()等。
var date = new Date(); // 创建的是当前时间的日期对象
console.log(date); // 输出当前日期和时间
通过let date2=new Date('2023-08-01 12:00:00')
构造函数创建指定日期的date对象,可以用来做倒计时/时间的计算等等
时间戳
是一份时间凭证,用于创建事物在某一时刻的数字签名,证明文件在特定时间已经存在,并且未被修改和篡改。
计算方式:从1970年0时0分0秒到现在时间经过的毫秒数
它的提出可以很方便的对时间进行基本的操作。
获取时间戳的方式:(new Date()).getTime()
或者+new Date() (隐式转换)
还有Date.now() (这个时间是当前时间的时间戳)
通过时间戳转换相应的日期时间格式 let date = new Date(时间戳)
DOM
document object model,文档对象模型,利用js方式操作HTML内容。把网页内容当作对象来处理
BOM:浏览器对象模型:利用js操作浏览器(alert、prompt等)
DOM树:将HTML文档以树状结构直观的表示出来,直观体现了标签与标签的关系
DOM对象:浏览器根据HTML标签生成的js对象(document对象)
- 所有的标签属性都可以在这个对象上面找到
- 修改这个对象的属性会自动映射到标签上
DOM操作
- 通过css选择器获取dom元素
// 选择匹配的第一个元素
document.querySelector('css选择器')
// 选择匹配的所有元素
document.querySelectorAll('css选择器')
- 通过id/class获取元素
document.getElementById('xxx')
document.getElementsByClassName('xxx') //这个的结果是数组
- 根据标签获取一类元素
document.getElementsByTagName('div')
操作元素内容
根据dom操作修改HTML元素的文本内容
- 元素对象.innerHTML=xxx
- 元素对象.innerText=xxx
// 实时更新时间demo
<div id="showTime"></div>
<script type="application/javascript">
let div = document.getElementById("showTime")
console.log(div.innerText) //获取元素的内容
setInterval(()=>{
div.innerText=(new Date()).toLocaleString()
},1000)
</script>
innerText和innerHTML的区别:
innerText 纯文本信息,不解析标签;innerHTML解析标签;没有特殊 要求时一般常用innerHTML获取/修改元素内容
操作元素属性
操作元素常用样式
通过js设置/修改标签元素属性,比如img的src,a的href等等
//获取元素
const pic=document.querySelector('img')
//操作元素
pic.src='./imgages/pic1.png'
pic.title='这是图片'
操作元素css样式属性
通过js设置/修改标签元素css样式,比如轮播图
对象.style.样式属性=值
const box = document.querySelector('.box')
//修改样式
box.style.width='200px'
//修改背景颜色
box.style.background-color='pink' //这里会报错,-会被当成减号
box.style.backgroundColor='pink'
或者
box.style['background-color']='pink'
通过class类名修改样式属性:先定义好class 属性样式,当经过某个事件以后,用js对元素添加className,将定义好的class样式绑定到元素上。
.box{
width: 200px;
height: 200px;
background-color: pink;
}
<div></div>
<script>
const div = document.querySelector('div')
//添加类名
div.className = 'box'
</script>
如果这个元素此前已经有了class会被覆盖;为了解决这个问题,可以通过classList方式
追加或删除类名。
元素.classList.add('类名') 添加一个类名
元素.classList.remove('类名') 删除一个类名
元素.classList.toggle('类名') 切换一个类名
操作表单元素
在JavaScript中,你可以使用不同的方法来获取不同类型的输入框的值。以下是一些基本的示例:
- 文本输入框(text input):
var textValue = document.getElementById("textBoxId").value;
- 密码输入框(password input):
var passwordValue = document.getElementById("passwordBoxId").value;
- 单选输入框(radio input):
var radioValue = document.querySelector('input[type="radio"]:checked').value;
- 多选输入框(checkbox input)获取所有选中的值:
var checkboxes = document.querySelectorAll('input[type="checkbox"]:checked');
var values = [];
for (var i = 0; i < checkboxes.length; i++) {
values.push(checkboxes[i].value);
}
console.log(values); // an array of selected values
- disabled属性:用于禁用表单元素
- checked属性:用于单选框和复选框,表示是否默认选中该选项。对于单选框,只能选中一个选项;对于复选框,可以同时选中多个选项。可以通过checked=true转换选中状态
- selected属性:用于选项框(如标签),表示是否默认选中该选项。与checked属性类似,但只适用于选项框。
<form action="">
<input type="text" name="username" id="username" />
<label for="username">用户名</label>
<input type="password" name="ped" id="passwd">
<label for="passwd">密码</label>
<label>
男<input type="radio" name="sex" value="male">
</label>
<label>
女<input type="radio" name="sex" value="female">
</label>
<label>
乒乓球<input type="checkbox" name="hobby" value="乒乓球">
</label>
<label>
下棋<input type="checkbox" name="hobby" value="下棋">
</label>
<label>
电竞<input type="checkbox" name="hobby" value="电竞" onblur="getData()">
</label>
<label for="city">城市</label>
<select id="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="南京">南京</option>
</select>
</form>
</div>
<script>
function getData(){
var username = document.querySelector('input[type="text"]');
console.log(`用户名为:${username.value}`)
var pwd = document.querySelector('input[type="password"]');
console.log(`密码是:${pwd.value}`)
var sex = document.querySelector('input[type="radio"]:checked');
console.log(`性别是:${sex.value}`)
var hobbys = document.querySelectorAll('input[type="checkbox"]:checked');
hobbys.forEach(x =>{
console.log('爱好有:'+x.value)
})
var city = document.getElementById("city");
console.log(`获取地址:${city.options[city.selectedIndex].value}`);
}
</script>
自定义属性
在html5中推出来的专门的data-xxx的自定义属性,通过添加自定义属性,可以在HTML元素中存储和传递额外的信息。在dom对象上一律以dataset对象方式获取
<div data-id="1">1</div>
<div data-id="2">2</div>
<div data-id="3">3</div>
<div data-id="4">4</div>
<div data-id="5">5</div>
<script>
const one = document.querySelectorAll("div")
console.log(one.dataset)
</script>
定时器
在JavaScript中,定时器有两种主要类型:setTimeout和setInterval。
参数都是 回调函数和时间(毫秒)
setTimeout: 这个函数用于在指定的毫秒数后执行一段代码。它返回一个代表定时器的ID,你可以使用这个ID来取消定时器。
例如:
setTimeout(function() {
console.log('这是一个延迟执行的函数!');
}, 2000); // 这个函数将在2秒后执行
setInterval: 这个函数用于每隔指定的毫秒数重复执行一段代码。同样,它也返回一个代表定时器的ID,可以使用这个ID来取消定时器。
例如:
setInterval(function() {
console.log('这是一个每隔1秒执行一次的函数!');
}, 1000); // 这个函数将每隔1秒执行一次
注意,setTimeout和setInterval的第二个参数都是以毫秒为单位的时间。1秒等于1000毫秒。
此外,还可以使用clearTimeout和clearInterval函数来取消定时器。这些函数需要一个定时器的ID作为参数。例如:
var timeoutId = setTimeout(function() {
console.log('这个函数将被取消!');
}, 2000);
clearTimeout(timeoutId); // 取消定时器
事件监听
事件监听是一种机制,允许为特定的HTML元素注册一个或多个事件处理器,以便在元素触发特定事件时执行相应的代码。
- 直接在HTML元素中使用on+事件类型作为事件监听的属性,值是监听的函数名
<button onblur='Function()'>点击</button>
# 点击按钮以后会触发Function()函数执行
- 1
元素对象.addEventListener('事件类型',执行函数)
为元素添加监听事件 - 2 元素对象.on+事件类型=Function(){}
- 区别:第1个添加多个事件会被覆盖,第2个则不会,多个事件按照绑定顺序处理
事件类型
- 鼠标事件:鼠标事件是指与鼠标相关的事件。常见的鼠标事件包括:
click(单击)、dblclick(双击)、mousedown(按下鼠标按钮)、mouseup(释放鼠标按钮)、mousemove(鼠标移动)、mouseover(鼠标进入元素)、mouseout(鼠标离开元素)、mouseenter(鼠标进入元素,不冒泡)、mouseleave(鼠标离开元素,不冒泡)、wheel(鼠标滚轮滚动)
。 - 键盘事件:键盘事件是指与键盘输入相关的事件。常见的键盘事件包括:
keydown(按下键盘按键)、keyup(释放键盘按键)、keypress(键盘按键被按下并释放
)。 - 表单事件:表单事件是指在表单元素上发生的事件, 表单获取光标。常见的表单事件包括:
focus(获取焦点)、blur(失去焦点)、change(元素的值发生变化)、select(文本被选择)、submit(表单提交),input(表单内容的值发生变化时触发事件执行)。
这里面的冒泡指的是在DOM树向上传播的行为:如下所示:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Mouse Enter and Mouse Leave Demo</title>
<style>
#container {
width: 200px;
height: 200px;
border: 1px solid #000;
position: relative;
}
#child {
width: 100px;
height: 100px;
background-color: #f00;
position: absolute;
top: 50px;
left: 50px;
}
</style>
</head>
<body>
<div id="container">
Container
<div id="child">
Child
</div>
</div>
<p id="output"></p>
<script>
window.onload = function() {
var container = document.getElementById('container');
var child = document.getElementById('child');
var output = document.getElementById('output');
// 添加鼠标进入事件处理器
container.addEventListener('mouseover', function() {
output.textContent = '鼠标进入了父容器元素';
});
// 添加鼠标离开事件处理器
container.addEventListener('mouseout', function() {
output.textContent = '鼠标离开了父容器元素';
});
child.addEventListener('mouseover',function (){
output.textContent = '鼠标进入了子容器元素';
})
child.addEventListener('mouseout',function (){
output.textContent = '鼠标离开了子容器元素';
})
};
</script>
</body>
</html>
比如这个代码,当我们进入子元素时,output内容会变成“鼠标进入了子容器元素”,但是mouseover事件具有冒泡特性,会将事件行为向父级元素传播,所以container元素也会触发mouseover事件导致output内容被覆盖为“鼠标进入了父级元素”… 可以使用alert警示框来观看
内容的变化。
键盘事件常用案例
- 获取enter输入事件,监听键盘输入数据,直到输入enter键触发某个事件
输入框对象.addEventListener('keydown',function(event){
if (event.key==='Enter'){
// do something
}
// 第二种, 使用event的keyCode判断是否为13,13是回车键的asccii码
if (event.keyCode === 13){
// do Something
}
})
- 实时监听表单输入数据,一旦数据值发生变换就触发事件执行
<input type='text' id='username' name='username' />
<script>
document.getElementById(username).addEventListener('input',function(event){
console.log(event.target.value) // 获取实时变化的数据
})
</script>
demo: 仿照百度搜索框
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>focus blur事件讲解</title>
<style>
#search{
width: 300px;
}
.result-list{
width: 266px;
list-style-type: none;
border: 1px solid #5e5d5d;
margin-left: 37px;
margin-top: 0;
}
li{
margin-left: -15%;
font-size: 14px;
line-height: 24px;
}
ul > li:hover{
background-color: #cdcdcd;
}
#search:focus #search{
border-style: dotted;
border-radius: 0;
}
</style>
</head>
<body>
<label for="search">搜索</label>
<input type="text" name="search_data" id="search" />
<script>
let data = ['你好','好的','迪迦奥特曼','好的奥特曼']
let input_data = document.querySelector('#search')
input_data.addEventListener('input',function (event) {
let u = document.querySelector('.result-list')
if (u) u.remove() // 删除上一次的ul数据
let search_value = event.target.value.trim()
if (search_value.length > 0 ){
uls = '<ul class="result-list">\n'
isLi = false
data.forEach(item => {
if (item.indexOf(search_value) >= 0){
isLi = true
uls += '<li> '+item+'</li>\n'
}
})
if (isLi){
uls += '</ul>'
input_data.insertAdjacentHTML('afterend',uls)
}
}
})
input_data.addEventListener('blur',function () {
//这里编写代码删除ul元素
document.querySelector('.result-list').remove()
})
</script>
</body>
</html>
demo: 点击关闭广告示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.advertisement{
position: relative;
height: 400px;
width: 400px;
margin: 120px auto;
background-color: #c3eaaa;
text-align: center;
}
.advertisement > strong{
line-height: 400px;
}
.close{
position: absolute;
height: 15px;
width: 10px;
right: 0;top: 12px;
cursor: pointer;
}
.close:hover{
background-color: #e59a36;
}
</style>
</head>
<body>
<script>
setTimeout(function (){
document.querySelector('body').innerHTML = ' <div class="advertisement">\n' +
' <div class="close" οnclick="closeAdvertisement()">x</div>\n' +
' <strong>这是广告</strong></div>'
},4000)
function closeAdvertisement(){
// 关闭广告,这里不应该是删除而是隐藏
document.querySelector('.advertisement').style.display='none'
}
</script>
</body>
</html>
demo: 随机点名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>随机点名demo</title>
<style>
div{
width: 300px;
margin: 100px auto;
border: 2px solid #cecccc;
border-radius: 5px;
text-align: center;
}
</style>
</head>
<body>
<div>
<h2>随机点名</h2>
<p class="name"></p>
<button class="start">开始</button>
<button class="end">结束</button>
<br><br><br>
</div>
<script>
const names = ['张三','里斯','王五','刘德华','jian']
let start = document.querySelector('.start')
start_time = 0
let end = document.querySelector('.end')
start.addEventListener('click',function (){
start.disabled = true
let name = document.querySelector('.name');
start_time = setInterval(function (){
name.innerHTML = names[Math.floor(Math.random()*names.length)]
},50)
})
end.addEventListener('click',function (){
start.disabled = false
clearInterval(start_time)
})
</script>
</body>
</html>
事件对象
- 保存了事件触发的相关信息的对象
- 例如鼠标点击事件时,事件对象就存储了鼠标在那个位置等等
- 可以判断用户按下了哪个键,比如回车键,还可以判断点击了哪个元素,从而作出相应的操作
获取事件对象
- 在绑定事件的回调函数中,第一个参数就是事件对象
事件源.addEventListener('click',function(event){
// event就是事件对象
})
环境对象(上下文对象)
关键字:this
指的是一段代码块中的特殊变量this,它代表当前函数运行时所处的环境
- 每个函数里面都有this环境变量
- 普通函数中this指的是window对象(直接调用普通函数 全写 window.function(),所以函数的this是window)
btn.addEventListener('click',function(){
console.log(this) // 此时this指向bth对象
// 谁调用函数,this就指向谁
})
- 回调函数:把函数A作为参数传递给函数B,则A就是一个回调函数
全选、反选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>全选、反选</title>
</head>
<body>
<form action="#">
<label for="hobby">爱好:</label><br>
<div id="hobby">
<input type="checkbox" id="hobby1" name="hobby" value="下棋">
<label for="hobby1">下棋</label><br>
<input type="checkbox" id="hobby2" name="hobby" value="乒乓球">
<label for="hobby2">乒乓求</label><br>
<input type="checkbox" id="hobby3" name="hobby" value="book">
<label for="hobby3">book</label><br>
<input type="checkbox" id="hobby4" name="hobby" value="watch TV">
<label for="hobby4">watch TV</label>
</div>
<label for="all">全选</label>
<input type="checkbox" name="all" id="all" />
<label for="not_all">反选</label>
<input type="checkbox" name="not_all" id="not_all" />
</form>
<script>
document.getElementById('all').addEventListener('click',function(){
let _this = this // 这个this指代的是全选这个按钮
document.querySelectorAll('input[name="hobby"]').forEach(item =>{
item.checked = _this.checked // 因为箭头函数中不能用this,需要用其他变量存储
})
})
document.querySelectorAll('input[name="hobby"]').forEach(item =>{
let _this = this
item.addEventListener('click',function (){
document.getElementById('all').checked=(document.querySelectorAll('input[name="hobby"]:checked').length === 4)
})
})
document.getElementById('not_all').addEventListener('click',function(){
let _this = this // 这个this指代的是全选这个按钮
document.querySelectorAll('input[name="hobby"]').forEach(item =>{
item.checked = !item.checked // 因为箭头函数中不能用this,需要用其他变量存储
})
})
</script>
</body>
</html>
阻止默认行为
- form表单的提交(事先需要校验)
- a链接的跳转
<form action="http://www.itcast.cn">
<input type=:"submit"value="免费注册">
</form>
<a href="http://ww.baidu.com">百度一下</a>
<script>
const form=document.querySelector('form')
form.addEventListener('submit',function (e){
//阻止默认行为提交
e.preventDefault()
}
const a=document.querySelector('a')
a.addEventListener('click',function (e){
e.preventDefault()
}
</script>
页面加载事件
- 当初始的HTML文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而
无需等待样式表、图像完全加载
- 事件名:DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
// 在这里添加当 DOM 加载完毕后需要执行的 JavaScript 代码
});
元素滚动事件
- 滚动条在滚动的时候持续触发的事件
- 网页需要监测用户把页面滚动到某个区域后做一些处理,比如固定导航栏、比如返回顶部
- 事件名:scroll,监听整个页面滚动
window.addEventListener('scroll',function(){
console.log('我滚了')
})
使用场景:
- 比如让页面滚动一段距离,100px,就让某些元素隐藏/显示;利用scroll来检测滚动的距离
页面滚动事件获取滚动位置
- scrollLeft和scrollTop
利用window获取HTML元素的滚动距离
let scroll_test = document.querySelector('.scroll_test')
window.addEventListener('scroll',function (){
// 如果头部卷过的长度到达50%,就固定整个元素
// html元素获取位置的方式
const distance = document.documentElement.scrollTop
console.log(distance)
if (distance >= 300){
scroll_test.style.position = 'fixed'
}
})
页面尺寸事件
- 会在页面尺寸大小发生变换时触发的事件
事件名:resize
window.addEventListener('resize',function(){
//执行的代码
})
- 监测屏幕宽度
window.addEventListener('resize',function(){
let w=document.documentElement.clientWidth
console.log(w)
})
call 和 apply bind 函数
call 和 apply 函数都是JavaScript中的函数,用以调用其他函数并设置上下文对象(即this变量的值) 以及传递参数。
具体使用:
函数名.call(新的上下文对象,参数1,参数2...)
function seyName(name){
console.log(`你好${name},我的名字是 ${this.name}`)
}
const person={name: 'jian'}
seyName.call(person,'A') //这里会打印 你好A,我是jian
apply和call函数类似,只是传递的参数不一致,apply传递的参数是数组类型
function multiply(a,b){
console.log(`${this.name}计算的结果是 ${a}*${b}=${a*b}`)
}
const person={name:"jian"}
multiply.apply(person,[2,4])
bind() 方法不会调用函数,可以改变函数内部的上下文(this)
const obj = {
age:18
}
function fn(){
console.log(this)
}
// 返回值是个函数,但是这个函数里面的this是更改过的obj
const fun = fn.bind(obj)
BOM
BOM,全称Browser Object Model,是浏览器对象模型。它提供了独立于内容的、与浏览器窗口进行互动的对象结构。BOM由多个对象构成,其中代表浏览器窗口的window对象是BOM的顶层对象,其他对象都是该对象的子对象。
window对象是JavaScript的核心,它具有以下常用属性:
- window.navigator: 包含有关浏览器的信息.
- window.location: 可以用来获取当前文档的URL,也可以用来导航到新的文档.
- window.screen: 提供了关于客户端屏幕的信息.
- window.history: 提供了访问浏览器历史记录的功能.
window对象有以下常用方法:
- window.alert(): 显示带有一段消息和一个确定按钮的警告框.
- window.confirm(): 显示带有一段消息和确定/取消两个按钮的确认框.
- window.prompt(): 显示带有一段消息和输入框的提示框.
- window.setTimeout(): 在指定的毫秒数后执行函数.
- window.setInterval(): 每隔指定的毫秒数执行函数.
- window.clearTimeout(): 清除由setTimeout()函数设置的函数执行.
- window.clearInterval(): 清除由setInterval()函数设置的函数执行.
location对象
是一个window的对象,他提供了关于当前文档的url信息,并允许我们在浏览器中导航到新的页面。
属性:
- location.href 这是当前文档的完整url,更爱此属性时会导航到新的页面。
- location.protocol 当前url的协议(http https)
- host 、port 主机名和端口
方法: - location.assign(url) 加载新的文档
- location.reload(true/false) 重新加载当前文档,参数表示是否强制加载文档,即使它已经在浏览器的缓存中
在大多数情况下,使用 location.href 来导航到新的页面或重新加载当前页面。
navigator对象
该对象记录了浏览器自生相关的信息
- 常用属性和方法
- 通过userAgent检测浏览器的版本及平台
//检测userAgent(览器信息)
判断是否为移动端,如果是则跳转到移动端
!function (){
const userAgent= navigator.userAgent
//验证是否为Android或Phone
const android= userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
const iphone= userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
//如果是Android.或Phone,则跳转至移动站点
if (android || iphone){
location.href= 'http://m.itcast.cn'
}
}()
这个!的意思是将!function(){}() 中的 function(){}看成一个整体来执行
你也可以这样:(function(){})()来执行
history对象
history对象的方法 | 作用 |
---|---|
back() | 可以后退到上一个页面 |
forward() | 前进功能 |
go(参数) | 前进后退功能,前进2个就是go(2),后退3个就是go(-3) |
<button>前进</button>
<button>后退</button>
<script>
const back = document.querySelector('button:first-child')
const forward = back.nextElementSibling
back.onclick = function(){
history.back()
}
forward.onclick = function(){
history.forward()
}
</script>
localstorage本地存储
是一个持久化的本地存储api,可以用来存储键值对数据
- 作用可以将数据永久存储在本地(电脑),除非手动删除,否则关闭页面也会存在
- 特性:多个页面可以共享同一浏览器的数据;以键值对的形式存储数据;只能存储字符串数据
使用方式:
// 储存key数据,值为value
localStorage.setItem(key,value)
// 获取键为key的数据
localStorage.getItem(key)
// 删除键为key的数据
localStorage.removeItem(key)
// 清空所有数据
localStorage.clear()
sessionStorage:跟localStorage用法一样,只是生命周期为关闭浏览器窗口以后结束,而localStorage是浏览器持久化,关闭以后数据还会存在。
JSON
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,通常用于在网站上存储和传输数据。
JSON的优点包括易于阅读和编写、易于解析和生成、与多种编程语言兼容、支持复杂数据结构等。
JSON由键值对组成,键和值之间使用冒号分隔,键值对之间使用逗号分隔。键必须是字符串,值可以是字符串、数字、布尔值、数组、对象或null。
下面是一个JSON对象
let person = {
name: 'jian',
age: 19
}
//常见的使用方法
// 将json对象转换成json字符串
let p = JSON.stringify(person)
// 将json字符串转换成json对象
JSON.parse(p[,revive])
reviver: 可选,一个转换结果的函数, 将为对象的每个成员调用此函数。
------
var text = '{ "name":"Runoob", "initDate":"2013-12-14", "site":"www.runoob.com"}'
var obj = JSON.parse(text, function (key, value) {
if (key == "initDate") {
return new Date(value)
} else {
return value
}})
XML
xml是指可扩展标记语言,被设计用来传输和存储数据。
用法:
- 1、两个程序之间进行数据通信
- 2、给一台服务器做配置文件(比如spring中的ioc配置文件,Mybatis中XXXMapper.xml /
maven中的pom.xml)
// 创建students.xml存储多个student数据
<?xml version="1.0" encoding="utf-8" ?>
<students>
<stduent id="01">
<name>tom</name>
<gender>男</gender>
<age>18</age>
</stduent>
<stduent id="02">
<name>scott</name>
<gender>女</gender:>
<age>17</age>
</stduent>
<!-- 这是注释 -->
</students>
------
<student> --元素:XML中数据是由元素构成的。元素可以嵌套在其他元素中,形成一个树状结构。
元素由起始标签和结束标签组成,中间包含元素的文本内容。
------
<sutdnet id='student01'> id属性
属性:属性提供有关元素的附加信息。它们总是包含在起始标签中,并使用键值对的形式表示。
------
student01姓名为tom,性别男,年龄18岁...
XML 声明:每个 XML 文档都必须以 XML 声明开头,它告诉解析器该文档是 XML 文档。
- 1 xml:表示该文件的类型
- 2 version=“1.0” xml版本
- 3 encoding=“Utf-8” 文件编码
- 4 students:root元素/根元素,xml中有且只能有一个根元素,不能出现并列的情况
- 5 <student>表示students的一个子元素,可以有多个
- 6 id就是属性name,age,gender.又是student元素的子元素
- xml其中的标签都是可以自定义的(不像html中的标签都是预定义的,不能随意使用标签),所以xml的标签是任意可扩展的,标记语言。
xml中希望把某些字符串当作普通文本,使用CDATA包括
<? xml version="1.0" encoding="UTF-8"?>
<!CDATA[[
<student></student> <!-- 这些会被当成普通文本 -->
]]>
正则表达式
正则表达式:regular express,是用于匹配字符串中字符组合的模式。通常用来查找,替换那些符合正则表达式的文本。
- 1 定义正则表达式语法
const reg = /表达式/
- 2 是否匹配
reg.test("正则表达式,用于匹配字符串中字符组合的模式")
reg.exec() //用于检索符合规则的字符串,找到返回数组,index表示匹配的索引,否则为null
元字符
具有特殊含义的字符,可以极大提高灵活性和强大的匹配功能,比如26个英文字母可以使用元字符[a-z]来表示
分类:
- 边界符(表示位置,开头和结尾,必须用什么开头,用什么结尾) ^表示开头,$表示结尾
注意 ^哈$ 表示精确匹配,它只能匹配'哈',其他的都不匹配
- 量词(表示匹配次数)
- 字符类(比如\d表示0-9)
- [] 匹配字符集合
- [0-9] 匹配0-9的任一个数字
- [a-z] 匹配所有小写字母
- [A-Z] 匹配所有的大写字母
- [^1] 取反,表示匹配不是1的字符
- .(点) 除了换行之外的所有字符
//只要中括号里面的任意字符出现都返回为true
console.log(/[abc]/.test('andy'))
//true
console.log(/[abc]/.test('baby'))
//true
console.log(/[abc]/.test('cry'))
//true
console.log(/[abc]/.test('die'))
//false
垃圾回收机制
Garbage Collection,js中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收
内存的生命周期:
内存分配
:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存内存使用
:即读写内存,也就是使用变量函数内存回收
:使用完毕,由垃圾回收器自动回收不在使用的内存
const age=18 //为变量分配内存
const obj = { //为对象分配内存
age: 12
}
function fb(){ //为函数分配内存
console.log(age)
}
说明:
- 全局变量一般不会回收,页面关闭以后回收
- 一般情况下,局部变量的值不用了,就会被自动回收掉
内存泄漏:程序中分配的内存由于某种原因未释放或无法释放叫做内存泄漏
垃圾回收算法
栈堆空间分配区别:
- 栈:由操作系统自动分配释放函数的参数值、局部变量等,基本数据类型放到栈里。
- 堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收,复杂数据类型(对象,数组等)存放到堆里面。
- 也就是说,垃圾回收机制回收的是复杂数据类型
常见的浏览器垃圾回收算法:引用计数法 和 标记清除法
IE采用的引用计数法
,就是看一个对象是否有指向它的引用,没有了就回收对象- 跟踪记录被引用的次数
- 如果对象被引用了一次,那么记录次数+1,多次引用就累加++
- 如果减少一个引用就-1
- 如果引用次数为0,则释放内存
let arr = [1,2,3,4]
// 开辟一个数组内存,arr指向这个内存,记录数为1
arr = null // arr指向空,数组记录数-1=0,所以释放了数组
引用计数法存在一个致命的问题:循环引用,如果两个对象相互引用,尽管他们已经不在使用,垃圾回收器不会进行回收,导致内存泄漏,如图:
let p1 = {
name: 'p1'
}
let p2 = {
name: 'p2'
}
p1.member = p2
p2.member = p1
此时,尽管让p1=null, p2=null ,这两个对象也不会回收,因为他们的记录数始终不为0,导致内存泄漏。
- 现在的浏览器已经不在使用引用计数法了,大多是使用基于
标记清除法
的某些改进算法,总体思想都是一致的。- 核心是:将要师范的对象定义为“无法到达的对象”
- 从根部出发(在js中就是全局变量),定时扫描内存中的对象,凡是能从根部到达的对象都是还需要使用的
- 那些无法由根部出发触及到的对象被标记为不在使用,稍后进行回收
函数闭包
函数闭包是一种特殊的函数结构,它允许在一个内部函数中访问其外部函数的变量和参数,即使外部函数已经执行完毕。
这种特性使得闭包在编程中具有很多实用的应用,比如数据封装、模块化编程等。
- 简单理解:闭包=内部函数+外部函数变量
function outer(){
const a=1
function inner(){
console.log(a)
}
inner()
}
outer()
- 作用:封闭数据,提供操作,外部也可以访问函数内部的变量
比如我们实现一个需求:统计函数被调用多少次,一般的实现思路是:
let count = 0
function fn(){
count++
console.log(`函数被调用了${count}次`)
}
但是因为count是一个全局变量,可以对其任意修改,此时可以用闭包对count变量进行封闭,在内部函数中进行统计:
function outer(){
let count=0
return function(){
console.log(`函数被调用了${++count}次`)
}
}
let b=outer()
闭包的优缺点:
-
闭包可以让外部函数访问内部函数的作用域,从而实现跨作用域访问变量,使得代码更加灵活和可重用。
-
闭包可以创建私有变量,保护内部变量的隐私,同时也可以避免全局变量的污染。
-
缺点:闭包会使得函数中的变量都被保存在内存中,如果变量过多或者长时间持有状态,可能会导致内存消耗过大,甚至引起内存泄漏。
变量提升
变量提升: 允许在var变量声明之前即被访问
- 把所有var声明的变量提升到当前作用域的最前面
- 只提升变量声明,不提升变量赋值
console.log(num + '件')
var num = 3
// 结果是:undefined件
等价于:
var num
console.log(num + '件')
num = 3
如果:
console.log(num + '件')
let num = 3
// 直接报错
f()
function f(){} //不报错,函数提升
------
fun()
var fun = function(){}
// 报错,这里是赋值,等价于下面
------
var fun
fun() //这里fun是undefiend,当然不能执行函数
fun = function(){}
变量提升经常出现一些意想不到的bug,正因为如此,ES6引入了块级作用域,用let或者const声明变量,让代码写法更加规范和人性化。
函数参数
动态参数:arguments
是函数内置的数组变量,它包含了调用函数时传入的所有实参
// demo:给定任意个数字 ,求和
function getSum(){
let sum=0
for(let i=0;i<arguments.length;i++){
sum+=arguments[i]
}
console.log(sum)
}
getSum(1,2)
getSum(1,2,3,4)
剩余参数:...arr
函数的后几个参数
function getSum(...arr){
console.log(arr.reduce((a,b)=>a+b))
}
// 比如:至少输入两个参数时
function getSum2(a,b,...arr){
console.log(arr.reduce((a,b)=>a+b))
}
getSum2(1,2,3) // 1->a 2->b 3->arr
- 区别:剩余参数是个真数组,动态参数是伪数组;剩余参数更灵活
剩余参数中的...
符号是展开运算符,将一个数组进行展开(不会改变原数组)
const arr = [1,2,3,4]
console.log(...arr) // 结果是 1,2,3,4
展开运算符典型使用场景:求数组的最大值(最小值)、合并数组等(数组没有原生的api)
const arr = [1,2,3,4]
Math.max(...arr) // 求最大值
let arr3 = [...arr, ...arr2] //合并数组
解构赋值
解构赋值是一种快速为每个变量/方法赋值的简洁语法;[允许将值从数组或对象提取到不同的变量中]
数组解构
const arr = [1,2,3]
// 批量声明变量a=1,b=2,c=3
const [a,b,c] = arr
典型用法:交换两个变量
let a=1, b=2;
[a,b] = [b,a]
对象解构
let obj = {
name:'pink',
age: 28
}
// 对象解构语法(必须保证属性名一致)
let {name,age} = obj
// 如果属性名不一致(将uname改为name)
let {uname:name,age} =obj
------
等价于:
let name = obj.name
let age = obj.age
对象数组解构
let arr={
name: 'jian',
age: 18,
hobby: ['下棋','乒乓球']
}
// 解构
let {name,age,hobby:[h1,h2]} = arr
性能优化
防抖(debounce)
单位时间内,频繁触发事件,只执行最后一次
使用场景:
- 搜索框搜索输入。只需要用户最后一次输入完在发送请求
- 手机号、邮箱验证输入检测
核心思路:
- 声明一个定时器(setTimeout)变量
- 当鼠标每次滑动时都先判断是否有定时器,如果有定时器先清除以前的定时器
- 如果没有定时器则开启定时器,记得保存到变量里面
- 在定时器里面调用要执行的函数
节流
单位时间内,频繁触发事件,只执行一次
节流的核心就是利用定时器(setTimeout)来实现
- 声明一个定时器变量
- 当鼠标每次滑动都先判断是否有定时器,如果有定时器则不开启新定时器
- 如果没有定时器则开启定时器,记得存到变量里面
- 定时器里面调用执行的函数
- 定时器里面要把定时器清空
function throttle(fn,t){
let timer = null
return function() {
if (!timer){
timer=setTimeout(function (){
fn() // 执行具体操作
//清空定时器
timer = null //注意不能在定时器里面使用clear清除定时器
},t)
}
}
}
box.addEventListener('mousemove',throttle(mouseMove,3000))
demo: 当我们在播放一段时间的视频后再刷新可以从当前时间播放,而不从头播放。需要用到下面两个事件:
- timeupdate:在视频播放过程中,每当播放位置发生改变时触发事件(每播放一帧画面就触发事件)。
这个事件发生太快,可以使用节流来限制事件触发的频率。 - loadeddata:当浏览器已经加载了视频的第一帧时触发。
代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<video src="fengjing.mp4" controls width="500" height="500"></video>
<script>
let video = document.querySelector("video")
//播放位置发生改变时就触发函数执行
video.ontimeupdate = throttle()
// 打开浏览器时触发函数执行
video.onloadeddata = function (){
video.currentTime = localStorage.getItem('current_time') || 0
// 这里与操作是防止getItem('current_time')为undefined
}
//节流操作
function throttle(){
let timer = null
return function (){
//如果定时器为空,创建定时器操作
if (!timer){
timer = setTimeout(function (){
// 存储当前播放时间
localStorage.setItem('current_time', video.currentTime)
console.log(video.currentTime)
timer = null
},1000)
}
}
}
</script>
</body>
</html>
js实现验证码功能
<style>
#valid{
background-color: #e0e5e1;
height: 30px;
width: 110px;
}
.valid_inner{
width: 100px;
line-height: 30px;
margin-left: 10px;
}
.switchCode{
font-size: small;
color: #2980b9;
cursor: pointer;
}
</style>
验证码: <div id="valid" style="display: inline-block"></div>
<span class="switchCode" onclick="getValidCode()">看不清?切换</span>
<script>
getValidCode()
//存储随机生成的验证码,用以比较验证码是否正确
let charCode = ''
function getValidCode(){
let valid = document.getElementById("valid")
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let validChars = ''
let validHtml = '<div class="valid_inner">'
for (let i = 0; i < 6; i++) {
let rIndex = Math.floor(Math.random()*chars.length)
validChars += chars[rIndex]
validHtml += `<span style="display:inline-block;color: ${getRandomColor()}; transform: skewX(${Math.floor(Math.random() * 45) - 20}deg);">${chars[rIndex]}</span> `
}
charCode = validChars
valid.innerHTML = validHtml+'</div>'
}
// 随机获取颜色的十六进制
function getRandomColor() {
const letters = '0123456789ABCDEF'
let color = '#'
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]
}
return color
}
</script>
JavaScript创建提示框
function showSuccess(message) {
// 创建提示框元素
var modal = document.createElement("div")
modal.textContent = message
modal.style.cssText = `display: none;
position: fixed;
top: 10%;
left: 50%;
transform: translateX(-50%);
background-color:#9cd49c;
color: #fff;
padding: 10px 20px;
border-radius: 5px;
z-index: 1000`
// 将提示框添加到页面中
document.body.appendChild(modal)
// 显示提示框
modal.style.display = "block"
// 设置定时器,3秒后隐藏提示框
setTimeout(function() {
modal.style.display = "none"
document.body.removeChild(modal)
}, 3000)
}