• 【积累总结】JS基础日常总结


    1.类型转换

      1.1转换成String类型:

        五大基础数据类型除了undefined和null,其余都可以使用toString()方法转换成String类型;

        String()方法可以将五大基础数据类型转换成string类型,还可以使用+“”的方法;

      1.2转换成Number类型:

        Number()把字符串转换成数值类型的时候,如果字符串中有一个字符不是数字,返回NaN;

        parseInt()无法把Boolean类型的数据转换成数值类型,返回NaN;

        parseInt()在转换字符串的时候,会返回遇到第一个非数字字符之前的字符,如果此字符串以非数字字符开头,则返回NaN;

        parseFloat()无法转换Boolean类型的数据,返回NaN;

        parseFloat()会解析第一个.     直到遇到第二个.    或者非数字字符

        取正  +XXX  可以将纯数字字符串转换成正整数,非纯数字子字符串会返回NaN,+true操作会返回1,+false操作返回0

        取负  -XXX  可以将纯数字字符串转换成负整数,非纯数字字符串会返回NaN

        +操作符如果有一边是字符串 一边是数字 那么会进行字符串的拼接

      1.3转换成Boolean类型:

         0、空字符串、null、undefined、 NaN都会转换成false,其他都会转换成true

         !!XXX会将XXX转换成Boolean类型

    2.预解析

      javascript解析器执行javascript代码的时候分为两个过程:预解析过程和代码执行过程

      预解析过程中:

       2.1 var声明的变量和函数声明会被提升到作用域的最前面,如果var声明的变量和函数同名,那么函数优先,也就是函数声明的提升会覆盖var 声明的变量

       2.2 有如下代码 var a = b = c = d = 5;  那么变量提升的只有a, 剩下的b、c、d三个变量都是全局变量的声明,没有提升,随处可用

    3.new做了什么

      3.1在内存中创建了一个对象

      3.2让构造函数中的this指向了刚刚创建的对象

      3.3执行构造函数,在构造函数中设置属性和方法,当然还可以有别的操作

      3.4返回当前创建的对象

    4.基本包装类型:

      var bool = new Boolean(false);

      console.log(bool && true);//打印true  这是因为变量bool是个对象实例,他的原始值是传入的false,但是进行boolean类型的转换的时候,只有0,空字符"",null、undefined,NaN这五种才会转换成false 其余都是true

    5.原型:

      5.1 实例的__proto__恒等于构造函数的prototype对象   s1.__proto__ === Student.prototype

      5.2 实例的constructor记录了创建对象的构造函数    s1.constructor === Student  

      5.3 构造函数有一个属性prototype指向该构造函数的显示原型对象,

         该显示原型对象又有一个属性constructor属性,指向该构造函数,

         通过构造函数创建的实例对象有一个隐式原型对象__proto__ ,指向该构造函数的显示原型对象prototype

       

        5.4 读取属性或方法的时候,先从实例自身查找,找不到的话就向原型链的上一级查找,直到找到或者查找到了原型链的顶端,找不到就会返回undefined

           但是,设置属性的时候是不会去查找原型链的,如果自身有这个属性就设置,没有的话就新增该属性,并且设置的属性会覆盖掉原型链上的同名属性

        5.5  如果重置了构造函数的显示原型对象prototype,记得修正这个显示原型对象的constructor指向  

    function Student(name, age){
     2   this.name = name;
     3   this.age = age;        
     4 }
     5 
     6 Student.prototype = {
     7 
     8   constructor:Student, //这里是必须的,因为这种写法相当于重新修改了Student.prototype对象,将其指向了一个新的Object对象,所以要手动将显示原型对象的constructor属性重新指向原来的构造函数Student  
     9 
    10   sayHi:function(){
    11     console.log("sayhi");        
    12   } ,
    13   eat:function(){
    14     console.log("eat");
    15   }   
    16 }
    
    var stu = new Student("xiaoming",19);
    stu.sayHi();//实例要想读取原型上的属性或方法,那么必须在原型上设置好之后,才能实例化再进行读取,否则在实例化之后再去原型上设置的话是读取不到的,会报错

        5.6 数组和String类型的显示原型对象是不允许直接覆盖修改的,只能通过Array.prototype.xxx = xxxx 这种方式修改,否则即便进行了覆盖修改,数组和String的显示原型对象上原来那些内置还是会存在,覆盖修改里面新增的方法是不会存在的,也不会起作用的  

    6.自调用函数:

      6.1自调用函数可以创建一个私有的作用域,避免污染全局变量

      6.2书写自调用函数的时候 一定一定一定在最前面加上一个;      避免这个自调用函数跟前面的语句发生结合,导致报错

      6.3使用自调用函数的时候,实参一般会加上window和undefined

        添加window实参是为了可以压缩代码

        添加undefined是因为低版本的浏览器中undefined值可以被修改,所以为了防止出错,在自调用函数中的是惨重传入undefined

    1 ;(function(window, undefined){
    2   //window.Game = Game;
        //window.xxx..........
    3 })(window, undefined)//传入实参window和undefined

     7.继承

      7.1原型继承:设置继承关系的时候只能实例化父类一次,所以对于子类来说就相当于不能设置构造函数的参数

     1     // 父类型
     2     function Person() {
     3       this.name = 'zs';
     4       this.age = 18;
     5       this.sex = '男';
     6     }
     7 
     8     // 子类型
     9     function Student() {
    10       this.score = 100;
    11     }
    12 
    13     Student.prototype = new Person();//继承这里只能实例化一次,不能设置构造函数的参数
    14     Student.prototype.constructor = Student;
    15 
    16 
    17     var s1 = new Student();
    18     console.log(s1.constructor);
    19     console.dir(s1);
    20 
    21     function Teacher() {
    22       this.salary = 3000;
    23     }

      7.2构造函数继承:利用call方法,改变父类的this指向,相当于把子类当成参数传入到父类并指向父类的this,然后执行一遍父类的代码,相当于设置一遍子类没有的属性,相当于复制一遍父类的属性,缺点是不能继承父类原型上的方法

     1     // 父类型
     2     function Person(name, age, sex) {
     3       this.name = name;
     4       this.age = age;
     5       this.sex = sex;
     6       // this.sayHi  //借用构造函数继承,可以继承父类的属性和方法,如果在这里面加上方法,那么每个子类的实例都会为这个方法申请一个内存,造成浪费
     7     }
     8     Person.prototype.sayHi = function () {
     9       console.log(this.name);//借用构造函数继承,不能继承父类原型上的方法
    10     }
    11 
    12     // 子类型
    13     function Student(name, age, sex, score) {
    14       Person.call(this, name, age, sex);
    15       this.score = score;
    16     }
    17 
    18     var s1 = new Student('zs', 18, '男', 100);
    19     console.dir(s1);

      7.3组合继承:利用原型继承来继承父类原型上的方法,再利用构造函数继承来继承父类的属性。由此,多个子类型也可以在自己的子类的原型上添加自己的独有的方法,不会影响别的子类,比如学生有自己的exam方法,而老师类就不会有

     1     //父类型
     2     function Person(name, age, sex) {
     3       this.name = name;
     4       this.age = age;
     5       this.sex = sex;
     6     }
     7 
     8     Person.prototype.sayHi = function () {
     9       console.log('大家好,我是' + this.name);
    10     }
    11 
    12     // 子类型1:Student
    13     function Student(name, age, sex, score) {
    14       // 借用构造函数
    15       Person.call(this, name, age, sex);
    16 
    17       this.score = score;
    18     }
    19 
    20     // 通过原型,让子类型,继承父类型中的方法
    21     Student.prototype = new Person();
    22     Student.prototype.constructor = Student;
    23     // 学生特有的方法
    24     Student.prototype.exam = function () {
    25       console.log('考试');
    26     }
    27 
    28     //子类型2:Teacher
    29     function Teacher(name, age, sex, salary) {
    30       // 借用构造函数
    31       Person.call(this, name, age, sex);
    32 
    33       this.salary = salary;
    34     }
    35 
    36     // 通过原型让子类型继承父类型中的方法
    37     Teacher.prototype = new Person();
    38     Teacher.prototype.constructor = Teacher;
    39 
    40     var t1 = new Teacher('ww', 30, '男', 100000);
    41     console.dir(t1);
    42 
    43     t1.sayHi();

     附上一张继承的原型图

    8.this指向: 函数内部的this不是由书写时候确定的, 而是由调用的时候确定的

        //1 普通函数调用    this指向window
        function fn() {
          console.log(this);
        }
        window.fn();
    
        //2 方法调用     this指向调用该方法的对象
        var obj = {
          fn: function () {
            console.log(this);
          }
        }
        obj.fn();
    
        //3 作为构造函数调用   构造函数内部的this指向由该构造函数创建的对象
    
        //4 作为事件的处理函数   this指向触发该事件的对象
        btn.onclick = function() {
          console.log(this);
        }  
    
        //5 作为定时器的参数   this指向window
        setInterval(function () {
          console.log(this);
        }, 1000);
    
        //终结总结:函数内部的this,是由函数调用的时候来确定其指向的
    
        //栗子1:
        function fn() {
          console.log(this);
        }
         fn(); // this -> window
    
        //栗子2:
        function fn() {
          console.log(this);
        }
        var obj = {
          name: 'zs',
          fn: fn
        }:
        obj.fn();//this指向obj
    
        //栗子3:
        var obj = {
          name: 'zs',
          fn: function () {
            console.log(this);
          }
        }:
        var fn = obj.fn;
        fn();   // this -> window 重点哦
    
        obj.fn();//this->obj 

    9.闭包:

      之前针对闭包总结了一个帖子 https://www.cnblogs.com/buerjiongjiong/p/10875961.html

    10.拷贝

      10.1浅拷贝:简单类型直接拷贝,复杂类型拷贝的是复杂对象的内存地址,拷贝后都指向同一个内存地址,如果有一个地方修改了,那么将会影响所有指向该内存地址的对象。浅拷贝表面上来理解就是只是拷贝了一层

      10.2深拷贝:相对于浅拷贝来说就是复制了多层,简单数据类型直接拷贝,遇到复杂类型就会遍历这个复杂类型的所有属性,简单数据直接拷贝,复杂数据类型再进行遍历,直至没有复杂数据类型,这样就不会拷贝到复杂类型的内存地址,拷贝之后的结果即便修改了也互不影响。

     1   function deepCopy(sourceObj,rltObj){
     2     for(var key in sourceObj){
     3       if(sourceObj[key] instanceof Object){
     4         //复杂数据类型递归拷贝
     5         rltObj[key] = {};
     6         deepCopy(sourceObj[key],rltObj[key]);
     7       }else if(sourceObj[key] instanceof Array){
     8         //复杂数据类型递归拷贝
     9         rltObj[key] = [];
    10         deepCopy(sourceObj[key],newArr);
    11       }else{
    12           rltObj[key] = sourceObj[key];
    13       }
    14     }
    15   }

    11.正则表达式:

    12.数组去重:参考可单列一张博客随笔

    13. let

    • let声明的变量不存在预解析,必须先声明再使用(暂时性锁区:使用let声明的变量在声明之前的区域是不能够使用这个变量的)
    • let声明的变量不允许重复声明(在同一个作用域内)
    • ES6引入了块级作用域,在块内使用let声明的变量在块外面是不能够使用的
       1 console.log(a);//undefined
       2 console.log(b);//Uncaught ReferenceError: b is not defined
       3 {
       4     console.log(a);//undefined
       5     console.log(b);//报错了,因为暂时性锁区 Uncaught ReferenceError: Cannot access 'b' before initialization
       6     var a = 0;
       7     let b=1;
       8     console.log(a);//0
       9     console.log(b);//1
      10 } 
      11 console.log(a);//0
      12 console.log(b);//Uncaught ReferenceError: b is not defined

    14.const:用来声明常量

    • const声明的常量不允许重新赋值
    • const声明的常量必须初始化
    • 适应于let声明的规则也适应于const,也就是上面第13条关于let的总结的规则const也要遵守

    15.箭头函数:

    • 箭头函数中的this取决于定义时候,而不是调用的时候
    • 箭头函数不可以new
    • 箭头函数不可以使用arguents获取参数,可以使用剩余参数rest代替
       let foo = (...param)=>{
           console.log(param);
       }
       foo(1,'2',3);//输出[1,'2',3]

    16.变量的解构赋值:

    • 数组的解构赋值:按照数组下标的顺序依次赋值,还可以设置默认值
      1 let [a, b, c] = [1, 2, 3];
      2 console.log(a, b, c);//1,2,3
      3 
      4 let [d, e, f] = [, 5,];
      5 console.log(d, e, f);//undefined,5,undefined
      6 
      7 let [i = 7, j, k] = [, 8, 9]
      8 console.log(i, j, k);//7,8,9
    • 对象的解构赋值:根据键的名称赋值
       1 let { foo, bar } = { bar: 'hi', foo: 'hello' };
       2 console.log(foo, bar);//helo hi
       3 
       4 //属性重命名,原来的变量名称就不能用了
       5 let { foo: newFoo, bar } = { bar: 'hi', foo: 'hello' };
       6 console.log(newFoo,bar);//hello hi
       7 console.log(foo)//报错Uncaught ReferenceError: foo is not defined,因为解构赋值的时候foo已经被重命名为newFoo了
       8 
       9 //默认值
      10 let {foo = 'hello0000',bar} = {bar:'hi'};
      11 console.log(foo,bar)//hello0000 hi
    • 字符串的解构赋值:基本上跟数组的解构赋值差不多,只是解构赋值字符串的length属性的时候要是用对象解构赋值的方式,而不是数组
      1 let [a,b,c] = 'hello';
      2 console.log(a,b,c);//h e l
      3 
      4 let [a,b,c,d,e,f] = 'hello';
      5 console.log(a,b,c,d,e,f);//h e l l o undefined
      6 
      7 let {length} = 'hello';//解构赋值字符串的length属性的时候要是用对象结构的方式,而不是数组
      8 console.log(length);//5
    • 函数参数的解构赋值
      1 function foo({ name, age, sex = '男' } = {}) {//除了sex的默认值,foo函数整体也给了一个默认值{}
      2     console.log(name, age, sex);//张三 18 男
      3 }
      4 
      5 foo({ name: '张三', age: 18 });

    17.剩余参数rest和扩展运算符

    • 剩余参数rest:剩余参数以数组方式读取
      1 function foo(a,b,...params){
      2     console.log(a,b,params);//1 2 [3,4,5]
      3 }
      4 
      5 foo(1,2,3,4,5)
    • 扩展运算符
       1   function foo(a, b, c) {
       2        console.log(a, b, c);//1 2 3
       3   }
       4    
       5   foo(...[1, 2, 3]);
       6   
       7   
       8   //类似于函数的apply方法
       9   function foo(a, b, c) {
      10      console.log(a, b, c);//1 2 3
      11  }
      12  
      13  foo.apply(null, [1, 2, 3]);
      1 //数组合并
      2 let arr = [1,2,3];
      3 let arr2 = [3,4,3];
      4 let arr3 = [...arr,...arr2]
      5 console.log(arr3);// [1, 2, 3, 3, 4, 3]

    18.

  • 相关阅读:
    07java数组、排序算法
    06方法定义及调用、方法重载、命令行参数、可变参数
    04用户交互scanner
    01IDEA新建一个java程序
    05顺序结构、选择结构、循环、、
    【Linux】symbol lookup error: undefined symbol + nm指令定位错误
    linux命令——crontab的使用方法
    WSL2 Ubuntu固定IP,开机启动SSH
    AArch64下编译及使用sigar
    使用last命令找出是谁重启了你的服务器(linux)
  • 原文地址:https://www.cnblogs.com/buerjiongjiong/p/11985598.html
Copyright © 2020-2023  润新知