BOM
浏览器对象模型. 把浏览器当成一个对象来看待. 用于和浏览器窗口进行交互.
例如: 后退页面, 刷新页面, 修改窗口大小等.
注意:
BOM 是缺乏标准的.
JS 有 ECMA 标准, DOM 有 W3C 标准. 而 BOM 取决于各个浏览器具体的实现.
BOM 比 DOM 更大.
Window 对象
基本概念
window 是 BOM 中的顶层节点对象.
document 其实是 window 对象中的一个属性. 也可以写作
window.document
.
window 在我们开发中有两层用途:
作为 js 代码和浏览器交互的接口.
作为 js 代码的全局命名空间. 所谓的 "全局变量" 其实就是 window 的一个属性.
a = 10;console.log(window.a);function hello() { alert('hello');}window.hello();
平时是用这些变量和函数的时候可以省略 window.
像 alert 等函数其实都是 window 的方法.
窗口加载事件
如果把 script 标签写到页面结构上面, 则无法正确获取到对应的元素.
因为浏览器会从上到下解析 html 的结构. 执行到 document.querySelector('button') 时浏览器还没有读取到
button 标签, 此时是无法获取到 button 对象的.
<script> var button = document.querySelector('button'); button.onclick = function () { alert('hello'); }script><button>点我一下button>
为了解决这个问题, 就可以使用 load 事件
load 事件, 会在页面完全加载完毕时触发.
<script> window.onload = function () { var button = document.querySelector('button'); button.onclick = function () { alert('hello'); } } // 或者使用 window.addEventListener('load', function () { var button = document.querySelector('button'); button.onclick = function () { alert('hello'); } });script><button>点我一下button>
DOMContentLoaded 事件, 会在页面 DOM 加载完就执行, 不必等待 CSS, 图片等其他资源加载. (IE9以上支持)
<script> window.addEventListener('DOMContentLoaded', function () { var button = document.querySelector('button'); button.onclick = function () { alert('hello'); } });script><button>点我一下button>
注意, 这种方式只能使用 addEventListener, 不能使用
onDOMContentLoaded
的方式进行.
pageshow 事件. 和 load 事件基本类似. 但是在 firefox 上, 浏览器会缓存前进后退的页面, 此时前进后退时不会触发 load 事件, 但是能触发 pageshow 事件.
调整窗口大小事件
resize 事件会在窗口大小发生变化时触发.
window.innerWidth/window.innerHeight 来获取到当前屏幕的尺寸.
<script> window.onresize = function() { console.log(window.innerWidth, window.innerHeight); }script>
基于这种方式可以实现响应式布局.
"响应式布局" 指的是根据屏幕的尺寸决定页面的排列方式.
比如是 PC 端, 屏幕比较宽, 就可以横版排列. 如果是手机端, 屏幕比较窄, 就可以竖版排列.
<div> 我是一个区域div><style> div { background-color: red; height: 300px; }style><script> window.onresize = function () { var div = document.querySelector('div'); if (window.innerWidth >= 1000) { div.style.width = '600px'; } else { div.style.width = '300px'; } }script>
定时器
相当于一个闹钟. 设定一定的时间之后, 触发对应的函数.
setTimeout
var timeoutID = window.setTimeout(function[, delay]);var timeoutID = window.setTimeout(function[, delay, arg1, arg2, ...]);
delay 的单位为 ms. 可以省略. 省略则默认值为 0. (立刻执行)
arg1, arg2, ... 是给 function 传递的参数. (低于IE9不支持)
返回值是该定时器的标识符(就是个名字), 用来区分多个定时器.
<script> var timer = window.setTimeout(function () { alert('hello'); }, 5000);script>
代码示例: 3s 钟后关闭广告界面
此处的广告直接使用一张图片表示了.
clearTimeout
用于停止 setTimeout 定时器.
window.clearTimeout(timeoutID);
参数就是 setTimeout 的返回值.
停止定时器
setInterval
var intervalID = scope.setInterval(func, delay, [arg1, arg2, ...]);
delay 的单位为 ms. 可以省略. 省略则默认值为 0. (立刻执行)
arg1, arg2, ... 是给 function 传递的参数. (低于IE9不支持)
返回值是该定时器的标识符(就是个名字), 用来区分多个定时器.
用法和 setTimeout 非常相似.
区别: setInterval 是每隔 delay 时间都会执行一次(周期性执行), 而 setTimeout 只执行一次.
可以看到每隔一秒打印一次 hehe 的值.
代码示例: 3秒钟后关闭广告, 关闭过程中显示一个倒计时.
还剩 3 秒自动关闭广告
注意, 这里一定要先给 div 中设置好初始值, setInterval 的第一次执行要等 delay 时间到才会触发.
clearInterval
停止计数
this 的指向问题
this 始终指向调用函数的对象.
1) 如果是一个全局函数或者是注册到定时器中的函数, this 指向 window
function hello() {
console.log(this);
}
hello();
setTimeout(hello, 500);
2) 如果函数是一个方法, 则指向该方法所属对象
function hello() {
console.log(this);
}
var obj = {
name: '张三',
say: hello
}
obj.say();
形如
btn.addEventListener('click', fn)
这样的代码, 其实就相当于是给 btn 增加了方法 fn.所以 fn 内部的 this 就指向 btn 对象.
3) 如果是构造函数, 则 this 指向被新创建出的实例.
function Cat() {
this.name = '小黑';
this.type = '中华田园';
this.miao = function () {
alert('喵');
}
console.log(this);
}
var cat = new Cat();
同步和异步
一个代码
console.log('1');
setTimeout(function () {
console.log('2');
}, 0);
console.log('3');
// 执行结果
1
3
2
虽然 setTimeout 的第二个参数是 0, 但是仍然在 console.log('3'); 之后执行的.
同步任务和异步任务
同步任务都在主线程上执行.
异步任务是通过回调函数的方式执行的.
异步任务的类型:
普通事件: click, mousemove等
资源加载: load, DOMContentLoaded等
定时器: setTimeout, setInterval
异步任务会放到一个任务队列中.
JS 执行时会先把所有的同步任务都执行完, 然后再检查异步任务是否可以执行.
此时我们发现, while 是一个死循环, 这个死循环导致页面无法正常加载, 也就更无法响应点击事件.
事件循环
JS 是一个只能单线程执行的语言. 使用事件循环的机制实现了异步任务.
理解事件循环的过程
1) 关键要素:
主线程: 执行同步任务的线程. 当遇到异步任务时, 则把异步任务交给异步处理进程.
异步处理进程: 用来管理异步任务, 判断该异步任务是否已经到了可以执行的时机. 如果时机成熟, 则放到回调队列中执行.
回调队列/消息队列: 放置待执行的回调函数的队列. 主线程在完成自己已有的同步任务之后, 就会从回调队列中取异步任务来执行.
2) 类比:
主线程可以想象成是一个高速公路, 上面跑过的一辆一辆车, 就是执行的一个一个任务.
如果发生了交通事故, 那么相关车辆就不能立刻往下跑了, 而应该要进入应急车道, 同时通知 110 来处理(110 就是异步处理进程)
110 来事故现场定责, 处理完毕后, 警察会判定哪个车可以继续跑, 哪个车要被暂时扣下. 警察说 "张三你的车可以走了", 就相当于把该任务放到回调队列中. 张三真的把车开走的时候, 就相当于通过主线程来从回调队列中取了一个任务继续执行(还是要通过公路往前走)
另外可以参考知乎帖子: "男朋友的大脑是单线程的怎么办"
参考 https://www.zhihu.com/question/358389988
location 对象
location 的属性
是 window 对象的一个重要属性. 用来获取或者设置当前页面的 url.
url 就是网址. 格式形如:
location 对象的主要属性也就是围绕着 url 的结构来展开的.
Location.href
包含整个URL的一个DOMString
Location.protocol
包含URL对应协议的一个DOMString
,最后有一个":"。Location.host
包含了域名的一个DOMString
,可能在该串最后带有一个":"并跟上URL的端口号。Location.hostname
包含URL域名的一个DOMString
。Location.port
包含端口号的一个DOMString
。Location.pathname
包含URL中路径部分的一个DOMString
,开头有一个“/"。
Location.search
包含URL参数的一个DOMString
,开头有一个“?”
。Location.hash
包含块标识符的DOMString
,开头有一个“#”。
Location.username
包含URL中域名前的用户名的一个DOMString
。Location.password
包含URL域名前的密码的一个DOMString
。Location.origin
只读包含页面来源的域名的标准形式DOMString
。
这些属性中我们重点关注 href 和 search
console.log(window.location);
代码示例: 点击跳转到其他页面(不使用 a 标签)
点我跳转
代码示例: 5秒后跳转到其他页面
5 秒后跳转
注意: 通过 location.href 的方式进行跳转没有历史记录, 不能使用后退功能.
location 的方法
assign: 跳转到一个新的链接. 带有历史记录.
replace: 替换当前页面. 相当于 location.href.
reload: 刷新页面(F5). 参数为 true , 则相当于强制刷新 (ctrl+F5)
访问服务器的时候很多资源会被缓存在浏览器. 强制刷新就是不使用缓存, 强行去服务器重新获取数据. ```
点我使用 assign点我使用 replace点我使用 reload
navigator 对象
表示浏览器的对象. 包含了一些浏览器的信息.
navigator 的属性
userAgent: 包含了浏览器版本和操作系统版本.
console.log(navigator.userAgent);
// 结果
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
基于这个字段可以判定当前用户是 PC 端还是移动端.
function IsPC(){
var userAgentInfo = navigator.userAgent;
var Agents = new Array("Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod");
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) { flag = false; break; }
}
return flag;
}
history 对象
foward(): 前进
back(): 后退
go(): 参数为 1 表示前进一步. 参数为 -1 表示后退一步.
demo.html
demo2前进
demo2.html
后退
本地存储
数据存储在浏览器中.
sessionStorage
容量: 5M
按照键值对的方式来使用. (key 和 value 都只能是字符串).
生命周期为关闭浏览器窗口: 关闭浏览器页面数据就没了. 刷新页面不丢失.
基本操作:
setItem: 如果 key 不存在就创建新的. 存在就修改对应的 value
getItem: 按照 key 来找 value
removeItem: 按照 key 来删除
clearItem: 删除所有 key.
插入获取删除清空
localStorage
容量: 20M
按照键值对的方式来使用. (key 和 value 都只能是字符串).
生命周期为永久生效.
同一个浏览器中的多个窗口之间可以共享.
基本操作(和 sessionStorage 一致):
setItem: 如果 key 不存在就创建新的. 存在就修改对应的 value
getItem: 按照 key 来找 value
removeItem: 按照 key 来删除
clearItem: 删除所有 key.
<input type="text" id="key"><input type="text" id="value"><button id="set">插入button><button id="get">获取button><button id="remove">删除button><button id="clear">清空button><script> var k = document.querySelector('#key'); var v = document.querySelector('#value'); var setBtn = document.querySelector('#set'); setBtn.addEventListener('click', function () { localStorage.setItem(k.value, v.value); }); var getBtn = document.querySelector('#get'); getBtn.addEventListener('click', function () { var value = localStorage.getItem(k.value); console.log(value); }); var removeBtn = document.querySelector('#remove'); removeBtn.addEventListener('click', function () { localStorage.removeItem(k.value); }); var clearBtn = document.querySelector('#clear'); clearBtn.addEventListener('click', function () { localStorage.clear(); });script>
注意: 所有页面都共用 localStorage , 这就意味着容易和其他的网页的存储数据冲突. 尤其谨慎使用 clear 方法.