手动:prefetch preload
<link rel="prefetch" href="next.html">
<link rel="preload" as="style" href="styles.css">
<link rel="preload" as="javascript" href="1.js">
会尽早加载但不会过早执行script
自动:浏览器自身的智能预测和预先加载下一页内容的功能。浏览器内部策略决定。
动态加载脚本
通过script标签实现
缺点:对浏览器预加载器是不可见的
下载图片并不一定要将image添加到dom中,只要添加了src就会下载。
下载Js需要添加src,并添加到dom中。
load:整个页面的所有资源已完成加载后触发。
DOMContentLoaded:HTML文档被完全加载和解析完成时触发,不用等样式表、img、js、其他资源加载完毕。在load之前触发。
1.跟踪属性的访问,设置get set函数,来跟踪什么时候去获取属性,什么时候设置属性,并进行拦截
2.隐藏属性,在get set函数中进行判断,来隐藏属性,外部不能访问这些属性
3.属性验证,在get set函数中,set时进行属性验证,来决定是否允许还是拒绝赋值
4.函数参数与构造函数参数的验证
在apply中,判断arguments参数的类型
在construct中,判断arguments参数的类型
5.数据绑定与可观察对象
在construct中,将所有的proxy对象添加到list集合中,再把集合通过new Proxy中的set函数,来进行事件绑定程序
代理是object的透明抽象层,代理的反射Reflect的api,封装了拦截的相对应的方法
const target = {
foo: "bar",
};
const handler = {
//定义一个get捕获器,在获取属性和Object.create时候会调用,在代理对象上执行操作时才会调用,在目标对象上执行操作是正常行为
get() {
return "handler";
},
};
const proxy = new Proxy(target, handler);
console.log(target.foo);
console.log(proxy.foo);
console.log(Object.create(target)['foo']);
console.log(Object.create(proxy)['foo']);
const target = {
foo:'bar'
}
const handler = {
//get捕获器的参数get(target,property[,receiver])
get(trapTarget,property,receiver){
console.log(trapTarget===target);
console.log(property);
console.log(receiver===proxy);
return trapTarget[property];
}
}
const proxy = new Proxy(target,handler);
console.log(target.foo);
console.log(proxy.foo);
const target = {
foo:'bar'
}
const handler = {
//get捕获器的参数get(target,property[,receiver])
// get(trapTarget,property,receiver){
// return Reflect.get(...arguments)
// }
//简洁的写法
get:Reflect.get
}
const proxy = new Proxy(target,handler);
//捕获所有方法,利用Reflect转发给对应反射API的空代理来实现
const proxy1 = new Proxy(target,Reflect);
console.log(target.foo);
console.log(proxy1.foo);
console.log(proxy.foo);
const target = {
foo:'bar',
baz:'121212'
}
const handler = {
//get捕获器的参数get(target,property[,receiver])
get(trapTarget,property,receiver){
let decoration = '';
if(property==='foo'){
decoration='!!!';
}
return Reflect.get(...arguments)+decoration;//获取foo和baz属性时,显示的结果不一样
}
}
const proxy = new Proxy(target,handler);
console.log(target.foo);
console.log(proxy.foo);
console.log(target.baz);
console.log(proxy.baz);
target的属性不可配置时,在捕获器中去修改属性会报错
const target = {};
Object.defineProperty(target,'foo',{
configurable:false,
writable:false,
value:'bar'
})
const handler = {
get(){
return 'quz'
}
}
const proxy = new Proxy(target,handler);
console.log(proxy.a);
// console.log(proxy.foo);
const target = {
foo:'bar'
}
const handler = {
get(){
return 'inter'
}
}
const {proxy,revoke} = Proxy.revocable(target,handler);// 撤销函数和代理对象是在实例化的时候同时产生的
console.log(proxy.foo);
revoke();//撤销后,Proxy与target之间的管理取消,而且不可恢复
console.log(proxy.foo);
const target = {
foo: "bar",
};
const firstProxy = new Proxy(target,{
get(){
console.log('first proxy');
return Reflect.get(...arguments);
}
})
const secondProxy = new Proxy(firstProxy,{
get(){
console.log('second proxy');
return Reflect.get(...arguments);q
}
})
console.log(secondProxy.foo);
const target = {
thisValEqualsProxy() {
return this === proxy;
},
};
const proxy = new Proxy(target, {});
console.log(target.thisValEqualsProxy());//false
console.log(proxy.thisValEqualsProxy());//true
const target = new Date();
const proxy = new Proxy(target,{});
console.log(target instanceof Date);
target.getDate();
console.log(proxy instanceof Date);
proxy.getDate();//报错
获取query参数
let getQueryStringArgs = function () {
//?a=1&b=2
let location = {};
location.search = "?a=1&b=2";
let qs = location.search.length > 0 ? location.search.substring(1) : "";
let args = {};
//[a=1,b=2]
qs.split("&")
.map((item) => item.split("="))
.map((item) => {
let name = decodeURIComponent(item[0]),
value = decodeURIComponent(item[1]);
name.length > 0 ? (args[name] = value) : "";
});
console.log(args);
return args;
};
let res = getQueryStringArgs();
console.log(res.c);
encodeURL对整个url进行编码,但是会保留某些字符不变,不会对=&编码,适用于整个URL编码
更严格的编码,会编码所有非字母数字符号,确保所有引起解析问题的字符都被正确编码,适用于URL的各个部分编码
let url = 'https://example.com/path?name=John Doe&age=30';
console.log(encodeURI(url));
console.log(encodeURIComponent(url));
let name = encodeURIComponent('j A');
let age = encodeURIComponent(30);
let query = `name=${name}&age=${age}`;
console.log(query);
const s= new URLSearchParams('?a=1&b=2');
console.log(s.get('a'));
s.set('c',3);
console.log(s.has('a'))
s.delete('a');
history.pushState() history.replaceState() popstate事件
是W3C制定的一系列接口和协议,用于标识XML或HTML文档的结构,允许开发者通过js等脚本语言动态访问和操作网页内容
document:根节点
元素:html文档元素,为根节点的唯一子节点
DOM中有12种节点类型,这些类型都继承一种基本类型
Node.ElEMENT_NODE(1)
someNode.nodeType==Node.ELEMENT_NODE
1. nodeName与nodeValue属性
2. 节点关系:每个节点都有childNodes属性,为一个NodeList的实例,是一个实时的活动对象。一个节点不会在文档中有两个位置。
length,hasChildNodes(),firstChild,lastChild,previousSibling,nextSibling,patentNode
3.操作节点:appendChild(),insertBefore(),replaceChild(),removeChild(),cloneNode(false/true表示深复制还是浅复制)
document.documentElement //html
document.body //body
document.doctype //doctype
文档信息 document.title
document.URL
document.domain
document.referrer
定位元素 document.getElementById()
document.getElementByTagName()
document.getElementByTagName('div')['value']即为document.getElementByTagName('div').namedItem('value')
document.getElementByTagName('*')
document.getElementsByName()
文档写入 document.write() //在window.onload之后write则会覆盖全Html
document.writeIn()
document.open()
document.close()
3. Element类型
```javascript
div.nodeType //1
div.tagName==div.nodeName//true
div.id
div.title
div.className
div.dataset
div.getAttribute('class')//getAttribute用于取得自定义属性的值
div.getAttribute('id')
div.getAttribute('title')
div.getAttribute('xx')
div.setAttribute(key,value)//设置属性
div.abcd=value//通过此种方法设置的属性无法通过getAttribute获取
div.removeAttribute(key)
div.attributes//是一个NamedNodeMap实例
div.attributes.getNamedItem(name)
div.attributes.removeNamedItem(name)
div.attributes.setNamedItem(node)
div.attributes.getNamedItem('id').nodeValue//返回的是id的值
div.attributes['id'].nodeValue//返回的是id的值
div.attributes['title'].nodeValue='1'//设置title的值为1
document.createElement('div')
element.childNodes
```
4. Text类型
```javascript
div.nodeType //3
div.appendData(text)
div.insertData(offset,text)
div.deleteData(offset,count)
div.replaceDate(offset,count,text)
div.splitText(offset)
div.substringData(offset,count)
div.length
document.createTextNode(text)
element.normalize()//规范化文本节点,即合并两个相邻文本节点
```
5. Comment类型
```javascript
div.nodeType //8
div.data//为注释的文字
document.createComment('这是注释')
```
6. CDATASection类型
7. DocumentType类型
```javascript
div.nodeType //10
document.doctype//
document.doctype.name//html
```
8. DocumentFragment类型
```javascript
div.nodeType //11
document.createDocumentFragment()
```
9. Attr类型
```javascript
div.nodeType //2
let attr = document.createAttribute('align')
attr.value="left"
element.setAttributeNode(attr)
element.attributes['align'].value//left
element.getAttributeNode('align').value//left
element.getAttribute('align')//left
//推荐使用getAttribute() removeAttribute() setAttribute()来操作属性
```
document.createElement('script')
document.createElement('link')
NodeList是基于DOM文档的实时查询,使用时需缓存NodeList let observer = new MutationObserver(()=>console.log('change'))
observer.observe(document.body,{attributes:true})
回调与MutationRecordlet observer = new MutationObserver((mutationRecords,mutationObserver)=>console.log(mutationRecords,mutationObserver));
observer.disconnect()//提前终止执行回调,一刀切。终止后可重新关联
observer.observe(childA,{attributes:true});
observer.observe(childB,{attributes:true});//observer可复用
let observer = new MutationObserver((mutationRecords, mutationObserver) => {
console.log(mutationRecords, mutationObserver);
});
observer.observe(document.body,{
attributes:true
});
document.body.className='a';
document.body.className='b';
document.body.className='c';
console.log(observer.takeRecords());//返回所有的MutationRecords实例,并清空 记录队列
//observer.takeRecords();//希望断开与目标对象的联系,但又希望处理由于调用disconnect()而被抛弃的记录队列中的MutationRecord实例
console.log(observer.takeRecords());