笔记整理(五)

Ajax

  • 什么是Ajax:Ajax(Asynchronous JavaScript and XML)是一种在无需重新加载整个网页的情况下能够更新部分网页的技术
  • 一个完整的HTTP请求过程

    1. 建立TCP连接
    2. Web浏览器向Web服务器发送请求命令
    3. Web浏览器发送请求头信息
    4. Web服务器应答
    5. Web服务器发送应答头信息
    6. Web服务器向浏览器发送数据
    7. Web服务器关闭TCP连接
  • HTTP状态码

    • 1XX:信息类,表示收到Web浏览器请求,正在进一步的处理中
    • 2XX:成功,表示用户请求被正确接收,理解和处理。 200-OK
    • 3XX:重定向,表示请求没有成功,客户必须采取进一步的动作
    • 4XX:客户端错误,表示客户端提交的请求有错误。 400-NOT Found
    • 5XX:服务器错误,表示服务器不能完成对请求的处理。 500
  • readyState属性(表示请求响应过程的当前活动阶段,只要值发生变化都会触发一次onreadystatechange事件)

    • 0:未初始化。尚未调用open()方法
    • 1:启动。已经调用open()方法,但尚未调用send()方法
    • 2:发送。已经调用send()方法,但尚未接收到响应
    • 3:接收。已经接收到部分响应数据
    • 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了
  • 封装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    // 请求参数序列化,把对象转换为‘name1=value1&name2=value2’的格式
    function serialize(data) {
    if (!data) {
    return '';
    }
    var pairs = [];
    for (var name in data) {
    if (!data.hasOwnProperty(name)) {
    continue;
    }
    if (typeof data[name] === 'function') {
    contunue;
    }
    var value = data[name].toString();
    name = encodeURIComponent(name);
    value = encodeURIComponent(value);
    pairs.push(name + '=' + value);
    }
    return pairs.join('&')
    }
    // get请求
    function get(url, options, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
    callback(xhr.responseText);
    } else {
    console.log('Requeset was unsuccessful: ' + xhr.status);
    }
    }
    }
    var URL = url + serialize(options); // 如果url后没有问号,还应该加个?
    xhr.open('GET', URL, true);
    xhr.setRequestHeader('myHeader', 'myValue'); // 可以省略
    xhr.send(null);
    // post请求
    function post(url, options, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
    if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
    callback(xhr.reponseText);
    } else {
    console.log('Requeset was unsuccessful: ' + xhr.status);
    }
    }
    }
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send(serialize(options));
    }
    }
  • jQuery中的Ajax

    • $.ajax([settings]) 这里的[settings]以对象的形式进行设置
    • type:类型,“POST”或“GET”,默认为“GET”
    • url:发送请求的地址
    • data:是一个对象,连同请求发送到服务器的数据
    • dataType:预期服务器返回的数据类型。如果不知道,jQuery将自动根据HTTP包MIME信息来智能判断,采用json格式的话可以设置为“json”
    • success:是一个方法,请求成功后的回调函数。传入返回后的数据、以及包含成功代码的字符串
    • error:是一个方法,请求失败时调用此函数。传入XMLHttpRequest对象
  • 关于跨域

    • 当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域;不同域之间相互请求资源,就算作跨域
    • 因为JavaScript同源策略的限制,a.com域名下的js无法操作b.com或是c.a.com域名下的对象
    • 处理跨域方式
      • JSONP:通过动态<script>元素来使用,为src属性指定一个跨域URL,只支持GET请求。
      • XMLHttpRequest Level2:IE10以下不支持
  • 参考资料
    Ajax全接触

this的指向

  • 作为对象的方法调用:this指向该对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var obj = {
    a: 1,
    getA: function() {
    console.log(this === obj);
    console.log(this.a);
    }
    };
    obj.getA(); // 分别输出true和1
  • 作为普通函数调用:this指向全局对象,在浏览器里即window对象;在use strict模式下,this会绑定到undefined

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    window.name = 'globalName';
    var myObj = {
    name: 'whiskey',
    getName: function() {
    return this.name;
    }
    };
    var a = myObj.getName;
    var b = myObj.getName();
    console.log(a()); // "globalName" 作为普通函数调用
    console.log(b); // "whiskey" 作为对象的方法调用
  • 构造器调用

    • 通常情况下构造器里的this指向返回的这个对象

      1
      2
      3
      4
      5
      var MyClass = function() {
      this.name = 'whiskey';
      };
      var obj = new MyClass();
      console.log(obj.name); // 输出"whiskey"
    • 如果构造器显示地返回了一个object类型的对象,那么运算结果会返回这个对象,而不是之前的this

      1
      2
      3
      4
      5
      6
      7
      8
      var MyClass = function() {
      this.name = 'whiskey';
      return {
      name: 'lily' // 显示返回一个对象
      };
      };
      var obj = new MyClass();
      console.log(obj.name); // 输出"lily"
  • Function.prototype.call 或 Function.prototype.apply调用:可以动态改变传入函数的this

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    var obj1 = {
    name: 'whiskey',
    getName: function() {
    return this.name;
    }
    };
    var obj2 = {
    name: 'lily'
    };
    console.log(obj1.getName()); // whiskey
    console.log(obj1.getName.call(obj2)); // lily
    // 如果把null、undefined作为this的绑定对象传入,this会指向window
    function foo() {
    console.log(this.a);
    }
    var a = 2;
    foo.call(null); // 2,如果把上面的var a = 2注释掉,会得到undefined

比较undefined和null

  • undefined(表示“没有值”)

    • 未初始化的变量是undefined
    • 缺失的参数是undefined
    • 访问不存在的属性,返回undefined
    • 函数中没有显示返回值,函数会隐式返回undefined
  • null(表示“没有对象”,将属性或者元素设置为空)

    • null是原型链最顶端的元素
    • 当字符串中没有匹配到正则表达式的结果时,RegExp.prototype.exec()返回null

闭包

闭包指有权访问另一个函数作用域中变量的函数;利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部

  • 解决循环问题 在线demo
    1
    2
    3
    4
    5
    <div>0</div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var aDiv = document.getElementsByTagName('div');
for (var i = 0; i < aDiv.length; i++) {
aDiv[i].onclick = function() {
alert(i); // click事件触发时for循环已经结束,所以alert都是5
};
}
// 利用IIFE创建闭包后
for (var i = 0; i < aDiv.length; i++) {
(function(n){
aDiv[i].onclick = function() {
alert(n); // alert跟节点对应的数
};
})(i);
}
  • 外部访问函数内部定义的变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function sayHi() {
    var name = 'whiskey';
    var say = function() {
    console.log('hi, ' + name);
    };
    return say;
    }
    // say(); // 报错, say is not defined
    var sayName = sayHi();
    sayName(); // 'hi, whiskey'
  • 封装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function countNum(initial) {
    var num = initial || 0;
    return {
    inc: function() {
    num += 1;
    return num;
    }
    };
    }
    var c1 = countNum();
    console.log(c1.inc()); //1 第一次调用
    console.log(c1.inc()); //2 第二次调用
    var c2 = countNum(10);
    console.log(c2.inc()); // 11
    console.log(c2.inc()); // 12
  • 多参函数变单参函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function sum(x) {
    return function(y) {
    return x + y;
    };
    };
    var addSum = sum(1);
    console.log(addSum(1)); //2
    var addSum2 = sum(10);
    console.log(addSum2(10)); //20

call和apply

  • 如果传入的第一个参数为null,函数体内的this会指向默认的宿主对象,浏览器即window
  • 区别:apply接收的第二个参数是个集合,可以是数组或者类数组;
  • 用途

    • 改变this指向

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      var obj1 = {
      name: 'whiskey',
      };
      var obj2 = {
      name: 'lily'
      };
      var getName = function() {
      console.log(this.name);
      };
      window.name = 'window';
      getName(); // 输出window
      getName.call(obj1); // 输出whiskey
      getName.call(obj2); // 输出lily
    • 借用其他对象的方法

      // 实例一
      var A = function(name, age) {
          this.name = name;
          this.age = age;
      };
      
      var B = function() {
          A.apply(this, arguments); // B得到了A的所有属性
      };
      
      B.prototype.say = function() {
          return this.name + ' is ' + this.age + ' years old';
      };
      
      var b = new B('whiskey', 20);
      console.log(b.say()); // "whiskey is 20 years old"
      
      // 实例二
      var maxNum = Math.max.apply(null, [1, 2, 3, 4, 5]);
      console.log(maxNum); // 5
      
      // 实例三
      var a = {};
      Array.prototype.push.call(a, 'first', '语文');
      console.log(a[0]); // first
      console.log(a[1]); // 语文