前言:JavaScript(简称 JS)是一种 动态类型、基于原型、多范式 的编程语言。最初由 Brendan Eich 在 1995 年开发,用于在浏览器中实现交互式网页。
如今,它已成为 前端开发的核心语言,并借助 Node.js 扩展到后端、移动端和桌面端开发。
语法基础
注释和分号问题
单行注释 //
多行注释 /* ... */
但为了风格统一,结束符要么每句都写,要么每句都不写 (团队约定)
数据类型
输入输出
1 2 3 4 5 6 7 8 9 document .write ('<h1>hello world</h1>' )alert ('hello world' );console .log ('hello world' );let name = prompt ('请输入你的名字' );alert ('hello ' + name);
注意:JavaScript代码执行顺序:①按HTML文档流顺序执行②代码 alert()和 prompt()它们会跳过页面渲染先被执行(目前作为了解,后期讲解详细执行过程)
变量的声明
1 2 3 4 5 6 7 8 9 10 let a;a = 3 ; console .log (a);let name = '张三' ;console .log (name);let age = 18 , uname = '迪丽热巴' ;
1 2 3 4 5 6 7 8 let arr = [1 , 2 , 3 , 4 , 5 ];console .log (arr[0 ]);console .log (arr[4 ]);let arr2 = [1 , 'hello' , true , [1 , 2 , 3 ]];console .log (arr2.length );
注意:①数组可以存储任意类型的数据②长度:数组中数据的个数,通过数组的length属性获得
常量(注意:常量不允许重新赋值,声明的时候必须赋值 (初始化))
1 2 3 4 5 const PI = 3.14 ;console .log (PI );const myName = '王伟' ;console .log (myName);
注意:var— 以前的声明变量的方式,会有很多问题。
数据类型
number: 数字型
注意:NaN代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果,NaN是粘性的。任何对NaN的操作都会返回NaN。
string: 字符串型
注意:通过单引号"、双引号""或反引号``包裹的数据都叫字符串,单引号和双引号没有本质上的区别,推荐使用单引号。
1 2 3 4 5 6 7 8 9 let str ='pink' ;let str1 = "pink" ;let str2 = `中文` ;console .log (str2);let name = 'pink' ;let age = 18 ;let info = `${name} 今年${age} 岁` ;console .log (info);
boolean: 布尔型
注意:它有两个固定的值true和false,表示肯定的数据用true(真),表示否定的数据用false(假)
undefined: 未定义型
注意:只声明变量,不赋值的情况下,变量的默认值为undefined,一般很少【直接】为某个变量赋值为undefined。
null: 空类型
注意:null表示空对象,null是一个对象,null对象没有属性和方法。
null和undefined区别:①undefined表示没有赋值②null表示赋值了,但是内容为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 console .log (undefined + 1 ) console .log (null + 1 ) let num = 10 console .log (typeof num) let str = 'pink' console .log (typeof str) let str1 ='10' console .log (typeof str1) let flag = false console .log (typeof flag) let unconsole .log (typeof un) let obj= null console .log (typeof obj)
+号两边只要有一个是字符串,都会把另外一个转成字符串
除了+以外的算术运算符比如-、*、/等都会把数据转成数字类型
+号作为正号解析可以转换成数字型
任何数据和字符串相加结果都是字符串
1 2 3 4 5 6 7 8 9 console .1og(11 + 11 ) console .log ('11' +11 ) console .1og(11 - 11 ) console .log ('11' -11 ) console .log (1 * 1 ) console .log ('1' * 1 ) console .log (typeof '123' ) console .log (typeof +'123' ) console .log (+'11' + 11 )
object: 对象型
运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let a = 1 console .log (a++)console .log (2 == '2' )console .log (NaN == NaN ) console .log (2 === '2' ) console .log (2 !== '2' ) console .log (2 != '2' ) console .log ('a' < 'b' )console .log ('ab' < 'abc' )
语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 if ('pink老师' ) console .log ('pink老师' ) if ('' ) console .log ('' ) else console .log ('没有内容' ) if (' ' ) console .log ('字符串的内容是一个空格' ) switch (true ) { case 'pink老师' : console .log ('pink老师' ) break ; case '' : console .log ('' ) break ; default : console .log ('没有内容' ) break ; } for (let i = 1 ; i < 10 ; ++i) { for (let j = 1 ; j <= i; ++j) { document .write (`<span>${j} x ${i} = ${i * j} </span>` ) } document .write ('<br>' ) }
数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let arr0 = [1 ,2 ,3 ,4 ,5 ]let arr1 = new Array (1 ,2 ,3 ,4 ,5 , 6 , 7 , 8 , 9 , 10 )let arr2 = []arr1.push (1 ) arr1.unshift (2 ) console .log (arr1.pop ()) console .log (arr1.shift ()) arr1.splice (1 ,2 ) arr1.splice (1 ) for (let i = 0 ; i < arr2.length ; i++) { console .log (arr2[i]) }
函数
两个相同的函数后面的会覆盖前面的函数
Javascript中实参的个数和形参的个数可以不一致
如果形参过多会自动填上undefined(了解即可)
如果实参过多那么多余的实参会被忽略(函数内部有一个arguments,里面装着所有的实参)
函数一旦碰到return就不会在往下执行了函数的结束用return
匿名函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 function sayHi ( ) { console .log ('hello' ) } sayHi ()function sum (num1, num2 ) { return num1 + num2 } console .log (sum (1 , 2 ))function point (x = 0 , y = 0 ) { return `(${x} , ${y} )` } function scope ( ) { notRecommended = 'no' let num = 3 function inner ( ) { let num = 4 console .log (num) } } let func = function ( ) { console .log ('anonymous function' ) } func (); (function ( ) { console .log ('immediately invoked function' ) console .log ('anonymous function' ) })(); (function (x, y ){ console .log ('immediately invoked function2' ) console .log (x + y) }(3 , 4 )); function logicFunc (x, y ) { x = x || 1 y = y || 1 console .log (`x = ${x} , y = ${y} ` ) } logicFunc () logicFunc (0 , 0 ) logicFunc (2 , 2 ) console .log (Boolean ('' ))
object对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 let obj = { name : '小米10青春版' , num : '100012816024' , weight : '0.55kg' , address : '中国大陆' , welcome : function ( ) { console .log ('欢迎来到小米' ) } } obj.weight = '0.50kg' obj.price = '6999' console .log (obj.name )console .log (obj['name' ])console .log (obj.address )console .log (obj)obj.welcome () for (const key in obj) { console .log (`key = ${key} , obj[key] = ${obj[key]} ` ) } console .log (Math .PI )console .log (Math .pow (2 ,3 ))console .log (Math .ceil (2.1 )) console .log (Math .floor (2.9 )) console .log (Math .round (-1.5 )) console .log (Math .round (-1.51 )) console .log (Math .random ())console .log (Math .floor (Math .random () * 11 ))let N = 5 , M = 10 console .log (Math .floor (Math .random () * (M - N + 1 )) + N)
注意:
简单数据类型存放到栈里面(操作系统自动分配释放存放函数的参数值、局部变量的值)
引用数据类型存放到堆里面(存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收)
Js & Web
WebAPI基本认知
作用和分类
作用:就是使用JS去操作html和浏览器
分类:DOM(文档对象模型)、BOM(浏览器对象模型)
DOM树
将HTML文档以树状结构直观的表现出来,我们称之为文档树或DOM树
描述网页内容关系的名词
作用:文档树直观的体现了标签与标签之间的关系
DOM对象
浏览器根据html标签生成的JS对象
所有的标签属性都可以在这个对象上面找到
修改这个对象的属性会自动映射到标签身上
DOM的核心思想,把网页内容当做对象来处理
获取DOM对象操作元素内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const box = document .querySelector ('div' )for (const key in box) { console .log (`key = ` ) console .log (`${key} : ${box[key]} ` ) } console .log (box.textContent )const pNav = document .querySelector ('#nav' )console .log (pNav)const li = document .querySelector ('ul li:first-child' )console .log (li)const list = document .querySelectorAll ('ul li' )console .log (list)for (let i = 0 ; i < list.length ; ++i) { list[i].style .color = 'pink' }
操作元素属性
操作元素的普通属性
1 2 3 4 5 6 7 8 const box = document .querySelector ('.box' )for (const key in box) { console .log (`${key} : ${box[key]} ` ) } box.innerText = '我是一个盒子' box.innerHTML = '<strong>我是一个盒子</strong>'
操作元素的样式属性
1 2 3 4 const box = document .querySelector ('.box' )box.style .width = '300px' box.style .backgroundColor = 'hotpink' box.style .border = '2px solid blue'
操作类名(className)操作CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .nav { color : red; } .box { width : 300px ; height : 300px ; background-color : blue; margin : 100px auto; padding : 10px ; border : 1px solid black; } </style > </head > <body > <div class ="nav" > 123</div > <script > const box = document .querySelector ('div' ) box.className = 'nav box' </script > </body > </html >
通过classList操作类控制CSS(最推荐的方式)
为了解决className容易覆盖以前的类名,我们可以通过classList方式追加和删除类名
语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .box { width : 200px ; height : 200px ; color : #333 } .active { color : red; background-color : pink; } </style > </head > <body > <div class ="box active" > 文字</div > <script > const box = document .querySelector ('.box' ) box.classList .add ('active' ) box.classList .remove ('active' ) box.classList .toggle ('active' ) </script > </body > </html >
操作表单元素属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <input type ="text" value ="默认值" > <div data-id ="1" > one</div > <div data-id ="2" > two</div > <div data-id ="3" > three</div > <div data-id ="4" > four</div > <div data-id ="5" > five</div > <script > const input = document .querySelector ('input' ) console .log (input.value ) input.value = '修改后的值' console .log (input.type ) input.type = 'password' const one = document .querySelector ('div' ) console .log (one.dataset ) console .log (one.dataset .id ) </script > </body > </html >
定时器-间歇函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let i = 0 let n = setInterval (() => { i++ console .log (`${i} ` ) }, 1000 ) let m = setInterval (function ( ) { console .log ('匿名函数的方式调用' ) }, 1000 ) function func ( ) { console .log ('具名函数的方式调用' ) } let t = setInterval (func, 1000 )console .log (n)clearInterval (n)clearInterval (m)clearInterval (t)
事件监听 (绑定)
绑定事件监听
1 2 3 4 const btn = document .querySelector ('button' )btn.addEventListener ('click' , function ( ) { alert ('点击了' ) })
事件类型
事件对象
也是个对象,这个对象里有事件触发时的相关信息
例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息
可以判断用户按下哪个键,比如按下回车键可以发布新闻
可以判断鼠标点击了哪个元素,从而做相应的操作
部分常用属性
环境对象
指的是函数内部特殊的变量this,它代表着当前函数运行时所处的环境
弄清楚this的指向,可以让我们代码更简洁
能够分析判断函数运行在不同环境中this所指代的对象
谁调用,this就是谁—> 判断this指向的粗略规则
1 2 3 4 5 6 7 8 9 10 function func ( ) { console .log (this ) } func ();const btn = document .querySelector ('.btn' )btn.addEventListener ('click' , function (e ) { console .log (this ) });
事件流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 document .addEventListener ('click' , function (e ) { console .log ('我是爷爷' ) }, true ) const father = document .querySelector ('.father' )father.addEventListener ('click' , function (e ) { console .log ('我是爸爸' ) }, true ) const son = document .querySelector ('.son' )son.addEventListener ('click' , function (e ) { console .log ('我是儿子' ) e.stopPropagation () }, true )
事件流与两个阶段说明
①事件捕获
②事件冒泡
事件捕获
事件捕获阶段:从最外层元素开始,依次向内调用所有同名事件
事件冒泡阻止冒泡
当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
解绑事件
鼠标经过事件:
mouseover和mouseout会有冒泡效果
mouseenter和mouseleave没有冒泡效果(推荐)
事件委托
原理:事件委托其实是利用事件冒泡的特点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <ul > <li > 第一个孩子</li > <li > 第二个孩子</li > <li > 第三个孩子</li > <li > 第四个孩子</li > <li > 第五个孩子</li > <p > 我不需要变色</p > </ul > <script > const ul = document .querySelector ('ul' ) ul.addEventListener ('click' , function (e ) { if (e.target .tagName === 'LI' ) { e.target .style .color = 'red' } }); </script >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <form action ="https://www.itcast.cn" > <input type ="submit" value ="免费注册" > </form > <a href ="https://www.baidu.com" > 百度一下</a > <script > const form = document .querySelector ('form' ) form.addEventListener ('submit' , function (e ) { e.preventDefault () console .log ('提交表单' ) }) const a = document .querySelector ('a' ) a.addEventListener ('click' , function (e ) { e.preventDefault () console .log ('点击超链接' ) }) </script >
其他事件
页面加载事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 window .addEventListener ('load' , function ( ) { const btn = document .querySelector ('button' ) btn.addEventListener ('click' , function ( ) { console .log ('点击了' ) }) console .log ('页面加载完毕' ) }) const img = new Image ()img.src = 'https://picsum.photos/id/237/200/300' img.addEventListener ('load' , function ( ) { console .log ('图片加载完毕' ) }) document .addEventListener ('DOMContentLoaded' , function ( ) { const btn = document .querySelector ('button' ) btn.addEventListener ('click' , function ( ) { console .log ('点击了' ) }) })
元素滚动事件
1 2 3 4 window .addEventListener ('scroll' , function ( ) { console .log ('我滚动了' ) })
页面尺寸事件
会在窗口尺寸改变的时候触发事件:resize
检测屏幕宽度:
获取元素的可见部分宽高(不包含边框,margin,滚动条等)
clientWidth和clientHeight
日期对象
实例化
1 2 3 4 5 6 7 8 9 const date = new Date ()console .log (date)const date1 = new Date ('2025-5-1' )console .log (date1)console .log (date.getMonth ())console .log (date.getDay ())console .log (date.toLocaleString ())
时间对象方法
时间戳
是指1970年01月01日00时00分00秒起至现在的秒数(javascript中的时间戳是毫秒数),它是一种特殊的计量时间的方式
1 2 3 4 console .log (Date .now ())console .log (new Date ().getTime ())console .log (+new Date ())
JS进阶
ES6 新的语法
作用域
let声明的变量会产生块作用域,var不会产生块作用域
const声明的常量也会产生块作用域
全局作用域中声明的变量,任何其它作用域都可以被访问
垃圾回收机制(GarbageCollection)简称GC
JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收
一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
简单理解:闭包=内层函数+外层函数的变量
闭包作用:封闭数据,提供操作,外部也可以访问函数内部的变量
1 2 3 4 5 6 7 8 9 10 function outer ( ) { let a = 10 function inner ( ) { console .log (a) } return inner } const func = outer ()func ()
变量提升是JavaScript中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于var声明变量)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 console .log (num + '件' ) var num = 10
函数进阶
动态参数, arguments是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
1 2 3 4 5 6 7 8 9 10 function getSum ( ) { console .log (arguments ) let sum = 0 for (let i = 0 ; i < arguments .length ; ++i) { sum += arguments [i] } return sum } let ret = getSum (1 , 2 , 3 , 4 , 5 )console .log (ret)
剩余参数,充许我们将一个不定数量的参数表示为一个数组
1 2 3 4 5 6 function config (baseUrl, ...others ) { console .log (baseUrl) console .log (others) } config ('https://www.baidu.com' , 'get' , 'json' )
展开运算符(…)将一个数组进行展开
不会修改原数组
1 2 3 let arr = [1 , 2 , 3 , 4 , 5 ]console .log (...arr) console .log (Math .max (...arr))
使用场景:箭头函数更适用于那些本来需要匿名函数的地方
箭头函数没有arguments动态参数,但是有剩余参数...args
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const fn = (a ) => { console .log ('这是一个箭头函数' ) console .log (a) } fn (1 )const fn1 = a => { console .log ('只有一个形参的时候,可以省略小括号' ) console .log (a) } fn1 (2 )const fn2 = a => console .log (a)fn2 (3 )const fn3 = x => x * xconsole .log (fn3 (4 ))const fn4 = (uname ) => ({uname : uname})console .log (fn4 ('刘德华' )) const sum = (a, b, ...args ) => { const s1 = a + b let s2 = 0 for (let i = 0 ; i < args.length ; ++i) { s2 += args[i] } return s1 + s2 } const s = sum (1 , 2 , 3 , 4 , 5 )console .log (s)
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this
解构赋值
数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法
1 2 3 4 5 6 7 const arr = [1 , 2 , 3 ]const [a, b, c] = arrconsole .log (a, b, c)let m = 10 , n = 20 ;[m, n] = [n, m] console .log (m, n)
对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const {uname, age} = {uname : '张三' , age : 18 }console .log (uname, age)const {uname : name, age : age0 } = {uname : '张三' , age : 18 }console .log (name, age0)const pig = [ { uname:'佩奇' , age :6 } ] const [{ uname, age }] = pigconsole .log (uname, age)
构造函数
1 2 3 4 5 6 7 function Person (uname, age ) { this .uname = uname; this .age = age; } const person = new Person ('张三' , 18 )console .log (person)
实例成员&静态成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function Person (uname, age ) { this .uname = uname; this .age = age; } const person = new Person ('张三' , 18 )console .log (person)person.gender = 'male' person.sayHi = () => { console .log (person) } person.sayHi () Person .country = '中国' Person .show = () => { console .log (Person .country ) } Person .show ()
内置构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const obj = { uname : '张三' , age : 18 , sayHi : () => { console .log ('hello world' ) } } const keys = Object .keys (obj)const values = Object .values (obj)console .log (keys) console .log (values) const copyObj = {}Object .assign (copyObj, obj)
常用API
Array Api
reduce 执行过程:
①如果没有起始值,则上一次值以数组的第一个数组元素的值
②每一次循环,把返回值给做为下一次循环的上一次值
③如果有起始值,则起始值做为上一次值
面向对象
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作
面向对象的特性: ①封装性 ②继承性 ③多态性
原型
每个原型对象里面都有个constructor属性(constructor构造函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Star (uname, age ) { this .uname = uname this .age = age } Star .prototype .show = function ( ) { console .log (`姓名:${this .uname} ,年龄:${this .age} ` ) } const star0 = new Star ('刘德华' , 18 )const star1 = new Star ('周杰伦' , 19 )star0.show () star1.show ()
prototype属性
1 2 3 4 5 6 7 8 9 10 11 12 13 Star .prototype = { constructor : Star , sing : function ( ) { console .log ('正在唱歌...' ) }, dance : function ( ) { console .log ('正在跳舞...' ) } } const star2 = new Star ('王源' , 18 )star2.sing ()
对象原型
对象都会有一个属性_proto_指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有_proto_原型的存在。
高阶技巧
深浅拷贝
浅拷贝:拷贝的是地址,特别是遇到嵌套对象时,对象属性的引用地址会相同,修改一个对象属性,另一个对象属性也会改变。
拷贝对象:Object.assgin()/展开运算符{…obj}拷贝对象
拷贝数组:Array.prototype.concat()或者[…arr]
浅拷贝可以用在简单对象或数组上,不要有嵌套对象也是可以的。
深拷贝:拷贝的是对象,不是地址
通过递归实现深拷贝
lodash/cloneDeep
通过JSON.stringify()实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function deepCopy (newObj, oldObj ) { for (const k in oldObj) { if (oldObj[k] instanceof Array ) { newObj[k] = [] deepCopy (newObj[k], oldObj[k]) } else if (oldObj[k] instanceof Object ) { newObj[k] = {} deepCopy (newObj[k], oldObj[k]) } else { newObj[k] = oldObj[k] } } }
异常处理
throw抛异常
try/catch捕获异常
debugger
处理this
JavaScript中还允许指定函数中this的指向,有3个方法可以动态指定普通函数中this的指向 call(), apply(), bind()
1 2 3 4 5 6 7 8 9 10 11 12 13 const anObj = { name : '张三' , age : 18 } function func (a, b ) { console .log (this ) console .log (a, b) } func.apply (anObj, [1 , 2 ]) const max = Math .max .apply (null , [1 , 2 , 3 , 4 , 5 ])console .log (max)
bind()-重点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <button > 点击发送短信</button > <script > const obj = { uname : '张三' , age : 18 } function fn ( ) { console .log (this ) } const newfn = fn.bind (obj) newfn () const btn = document .querySelector ('button' ) btn.addEventListener ('click' , function ( ) { this .disabled = true setTimeout (() => { this .disabled = false }, 2000 ) }) </script > </body > </html >
性能优化
防抖(debounce)
防抖:单位时间内,频繁触发事件,只执行最后一次
使用场景:
搜索框搜索输入。只需用户最后一次输入完,再发送请求
手机号、邮箱验证输入检测
lodash提供的防抖来处理
手写一个防抖函数来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .box { width : 400px ; height : 400px ; background-color : pink; text-align : center; } </style > </head > <body > <div class ="box" > </div > <script > const box = document .querySelector ('.box' ) let i = 1 function moveMouse ( ) { box.innerHTML = i++ } function debounce (fn, t ) { let timer return function ( ) { if (timer) clearTimeout (timer) timer = setTimeout (function ( ) { fn () }, t) } } box.addEventListener ('mousemove' , debounce (moveMouse, 500 )) </script > </body > </html >
节流-throttle
节流:单位时间内,频繁触发事件,只执行一次
实现方式:
lodash提供的节流函数来处理
手写一个节流函数来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .box { width : 400px ; height : 400px ; background-color : pink; text-align : center; } </style > </head > <body > <div class ="box" > </div > <script > const box = document .querySelector ('.box' ) let i = 1 function moveMouse ( ) { box.innerHTML = i++ } function throttle (fn, t ) { let timer return function ( ) { if (timer) return timer = setTimeout (function ( ) { fn () timer = null }, t) } } box.addEventListener ('mousemove' , throttle (moveMouse, 500 )) </script > </body > </html >
总结: