JS基础——作用域、原型、闭包初探(中——引用类型)

(本文源自“JS高级程序设计”第5章读后梳理)

这一章主要讲的是JavaScript中的原生引用类型,包含的内容为:

(注,和“JS基础——作用域、原型、闭包初探(上)”中的内容一样,这些都是JS中十分基础的知识,要十分熟悉的记忆在脑子里面。)

依稀记得看过的其他一些博主写的文章,谈到学习JS基础,要有系统的去学习,作为小白的我,自学,也不知道啥是有系统的学习,那我干脆,直接把这本基础经典书的目录给背了下来。

还是有些些用,至少脑子里是知道哪些内容在哪里。 X)

应该没有人比我的方法更笨了。。。

接着说正题:

引用类型是JavaScript中的一种将数据和方法组织起来的数据结构。

不能把它们叫做类,虽然JavaScript是面向对象的编程语言,但是JavaScript中是没有类和接口这些基本结构的,所以对引用类型的称呼更准确的是“对象定义”,因为它定义了同一类对象应该具有的属性和方法。

应用类型的值就是它的一个实例,可以通过new操作符+构造函数来创建。


这一章我们通过目录的的顺序来讲:Object、Array、Date、RegExp、Function、基本包装函数、单体内置对象。


一、Object类型

Object类型有三个关键点:

  1. 创建Object实例的第一种创建方式:
    var person = new Object();
  2. 创建Object实例的第二种方式:对象字面量

    var person = {
        name:"dingding",
        job:"software engineer",
        age:29
    };
  3. 方括号访问符:(这个不重要)

    就是通过方括号访问实例中的变量。假如有变量名是“first name”,这种玩意,不可能通过点运算符去访问,这个时候就需要通过这个方括号访问。(这是我不是很明白,有什么变量能定义为first name的形式?不应该是驼峰写法——firstName吗?)
    //如果实例中有一个变量名字长成了first name这个样子
    var name = person.first name;//显然,这是不可能的
    var name = person["first name"];//正解

二、Array类型

Array类型一些基本的创建方式这里就不详细的描述了,着重的还是去记忆一些Array类型的方法:

检测数组、转换方法、栈方法、队列方法、重排序方法、操作方法、位置方法、迭代方法、归并方法。

总共九个小的专题,一个一个的来:

  1. 检测数组:Array.isArray(value),检测value是不是一个数组;
  2. 转换方法:toString()、toLocaleString()、valueOf()、join()
    1. 前两个的作用就不说了。
    2. valueOf()返回数组本身。
    3. join(),将数组转换为字符串,以传入join()的字符为间隔。如果没有传入任何值,或者“undefined”,就按照默认的方式转换(和toString()相同)——以逗号为间隔。
  3. 栈方法:push()、pop()
    1. 栈方法,“后进先出”,就像一个“没有出口的盒子”,一个一个的把数据放进去,后放进去的先拿出来。
    2. push(),将数据放入数组的最后一位,可以一次性push()多个数据,返回push()后数组长度
    3. pop(),将数据从栈中弹出,一次只能弹出一个,返回弹出的数据
  4. 队列方法:shift()、unshift()
    1. 队列,“先进先出”,就把它想象成普通的排队好了,排在前面的先出去。
    2. shift(),将数组第一个数据弹出,一次一个,返回弹出的数据。搭配push()使用。
    3. unshift(),将数据推入数组第一位,一个可多个,返回数组长度,搭配pop()使用。
  5. 重排序方法:reverse()、sort()
    1. reverse(),将数组的数据,倒叙排列。
    2. sort()将数组升序排列——即从小到达,注意这里的从小到达,是字符的序号,而不是数字的大小。
      var arr =[1,3,5,15,25];
      arr.sort();//[1,15,25,3,5],是按照字符序号升序,而不是数字

      想要通过数字的大小排列,我们就需要给sort()方法传入一个compare()方法:

      var arr = [1,3,15,5,25];
      
      function compare(value1,value2){
          if(value1 < value2){
              return -1;
          }else if(value1 > value2){
              return 1;
          }else{
              return 0;
          }
      }
      
      arr.sort(compare);//[1,3,5,15,25]

  6. 操作方法:concat()、slice()、splice()
    1. concat(),可接受多个参数,创建数组的副本,将数据添加到数组的末尾,返回数组。
    2. slice(),接受两个参数,截取,两个参数分表表示开始截取位置,和结束截取位置。
      1. 返回原数组截取段的副本,结束截取位置的值不包含,可以这么记忆——数组中的[index1,index2)。
      2. 如果两个参数中有负数,表示的就是数组的长度加上该负数的结果。
    3. splice(),这个方法会直接在数组上操作,操作后,原数组会发生变化,不同于前两个方法。接收参数的方式很灵活,但可以理解为接收三段参数
      1. 第一个参数表示截取开始位置;
      2. 第二个参数表示,要删除的项数,会删除掉包括第一个位置的数据哦
      3. 第三个参数及以后的参数,都表示要插入到第一个参数位置及之后的数据。
      4. 当第二参数为0的时候,可以通过第三个参数实现插入数据;当第二个参数不为0的时候,可以实现替换数据。
      5. splice()函数返回截取出来的数组。
  7. 位置方法:indexOf()、lastIndexOf()
    1. 查找位置,传入两个参数,第一位是要找到数据,第二位开始查找的位置;
    2. indexOf()从前往后找,lastIndexOf()从后往前找;
    3. 返回索引值。
  8. 迭代方法:every()、some()、filter()、map()、forEach()
    1. 这些方法都需要传入一个匿名函数,匿名函数有接收三个参数:
      function(item,index,array){
          //需要进行的操作
      
      }
    2. every(),对数组中的每一个项,进行一个操作,如果数组每一个项在匿名函数中都return true,那么every()函数返回true,反之,返回false。

      var arr = [1,2,3,4,5];
      
      //要所有的项都满足>2,那么every()才会返回true
      //这里every()返回false
      var val = arr.every(function(item,index,array){
          item>2;
      });
    3. some(),与上面every()的操作相同,但是如果数组中有一个符合条件,就返回true。所以上面如果调用的是some()就返回true。

    4. filter(),返回满足条件的值组成的数组。

      var arr = [1,2,3,4];
      
      var val = arr.filter(function(item,index,array){
          return item>2;
      });//返回一个数组,为[3,4,5]
    5. map(),对数组的每一项进行一个操作,返回经过操作后的数组值 所组成的数组。

      var arr = [1,2,3,4,5];
      
      var val = arr.map(function(item,index,array){
          retrun item*2;
      });//返回一个数组,[2,4,6,8,10]
    6. forEach(),对数组的每一项运行一个操作,没有返回值。

      var arr = [1,2,3,4];
      
      var val = arr.forEach(function(item,index,array){
          //执行某些操作,然后返回这个数组
      
      });
  9. 归并方法:reduce()、reduceRight()

    1. 对数组进行迭代,并归并为一个值;

    2. reduce(),从前到后归并;reduceRight(),从后到前归并。

    3. 需要向reduce()、reduceRight()中传递一个匿名函数,匿名函数包含四个参数——前一项,当前项,索引,数组。看代码:

      var arr = [1,2,3,4,5];
      
      var val1 = arr.reduce(function(prev,cur,index,array){
          //需要进行的操作
          return prev + cur;
      });//返回整个数组项相加的结果

三、Date类型

继承的方法,日期格式化方法,日期/时间组件方法

其他的都不细说了,简单的记一下两个关键点:

  1. 日期的格式化书写方式:
    1. 6/13/2020
    2. january 12,2020
    3. Tue January 12 2020 00:00:00 GMT-0700
    4. 2020-01-12T00:00:00
  2. 加时间戳
    //获取代码运行到此处的时间点
    var timeBegin = +new Date();
    ...
    var timeEnd = +new Date();
    
    //获取代码运行到此处的时间点
    var timeBegin = Date.now();
    ...
    var timeEnd = Date.now();

四、RegExp类型

有助于理解RegExp的是一种方式是记住三种的东西: 

RegExp实例中是我们要应用的正则表达式,在目标字符串(String)上面应用我们的模式(pattern),然后得到我们的匹配项(match)。


正则表达式,两种创建方式:字面量、RegExp实例

RegExp字面量这样创建:

//这里的pattern就是我们要用到的正则表达式字面量,
//flag有三个值:i,g,m,分别表示忽略大小写,对整个字符串应用,对多行应用
var expression = /pattern/flag;

RegExp实例像这样创建:

//pattern就是要应用的模式,flag的取值也是i,g,m
var expression = new RegExp("pattern","flag");

注意在模式中使用的元字符都需要转义:{ [ ( * + \ . ^ | ? $ ) ] }

RegExp实例属性,RegExp实例方法、RegExp构造函数,可以用这个图来概括:

  1. exec()传入目标字符串,然后返回一个数组,数组中的内容为图中所示;
  2. test()传入目标字符串,如果目标字符串上有符合调用者——RegExp实例(或者看做是pattern)的匹配项,则返回true;没有,则返回false。
  3. toString()、toLocaleString(),返回正则表达式的字面量。
  4. valueOf(),返回正则表达式本身。
  5. 长属性名都可以用相应的短属性名来代替。只不过这些短属性名大都不是有效的ES标识符,因此必须通过方括号语法来访问:
    var text = "this has been a short summer";
    var pattern = /(.)hort/g;
    
    if(pattern.test(text)){
        alert(RegExp.$_);    //this has been a short summer
        alert(RegExp["$&"]); //short
        alert(RegExp["$+"]); //s
        alert(RegExp["$`"]); //this has been a 
        alert(RegExp["$'"]); //summer
        alert(RegExp["$*"]); //false
        
        alert(RegExp.$1);    //s
    }
  6. 第一个捕获组访问符的简写形式:$1,第二捕获组访问符简写形式为:$2。。。。

五、Function类型

按顺序介绍:没有重载(深入理解)、函数声明与函数表达式、作为值的函数、函数内部属性、函数属性和方法

在这之前我们要知道创建Function类型实例的三种方式:

  1. 函数声明:
    function addNum(num1,num2){
        //要执行的函数体
    
    }
  2. 函数表达式:

    var addNum = function(){
        //要执行的内容
    
    }
  3. 利用new创建实例:(不推荐这种方式,会导致解析两次代码,解析ES代码,第二次解析传入构造函数中的字符串)

    //接收三个参数,最后一个参数为再实例中进行的操作
    //不推荐这种使用方式是因为创建的过程中,需要
    var addNum = new Function("num1","num2","return num1+num2");

开始一个一个的介绍:

  1. 没有重载:前面讲到过,因为函数的接收参数是通过一个数组接受的,虽然定义函数的时候可以定义一定数量要求的参数,比如要求传入两个参数,但是在实际调用的时候时,可以传入一个参数、两个参数、三个参数、四个参数,甚至更多。
    1. 这个时候函数是没有函数签名的,真正的重载是做不到的。
    2. 在ES5中,函数名,其实是一个指向堆内存中一个函数体,后面重写的同名函数,会将前面的同名函数覆盖掉。
  2. 函数声明与函数表达式:具体的形式前面都讲到了,这里助于一个点就是:
    1. 函数声明提升:function declaration hoisting,在对函数求值时,JavaScript引擎在第一遍声明函数并将它们放到源代码树的顶部。
      //由于addNum()是通过函数声明创建的,所以addNum()会被放到顶部,
      //所以先调用,或声明,也可以得到正确的答案
      alert(addNum(1,3));//4
      
      function addNum(num1,num2){
          return num1+num2;
      }
  3. 作为值的函数:即一个函数作为另一个函数的值,被return,这里我们在闭包再重点讲解。。。

    function compare(propertyName){
        return function(object1,object2){
            name1 = object1[propertyName];
            name2 = object2[propertyName];
            
            if(name1 < name2){
                return -1;
            }else if(name1 > name2){
                return 1;
            }else{
                return 0;
            }
        }
    }
  4. 函数的内部属性:arguments.callee,this,caller。

    1. arguments.callee,取得当前函数的引用,可以应用于递归函数的解耦,这个属性在严格模式不能使用。

    2. this,表示当前函数的执行环境对象;

    3. caller表示调用当前函数的函数的引用。

      function outer(){
          inner();
      }
      
      function inner(){
          alert(inner.caller);
      }
      
      outer();

      这里调用outer(),会调用inner()函数,inner函数内部又会通过caller,将调用inner的函数(也就是outer())的函数体给通过警告框展示出来。
      注意:这样可能会导致outer()的函数体内容泄漏。
      在严格模式下,不允许向caller属性赋值。

  5. 函数属性和方法

    1. 内部属性:length,prototype。
      length就是定义函数的定义的参数个数;
      prototype,原型,在后面将原型的时候,再细说。

    2. 内部方法:apply(),call(),bind()。

      1. apply(),接收两个参数,调用者要运行的环境(也就是调用者的this值),和 传入调用者的参数数组(可以是Array实例,也可以是arguments对象)。

      2. call(),接收两个参数,和apply类似,只是第二参数传入时,必须逐个列举出来。

      3. bind(),这个方法会创建一个实例,然后将调用者的this值绑定为传入bind()的参数。

      4. 这些方法的实现细节不在这里细讲,但需要去搞清楚。

      5. 这些方法的优点,会在后面讲到——函数绑定、函数柯里化。。

六、基本包装类

ES中的三种特殊的引用类型:Boolean、Number、String。

它们三个是基本类型,但在创建以后,ES会在后台创建一个对应的基本包装类,以便我们能够调用响应的方法。

就是说,这三种类型本来时基本类型,但在创建后,后台会为它们创建一个对应的对象,方便调用关于它们的一些方法,来操作它们。

  1. Boolean:没啥可说的,,因为建议永远不要使用Boolean对象
  2. Number:同样不建议直接实例化Number,和Boolean一样。三个方法,有兴趣了解的童鞋自己看书哦。
    1. toFixed(),将数字保留小数位,保留的位数由传入函数的参数值决定;
    2. toExpronential(),将数字保留位数,但是这是指数,同样,保留位数由传入函数的参数数值决定;
    3. toPrecision(),将数字保留位数,至于是小数还是指数,由引擎“自己看着办”。
  3. String:记住这么一些方法就好了。。这里都不将这些方法了,大家可以自行看书了解。。
    1. 字符方法:charAt()、charCodeAt()。
    2. 字符串操作方法:concat()、slice()、substring()、substr()。
    3. 字符位置方法:indexOf()、lastIndexOf()。
    4. trim()。
    5. toLowerCase()、toUpperCase()。
    6. 模式方法:match()、search()、replace()、split()。
    7. localeCompare()。
    8. fromCharCode()。
    9. HTML方法。

七、单体内置对象

ES中对内置对象的定义是:不依赖于宿主环境的对象,这些对象在ES程序执行之前就已经存在了。

意思是说开发人员不必显示的实例化内置对象,因为它们已经实例化了。

Object、Array、String等都是内置对象。

这里介绍两个ES定义的单体内置对象:Global和Math。

  1. Global对象:终极“兜底”对象,不属于任何其他对象的属性和方法,最终都是它的属性和方法。
    1. 我现在还不知道怎么用它这个东西,先知道有这么个东西存在,到以后在下去细致的了解吧。。。
    2. 记住三个方法:
      1. encodeURIComponent(),对uri的某一段进行编码,把uri的所有没标准字符进行编码转换;
        对应的就是decodeURIComponent(),
      2. encodeURI(),对整个uri进行编码。与上面这个方法的区别就是:
        encodeURI()不会对本身属于URI的特殊字符进行编码,如冒号、正斜杠、问号、井字号而encodeURIComponent()会对发现的所有非标准字符进行编码
        一般来说,使用encodeURIComponent()方法的时候要比使用encodeURI()更多,因为在实践中更常见的是对查询字符串参数而不是基础URI进行编码。
      3. eval()方法,ES中最强大的一个方法,这个方法就像是一个完整的ES解析器。
        1. 只接受一个参数,即要执行的ES字符串。
        2. 具体的大家自行看书。
  2. Math对象,记住几个方法:
    1. ceil(),向上舍入;
    2. floor(),向下舍入;
    3. round(),“四舍五入”;
    4. random(),随机数,范围[0,1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值