浏览器的核心主要是:渲染引擎和JavaScript解释器(又称 JavaScript 引擎)
window 对象 => window 指当前的浏览器窗口。也是当前页面的顶层对象。
Navigator 对象
Navigator.userAgent - 返回浏览器的User Agent 字符串 表示用户设备信息,包含了浏览器的厂商、版本、操作系统(通常用来使用判断手机浏览器是否是ios系统和android系统)
Screen 对象 => 当前窗口所在的屏幕,提供显示设备的信息 window.screen 属性指向这个对象
Cookie => 服务器保存在浏览器的一小段文本信息。
AJAX =>
- 创建XMLHttpRequest
- 发出HTTP请求
- 接受服务器传回的数据
- 更新网页数据
AJAX 只能向同源网址(协议、域名、端口都相同)发出 HTTP 请求,如果发出跨域请求,就会报错
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
// 通信成功时,状态值为4
if (xhr.readyState === 4){
if (xhr.status === 200){
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.open('GET', '/endpoint', true);
xhr.send(null);
XMLHttpRequest.responseType 表示服务器返回数据的类型
- "" (空字符串):等同于 text ,表示服务器返回文本数据
- "arraybuffer" : ArrayBuffer对象,表示服务器返回二进制数组
- "blob" : Blob 对象,表示服务器返回二进制对象
- "document" : Document 对象,表示服务器返回一个文档对象
- "json" : JSON 对象
- "text" : 字符串
XMLHttpRequest.status 表示服务器回应的HTTP状态码
- 200,ok,访问正常
- 301,Moved Permanently,永久移动
- 302,Moved temporarily,暂时移动
- 304,Not Modified,未修改
- 307,Temporary Redirect,暂时重定向
- 401,Unauthorized,未授权
- 403,Forbidden,禁止访问
- 404,Not Found,未发现指定网址
- 500,Internal Server Error,服务器发生错误
XMLHttpRequest.timeout 表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。
同源限制 => 为了保证用户信息的安全,防止恶意的网站窃取数据
- 协议相同
- 域名相同
- 端口相同 限制行为:
- 无法读取非同源网页的Cookie、LocalStorage和IndexedDB
- 无法接触非同源网页的DOM
- 无法向非同源地址发送AJAX 请求(可以发送,但浏览器会拒绝接受响应) 解决跨域的方法
- Cookie 浏览器允许通过 document.domain 共享 Cookie。只要设置相同的 document.domain ,两个网页就可以共享 Cookie (只适用于一级域名相同,次级域名不同的Cookie和iframe窗口)
- iframe和多窗口通信
- 片段识别符 指 URL 的 # 号后面的部分。父窗口可以把信息写入子窗口的片段标识符(子窗口通过监听 hashchange 事件得到通知)
- 跨文档通信API postMessage()
// 父窗口打开一个子窗口 var popup = window.open('http://bbb.com', 'title'); // 父窗口向子窗口发消息 popup.postMessage('Hello World!', 'http://bbb.com'); // 子窗口向父窗口发消息 window.opener.postMessage('Nice to see you', 'http://aaa.com'); // 父窗口和子窗口都可以用下面的代码, // 监听 message 消息 window.addEventListener('message', function (e) { console.log(e.data); },false);
- AJAX
-
JSONP - 服务器与客户端跨源通信的常用方法(简单易用,没有兼容性问题)-只能发GET请求
function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.src = src; document.body.appendChild(script); }//动态插入<script>元素 window.onload = function () { addScriptTag('http://example.com/ip?callback=foo'); }//向跨域网址(example.com)发出请求 注意,该请求的查询字符串有一个 callback 参数 用来指定回调函数的名字(必需) //浏览器定义了foo函数,就会立即调用。 function foo(data) { console.log('Your public IP address is: ' + data.ip); }; //服务器收到请求之后,将数据放在回调函数的参数位置返回 foo({ 'ip': '8.8.8.8' })
-
WebSocket - 通信协议 使用 ws:// (非加密)和 wss:// (加密)作为协议前缀。(不实行同源策略跨源直接跨源通信)
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin : http://example.com //Origin 表示该请求的请求源,即发自哪个域名,服务器根据这个字段,判断是否许可本次通信。在白名单内则回应 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
-
CORS - 跨源资源分享(Cross-Origin Resource Sharing) W3C标准,属于跨源AJAX请求的根本解决方法
简单请求 同时满足以下两大条件
方法是: HEAD GET POST
头信息不超出: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
非简单请求 凡是不同时满足上面两个条件的就是非简单请求 比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json
简单请求:浏览器直接发出 CORS 请求,就是在头信息之中,增加一个 Origin 字段
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
非简单请求:浏览器自动发出一个“预检”请求,要求服务器确认可以这样请求
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
通过“预检”请求之后,以后每次浏览器正常的CORS请求,就跟简单请求一样会有一个Origin头信息字段。
CORS 与 JSONP 的比较
CORS 和 JSONP 的使用目的相同,但是比 JSONP 更强大。JSONP 只支持 GET 请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据
Storage 接口
window.sessionStorage => 保存的数据用于浏览器的一次会话,当会话结束(通常是窗口关闭),数据被清空。
window.localStorage => 保存的数据长期存在,下一次访问该网站的时候,网页可以直接读取以前保存的数据。
Storage.setItem() => 方法用于存入数据
Storage.getItem() => 方法用于读取数据
Storage.removeItem() => 方法用于清除某个键名对应的键值
Storage.clear() => 方法用于清除所有保存的数据
Storage.key() => 方法接受一个整数作为参数(从零开始),返回该位置对应的键名
window.sessionStorage.setItem(3, { foo: 1 });
window.sessionStorage.getItem('3') // "[object Object]"
sessionStorage.removeItem('key');
localStorage.removeItem('key');
window.sessionStorage.setItem('key', 'value');
window.sessionStorage.key(0) // "key"
当Storage接口储存的数据发生变化时,会触发 storage 事件,可以指定这个事件的监听函数
window.addEventListenter('storage',onStorageChange)
function onStorageChange(e){
console.log(e.key);
}
History 对象 => 表示当前窗口的浏览历史
属性
window.history.length => 当前窗口访问过的网址数量
window.history.state => History 堆栈最上层的状态值
方法
history.back() => 移动到上一个网址,等同于点击浏览器的后退键
history.forward() => 移动到下一个网址,等同于点击浏览器的前进键
history.go() => 接收一个整数作为参数,以当前网址为基准,移动到参数指定的网址。
window.history.pushState() => 方法用于在历史中添加一条记录
window.history.pushState(state , title , url)//pushState 方法不会触发页面更新,只是导致History 对象发生变化,地址栏会有反应
Vue-Router (v3.x)
hash 默认 hash 模式 -- 使用URL的hash来模拟一个完整的URL,于是当 URL 改变时,页面不会重新加载会带有一个# 利用了window.onhashchange()原理实现
HTML5 History 这种history模式,URL 就像正常的url history 模式 充分利用 history.pushState API 来完成URL跳转 而无须重新加载页面不过history 模式需要后台配置支持
Vue-Router (v4.x)
hash createWebHashHistory()创建的,在内部传递的实际URL 之前使用了一个哈希字符(#),在SEO中确实有不好的影响。
HTML5 createWebHistory()创建的,当使用这种历史模式时,URL 会看起来很 "正常"。(history 模式 充分利用 history.pushState API 来完成URL跳转 而无须重新加载页面)不过history 模式需要后台配置支持
es5的继承和es6的继承
-
构造函数 - 使用call函数改变this指向
function Parent(){ this.name = 'qx' } function Child(age){ Parent.call(this) this.age = age } var c = new Child(19) console.log(c.name)//qx
原理就是在child的构造函数中,调用Parent构造函数,利用call改变this的指向 此时的this事Child里面的,被调用后Child里面的 this有了那么属性
但是这种方法不能够继承到父函数原型链上的东西
- 原型链继承
function Parent() {
this.name = 'qx';
}
Parent.prototype.hi = function () {
console.log('hi');
};
function Child(age) {
this.age = age;
}
Child.prototype = new Parent();//让原型对象等于另一个类型的实例
var c = new Child(19);
console.log(c.name); //输出qx
//寻找name这个属性的过程:
//现在c内部属性中找一遍,没有找到,然后去c的原型也就是c.__proto__中找一遍,而看上面的图c.__proto__就是Child.prototype,而上面定义了Child.prototype = new Parent(),所以会直接去parent实例中寻找name,于是找到name='qx'
c.hi() //输出say
//调用这个方法和上面类似,一路寻找到parent实例发现也还是没有这个方法,于是继续去找这个实例的原型,也就是Parent.prototype,然后找到了这个方法
发现通过使原型=实例的方法,也就是原型链的方法,可以继承到实例所属类的原型链上的所有的属性和方法
但是这种方法存在一些缺陷:
-
引用值共享问题 引用值会被所有的实例,一个对象修改了原型属性,那么另一个的原型属性也会被修改
-
不能传参 在创建Child的实例时,不能向Parent传递参数,如果传递也不会有作用,也就是无法去修改父类的属性
function Parent(name){ this.name = name||parent; this.value = 19; this.arry = [1,2,3]; } function Child(){ } Child.prototype = new Parent(); var child1 = new Child('child1'); var child2 = new Child('child2');
- 组合继承 就是将上面两种继承方式结合再一起
结合了两者的优点:
-
Parent上的原型可以被继承
-
解决了引用值共享问题
-
Child也可以向Parent传参数
function Parent(name) { this.name = name || 'parent'; } function Child(name, age) { Parent.call(this, name); //继承实例属性,第一次调用Parent() this.age = age; } Child.prototype = new Parent(); //继承原型,第二次调用Parent() Child.prototype.constructor = Child;//修正构造函数为自己本身 var child1 = new Child('child1', 18); var child2 = new Child('child2', 19);
-
寄生组合式继承
function extend(subClass, superClass) { var prototype = Object(superClass.prototype);//创建对象 prototype.constructor = subClass;//增强对象 subClass.prototype = prototype;//指定对象 } function Parent(name) { this.name = name || parent; this.value = 19; this.arry = [1, 2, 3]; } function Child(name) { Parent.call(this, name); //继承第一步,继承实例属性,调用Parent() } //Child.prototype = new Parent(); extend(Child, Parent); //继承第二步,不会调用Parent() var child1 = new Child('child1'); var child2 = new Child('child2'); console.log(child1 instanceof Parent);//true function Son() { Child.call(this); } extend(Son, Child); var son = new Son(); console.log(son instanceof Child);//true console.log(son instanceof Parent);//true //这里就简单测试了下,父类的父类也可以算
用自己的理解来解释下这三行代码:
首先是在函数中封装好这个继承方便之后直接用,subClass是子类,superClass是父类
创建对象:创建一个父类的原型对象,作为备用
增强对象:原本这个原型对象的constructor应该是父类的构建函数,但是被指向了子类的构造函数
指定对象:最好将这个原型指定为子类的原型
三行代码最后生成了一个拥有子类本身构造函数和父类原型的对象
最后想实现一个继承: Parent.call(this, name); //继承第一步,继承实例属性,调用Parent()
extend(Child, Parent); //继承第二步,不会调用Parent()
-
ES6类继承 类似于java c++
class Point{ constructor(x,y){ this.x = x this.y = y } toString(){ return this.x + '' + this.y } } class ColorPoint extends Point{ constructor(x,y,color){ super(x,y) //调用父类的constructor(x,y) this.color = color } toString(){ return this.color + ' ' + super.toString() //调用父类的toString() } } let colorPoint = new ColorPoint('1','2','red') console.log(colorPoint.toString()) //red 12