一、构造函数中的this指向

  • 构造函数在没有实例化之前,this是指向window的
  • 构造函数在实例化之后,this是指向当前这个实例化对象本身

    1. // 构造函数实例化的原理
    2. // 构造函数在没有实例化之前,this是指向window的
    3. // 构造函数在实例化之后,this是指向当前这个实例化对象本身
    4. function Car(opt){
    5. this.color = opt.color;
    6. this.brand = opt.brand;
    7. }
    8. // 在此时构造函数本没有实例化,函数也没有执行,那么里面的this是没有意义的
    9. // 把构造函数当做普通函数执行,此时构造函数并没有实例化;那么此时的this是指向window的
    10. // Car();
    11. // 构造函数实例化后,this就指向当前实例化的对象本身了
    12. var car1 = new Car({
    13. color: 'red',
    14. brand: '比亚迪'
    15. });
    16. var car2 = new Car({
    17. color: 'black',
    18. brand: '大众'
    19. });
    20. console.log(car1.color);
    21. console.log(car2.color);

    二、构造函数实例化原理

  • 构造函数执行时,形成自己的AO;形成自己的执行期上下文时,首先会创建一个this空对象

  • 构造函数执行过程中,new的作用其实就是为了改变this指向
  • 当JS引擎看到new执行的时候,首先会在AO里面保存一个this空对象
  • 在构造函数执行过程中,this.xxx;都是在给这个this空对象设置私有属性和方法
  • 最后JS引擎会在构造函数末尾隐式加上 return this;

    • 如果我们自己写了return,且return后面跟的是一个原始值,那么还是默认隐式返回 return this
    • 如果我们自己写了return,且后面跟的是引用类型的值,那么就返回我们自己写的引用值

      1. // 构造函数实例化原理
      2. // 1. 构造函数在执行时,形成AO后,首先保存this对象
      3. // 2. 构造函数执行过程中,new的作用其实就是为了改变this指向
      4. // 3. 当JS引擎看到new执行的时候,首先会在AO里面保存一个this空对象
      5. // 4. 在构造函数执行过程中,this.xxx;都是在给这个this空对象设置私有属性和方法
      6. // 5. 最后JS引擎会在构造函数末尾隐式加上 return this;
      7. // + 如果我们自己写了return,且return后面跟的是一个原始值,那么还是默认返回 return this
      8. // + 如果我们自己写了return,且后面跟的是引用类型的值,那么就返回我们自己写的引用值
      9. // GO = {
      10. // Car: function(color, brand){....},
      11. // car1:{
      12. // color: color,
      13. // brand: brand
      14. // },
      15. // car2:{
      16. // color: color,
      17. // brand: brand
      18. // }
      19. // }
      20. // AO = {
      21. // this: {
      22. // color: color,
      23. // brand: brand
      24. // }
      25. // }
      26. function Car(color, brand){
      27. // 构造函数执行时,形成AO,首先会创建一个this空对象
      28. // this.xxx; 都是给这个空对象添加属性或者是方式
      29. // this = {
      30. // color: color,
      31. // brand: brand
      32. // }
      33. this.color = color;
      34. this.brand = brand;
      35. // 不写return,或者return的是一个原始值,那么都是隐式返回return this这个对象
      36. // return this;
      37. }
      38. var car1 = new Car('red', 'Benz');
      39. var car2 = new Car('black', 'BMW');
      40. console.log(car1.brand);
      41. console.log(car2.brand);

      自己模拟构造函数的实例化原理

      1. // 自己模拟构造函数实例化的过程
      2. function Car(color, brand){
      3. var obj = {};
      4. obj.color = color;
      5. obj.brand = brand;
      6. return obj;
      7. // obj = {
      8. // color: color,
      9. // brand: brand
      10. // }
      11. }
      12. var car1 = new Car('red', 'Benz');
      13. var car2 = new Car('black', 'BMW');
      14. console.log(car1.brand);
      15. console.log(car2.brand);

      三、构造函数中的return问题

      3.1、构造函数中的this问题

  • 构造函数如果不实例化且不执行,那么里面的this的没有意义的

  • 构造函数如果不加new关键字执行,仅仅是当做普通函数执行,那么里面的this指向的是window
  • 构造函数加new关键词执行,里面的this指向的是当前这个实例化对象本身

    3.2、构造函数中的return问题

  • 在构造函数中,如果我们不写return,系统会自动给我们隐式加上return this;

  • 在构造函数中,如果我们写了return,但是return后面跟的是原始值类型,那么这个构造函数仍旧返回的是return this
  • 在构造函数中,如果我们写了return且后面跟的是引用数据类型,那么就会返回的写的这个引用类型值

    1. // 构造函数中的this问题
    2. // 构造函数如果不实例化且不执行,那么里面的this的没有意义的
    3. // 构造函数如果不加new关键字执行,仅仅是当做普通函数执行,那么里面的this指向的是window
    4. // 构造函数加new关键词执行,里面的this指向的是当前这个实例化对象本身
    5. // 构造函数中的return问题
    6. // 在构造函数中,如果我们不写return,系统会自动给我们隐式加上return this;
    7. // 在构造函数中,如果我们写了return,但是return后面跟的是原始值类型,那么这个构造函数仍旧返回的是return this
    8. // 在构造函数中,如果我们写了return且后面跟的是引用数据类型,那么就会返回的写的这个引用类型值
    9. function Car(color, brand){
    10. this.color = color;
    11. this.brand = brand;
    12. // return this; //系统默认返回
    13. // return 10; // 返回原始值,无效
    14. // return 'kola'; // 返回原始值无效
    15. // return []; // 返回引用值
    16. return {};
    17. }
    18. var car = new Car('red', 'Benz');
    19. console.log(car);

    四、包装类

    只有Number、String、Boolean才会有包装类

4.1、原始值是没有自己的方法和属性的

  1. // 原始值是没有自己的属性和方法的
  2. var a = 1;
  3. a.len = 3;
  4. console.log(a.len);

4.2、当一个数字被new以后,它就成了一个实例化的对象;既然是对象,那么此时便可以设置属性和方法了

  1. // 当一个数字被new后,那么这个数字就变成了实例化对象了;既然是对象那么此时便可以设置属性和方法了
  2. var a = 1;
  3. var b = new Number(a);
  4. b.len = 3;
  5. b.say = function(){
  6. return '我是一个包装类'
  7. };
  8. console.log(b.len);
  9. console.log(b.say());

4.3、原始值经过new包装后,如果再次参与运算,那么它最后将又返回原始值

  1. // 原始值经过new包装后,如果再次参与运算,那么它最后将又返回原始值
  2. var a = 1;
  3. var c = 3;
  4. console.log(a + c);
  5. var b = new Number(a);
  6. b.len = 2;
  7. b.add = function(){
  8. return '我要做加法了哦';
  9. };
  10. console.log(b); // Number {1, len: 2, add: ƒ}
  11. var d = b + 1;
  12. console.log(d); // 2

4.4、系统内置的包装类

  • new Number
  • new String
  • new Boolean

    1. // 包装类
    2. var test1 = new Number(undefined);
    3. var test2 = new Number(null);
    4. var test3 = new String('undefined');
    5. var test4 = new String('null');
    6. // Number {NaN}; Number {0}; String {'undefined'}; String {'null'}
    7. console.log(test1, test2, test3, test4);

    4.5、undefined和null是无法设置属性和方法的

    1. // undefined和null是无法设置属性和方法的
    2. console.log(undefined.len);
    3. console.log(null.len);

    五、JS包装类的过程

    5.1、系统包装类的问题

    如果不声明变量去保存这个包装类的话,那么系统会将其删除掉

    1. // JS包装类的过程
    2. var a = 123; // 原始值
    3. a.len = 3; // new Number(a).len = 3; JS包装类完成后,没有变量保存;所以系统会将其删除掉 delete
    4. console.log(a.len);
    5. var obj = 3; // 原始值
    6. new Number(obj).name = '123'; // 包装类完成后,没有变量保存,所以系统会将其delete掉
    7. console.log(obj.name);

    解决包装类无法保存的问题:声明一个变量去保存这个包装类即可

    1. // 解决包装类无法保存的问题
    2. var a = 3;
    3. // a.len = 3; // new Number(a).len; 虽然经过了包装类,但是没有变量去保存它,解决的办法就是声明一个变量去保存它即可
    4. var b = new Number(a);
    5. b.len = 3;
    6. console.log(b.len)

    5.2、字符串并没有包装类

    字符串并没有包装类,之所以有str.length 是因为系统进行了包装类

    1. // 字符串并没有包装类,之所以有str.length是因为系统内部进行了包装类
    2. var str = 'kola';
    3. // 系统内部进行了包装类
    4. console.log(str.length); //console.log(new String(str).length);

    5.3、数组中的length属性和数组截断

    注意:字符串的length属性是系统包装类的结果,所以字符串的length属性是无法做字符串截断的

    1. // 数组中的length属性,可以用来做数组截断
    2. var arr = [1, 2, 3, 4, 5];
    3. arr.length = 2;
    4. console.log(arr); // [1, 2]
    5. // 字符串中的length属性是系统包装类的结果,所以无法做字符串截断
    6. var str = 'liangyu';
    7. str.length = 2;
    8. console.log(str); // liangyu

    六、练习题

    1. // 练习题
    2. var name = 'liangyu';
    3. name += 10;
    4. var type = typeof(name);
    5. if(type.length === 9){
    6. type.text = 'string'; // new String(type).text = 'string'; 没有变量保存,系统会将其删除掉
    7. }
    8. console.log(type.text); // undefined
    1. function Test(a, b, c){
    2. var d = 1;
    3. this.a = a;
    4. this.b = b;
    5. this.c = c;
    6. function f(){
    7. d++;
    8. console.log(d);
    9. }
    10. this.g = f;
    11. }
    12. var test1 = new Test();
    13. test1.g();
    14. test1.g();
    15. var test2 = new Test();
    16. test2.g();
    1. // 练习题三
    2. var x = 1,
    3. y = z = 0;
    4. function add(n){
    5. return n = n + 1;
    6. }
    7. y = add(x); // 4
    8. function add(n){
    9. return n = n + 3;
    10. }
    11. z = add(x); // 4
    12. console.log(x, y, z);

    七、面试题

    1. function foo1(x){
    2. console.log(arguments);
    3. return x;
    4. }
    5. foo1(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
    6. // 函数声明不能跟执行符号,只有表达式才可以跟执行符号
    7. function foo2(x){
    8. console.log(arguments);
    9. return x;
    10. }(1, 2, 3, 4, 5); // 后面的小括号传值了,当做匿名函数来处理,会忽略掉函数名;最后的小括号会被当做括号运算符,此函数不会被执行
    11. (function foo3(x){
    12. console.log(arguments);
    13. return x;
    14. })(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

    阿里面试题

    1. function b(x, y, a){
    2. a = 10;
    3. console.log(arguments[2]);
    4. }
    5. b(1, 2, 3);
    1. function b(x, y, a){
    2. arguments[2] = 10;
    3. console.log(a);
    4. }
    5. b(1, 2, 3);

    八、ASCII码表和UNICODE码

  • ASCII码表:分为表一 0~127 表二:128~255;大小都是一个字节 byte

  • UNICODE码:涵盖ASCII码表0~255,后255之后的字节大小为二个字节 byte
  • str.charCodeAt(字符串下标);

    1. // ASCII码表:分为表一 0~127 表二:128~255;大小都是一个字节 byte
    2. // UNICODE码:涵盖ASCII码表0~255,后255之后的字节大小为二个字节 byte
    3. var str = 'abc';
    4. var pos = str.charCodeAt(1);
    5. console.log(pos); // 98

    九、作业

    写一个函数,接收任意一个字符串,算出这个字符串的总字节数

    1. // 课时九作业
    2. // 写一个函数,接收任意一个字符串,算出这个字符串的总字节数
    3. function getBytes(str){
    4. var bytes = 0;
    5. for(var i = 0; i < str.length; i++){
    6. var pos = str.charCodeAt(i);
    7. if(pos <= 255){
    8. bytes++;
    9. }else{
    10. bytes+=2;
    11. }
    12. }
    13. return bytes;
    14. }
    15. console.log(getBytes('你好,世界!Hello World!'));
    16. // 课时九作业
    17. // 写一个函数,接收任意一个字符串,算出这个字符串的总字节数
    18. function getBytes(str){
    19. var bytes = str.length;
    20. for(var i = 0; i < str.length; i++){
    21. var pos = str.charCodeAt(i);
    22. if(pos > 255){
    23. bytes++;
    24. }
    25. }
    26. return bytes;
    27. }