浏览器的核心主要是:渲染引擎和JavaScript解释器(又称 JavaScript 引擎)

window 对象 => window 指当前的浏览器窗口。也是当前页面的顶层对象。

Navigator 对象

Navigator.userAgent - 返回浏览器的User Agent 字符串 表示用户设备信息,包含了浏览器的厂商、版本、操作系统(通常用来使用判断手机浏览器是否是ios系统和android系统)

Screen 对象 => 当前窗口所在的屏幕,提供显示设备的信息 window.screen 属性指向这个对象

Cookie => 服务器保存在浏览器的一小段文本信息。

AJAX =>

  1. 创建XMLHttpRequest
  2. 发出HTTP请求
  3. 接受服务器传回的数据
  4. 更新网页数据

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 请求(可以发送,但浏览器会拒绝接受响应) 解决跨域的方法
  1. Cookie 浏览器允许通过 document.domain 共享 Cookie。只要设置相同的 document.domain ,两个网页就可以共享 Cookie (只适用于一级域名相同,次级域名不同的Cookie和iframe窗口)
  2. 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);
  1. 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有了那么属性

但是这种方法不能够继承到父函数原型链上的东西

  • 原型链继承

alt

      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,然后找到了这个方法

发现通过使原型=实例的方法,也就是原型链的方法,可以继承到实例所属类的原型链上的所有的属性和方法

但是这种方法存在一些缺陷:

  1. 引用值共享问题 引用值会被所有的实例,一个对象修改了原型属性,那么另一个的原型属性也会被修改

  2. 不能传参 在创建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');
    
  • 组合继承 就是将上面两种继承方式结合再一起

结合了两者的优点:

  1. Parent上的原型可以被继承

  2. 解决了引用值共享问题

  3. 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