【积累总结】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.

原文地址:https://www.cnblogs.com/buerjiongjiong/p/11985598.html