• JS基础知识系统整理(不断更新)


    一、基础知识

    1.变量类型

    • JS中使用typeof 能得到哪些类型
    • 何时使用 === 何时使用 ==
    • JS中有哪些内置函数
    • JS变量按照存储方式区分为哪些类型,并描述其特点
    • 如何理解JSON

    值类型:

    每个变量存储各自的值,不会相互影响,number , string , boolean 

    var a = 100;
    var b = a;
    a = 200;
    console.log(b);    //100

    引用类型:

    变量只是通过一个指针指向对象,改变了age对象,由于a也指向该对象,所以a指向的age对象为21, object , array , function

    var a = {age:20}
    var b = a
    b.age = 21
    console.log(a.age)    //21

    typeof 运算符

    有六种类型:undefined , string , number , boolean , object , function ; typeof只能区分值类型的详细类型;

    typeof {}    //object
    typeof []    //object
    typeof null    //object
    typeof console.log    //function

    2.变量计算 - 强制类型转换

    字符串拼接

    var a = 100 + 10    //110
    var b = 100 + '10'    //10010

    ==运算符

    obj.a == null ——> obj.a === null || obj.a === undefined

    (除了 obj.a == null 用== 其余都用=== ,jQuery 源码推荐写法)

    100 == ‘100’    //true
    0 == ''    //true
    null == undefined    //true

    if语句

    var a = true
    if(a){//...}
    
    var b = 100
    if(b){//...}
    
    var c = ''
    if(c){//...}

    if中转换为false的情况:

    if(0){}
    if(NaN){}
    if(''){}
    if(null){}
    if(false){}

    逻辑运算符

    console.log(10 && 0)    //0
    console.log('' || 'abc')    //'abc'
    console.log(!window.abc)    //true  因为window.abc 是undefined

    判断一个变量会被当作true还是false

    var a = 100;
    console.log(!!a) 

    JS中的内置函数

    Object , Array , Boolean , Number , String , Function , Date , RegExp , Error

    (注意:Math 是对象,不是函数)

    理解JSON

    //JSON 是 JS 一个内置对象而已

    JSON.stringify({a:10, b:20})   对象转换字符串

    JSON.parse('{"a":10, "b":20}')  字符串转换成对象

    3.原型和原型链

    • 如何准确判断变量是数组类型
    • 写一个原型链继承的例子
    • 描述new 一个对象的过程
    • zepto源码中如何使用原型链

    构造函数

    function Foo(name, age){
        this.name = name;
        this.age = age;
        this.class = 'class-1'
        //return this  //默认有这一行
    }
    
    var f = new Foo('zhangsan',20)
    // var f1 = new Foo('lisi',22)    //可创建多个对象

    开头字母须大写

    new Foo()时把参数传进去,this会先变成空对象,挨个赋值之后,会return出来给f,

    f就具备了调用属性的能力。

    构造函数扩展

    • var a = {} 其实是 var a = new Object() 的语法糖
    • var a = [] 其实是 var a = new Array()的语法糖
    • function Foo(){...} 其实是 var Foo = new Function(...)
    • 使用instanceof 判断一个函数是否是一个变量的构造函数(判断一个变量是否为“数组”: 变量 instanceof Array)

    原型规则和示例

    • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了“null” 以外)
    • //自由扩展属性
      var obj = {}; obj.a = 100;
      var arr = []; arr.a = 100;
      function fn (){}
      fn.a = 100;
    • 所有的引用类型(数组、对象、函数),都有一个 __proto__属性(隐式原型),属性值是一个普通对象
      console.log(obj.__proto__);    //Object
      console.log(arr.__proto__);    //Array[0]
      console.log(fn.__proto__);    //function(){}
    • 所有的函数,都有一个prototype属性(显式原型),属性值也是一个普通的对象
      console.log(fn.prototype);    //Object{}
    • 所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的"prototype"属性值,(指向和完全等是一个概念)
      console.log(obj.__proto__ === Object.prototype);    //true
      • 当试图得到一个引用类型值的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。
        function Foo(name,age){
            this.name = name;
        }
        Foo.prototype.altername = function(){
            alert(this.name);
        }
        
        var f = new Foo('zhangsan');
        f.printname = function(){
            console.log(this.name);
        }
        
        f.printname();
        f.altername();
        f.toString();  //要去 f.__proto__.__proto__中查找

     循环对象自身的属性:

    var item;
    for(item in f){
        //高级浏览器已经在 for in 中屏蔽了来自原型的属性
        //但是这里建议大家还是加上这个判断,保证程序的健壮性
        if(f.hasOwnProperty(item)){
            console.log(item);
        }
    }

    原型链:

    instanceof

    判断引用类型 属于哪个构造函数的方法

    比如 f instanceof Foo 的判断逻辑是:

    f 的 __proto__ 一层一层往上,能否对应到Foo.prototype,再试着判断 f instanceof Object

    原型链继承的例子

    基本:

    //动物
    function Animal(){
        this.eat = function(){
            console.log('animal eat');
        }
    }
    //
    function Dog(){
        this.bark = function(){
            console.log('dog bark');
        }
    }
    
    Dog.prototype = new Animal();
    var hashiqi = new Dog();

    实例:

    function Elem(id){
        this.elem = document.getElementById(id);
    }
    
    Elem.prototype.html = function(val){
        var elem = this.elem;
        if(val){
            elem.innerHTML = val;
            return this;    //链式操作
        }else{
            return elem.innerHTML;
        }
    }
    
    Elem.prototype.on = function(type,fn){
        var elem = this.elem;
        elem.addEventListener(type,fn);
    }
    
    var div1 = new Elem('div1');
    
    div1.html('<p>hello world</p>').on('click', function(){
        alert('clicked');
    })

    描述new一个对象的过程

    1. 创建一个新对象
    2. this 指向这个新对象
    3. 执行代码,即对 this 赋值
    4. 返回 this

    4、作用域和闭包

    • 说一下对变量提升的理解
    • 说明this几种不同的使用场景
    • 创建 10 个<a>标签,点击的时候弹出来对应的序号
    • 如何理解作用域
    • 实际开发中闭包的应用

    执行上下文

    在执行代码前,先把定义声明获取一遍,再由上到下执行

    • 范围:一段<script>或者一个函数
    • 全局:变量定义、函数声明
    • 函数:变量定义、函数声明、this、arguments

    PS:注意“函数声明”和“函数表达式”的区别

    console.log(a);  //undefined
    var a = 100;
    
    fn('zhangsan');  //'zhangsan' 20
    function fn(name){
        age = 20;
        console.log(name, age);
        var age;  
    }

    this

    this要在执行时才能确认值,定义时无法确认

    var a = {
        name: 'A';
        fn: function(){
            console.log(this.name);        
        }
    }
    
    a.fn(); //this === a
    a.fn.call({name: 'B'}); //this === {name: 'B'} 
    var fn1 = a.fn;
    fn1()   //this === window

    几种场景:

    • 作为构造函数执行
      • function Foo(name){
            this.name = name;  //this === Foo
        }
        var f = new Foo('zhangsan');
    • 作为对象属性执行
    • var obj = {
          name : 'A',
          printName : function(){
              console.log(this.name);
          }
      }
      obj.printName();  //this === obj
    • 最为普通函数执行
    • function fn(){
          console.log(this);
      }
      fn();  //this就是Window
    • call apply bind (其实就是用来改变this指向的)
    • function fn1(name,age){
          alert(name);
          console.log(this);
      }
      fn1.call({x:100}, 'zhangsan', 20);  //this就是{x:100}
      fn1.apply({x:100}, ['zhangsan', 20]);  //this就是{x:100}
      
      var fn2 = function(name,age){
          alert(name);
          console.log(this);
      }.bind({y:200});
      fn2('zhangsan',20);//this就是{y:200}

    作用域

    • 没有块级作用域
    • if(true){
          var name = 'zhangsan';
      }
      console.log(name);
    • 只有函数和全局作用域
    • var a = 100;
      function fn(){
          var a = 200;
          console.log('fn',a);
      }
      console.log('global',a)
      fn();

    作用域链

    function fn(){
        var b = 200;
        //当前作用域没有,向父级作用域去找
        console.log(a);
    
        console.log(b);
    }
    fn();
    var a = 100;
    function F1(){
        var b = 200;
        function F2(){
            var c = 300;
            console.log(a); //a是自由变量
            console.log(b); //b是自由变量
            console.log(c);
        }
        F2();
    }
    F1();

    一个自由变量,一直不断的去往它的父级作用域找,形成了一个链式结构

    闭包

    function F1(){
        var a = 100;
    
        //返回一个函数(函数作为返回值)
        return function(){
            console.log(a)
        }
    }
    
    //f1 得到一个函数
    var f1 = F1();
    var a = 200;
    f1();   //100

    使用场景:

    • 函数作为返回值(上一个例子)
    • 函数作为参数传递
    • function F1(){
          var a = 100;
          return function(){
              console.log(a)  //这个a首先去声明的作用域找
          }
      }
      
      var f1 = F1();
      function F2(fn){
          var a = 200;
          fn();
      }
      F2(f1); //100

    实际开发的应用:

    //闭包实际应用中主要用于封装变量,收敛权限
    function
    isFirstLoad(){ var _list = []; return function(id){ if(_list.indexOf(id) >= 0){ return false; }else{ _list.push(id); return true; } } } var firstLoad = isFirstLoad(); firstLoad(10) //true firstLoad(10) //false firstLoad(20) //true
    //在isFirstLoad 函数外,根本不可能修改掉 _list 的值

    创建 10 个<a> 标签,点击的时候弹出来对应的序号

    var i;
    for (i = 0; i < 10; i++) {
        (function(i){  //自执行函数
            var a = document.createElement('a');
            a.innerHTML = i + '<br>';
            a.addEventListener('click', function(){
                alert(i);
                return false;
            })
            document.body.appendChild(a);
        })(i)
    };
    for (var i = 0; i < 10; i++) {
        (function(i){
            var a = document.createElement('a');
            a.innerHTML = '第'+i+'个<br>';
            a.onclick = function(){
                alert(i);
            }
            document.body.appendChild(a);
        })(i)
    };

     5、异步和单线程

    • 同步和异步的区别是什么?分别举一个同步和异步的例子
    • 一个关于setTimeout的笔试题
    • 前端使用异步的场景有哪些

    什么是异步

    console.log(100)
    setTimeout(function(){
        console.log(200)
    },1000)
    console.log(300)
    
    //100
    //300
    //200

    异步和同步最大的区别在于有没有阻塞程序的进行 

    对比同步

    console.log(100)
    alert(200)
    console.log(300)
    //不点击确认,程序会一直卡,不输出300

    何时需要异步

    • 可能发生等待的情况
    • 等待过程中不能像 alert 一样阻塞程序运行
    • 因此,所有的“等待的情况”都需要异步

    使用异步场景:

    • 定时任务:setTimeout,setInterval
    • 网络请求:ajax请求,动态<img>加载
    • 事件绑定
    //ajax请求代码实例  响应事件需要等待
    console.log('start');
    $.get('./data1.json',function(data1){
        console.log(data1);
    })
    console.log('end');
    //<img>加载实例  图片加载需要等待
    console.log('start');
    var img = document.createElement('img');
    img.onload = function(){
        console.log('loaded');
    }
    img.src = '/xxx.png';
    console.log('end');
    //事件绑定实例  触发事件需要等待
    console.log('start');
    document.getElementById('btn1').addEventListener('click',function(){
        alert('clicked');
    })
    console.log('end');

    单线程

    JS是单线程语言,所有的异步程序会被拿出去先不执行,主线程执行完后,它要看边上有没有等待的程序需要执行

    console.log(100)
    setTimeout(function(){
        console.log(200)
    })
    console.log(300)
    
    //100
    //300
    //200
    • 执行第一行,打印100
    • 执行setTimeout后,传入setTimeout的函数会被暂存起来,不会立即执行(单线程的特点,不能同时干两件事)
    • 执行最后一行,打印300
    • 待所有程序执行完,处于空闲状态时,会立马看有没有暂存起来的要执行
    • 发现暂存起来的setTimeout 中的函数无需等待时间,就立即过来执行

    一个关于setTimeout的笔试题

    console.log(1);
    setTimeout(function(){
        console.log(2);
    },0)
    console.log(3);
    setTimeout(function(){
        console.log(4);
    },1000)
    console.log(5);
    //1
    //3
    //5
    //2
    //4

    六、其他知识

    • 获取 2018-01-23 格式的日期
    • 获取随机数,要求是长度一致的字符串格式
    • 写一个能遍历对象和数组的通用 forEach 函数

    日期

    Date.now()  //获取当前时间毫秒数
    var dt new Date();
    dt.getTime()    //获取毫秒数
    dt.getFullYear()    //
    dt.getMonth()   //月(0-11)
    dt.getDate()    //日(1-31)
    dt.getDay()     //星期(0-6)
    dt.getHours()   //小时(0-23)
    dt.getMinutes() //分钟(0-59)
    dt.getSeconds() //秒(0-59)

    Math

    获取随机数 Math.random() (0-1之间的小数)

    常见作用:清除缓存

    数组API

    • forEach 遍历所有元素
    • var arr = ['苹果','香蕉','西瓜'];
      arr.forEach(function(item,index){
          //遍历数组的所有元素
          console.log(index,item);
          //0 "苹果"
          //1 "香蕉"
          //2 "西瓜"
      
      })
    • every 判断所有元素是否都符合条件
    • var arr = [1,2,3];
      var result = arr.every(function(item,index){
          //用来判断所有的数组元素,都满足一个条件
          if(item < 4){
              return true;
          }
      })
      console.log(result);    //true
    • some 判断是否有至少一个元素符合条件
    • var arr = [1,2,3];
      var result = arr.some(function(item,index){
          //用来判断所有的数组元素,只要有一个满足条件
          if(item < 2){
              return true;
          }
      })
      console.log(result);    //true
    • sort 排序
    • var arr = [1,4,2,3,5];
      var arr2 = arr.sort(function(a,b){
          //从小到大排序
          return a - b;
          //从大到小排序
          //return b - a
      })
      console.log(arr2);
    • map 对元素重新组装,生成新数组
    • var arr = [1,2,3,4];
      var arr2 = arr.map(function(item,index){
          //将元素重新组装,并返回
          return '<b>' + item + '</b>';
      })
      console.log(arr2);
      //["<b>1</b>", "<b>2</b>", "<b>3</b>", "<b>4</b>"]
    • filter 过滤符合条件的元素
    • var arr = [1,2,3,4,5];
      var arr2 = arr.filter(function(item,index){
          //通过某一个条件过滤数组
          if(item >= 2){
              return true;
          }
      });
      console.log(arr2);//[2, 3, 4, 5]

    对象API

    var obj = {x:100,y:200,z:300};
    for(var key in obj){
        //如果key是自身的属性,那么打印出来
        if(obj.hasOwnProperty(key)){
            console.log(key,obj[key]);
        }
    }

    获取 2018-01-23 格式的日期:

    var dt = new Date();
    
    function formatDate(dt){
        if(!dt){
            dt = new Date();
        }
        var year = dt.getFullYear();
        var month = dt.getMonth() + 1;
        var date = dt.getDate();
    
        if(month < 10){
            month = '0'+month;
        }
        if(date < 10){
            date = '0'+month;
        }
    
        return year + '-' + month + '-' + date;
    }
    console.log(formatDate(dt));

    获取随机数,要求是长度一致的字符串格式:

    var random = Math.random();
    random = random + '0000000000';//后面加上10个0
    random = random.slice(0,10);
    console.log(random);

    写一个能遍历对象和数组的通用 forEach 函数

    function forEach(obj,fn){
        var key;
        if(obj instanceof Array){
            //准确判断是不是数组
            obj.forEach(function(item,index){
                fn(index,item);
            });
        }else{
            //不是数组就是对象
            for(key in obj){
                fn(key,obj[key]);
            }
        }
    }
    //使用
    var arr = [1,2,3];
    //注意,这里参数顺序换了,为了和对象的遍历格式一致
    forEach(arr,function(index,item){
        console.log(index,item);
    })
    
    var obj = {x:100,y:200};
    forEach(obj,function(key,value){
        console.log(key,value);
    })
  • 相关阅读:
    BZOJ3631 [JLOI2014] 松鼠的新家
    HDU
    HDU
    HDU
    二分图求最大独立集模板
    HDU
    HDU
    HDU
    Codeforces 1197F Coloring Game 矩阵快速幂 (看题解)
    HDU
  • 原文地址:https://www.cnblogs.com/anqwjoe/p/8893913.html
Copyright © 2020-2023  润新知