JavaScript基础知识(三)

news2024/7/30 15:17:19

JavaScript基础知识(三)

  • 一、事件
    • 1. 事件绑定
    • 2.事件流
      • 2.1 事件捕获与事件冒泡
    • 3.事件对象扩展
      • 3.1 阻止事件冒泡
      • 3.2 事件默认行为
    • 4.事件委托
    • 5.事件类型
      • 5.1 鼠标事件
      • 5.2 键盘事件
      • 5.3 触屏事件
  • 二、计时器方法
    • 1. setInterval 与 clearInterval
    • 2. setTimeout 与 clearTimeout
    • 3. 防抖与节流
      • 3.1 防抖 (debounce)
      • 3.2 节流(throttle)
      • 3.3 防抖与节流的案例
  • 三、BOM
    • 1. 基本概念
    • 2. BOM对象
    • 3. window对象
      • 3.1 计时器方法
      • 3.2 弹出框方法
    • 4. location对象
    • 5. navigator对象
  • 四、原始类型与引用类型
    • 1. JS数据类型
      • 1.1 动态/静态:
      • 1.2 强/弱:
    • 2. 数据类型分类
      • 2.1 六种数据类型:
      • 2.2 ECMAScript 有 8 种数据类型:
    • 3. 原始类型 与 引用类型
      • 3.1 原始类型与引用类型的区别
      • 3.2 原始类型与引用类型的类型检测
  • 五、异步编程
    • 1. 同步与异步
    • 2. 异步获取数据的方法
    • 3. 异步编程的解决方案
  • 总结


一、事件

1. 事件绑定

两种方法:

element.onEventType = func
element.addEventListener( 'eventType', func)

区别 :

  • addEventListener 在同一元素上的同一事件类型添加多个事件,不会被覆盖,而 onEventType 会覆盖;
  • addEventListener 可以设置元素在捕获阶段触发事件,而 onEventType 不能。

示例1:在同一元素上的同一事件类型添加多个事件。

    let btn = document.querySelector("#btn");
    btn.onclick = () => {
        console.log('hello world');
    }
    btn.onclick = () => {
        console.log('hello javascript');
    }

控制台打印效果:
在这里插入图片描述
只打印了后面的事件执行程序结果,再看下 addEventListener 的执行效果。

    let btn = document.querySelector("#btn");
    btn.addEventListener('click', () => {
        console.log('hello world');
    })
    btn.addEventListener('click', () => {
        console.log('hello javascript');
    })

在这里插入图片描述
添加的两个事件处理程序全部被执行了。

示例2:addEventListener 可以通过第三个参数来设置元素是在冒泡阶段还是在捕获阶段触发。

    // 冒泡阶段触发:默认为false
    btn.addEventListener('click', () => {
        console.log('hello world');
    }, false)
    // 捕获阶段触发
    btn.addEventListener('click', () => {
        console.log('hello javascript');
    }, true)

2.事件流

问题:三个div嵌套,都绑定click事件,点击最内层的元素,事件如何执行?
a : 只执行最内层
b: 从内到外都执行
c: 从外到内都执行

2.1 事件捕获与事件冒泡

在这里插入图片描述
默认情况下,事件会在冒泡阶段执行。
addEventListener(eventType, func, boolean);
默认 false:冒泡阶段触发,true:捕获阶段触发。

示例:三个 div 嵌套,都绑定 click 事件,点击最内层的元素。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件</title>
</head>
<style>
    .big {
        width: 500px;
        height: 500px;
        background-color: red;
    }

    .medium {
        width: 300px;
        height: 300px;
        background-color: yellow;
    }

    .small {
        width: 100px;
        height: 100px;
        background-color: blue;
    }
</style>
<body>
<div class="big">
    <div class="medium">
        <div class="small"></div>
    </div>
</div>
<script>
    let bigBox = document.querySelector(".big");
    let mediumBox = document.querySelector(".medium");
    let smallBox = document.querySelector(".small");

    bigBox.addEventListener('click', () => {
        console.log('Hi,I am big');
    })
    mediumBox.addEventListener('click', () => {
        console.log('Hi,I am medium');
    })
    smallBox.addEventListener('click', () => {
        console.log('Hi,I am small');
    })
</script>
</body>
</html>

点击最里层蓝色box,看下控制台的打印结果:
在这里插入图片描述
可以看到,事件是按照冒泡顺序从内到外执行的。

如果我们将 addEventListener 的第三个参数改为 true,再来看下页面效果:

    bigBox.addEventListener('click', () => {
        console.log('Hi,I am big');
    }, true)
    mediumBox.addEventListener('click', () => {
        console.log('Hi,I am medium');
    }, true)
    smallBox.addEventListener('click', () => {
        console.log('Hi,I am small');
    }, true)

在这里插入图片描述
可以看到,这次事件是按照捕获顺序从外到内执行的。

3.事件对象扩展

3.1 阻止事件冒泡

阻止事件冒泡执行,让外层的事件不被执行:

e.stopPropagation();

上面的冒泡示例中,在小盒子的事件处理程序中添加阻止事件冒泡:

    bigBox.addEventListener('click', () => {
        console.log('Hi,I am big');
    })
    mediumBox.addEventListener('click', () => {
        console.log('Hi,I am medium');
    })
    smallBox.addEventListener('click', (e) => {
        console.log('Hi,I am small');
        e.stopPropagation();
    })

我们点击小盒子,发现这次只触发了小盒子的事件处理程序,并没有触发中盒子和大盒子的事件处理程序:在这里插入图片描述

3.2 事件默认行为

去掉事件默认行为:

e.preventDefault();

或者

return false;

示例:为一个可以跳转到百度的 a 标签设置点击事件,点击事件触发时,a 标签不进行跳转。

<a href="https://www.baidu.com" class="alink">hello world</a>
let alink = document.querySelector('.alink');
alink.addEventListener('click', (e) => {
	console.log('hello world');
	e.preventDefault()
	// return false;
})

在这里插入图片描述

4.事件委托

通过 e.target 将子元素的事件委托给父级处理。

示例:实现一个水果列表,可以添加和移除每项水果。

<div>
    <input type="text">
    <button class="add">添加</button>
</div>

<ul class="list">
    <li>香蕉</li>
    <li>西瓜</li>
    <li>鸭梨</li>
</ul>

在这里插入图片描述
添加水果:

    // 添加水果
    btn.addEventListener('click', () => {
        let value = input.value;
        let li = document.createElement('li');
        let txt = document.createTextNode(value);
        li.appendChild(txt);
        list.appendChild(li);
        input.value = '';
    })

在这里插入图片描述
在这里插入图片描述
点击水果进行移除:
如果在页面初始化对每个 li 添加点击事件,则后面通过输入框动态添加的水果不具有这个点击事件;
所以需要直接对 ul 元素添加,再通过 e.target 获取到当前点击的元素,再进行移除。

    list.addEventListener('click', (e) => {
        // e.target => 当前 li
        list.removeChild(e.target)
    })

5.事件类型

5.1 鼠标事件

  • click:按下鼠标时触发;
  • dblclick:在同一个元素上双击鼠标时触发;
  • mousedown:按下鼠标键时触发;
  • mouseup:释放按下的鼠标键时触发;
  • mousemove:当鼠标在一个节点内部移动时触发;
  • mouseenter:鼠标进入一个节点时触发,进入子节点不会触发这个事件;
  • mouseover:鼠标进入一个节点时触发,进入子节点会再一次触发这个事件;
  • mouseout:鼠标离开一个节点时触发,离开父节点也会触发这个事件;
  • mouseleave:鼠标离开一个节点时触发,离开父节点不会触发这个事件;

5.2 键盘事件

js中的键盘事件分为三种:keydownkeypresskeyup

  • keydown:按下键盘时触发;
  • keypress:按下有值的键时触发,即按下 Ctrl、Alt、Shift、Meta这样无值的键,这个事件不会触发;
  • keyup:松开键盘时触发;

注意:对于有值的键,按下时先触发 keydown 事件,再触发 keypress 事件。

键盘的每个按键都有绑定的键码,可以通过e.keyCode 获取。

document.onkeydown = function (e) {
	console.log(e.keyCode);
}

在这里插入图片描述
示例:通过上下左右键控制红色方块移动。
首先,我们在控制台分别打印下左、上、右、下这四个方向键的键码:
在这里插入图片描述
然后,我们再来了解下 偏移量offset 常用属性:

左偏移量上偏移量右偏移量下偏移量
offsetLeftoffsetTopoffsetRightoffsetDown

在这里插入图片描述
下面我们开始进行编写我们的代码了。
html 和 css 代码:

	.box {
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
        left: 100px;
        top: 100px;
	}

	<div class="box"></div>

js 代码:

    let box = document.querySelector('.box');
    document.onkeydown = (e) => {
        let code = e.keyCode;
        switch (code) {
            // 左键
            case 37:
                box.style.left = (box.offsetLeft - 5) + 'px';
                break;
            // 上键
            case 38:
                box.style.top = (box.offsetTop - 5) + 'px';
                break;
            // 右键
            case 39:
                box.style.left = (box.offsetLeft + 5) + 'px';
                break;
            // 下键
            case 40:
                box.style.top = (box.offsetTop + 5) + 'px';
                break;
        }
    }

最终效果:
在这里插入图片描述

5.3 触屏事件

  • touchstart:手指触摸到一个DOM元素时触发;
  • touchend:手指从一个DOM元素上移开时触发;
  • touchmove:手指在一个DOM元素上滑动时触发。
    let box = document.querySelector('.box');
    
    box.ontouchstart = () => {
        console.log('start');
    }
    box.ontouchend = () => {
        console.log('end');
    }
    box.ontouchmove = () => {
        console.log('move');
    }

在这里插入图片描述

二、计时器方法

1. setInterval 与 clearInterval

语法:

// 设置定时器:
setInterval(fn, seconds)
// 清除定时器:
clearInterval(定时器名)

例 1 - 每隔两秒钟输出一次hello world。

setInterval(() => {
  console.log("hello world");
}, 2000);

例 2 - 点击暂停按钮可以结束打印输出。

let btn = document.querySelector('button');
// 每隔两秒钟输出一次
let timer = setInterval(() => {
  console.log("hello world");
}, 2000);
// 点击事件
btn.addEventListener('click', () => {
  // 暂停结束计时器 timer
  clearInterval(timer);
}, false) ;

例 3 - 在网页中显示当前时间。

<h1></h1>
<script>
    let h1 = document.querySelector('h1');
    let timer = setInterval(() => {
    	// 获取当前时间
        let time = new Date();
        let h = time.getHours();
        let m = time.getMinutes();
        let s = time.getSeconds();
        let result = `${addZero(h)}:${addZero(m)}:${addZero(s)}`;
        h1.innerHTML = result;
    }, 1000)
	// 用零补位
    function addZero(num) {
        if (num < 10) {
            return `0${num}`
        } else {
            return num;
        }
    }
</script>

在这里插入图片描述

例 4 - 在网页中制作一个秒表(开始功能、停止功能、重置)。

<h1>0:0</h1>
<button id="start">开始</button>
<button id="stop">停止</button>
<button id="reset">重置</button>
<script>
    let h1 = document.querySelector('h1');
    let startBtn = document.querySelector('#start');
    let stopBtn = document.querySelector('#stop');
    let resetBtn = document.querySelector('#reset');
    // 声明定时器
    let timer = null;
    // 初始化时间
    let s = 0, ms = 0;
    // 开始
    startBtn.addEventListener('click', () => {
        if (timer) {
            clearInterval(timer);
        }
        timer = setInterval(() => {
            if (ms === 9) {
                s++;
                ms = 0;
            }
            ms++;
            let timeStr = `${s}:${ms}`;
            h1.innerHTML = timeStr;
        }, 100)
    })
    // 停止
    stopBtn.addEventListener('click', () => {
        clearInterval(timer);
    })
    // 重置
    resetBtn.addEventListener('click', () => {
        s = 0;
        ms = 0;
    })
</script>

在这里插入图片描述

在这里插入图片描述

2. setTimeout 与 clearTimeout

语法:

// 设置定时器:
setTimeout(fn, seconds)
// 清除定时器:
clearTimeout(定时器名)

例 1 - 3 秒后跳转到百度。

setTimeout(() => {
  window.location.href = "https://www.baidu.com";
}, 3000);

例 2 - 点击暂停按钮,可以停止计时器。

let btn = document.querySelector('button');
// 定时器初始化:
let timer = null;
// 设置定时器:
timer = setTimeout(() => {
	console.log('hello world');
},2000)
btn.addEventListener('click', () => {
	// 清除定时器
	clearTimeout(timer);
}) ;

3. 防抖与节流

解决性能问题,开发中常会遇到。

  • 防抖:对于短时间内多次触发事件的情况,可以使用防抖停止事件持续触发;
  • 节流:防止短时间内多次触发事件的情况,但是间隔事件内,还是需要不断触发;

例如:window.onscroll 事件,input 输入搜索内容(当你一直输入的时候不会自动搜索内容,当你停止输入一会后才会自动搜索)。

3.1 防抖 (debounce)

多次触发事件时,它只执行事件的最后一次。

例如:鼠标滚轮滚动事件不会连续触发。

let timer = null;
window.onscroll = function() {
    if (timer !== null) {
        clearTimeout(timer);
    }
    timer = setTimeout(() => {
        console.log("hello world");
        timer = null;
    }, 1000);
}

3.2 节流(throttle)

多次触发事件时,每隔 x 秒会执行一次。

例如:鼠标滚轮滚动的事件按时间间隔触发。

let flag = true;
window.onscroll = function() {
    if (flag) {
        setTimeout(() => {
            console.log("hello world");
            flag = true;
        }, 1000)
    }
    flag = false;
}

3.3 防抖与节流的案例

下面有这样一个案例,鼠标滚轮滚动过程中,底部按钮出现,点击底部按钮,则会返回网页顶部。

body {
	height: 2000px;
	overflow: scroll;
}

.top {
	position: fixed;
	right: 100px;
	bottom: 100px;
	display: none;
}
...
<h1>hello world</h1>
<button class="top"></button>
let btn = document.querySelector('.top');
//  滚动条滚动
window.onscroll = () => {
	// 页面滚动位置距离顶部距离大于0 时,返回顶部按钮出现
	if (document.documentElement.scrollTop > 0) {
		btn.style.display = 'block';
	}else {
		btn.style.display = 'none';
	}
}
// 点击返回顶部按钮,让页面滚动条返回至顶部
btn.onclick = () => {
	// 让滚动条滚动到某个位置:window.scrollTo(x, y)
	window.scrollTo(0, 0);
}

页面初始化效果:
在这里插入图片描述
向下滚动后,按钮出现效果:
在这里插入图片描述
点击按钮,返回顶部后的效果:
在这里插入图片描述
现在功能已经完成了,但是我们发现性能似乎有些问题,我们在事件执行代码添加一句测试代码:

window.onscroll = () => {
if (document.documentElement.scrollTop > 0) {
	btn.style.display = 'block';
}else {
	btn.style.display = 'none';
}
// test code
console.log('计数器');
}

我们会发现随着鼠标滚轮的滚动,事件处理程序会一直不停的被触发:
在这里插入图片描述
这对我们的性能的影响是非常的大。

我们用 防抖 来优化下上述代码:

window.onscroll = () => {
	if (timer !== null) {
		clearTimeout(timer);
	}
	timer = setTimeout(() => {
		// 业务逻辑
		if (document.documentElement.scrollTop > 0) {
			btn.style.display = 'block';
		} else {
			btn.style.display = 'none';
        }
        console.log('计数器');
        
        timer = null;
	}, 1000)
}

在控制台上观察下效果:
在这里插入图片描述
功能虽然实现了,但是上面的代码把防抖的算法和真正事件的业务逻辑混到了一起,在项目开发中其实是非常不好的。
所以我们利用 闭包 来封装一下上述代码,把防抖算法和业务逻辑做区分:

// 利用闭包封装防抖算法:
// fn:真正事件的业务逻辑函数
function debounce(fn) {
	let timer = null;
	// 利用闭包返回要执行的函数
	function eventFun() {
		if (timer !== null) {
			clearTimeout(timer);
		}
        timer = setTimeout(() => {
        	fn()
            timer = null;
        }, 1000)
	}

	return eventFun;
}

window.onscroll = debounce(() => {
	if (document.documentElement.scrollTop > 0) {
		btn.style.display = 'block';
	} else {
		btn.style.display = 'none';
	}
	console.log('计数器');
})

如果使用 节流 来优化这个案例呢?

// 利用节流封装防抖算法:
function throttle(fn) {
	let flag = true;

	return function() {
		if (flag) {
        	setTimeout(() => {
				fn()
                flag = true;
            }, 1000)
        }
        flag = false;
	}
}

window.onscroll = throttle(() => {
	if (document.documentElement.scrollTop > 0) {
        btn.style.display = 'block';
	} else {
		btn.style.display = 'none';
	}
	console.log('计数器');
})

三、BOM

1. 基本概念

《JavaScript高级程序设计》这本书讲过:
JavaScript = ECMAScript + DOM + BOM

  • DOM:文档对象模型( document对象);
  • BOM: 浏览器对象模型。

2. BOM对象

  • window对象(全局对象);
  • screen对象包含有关用户屏幕的信息;
  • location对象用于获得当前页面的地址(URL),并把浏览器重定向到新的页面;
  • history对象包含浏览器的历史;
  • navigator对象包含有关访问者浏览器的信息;

3. window对象

window对象是全局对象,所有在浏览器可以直接使用的方法,都是window对象的方法。

  • 计时器方法;
  • 弹出框方法;

3.1 计时器方法

window.setTimeout(() => {
	console.log('hello world');
}, 1000)

3.2 弹出框方法

  • alert
  • prompt
  • confirm

注意:在开发应用当中,一般不使用系统自带的弹出框,移动端可能会被屏蔽。

window.alert('hello world')

在这里插入图片描述

let msg = prompt();
// 返回值是输入的内容
console.log(msg);

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

confirm('确认要删除该信息吗?')

在这里插入图片描述
例 1 - 猜数字

  1. 随机生成一个 1~100 的数字;
  2. 在 prompt 弹出框中猜数字;
  3. 提示【大于目标结果】【小于目标结果】【恭喜你回答正确】。
// 1. 随机生成一个1-100的数字
let num = Math.floor(Math.random() * 100 + 1);

// 2. 递归函数
function guess() {
	let guessNum = prompt('请输入你猜想的数字');
	if (guessNum < num) {
		confirm('小于目标结果')
        guess()
    } else if (guessNum > num) {
		confirm('大于目标结果')
        guess()
    } else if (guessNum == num) {
        confirm('恭喜你回答正确')
	}
}

guess();

例 2 - 水果列表删除提示功能

  • 制作一个水果列表;
  • 删除选中的水果;
  • 删除时,使用 confirm 提示是否确认删除。
let fruitList = document.querySelector('.fruit-list');
fruitList.addEventListener('click', (e) => {
	let flag = confirm('确定要删除嘛?');
	if (flag) {
    	fruitList.removeChild(e.target)
	}
})

4. location对象

  • location.href :属性返回当前页面的url,比如:https://www.baidu.com;
  • location.hostname:主机的域名,比如:www.baidu.com;
  • location.pathname :当前页面的路径和文件名,比如:/s;
  • location.port:端口,比如:8080;
  • location.protocol:协议,比如:https。

页面跳转: location.href = ‘http://baidu.com’

5. navigator对象

navigator.userAgent:检查当前设备,并在控制台输出。

判断手机品牌类型:

   function judgeBrand(sUserAgent) {
       var isIphone = sUserAgent.match(/iphone/i) == "iphone";
       var isHuawei = sUserAgent.match(/huawei/i) == "huawei";
       var isHonor = sUserAgent.match(/honor/i) == "honor";
       var isOppo = sUserAgent.match(/oppo/i) == "oppo";
       var isOppoR15 = sUserAgent.match(/pacm00/i) == "pacm00";
       var isVivo = sUserAgent.match(/vivo/i) == "vivo";
       var isXiaomi = sUserAgent.match(/mi\s/i) == "mi";
       var isXiaomi2s = sUserAgent.match(/mix\s/i) == "mix";
       var isRedmi = sUserAgent.match(/redmi/i) == "redmi";
       var isSamsung = sUserAgent.match(/sm-/i) == "sm-";

       if (isIphone) {
           return 'iphone';
       } else if (isHuawei || isHonor) {
           return 'huawei';
       } else if (isOppo || isOppoR15) {
           return 'oppo';
       } else if (isVivo) {
           return 'vivo';
       } else if (isXiaomi || isRedmi || isXiaomi2s) {
           return 'xiaomi';
       } else if (isSamsung) {
           return 'samsung';
       } else {
           return 'default';
       }
   }
   
   let brand = judgeBrand(navigator.userAgent.toLowerCase()); 
   console.log(brand)

四、原始类型与引用类型

1. JS数据类型

每种编程语言都具有内建的数据类型,根据使用数据的方式可以从两个不同的维度将语言进行分类。

1.1 动态/静态:

  • 动态类型:运行过程中需要检查数据类型;
  • 静态类型:使用之前就需要确认其变量数据类型。

1.2 强/弱:

  • 强类型:不支持隐式类型转换;
  • 弱类型:支持隐式类型转换。

隐式类型转换 : 在赋值过程中, 编译器会把 int 型的变量转换为 bool 型的变量,每个变量只不过是一个用于保存任意值的命名占位符。

2. 数据类型分类

2.1 六种数据类型:

数值 (Number)、字符串 (String)、布尔 (Boolean)、空 (Null)、未定义 (Undefined)、对象 (Object)。

数据类型分为 原始类型引用类型 两大类,除了对象以外其他五个基础数据类型都是原始类型

2.2 ECMAScript 有 8 种数据类型:

  • Undefined
  • Null
  • Boolean
  • String
  • Number
  • Symbol (ES6新增)
  • BigInt (ES2020新增)
  • Object (基本引用类型)

根据数据存储位置的不同,我们将JS数据类型分为两大类:

  • 基本数据类型 存放在栈内存中,类型1-7;
  • 复杂数据类型/引用类型 存放在堆内存中, 类型8。

注意: null 值表示一个空对象指针,所以针对 typeof null 会返回 object

console.log(typeof null);

在这里插入图片描述

3. 原始类型 与 引用类型

原始类型
数值 (Number)、字符串 (String)、布尔 (Boolean)、空 (Null)、未定义 (Undefined)。

引用类型
对象 (Object),其中包括 Array、Date、Math 等等。

3.1 原始类型与引用类型的区别

  • 赋值的区别 :原始类型赋的是值,引用类型赋的是引用;
  • 比较的区别 :原始类型比较的是值,引用类型比较的是是否指向同一个对象;
  • 传参的区别 :原始类型的传参不管怎样传都不会影响到外面的值的变化,引用类型的传参不管在内部还是外部,它指向都是同一个内存空间同一个对象。

3.2 原始类型与引用类型的类型检测

  • 原始数据类型检测:typeof(值)
    经常用来检测一个变量是不是最基本的数据类型
  • 引用数据类型检测:值 instanceof(类型)
    用来判断该数据是否为某个构造函数的 prototype,即属性所指向的对象是否存在于另外一个要检测对象的原型链上,简单地说就是判断一个引用类型的变量具体是不是某种类型的对象。

五、异步编程

1. 同步与异步

例子: 打电话与发短信。

同步编程:

console.log("给1打电话"); // 1
console.log("给2打电话"); // 2
console.log("给3打电话"); // 3
console.log("给4打电话"); // 4
console.log("给5打电话"); // 5

异步编程:

// 给4发短信 
// 给1发短信 
// 给2发短信 
// 给5发短信 
// 给3发短信 
setTimeout(() => {
    console.log("给1发短信");
}, 200);
setTimeout(() => {
    console.log("给2发短信");
}, 500);
setTimeout(() => {
    console.log("给3发短信");
}, 2000);
setTimeout(() => {
    console.log("给4发短信");
}, 100);
setTimeout(() => {
    console.log("给5发短信");
}, 900);

异步可以多条任务线去执行程序,一条任务卡顿不影响其他任务。

2. 异步获取数据的方法

AJAX 与服务器通信,异步获取数据。现阶段还没接触到 AJAX,试一下其他方法。 首先先声明 target ,假设只能通过 getData 来获取数据 target。

  • 方案 1:回调函数

先回顾一下回调函数。函数可以作为一个参数在传递到另一个函数中。setTimeout、防抖和节流经常用到。函数体在完成某种操作后由内向外调用某个外部函数。

function fun(fn) {
    fn();
}
fun(() => {
    console.log("我是回调函数") // 我是回调函数
});

回归本题:

let target = "hello world";

function getData() {
  // // 同步的写法
  // return target;

  // // 异步写法测试 这样写返回的undefined,因为return只能返回同步的数据
  // setTimeout(() => {
  //     return target
  // }, 500);

  // 通过回调函数输出hello world
  setTimeout(() => {
    fn(target);
  }, 500);
}

// getData()穿递的参数是fn(),然后fn()传递的参数是d,d就是target.
getData((d) => {
  console.log(d);  // hello world
}); 

为了解决 JS 的异步执行回调地狱问题,人们又发明了一些其他解决方案,比如说 Promises、Async functions 等等。

  • 方案 2:Promise 对象获取数据

Promise 是 ES2015 提供的一个内置对象,Promise 就是用来解决异步问题。

let target = "hello promise"
// 创建一个promise对象, resolve是一个函数
let p = new Promise((resolve) =>{
    setTimeout(() => {
        resolve(target); // 把target作为参数传递给resolve函数给传递出来,并把promise对象赋给p
    }, 500)
});

// 利用p获取target
// promise对象有个then方法,then方法有个参数是一个函数,这个函数里面有个形参,这个形参就是resolve方法传出来的值。
p.then((d)=> {
    console.log(d);
})

回归本题:

let target = "hello world";

// promise版本的getData,这里是Promise原理
function getData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(target);
        }, 500)
    });
}
let p = getData(); // getData()的返回值是一个Promise对象
p.then((data) => {
    console.log(data);
})

方案 3:async 函数

await 后面跟着是一个 Promise 对象 ,等待 promise 对象获取到返回值后才会进行下一个。
注意:await 要在 async 函数中用 才有用。

let target = "hello world";
function getData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(target);
        }, 500)
    });
}
async function fun() {
    let data = await getData(); // getData()的返回值是一个Promise对象
    console.log(data);
}

fun(); // hello world

3. 异步编程的解决方案

  • 回调函数
  • Promise
  • async 函数

总结

以上方案是从语法层面来分析解决异步的问题。 后续将会学习 Ajax,异步获取服务端数据,需要用到大量的异步编程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1491142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

吴恩达机器学习笔记:第5周-9 神经网络的学习1(Neural Networks: Learning)

目录 9.1 代价函数9.2 反向传播算法9.3 反向传播算法的直观理解 9.1 代价函数 首先引入一些便于稍后讨论的新标记方法&#xff1a; 假设神经网络的训练样本有&#x1d45a;个&#xff0c;每个包含一组输入&#x1d465;和一组输出信号&#x1d466;&#xff0c;&#x1d43f;…

【数据存储】大端存储||小端存储(超详细解析,小白一看就懂!!!)

目录 一、前言 二、什么是低地址、高地址 &#xff1f; 三、什么是数据的高位和低位 &#xff1f; 四、什么是大小端存储&#xff1f; &#x1f349; 小端存储详解 &#x1f352; 大端存储详解 五、为什么会有大小端存储&#xff1f; &#x1f34d;大端存储的优点 &#…

保护模式笔记九 中断门和IDT(中断描述符表)

段选择子&#xff1a; 先直观认识一下GDT和段选择子在逻辑地址转换为线性地址中的作用&#xff0c;例如&#xff1a; 给出逻辑地址&#xff1a;21h:12345678h&#xff0c;需要将其转换为线性地址 a. 选择子SEL21h0000000000100 0 01b&#xff0c;他代表的意思是&#xff1a…

H3C 路由过滤路由引入实验

H3C 路由过滤&路由引入实验 实验拓扑 ​​ 实验需求 按照图示配置 IP 地址&#xff0c;R1&#xff0c;R3&#xff0c;R4 上使用 loopback 口模拟业务网段R1 和 R2 运行 RIPv2&#xff0c;R2&#xff0c;R3 和 R4 运行 OSPF&#xff0c;各自协议内部互通在 RIP 和 OSPF …

OpenAI划时代大模型——文本生成视频模型Sora作品欣赏(十五)

Sora介绍 Sora是一个能以文本描述生成视频的人工智能模型&#xff0c;由美国人工智能研究机构OpenAI开发。 Sora这一名称源于日文“空”&#xff08;そら sora&#xff09;&#xff0c;即天空之意&#xff0c;以示其无限的创造潜力。其背后的技术是在OpenAI的文本到图像生成模…

Gemma模型一些细节讲解

Gemma模型报告中提到的几个点进行代码细节解读一下&#xff1a; &#xff08;1&#xff09;Embedding层共享参数 &#xff08;2&#xff09;输入输出层均进行RMSNorm Embedding层共享参数 共享embedding的权重给最后的llm_head层。是词嵌入层的共享&#xff0c;与旋转位置编码…

低密度奇偶校验码LDPC(七)——SPA和积译码算法的简化

往期博文 低密度奇偶校验码LDPC&#xff08;一&#xff09;——概述_什么是gallager构造-CSDN博客 低密度奇偶校验码LDPC&#xff08;二&#xff09;——LDPC编码方法-CSDN博客 低密度奇偶校验码LDPC&#xff08;三&#xff09;——QC-LDPC码概述-CSDN博客 低密度奇偶校验码…

CNAN知识图谱辅助推荐系统

CNAN知识图谱辅助推荐系统 文章介绍了一个基于KG的推荐系统模型&#xff0c;代码也已开源&#xff0c;可以看出主要follow了KGNN-LS 。算法流程大致如下&#xff1a; 1. 算法介绍 算法除去attention机制外&#xff0c;主要的思想在于&#xff1a;user由交互过的item来表示、i…

前端小案例——登录界面(正则验证, 附源码)

一、前言 实现功能&#xff1a; 提供用户名和密码输入框。当用户提交表单时&#xff0c;阻止默认提交行为。使用正则表达式验证用户输入的内容&#xff0c;判断输入的是有效的邮箱地址还是身份证号码。根据验证结果&#xff0c;在输入框下方显示相应的提示信息。 实现逻辑&a…

【C++庖丁解牛】初始化列表 | Static对象 | 友元函数

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1. 再谈构造函数1.1 …

mininet虚拟网络中的主机与宿主Ubuntu及因特网互通实现

环境: Win10(物理机),Vmware workstation ,Ubuntu(vm中的虚拟机),mininet 构建的虚拟网络环境说明: 在一win10的物理机中安装了vm平台,在vm中加载了一ubuntun系统,在改ubuntu系统中安装了mininet。 目标: 通过mininet 构建虚拟网络环境(使用python代码构建一个交换…

【开源】SpringBoot框架开发用户画像活动推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 兴趣标签模块2.3 活动档案模块2.4 活动报名模块2.5 活动留言模块 三、系统设计3.1 用例设计3.2 业务流程设计3.3 数据流程设计3.4 E-R图设计 四、系统展示五、核心代码5.1 查询兴趣标签5.2 查询活动推荐…

mysql 同一条排序语句查询出来的结果某几条没按照排序查询

1501这个机床order 1 2 3 1 2 3 1 2 3 1502这个机床order 2 3 1 2 3 1 2 3 1 原因是order存在一致的 第一个123 第二个也有123 所以存在随机情况 正常应该是123456 但是需求是123 123 所以再按照id重新排序一下 原sql :select bindType.id, bindType.process_num as…

大模型学习笔记五:RAG

文章目录 一、RAG介绍1)局限性2)通过检索增强生成二、RAG系统的基本搭建流程1)搭建流程简介2)文档的加载和切割3)检索引擎4)LLM接口封装5)prompt模板6)RAG Pipeline初探7)关键字检索局限性三、向量检索1)文本向量2)向量相似度计算3)向量数据库4)基于向量检索的RAG…

一本书讲透ChatGPT,实现从理论到实践的跨越!大模型技术工程师必读书籍【送书活动】

目录 前言一、内容简介二、作者简介三、专家推荐四、读者对象五、目录福利总结 前言 OpenAI 在 2022 年 11 月推出了人工智能聊天应用—ChatGPT。它具有广泛的应用场景&#xff0c;在多项专业和学术基准测试中表现出的智力水平&#xff0c;不仅接近甚至有时超越了人类的平均水平…

40个Python字符串实例

Python 字符串是 Python 编程语言中最常用的数据类型之一&#xff0c;它可以表示文本或一组字符。Python 中的字符串是不可变的序列&#xff0c;意味着一旦创建&#xff0c;其值就不能被修改。下面是一些关于 Python 字符串的介绍。 概述 创建字符串&#xff1a;可以使用单引…

HI3516DV300 HI3516DRBCV300 海思安防监控芯片

Hi3516D V300是专为行业专用智能高清网络摄像机设计的新一代SoC。引入新一代ISP、最新H.265视频压缩编码器、高性能NNIE引擎&#xff0c;使Hi3516D V300在低码率、高图像质量、智能处理分析、低功耗等方面领先业界。能量消耗。Hi3516D V300集成了POR、RTC、音频编解码器和待机唤…

AI大模型的预训练、迁移和中间件编程

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…

测试用例术语5.0

一、软件测试中术语 1.动态测试&#xff08;dynamic testing&#xff09;&#xff1a;通过运行软件的组件或 系统来测试软件 例如&#xff1a;一辆汽车发动并行使测试 2.静态测试&#xff08;static testing&#xff09;&#xff1a;对组件的规格说明书进行 评审&#xff0c…

Linux——自写一个简易的shell

目录 前言 一、打印提示信息 二、分割字符串 三、替换程序 前言 之前学习了很多进程相关的知识&#xff0c;包括环境变量、进程的创建与退出、进程等待、进程替换。现在可以用所学的作一个小总结&#xff0c;手撕一个shell解释器&#xff0c;大致的思路是先通过环境变量获…