zoukankan      html  css  js  c++  java
  • js八种数据类型整理

    String

    所有的API都无法修改原字符串,只能返回新字符串

    API:

    • 大小写转换

      str.toUpperCase();

      str.toLowerCase();

    • 获取指定字符串位置

      str.charAt(); 得到下标 str[i]

      str.charCodeAt(i); 得到字符串编码

    • 选取字符串

      str.slice(start,end+1); 支出负数

      str.substring(start,end+1); 不支持负数

      str.substr(statr,n); 含头不含尾

    • 查找关键字

      1. 查找关键字出现的位置

        str.indexOf("关键字",from); 如果找不到返回-1

        优点:可以指定开始位置,可以查找所有

        缺点:不支持正则,一次只能找一个关键词

        专门查找最后一个关键词的下标,str.lastIndexOf("关键词")

      2. 判断是否包含符合条件的关键词

        str.search(/正则表达式/); 如果找不到就返回-1,不支持使用g

        优点:支持正则

        缺点:不支持设置开始位置,只能找第一个,不能找到所有

        ​ 只能返回关键词位置,不能返回关键词内容

      3. 获取所有关键词内容

        str.match(/正则表达式/g); 返回包含所有关键词内容的数组,如果找不到 返回null

        优点:返回所有关键词的内容

        缺点:无法返回关键词的下标

      4. 既能获取下标,又能获取内容

        regexp.exec(str)

    • 替换

      str.splice(/正则表达式/ig,"替换值"); 忽略大小写

    • 切割

      简单切割 str.split("分隔符")

      复杂切割 str.split(/正则表达式/)

    Number

    ​ 极大极小的数值,可以用e表示

    ​ 如果数值超出javaScript数值范围,会被自动转换为Infinity值(有正负之分);infinity不能参与下次计算

    ​ 确定一个数值是不是有穷的,可使用isFinite()函数

    • NaN

      表示一个本来要返回数值的操作数未返回数值的情况,这样不会抛出错误

      特点:

      1.任何涉及NaN操作 ( 如:NaN/10 ) 都会返回NaN

      2.NaN与任何值都不相等,包括NaN本身,如:alert(NaN==NaN)//false

      isNaN();接受一个参数,判断这个参数是否“不是数值”

    Boolean

    Null&&Undefined

    • null

      表示一个空指针,这也是使用typeof操作符检测null值时会返回object的原因

      定义一个变量在将来保存对象,那么最好将改变量初始化为null

    • undefined

      使用var声明变量但未对其加以初始化时,这个变量就是Undefined

    • 比较

      null===undefined //true

      尽管两者有这样的关系,但是它们的用途完全不同,无论什么情况下都没有必要把一个变量显示的设置为Undefined,而null就应该明确的让该变量保存为null值,这样做不仅可以提现null空对象指针的惯例,还有助于进一步区分null和undefined

    Object

    1、Arrary
    • 什么是

      内存中连续存储多个数据的存储控件,再起一个名字

    • 为什么

      连续存储的一组数据,可大量提高操作速度

    • 何时

      只要存储多个数据都要用数组

    • 如何

      • 创建

        1. 创建空数组

          var arr = []
          var arr = new Array()
          
        2. 创建数组并初始化数组元素

          var arr = [值1,只2,...]
          var arr = new Array(值1,值2,...)
          
        3. 创建n个空元素数组

          var arr = new Array(值1,值2,...)
          
      • 访问

        arr[i]

        用法和单个变量完全一样

        三个不限制:

        不限制元素个数,可以随时添加元素;

        不限制下标越界,取值:不报错,返回undefined;赋值:不报错,自动在指定位置添加元素

        不限制元素数据类型

      • 关联数组

        • 什么是

          可自定义下标名称的数组

        • 为什么

          索引数组没有意义,只能通过遍历查找指定的元素内容,查找速度受数组元素个数和元素位置影响

        • 何时

          希望快速查找某个元素时,不受元素个数和元素位置影响

        • 如何

          1. 创建

            var hash = [];
            hash[“下标名称”]="值(value)"
            
          2. 访问

            hash["下标名称"]
            
          3. 特点

            length始终为0

            无法使用索引数组API

            遍历:

            for(var key in hash){
            	key //下标名
            	hash[key] //元素值
            }
            

            固定套路,仅获取hash中所有key

      • 数组API

        • 转字符串

          //将arr中每个元素转为字符串,用逗号连接
          String(arr)
          
          //自定义连接符连接
          arr.join("连接符")
          
          //无缝拼接
          arr.join("")
          
          //判断空数组
          arr.join("")===""
          
        • 拼接和选取

          //拼接
          //无权修改原数组,只能返回新数组,可自动打散数组类型的数值为单个元素,再拼接
          arr.concat()
          
          
          //选取
          //无权修改原数组,只能返回新数组,含头不含尾
          arr.slice(start,end+1)
          
        • 修改数组

          //删除元素
          //直接修改原数组,返回值时被删除的元素组成的临时数组
          arr.splice(start,end+1)
          
          //插入数组
          //在arr中插入新值原始位置及后的元素顺序后移
          //不支持打散数组类型的数值,如果插入数组,会变成二维数组
          arr.splice(start,0,值1,值2...)
          
          //替换
          //先删除start位置的n个元素,再在start位置插入新元素
          //删除的个数跟插入的个数不一定要一致
          arr.splice(start,n,值1,值2...)
          
          //固定用法
          //广告轮播
          //移除开头的n个元素到结尾
          imgs = imgs.concat(imgs.splice(0,n))
          
          //移除结尾的n个元素到开头
          imgs = imgs.splice(imgs.length-n,n).concat(imgs)
          
        • 翻转

          arr.reverse()
          
        • 排序

          //将arr中每个元素转为字符串,再按升序排序
          arr.sort()
          
          //问题:只能按字符串升序排序
          //解决:自定义比较器
          function compare(a,b){
          	return a-b 
          };
          
          arr.sort(compare);
          
          
          //降序排列
          //将比较器函数的正负号颠倒就好了
          function compare(a,b){
          	return b-a
          };
          
        • 栈和队列

          栈:一端封闭,只能另一端进出的数组

          //强调:js中没有栈和队列的结构,都是用普通数组模拟
          //结尾出入栈
          //入栈
          arr.push()
          //出栈
          arr.pop()
          
          //开头出入栈
          //入栈
          arr.unshift()
          //出栈
          arr.shift()
          

          队列:只能一端进入,另一端出的数组

          //结尾入
          arr.push()
          //开头出
          arr.shift()
          
        • 二维数组

          二维数组:数组中的元素内容,又是一个子数组

          //创建
          var arr = []
          arr[i] = {值1,值2,值3...}
          
          
          var arr = [
          	{值1,值2,值3...},
          	{值1,值2,值3...}
          ]
          
          //访问
          arr[r][c]
          
          //遍历
          for(var r=0;r<arr.length;r++){
          	for(var c=0;c<arr[r].length;c++){
          		arr[r][c] //当前元素
          	}
          }
          
    2、Function
    • 创建

      //1.
      function 函数名(参数列表){
      	函数体;
      	return 返回值
      }
      //2.
      var 函数名 = function(参数列表){
      	函数体;
      	return 返回值
      }
      //3.
      var 函数名 = new Function(“参数1”,“参数2”,...){
      	函数体;
      	return 返回值
      }
      
    • 重载

      函数名相同,函数的参数列表不同(包括参数个数和参数类型),根据参数的不同去执行不同的操作。

      我们举个例子看看

      function overload(a){
          console.log('一个参数')
      }
      
      function overload(a,b){
          console.log('两个参数')
      }
      
      // 在支持重载的编程语言中,比如 java
      overload(1);         //一个参数
      overload(1,2);    //两个参数
      
      
      // 在 JavaScript 中
      overload(1);         //两个参数
      overload(1,2);    //两个参数
      

      在JavaScript中,同一个作用域,出现两个名字一样的函数,后面的会覆盖前面的,所以 JavaScript 没有真正意义的重载。

      但是有各种办法,能在 JavaScript 中模拟实现重载的效果。

      一、借助流程控制语句,通过 arguments 对象来实现

      arguments 对象,是函数内部的一个类数组对象,它里面保存着调用函数时,传递给函数的所有参数。

      function overload () {
        if (arguments.length === 1) {
          console.log('一个参数')
        }
        if (arguments.length === 2) {
          console.log('两个参数')
        }
      }
      
      overload(1);      //一个参数
      overload(1, 2);  //两个参数
      

      这个例子非常简单,就是通过判断 arguments 对象的 length 属性来确定有几个参数,然后执行什么操作。

      但是参数少的情况下,还好,如果参数多一些,if 判断就需要写好多,就麻烦了。

      二、巧用闭包特性

      ​ JQuery之父John Resig写的《secrets of the JavaScript ninja》找到了一个绝佳巧妙的方法!那种方法充分的利用了闭包的特性!

      ​ 在介绍这个方法之前,我们先来看看外国人名字组成哈,比如,John Resig,John是first-name,Resig是last-name,就相当于我们的姓名由姓和名组成一样。

      ​ 我们现在有这样的一个需求,有一个people对象,里面存着一些人名,如下:

      var people = {
        values: ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
      };
      

      ​ 我们希望people对象拥有一个find方法,当不传任何参数时,就会把people.values里面的所有元素返回来;当传一个参数时,就把first-name跟这个参数匹配的元素返回来;当传两个参数时,则把first-name和last-name都匹配的才返回来。因为find方法是根据参数的个数不同而执行不同的操作的,所以,我们希望有一个addMethod方法,能够如下的为people添加find的重载:

      addMethod(people, "find", function() {}); /*不传参*/
      addMethod(people, "find", function(a) {}); /*传一个*/
      addMethod(people, "find", function(a, b) {}); /*传两个*/
      

      这时候问题来了,这个全局的addMethod方法该怎么实现呢?John Resig的实现方法如下,代码不长,但是非常的巧妙:

      function addMethod(object, name, fn) {
        var old = object[name]; //把前一次添加的方法存在一个临时变量old里面
        object[name] = function() { // 重写了object[name]的方法
          // 如果调用object[name]方法时,传入的参数个数跟预期的一致,则直接调用
          if(fn.length === arguments.length) {
            return fn.apply(this, arguments);
          // 否则,判断old是否是函数,如果是,就调用old
          } else if(typeof old === "function") {
            return old.apply(this, arguments);
          }
        }
      }
      
         现在,我们一起来分析一个这个addMethod函数,它接收3个参数,第一个为要绑定方法的对象,第二个为绑定的方法名称,第三个为需要绑定的方法(一个匿名函数)。函数体的的分析已经在注释里面了。 
      

      ​ OK,现在这个addMethod方法已经实现了,我们接下来就实现people.find的重载啦!全部代码如下:

      //addMethod
      function addMethod(object, name, fn) {
        var old = object[name];
        object[name] = function() {
          if(fn.length === arguments.length) {
            return fn.apply(this, arguments);
          } else if(typeof old === "function") {
            return old.apply(this, arguments);
          }
        }
      }
       
       
      var people = {
        values: ["Dean Edwards", "Alex Russell", "Dean Tom"]
      };
       
      /* 下面开始通过addMethod来实现对people.find方法的重载 */
       
      // 不传参数时,返回peopld.values里面的所有元素
      addMethod(people, "find", function() {
        return this.values;
      });
       
      // 传一个参数时,按first-name的匹配进行返回
      addMethod(people, "find", function(firstName) {
        var ret = [];
        for(var i = 0; i < this.values.length; i++) {
          if(this.values[i].indexOf(firstName) === 0) {
            ret.push(this.values[i]);
          }
        }
        return ret;
      });
       
      // 传两个参数时,返回first-name和last-name都匹配的元素
      addMethod(people, "find", function(firstName, lastName) {
        var ret = [];
        for(var i = 0; i < this.values.length; i++) {
          if(this.values[i] === (firstName + " " + lastName)) {
            ret.push(this.values[i]);
          }
        }
        return ret;
      });
       
      // 测试:
      console.log(people.find()); //["Dean Edwards", "Alex Russell", "Dean Tom"]
      console.log(people.find("Dean")); //["Dean Edwards", "Dean Tom"]
      console.log(people.find("Dean Edwards")); //["Dean Edwards"]
      
      三、巧用引用类型特性

      核心思想:由于ECMAScript函数是一种引用类型对象,可扩展属性与方法。借此通过创建一个容器用于存储要重载的函数,并将容器挂载到代理函数上以便后续访问,而代理函数利用闭包特性访问容器。
      重载顺序:首先查找参数类型匹配的函数,其次查找参数个数匹配的函数。
      存储格式:键值对,键名由逗号与参数个数或参数类型组成,键值为要重载的函数,如下:

      {
        ',0': function(){/* code */},
        ',1': function(a){/* code */},
        ',string,number': function(a,b){/* code */}
      }
      

      工具函数被调用时:

      1. 先判断是否已重载过,若有,直接将要重载的函数按格式存入容器;
      2. 若未重载过,则创建一个容器变量;
      3. 判断未重载前的值是否为一个函数,若是,则以逗号+参数个数的格式存入容器;
      4. 将要重载的函数存入容器;
      5. 代理原函数,并将容器挂载到代理函数上;
      6. 当代理函数被调用时,将依次查找容器中匹配的函数并调用。
      /**
       * 重载工具函数
       * @param {Object} ctx - 上下文
       * @param {String} name - 函数名
       * @param {Function} fn - 函数体
       * @param {String} type - 参数类型
       * @author 范围兄 <ambit_tsai@qq.com>
       * @example 不指定参数类型
       *  overload(obj, 'do', function(){...});
       *  overload(obj, 'do', function(a){...});
       * @example 指定参数类型
       *  overload(obj, 'do', function(a,b){...}, 'string,number');
       */
      function overload(ctx, name, fn, type){
        type = type? type.trim().toLowerCase(): fn.length;
        // 已重载过
        if(typeof ctx[name]==='function' && typeof ctx[name]._$fnMap==='object'){
          ctx[name]._$fnMap[','+type] = fn;	// 将fn存入_$fnMap
          return;
        }
        // 未重载过
        var fnMap = {};   // 容器
        if(typeof ctx[name] === 'function'){
          // 若ctx[name]是一个函数,则存入容器
          fnMap[','+ctx[name].length] = ctx[name];
        }
        fnMap[','+type] = fn;
        ctx[name] = function overloading(){   // 代理
          var args = arguments, 
              len = args.length, 
              type, i;
          for(i=0, type=''; i<len; ++i){  // 计算参数类型
            type += ',' + typeof args[i];
          }
          // 依次匹配:参数类型->参数个数
          if(fnMap[type]) return fnMap[type].apply(this, args);
          if(fnMap[','+len]) return fnMap[','+len].apply(this, args);
          throw 'Overload: no matched function';
        };
        ctx[name]._$fnMap = fnMap;   // 将fnMap挂载到代理上
      }
      
    • 匿名函数

      没有实际名字的函数

      //自调函数
      //自己调用自己,调完后立即释放
      (function (str){
      	console.log(str)
      })(str)
      
      //函数表达式
      let fn = function(str){
      	console.log(str)
      }
      fn(str)
      
      //模仿块级作用域
      function fn(){
          (function(){
              var la="啦啦啦!";
          })();
          console.log(la);//报错---la is not defined
      }
      fn();
      

      匿名函数的作用:

      1、通过匿名函数可以实现闭包,关于闭包在后面的文章中会重点讲解。在这里简单介绍一下:闭包是可以访问在函数作用域内定义的变量的函数。若要创建一个闭包,往往都需要用到匿名函数。

      2、模拟块级作用域,减少全局变量。执行完匿名函数,存储在内存中相对应的变量会被销毁,从而节省内存。再者,在大型多人开发的项目中,使用块级作用域,会大大降低命名冲突的问题,从而避免产生灾难性的后果。自此开发者再也不必担心搞乱全局作用域了。

    • 作用域(scope)与作用域链(scope chain)

      • 函数生命周期
      1. 开始执行前:

        创建执行环境栈(数组): 临时保存正在执行的函数的执行环境

        向执行环境栈中压入第一个默认函数main()

      ​ 创建全局作用域对象window

      1. 定义函数时:

        创建函数对象,封装函数定义

        声明函数名变量,引用函数对象

        函数对象的scope属性引用回创建函数时的作用域

      2. 调用函数时:

        ECS(执行环境栈)中压入一个新的元素(执行环境)记录新函数的调用

        创建一个活动对象,保存本次函数调用用到的局部变量

        ECS(执行环境栈)中的新执行环境元素,引用活动对象

        活动对象中的parent属性引用函数的scope指向的父级作用域对象

        执行过程中: 优先使用活动对象中的局部变量

        局部没有,才延parent向父级作用域找

      3. 函数调用后:

        执行环境栈中本次函数的执行环境出栈

        导致活动对象被释放

        导致局部变量一同释放

      图示:

      前三步

      img

      img

      • 作用域

        作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。

        执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

        全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境不同,表示的执行环境的对象也不一样。

        • 在 Web 浏览器中,全局执行环境被认为是 window 对象,因此所有全局变量和函数都是作为 window 对象的属性和方法创建的
        • 在 NODE 环境中,全局执行环境是 global 对象。

        某个执行环境中所有的代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出时,如关闭浏览器或网页,才会被销毁)

        每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将被环境弹出,把控制权返回给之前的执行环境。ECMAScript 程序中的执行流正是由这个方便的机制控制着。

        概括来说:
        作用域就是代码执行开辟栈内存

        • 私有作用域 ----> 函数执行都会形成一个私有作用域
        • 全局作用域 ----> 页面一打开就会形成一个全局的作用域
        • 私有变量 ----> 在私有作用域里边形成的变量 (通过 var 声明; 形参)
        • 全局变量 ----> 在全局作用域形成的变量(var a = 12 或者函数内没有声明,直接赋值的变量)
      • 作用域链

        当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)

        • 作用域链的前端,始终都是当前执行的代码所在环境的变量对象
        • 作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境
        • 全局执行环境的变量对象始终都是作用域链上的最后一个对象

        内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。

        var n = 10;
        function outer(){
          function inner(){
            function center(){
              console.log(n);
            }
            center();
          }
          inner();
          var n = 15;
        }
        outer(); //=> undefined
        

        如函数的执行,形成一个私有作用域,形参和当前私有作用域中声明的变量都是私有变量,保存在内部的一个变量对象中,其下一个外部环境可能是函数,也就包含了函数的内部变量对象,直到全局作用域。

        当在内部函数中,需要访问一个变量的时候,首先会访问函数本身的变量对象,是否有这个变量,如果没有,那么会继续沿作用域链往上查找,直到全局作用域。如果在某个变量对象中找到则使用该变量对象中的变量值。

        由于变量的查找是沿着作用域链来实现的,所以也称作用域链为变量查找的机制

        这个机制也说明了访问局部变量要比访问全局变量更快,因为中间的查找过程更短。但是 JavaScript 引擎在优化标识符查询方面做得很好,因此这个差别可以忽略不计。

    • 闭包

      闭包(Closure):闭包就是指有权访问另一个函数作用域中的变量的函数。

      理解关键:外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。

    3、OOP(面向对象)
    1. 封装

      创建一个对象,集中存储一个事物的属性和功能

    2. 继承

      父对象的成员,子对象无需创建可直接使用

      原型对象、原型链

      https://www.cnblogs.com/AaronNotes/p/14381813.html

    3. 多态

      同一事物,在不同情况下,表现出不同的状态

    Symbol

    概述

    ​ ES6引入的一种新的原始数据类型Symbol,表示独一无二的值,最大的用法是用来定义对象的唯一属性名

    基本用法

    ​ Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。

    let sy = Symbol("KK");
    console.log(sy);   // Symbol(KK)
    typeof(sy);        // "symbol"
     
    // 相同参数 Symbol() 返回的值不相等
    let sy1 = Symbol("kk"); 
    sy === sy1;       // false
    

    BigInt

    ​ 在 ES10 增加了新的原始数据类型:BigInt,表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方。

    Js 中 Number类型只能安全的表示-(2^53-1)至 2^53-1 范的值

    console.log(2 ** 53) // es7 幂运算符
    console.log(Number.MAX_SAFE_INTEGER) // 最大值-1
    

    使用 BigInt 有两种方式:

    方式一:数字后面增加n
    const bigInt = 9007199254740993n
    console.log(bigInt)
    console.log(typeof bigInt) // bigint
    
    console.log(1n == 1) // true
    console.log(1n === 1) // false
    
    方式二:使用 BigInt 函数
    const bigIntNum = BigInt(9007199254740993n)
    console.log(bigIntNum)
    
  • 相关阅读:
    iOS Simulator功能介绍关于Xamarin IOS开发
    Unity中制作游戏的快照游戏支持玩家拍快照
    手机数据抓包入门教程
    Swift语言中为外部参数设置默认值可变参数常量参数变量参数输入输出参数
    Hierarchy视图里的Transform和Camera组件
    用JAVA编写MP3解码器——GUI(FFT)(转)
    功率W与dBm的对照表及关系(转)
    单鞭天线的长度计算方法(转)
    STM32F10X SPI操作flash MX25L64读写数据(转)
    利用STM32F唯一96bit序列号实现反拷贝加密的源代码公开(转)
  • 原文地址:https://www.cnblogs.com/AaronNotes/p/14551283.html
Copyright © 2011-2022 走看看