目录
一、BOM简介
BOM
– 浏览器对象模型
– BOM为我们提供了一组对象,通过这组对象可以完成对浏览器的各种操作
– BOM对象:
– Window —— 代表浏览器窗口(全局对象)
– Navigator —— 浏览器对象(可以用来识别浏览器,如火狐、IE)
– Location —— 浏览器的地址栏信息
– History —— 浏览器的历史记录(控制浏览器的前进后退)
– Screen —— 用户屏幕的信息
– BOM对象都是作为 window 对象的属性保存的,所以可以直接在JS中访问这些对象
<script>
console.log(history);//访问history对象
console.log(navigator);//访问navigator对象
</script>
二、Navigator
Navigator —— 浏览器对象(可以用来识别浏览器,如火狐、IE)
Navigator 的属性和方法特别多,如果有需要可以去查看文档
https://developer.mozilla.org/en-US/docs/Web/API/Navigator
如 Navigator.language 用来读取用户浏览器页面的语言信息
Navigator.userAgent属性 返回一个用来描述浏览器信息的字符串
通过该字符串可以检查出使用的浏览器
<script>
// 文档中的例子
function getBrowserName(userAgent) {
// The order matters here, and this may report false positives for unlisted browsers.
if (userAgent.includes("Firefox")) {
// "Mozilla/5.0 (X11; Linux i686; rv:104.0) Gecko/20100101 Firefox/104.0"
return "Mozilla Firefox";
} else if (userAgent.includes("SamsungBrowser")) {
// "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36"
return "Samsung Internet";
} else if (userAgent.includes("Opera") || userAgent.includes("OPR")) {
// "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_5_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36 OPR/90.0.4480.54"
return "Opera";
} else if (userAgent.includes("Trident")) {
// "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)"
return "Microsoft Internet Explorer";
} else if (userAgent.includes("Edge")) {
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"
return "Microsoft Edge (Legacy)";
} else if (userAgent.includes("Edg")) {
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36 Edg/104.0.1293.70"
return "Microsoft Edge (Chromium)";
} else if (userAgent.includes("Chrome")) {
// "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
return "Google Chrome or Chromium";
} else if (userAgent.includes("Safari")) {
// "Mozilla/5.0 (iPhone; CPU iPhone OS 15_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Mobile/15E148 Safari/604.1"
return "Apple Safari";
} else {
return "unknown";
}
}
const browserName = getBrowserName(navigator.userAgent);
console.log(`You are using: ${browserName}`);
</script>
三、Location
Location 表示的是浏览器的地址栏信息
– 可以直接将location 的值修改为一个新的地址,这样会使网页发生跳转
– location.assign( ) 跳转到一个新的地址
– location.replace( ) 使用新地址替换原地址(无法通过回退按钮回退)
– location.reload( ) 刷新页面,刷新页面,可以传递一个true,来强制清缓存刷新
– location.href 可以获取当前的地址
<body>
<button id="btn">点我一下</button>
<form action="#">
<input type="text" name="username" >
</form>
<!-- 在网页的在表单中输入数据时,在IE浏览器中点击刷新或使用location.reload()时,数据会消失,
但在火狐浏览器中,不会消失,因为火狐浏览器会缓存输入的数据,
若我们不想要这个缓存数据,可以在location.reload()中传入true ,表示强制清空缓存数据 -->
<script>
const btn = document.getElementById("btn")
btn.addEventListener("click",()=>{
console.log(location);
// location = "https://www.baidu.com"//将location 的值修改为一个新的地址,这样会使网页发生跳转
console.log(location.href); // http://127.0.0.1:5500/html/index.html#
// location.assign("https://www.baidu.com")//assign()方法也可以使地址发生跳转
// location.replace("https://www.baidu.com")//assign()方法也可以使地址发生跳转
location.reload(true)//刷新页面
})
</script>
</body>
四、History
History 浏览器的历史记录(控制浏览器的前进后退)
– history.back( ) 回退按钮
– history.forward( ) 前进按钮
– history.go( ) 可以向前跳转也可以向后跳转
当传入的参数为1时,等价于history.forward(),传入2时,表示前进2个…
当传入的参数为-1时,等价于history.back(),传入-2时,表示后退2个…
<body>
<button id="btn">点我一下</button>
<script>
const btn = document.getElementById("btn")
btn.onclick = function(){
// console.log(history.length);
// history.back()
history.forward()
}
</script>
</body>
五、定时器
通过定时器,可以使代码在指定时间之后执行
– 设置定时器的方式有两种:
setTimeout( )(只会执行一次)
– 参数:
1. 回调函数(要执行的代码)
2. 间隔的时间(单位为毫秒)
– 返回:timeoutID是一个正整数值,它标识调用setTimeout()创建的计时器
– 关闭定时器
clearTimeout( timeoutID )
setInterval( )(每间隔一段时间代码就会执行一次)
– 参数:
1. 回调函数(要执行的代码)
2. 间隔的时间(单位为毫秒)
– 返回:timeoutID是一个正整数值,它标识调用setInterval()创建的计时器
– 关闭定时器
clearInterval( timeoutID ) ,在关闭定时器时可以加上条件
在应用中,setTimeout( ) 使用得更多
<body>
<h1 id="num"></h1>
<script>
// 设置接收计时器返回的timeoutID
// const timer = setTimeout(()=>{
// alert("我是定时器中的代码")
// },3000)
// clearTimeout(timer)
let num = 0
const numH1 = document.getElementById("num")
const timer1 = setInterval(()=>{
num++
numH1.textContent = num
// 在关闭定时器时可以加上条件
if(num === 20){
clearInterval(timer1)
}
},1000)
</script>
</body>
六、调用栈(调用堆栈)
事件循环(event loop)
– 函数在每次执行时,都会产生一个执行环境
– 执行环境负责存储函数执行时产生的一切数据(如局部变量、this等)
– 问题:函数的执行环境要存储到哪里?
– 函数的执行环境存储到了一个叫做调用栈的地方
– 栈,是一种数据结构,特点:后进先出
调用栈(call stack)
– 调用栈负责存储函数的执行环境
– 当一个函数被调用时,它的执行环境会作为一个栈帧插入到调用栈的栈顶
函数执行完毕其栈帧会自动从栈中弹出
调用栈(调用堆栈)放的都是正在执行的代码的函数
<script>
function fn(){
let a = 10
let b = 20
function fn2(){
console.log("fn2");
}
fn2()
console.log("fn");
}
fn()
console.log(123);
</script>
七、消息队列
队列,也是一种数据结构,特点: 先进先出
消息队列
– 消息队列负责存储将要执行的函数
– 当我们触发一个事件时,其响应函数并不是直接就添加到调用栈中的
因为调用栈中有可能会存在一些还没有执行完的代码
– 事件触发后,JS引擎是将事件响应函数插入到消息队列中排队
<body>
<button id="btn">点我一下</button>
<button id="btn02">点我一下2</button>
<script>
function fn(){
let a = 10
let b = 20
function fn2(){
console.log("fn2");
}
fn2()
console.log("fn");
}
fn()
console.log(123);
const btn = document.getElementById("btn")
const btn02 = document.getElementById("btn02")
btn.onclick = function (){
alert(1111)
const begin = Date.now()
while(Date.now() - begin < 5000){}//会使点击按钮后出现alert,点击确定后停 5 秒之后再执行之后的
// 因此,会导致点击按钮出现alert,确定后,点击按钮2,并不会立即执行,会过几秒再出来
}
btn02.onclick = function (){
alert(2222)
}
</script>
</body>
八、定时器的本质
定时器的本质,就是在指定时间后将函数添加到消息队列中
使用concole.time( ) 和 concole.timeEnd( ) 来计算一段代码的执行时间
<script>
console.time()
setTimeout(function(){
console.timeEnd()//输出数为6 秒多,因为定时器的本质,就是在指定时间后将函数添加到消息队列中
// 我们在3秒后将该函数加入到消息队列中,但后面有一个循环使程序停了6 秒(全局)
// 也就是要至少6 秒后才能进入调用栈中执行函数
console.log("定时器执行了~~");
},3000)
// 使程序停止6 秒
const begin = Date.now()
while(Date.now() - begin < 6000){
}
</script>
setInterval( ) 每间隔一段时间就将函数添加到消息队列中,
但是如果函数执行的速度比较慢,它是无法确保每次执行的间隔都是一样的
<script>
console.time("间隔")
setInterval(function(){
console.timeEnd("间隔")
// console.log("定时器执行了");
alert("定时器执行了")
console.time("间隔")
},3000)//每隔3 秒将其放到消息队列中
// 假设该回调函数的代码执行时间较长,如6秒,并不是每隔3秒执行一次,
// 而是每隔3秒将其放到消息队列中,待调用栈空了之后,依次执行
</script>
希望可以确保函数每次执行都有相同间隔
<script>
console.time("间隔")
setTimeout(function fn(){
console.timeEnd("间隔")
// console.log("函数执行了~~");
alert("函数执行了~~");
console.time("间隔")
// 在setTimeout的回调函数的最后,再调用一个setTimeout
setTimeout(fn,3000)
},3000)
</script>
<script>
setTimeout(()=>{
console.log(1111);
},0)
console.log(2222);
// 2222先出来,因为setTimeout为0表示立即将其添加到消息队列中,
// 要等调用栈空出来后才能执行消息队列里的函数,而2222是在直接调用栈中
// 上面代码打印为
// 2222
// 1111
</script>