javascript 跳跃式前进 (2) - 作用域及引用类型

简介: 上一节我们说了那些JS的基本概念相关的..今天我们接着来扯扯作用域对象这些基础知识;


前言


上一节我们说了那些JS的基本概念相关的..今天我们接着来扯扯作用域对象这些基础知识;


变量


JS的变量是相当松散的,这个特性让人又爱又恨,因为我们可以在它的生命周期内进行各种各样的改变[比如值,数据类型,规则等].同样这个特性也提升了维护难度,一不小心自己给自己埋了个大坑


  • ECMAScript的变量可以包含以下两种值:基本类型值和引用类型值,前者是简单的赋值,后者是对象的操作


  • 简单的赋值和对象的赋值的较大区别在于,内存值是副本还是指针的指向,比如看下面


/*这个简单的赋值中,test2是直接把test1的值赋值一份到新的空间[test2的值只是test1的一个副本],两者的操作互不影响
  两者都属于number对象上的;
*/
var test1 = 123,
      test2 = test1;
/*
  然而在声明对象中,对象的相互赋值和引用就会**大爆炸**,会相互影响,看看我在chrome下测试的结果;
   obj是保存在一个新实例中的,而obj2的操作是把obj的实例也指向它,两者都是指向同个实例中[堆内存指向一致],所有操作都是引用他们共有的对象[这是和简单赋值的区别所在];
*/
var obj = {name:"123"};  
var obj2 = obj;                
obj2.name                         //打印输出:"123"
obj2.name = "flksjf";           //打印输出:"flksjf"
obj.name                          //打印输出:"flksjf"
复制代码


值传递及作用域


  • JS中,参数只能按值传递


//这里已经初步体现了值传递[结果上]
function add(test){
   test += test;
   return test;
}
var count = 10;
var test2 = add(count);
console.log(count)     //打印输出:10
console.log(test2)     //打印输出: 20
//若是针对于对象呢?答案就是在局部作用域中的修改会在全局作用域中体现出来
//若是在局部中重新定位该对象,局部中的二次修改不会反馈到全局中[因为在函数执行完毕后会呗销毁该对象]
function a(obj){
   obj.name = "LLL";
}
var t = {};   
a(t)
console.log(t.name)    //打印输出:LLL
//我改改改
function a(obj){
   obj.name = "我是设置对象的";
   obj = new Object(); //我重新定义对象
   obj.name = "我是局部对象中的二次赋值";  //外部我改不动.
}
a(t)
console.log(t.name)  // 打印输出:我是设置对象的


  • 延迟作用域链


在作用域链的前端添加一个变量对象,会延长作用域的的执行流,其中try..catch的catch和with语句都会代表/


/*finally是最终会执行,不用catch是否有错*/
   try {
  // 此处是可能产生例外的语句
  } catch(error) {
  // 此处是负责例外处理的语句
  } finally {
  // 此处是出口语句
  }
     /*
      width语句可以用来缩写对象,本人用的非常少..严格模式也是不允许用with的
      如何使用?,,看下面的代码
     */
     with(obj){
          statment;
     }
      /*eg:width demo*/
      /*常规写法1:*/
     var x = Math.random()*10,         //打印输出值:0.3079526301167945
            y =  Math.abs(-4),           //打印输出值:4
          z = Math.floor(3.25);     //打印输出值:3
     /*with写法:*/
      with(Math){
       var  x = random()*10,
              y = abs(-4),
              z = floor(3.25);
       console.log(y+z);      //打印输出值:7
    }      


  • 没有块级作用域[在ES6之前不存在官方定义]


在ES5前,一般都是用匿名函数来实现块级作用域
而ES6,出现了let和箭头函数,块级作用域算是正式出现了


对象


  • 对象声明有两种


//第一种,声明式
     var a = new Object();
     a.name = "123";
     a.age = 15;
     //第二种,字面量
     var b =  {name:"456",
                    age:15};
    //个人还是比较推荐使用字面量的.比较直观.


  • 对象的值访问也有两种方式


var b =  {name:"456",age:15};
      console.log(b["name"])      //打印输出值:456 ,适合带空格这类的
      console.log(b.name)          //打印输出值:456
      b["test vakye"]  = "sfdasdf"  //Object {name: "456", age: 15, test vakye: "sfdasdf"}
       console.log(b["test vakye"]);   //打印输出值:"sfdasdf"复制代码


数组


  • 数组的声明和对象类似


//声明型
    var arr = new Array();  //填写数据在括号内,则代表长度,,值的只有个数;
    //字面量型
    var arr1 = ['1',2,{name:"test"}]  //可以包含字符串,数字类型,对象等


  • 数组的取值


//数组的取值是根据下标来取值的,第一个值的下标为0,以此递增
      var arr1 = ['1',2,{name:"test"}]
      console.log(arr1[0]);          //打印值:"1"
      console.log(arr1[1]);          //打印值:2
       console.log(arr1[2]);          //打印值:Object {name: "test"}
//长度为数组内的个数,若是缩小长度[重新定义],会移除最后一个;反之,若是增加长度,会默认增加一个undefined
//索引的最大值始终是`length-1`


  • 数组栈队列


栈数据是LIFO(后入先出) ,队列数据是FIFO(先进先出)


/*设置值*/
    var arr = []   //length:0
    arr.push("1")    //length:1 , 数据推入尾部
    arr.push(2)    
    console.log(arr);   //length:2  , 输出值 ["1", 2]
    arr.unshift("fsdf",{test:"111"});   //length:4 , 把值推入到数组的第一位
    console.log(arr);     //输出值:["fsdf", Object, "1", 2]
    /*移除值*/
    arr.pop()   //移除并返回数组最后一项
    arr.shift()   //移除并返回数组第一项
   /*增删查改*/
    var arr = [55,1,78,"dfas",98,55,78,{"test":415}]       //测试数组
   /*1.查询
    indexOf()是从头到尾进行查询[查询过程是全等匹配 === ] 
    lastIndexOf()是尾从前进行查询[两者皆有两个参数,第一个是查询值,第二个是开始位置]
    没有查询到就返回-1
  */
    arr.indexOf("dfas");   //返回下标位置 : 3
 arr.indexOf("dfas",4);  //返回 : -1
   arr.lastIndexOf("dfas",2);  //返回下标位置 : -1 ,因为开始从下标2开始,自左往右查询,肯定木有
   arr.lastIndexOf("dfas",7);     //返回下标 3
   /*2.删除[截取],插入,替换
     splice :
        两个参数: 第一个是开始位置,第二个是结束位置(删除的项数)[实际下标等于length-1];
        三个乃至多个: 第一个是开始位置,第二个是删除项数,第三乃至N多个是追加的[替换就是控制删除项目达到替换]
  */
   arr.splice(0,3);         //返回[55, 1, 78] , 打印arr会返回["dfas", 98, 55, 78, Object]
   arr.splice(4,0,"insert1","insert2",{"insert3":3});   //返回 ["dfas", 98, 55, 78, "insert1", "insert2", Object, Object]
   arr.splice(1,4,"replace1","replace2","replace3");   //返回 ["dfas", "replace1", "replace2", "replace3", "insert2", Object, Object, "test"] , 替换


  • 数组迭代


/*
      every、filter、forEach、map、some的异同
      共同点: 对数组中的每一项执行回调函数;
      不同点:
          1. 方法返回值不同
              forEach只是执行函数,没有任何返回值。
              every和some执行函数后,返回Boolean值。
              filter和map执行函数后,返回Array值。
          2. every和some用于判断数组的整体。every需要所有项都满足条件,整体才返回true,相当于“与”条件;some仅需要有一项满足条件,整体就返回true,相当于“或”条件。二者可替换使用。
          3. forEach仅仅是执行函数;而map在执行函数后必须把处理结果返回,重新构造一个数组;filter是用来过滤数组,根据每项的判断返回结果,将满足条件的项重新构造一个函数。
          4. callback返回类型
          5.every、some、filter的callback返回类型必须是Boolean,因为三者的callback均为测试函数,仅仅用来判断;而map的callback返回类型可以依情况而定。forEach的callback返回类型必须为void。
*/
     /*every必须每个都为真才为真,some只要有一个就行了*/
    var arr = [1,2,3,4,5,6,7,8,9];
    arr.some(function(item,index,array){
         return item>5;   //返回true
    })
    arr.every(function(item,index,array){
          return item>5;   //返回false
    })
   /*只是依次执行每个函数,这个没有返回值*/
   arr.forEach(function(item){
        console.log(item * item);   //输出数组的平方 1,4,9,16,25,36,49,64,81
   })
  /*过滤,,相当实用*/
  arr.filter(function(item,index,array){
    return item>5;     //得到的值:[6, 7, 8, 9]
  })
   /*会保存值到新的数组返回,也是相当实用的功能*/
   arr.map(function(item,index,array){
    return item % 2 ;    //得到的返回值: [1, 0, 1, 0, 1, 0, 1, 0, 1]


  • 归并数组


/*原生态的递归数组的方法,相当实用~~~ ;
       reduce()和reduceRight()的区别在于开始计算的方向
       reduce()有四个参数(前一个值,当前值,项目索引和数组对象)
   */
   arr.reduce(function(i,j,index,array){
         return i+j;      //结果是:45
  })
   arr.reduceRight(function(i,j){
          return i*j;    //结果是:362880
    })


  • 数组排序


/*
       有reverse()和sort()两个内置的方法;
       reverse是倒序
       sort是升序
    */
   var arr = [7,6,5,4,3,2,1,2,3,4,5,6,7];
    arr.sort(); //返回值: [1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7];
    arr.reverse(); //返回值: [7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1];
    /*
    两数比较函数;
    相等为0;第一个大于第二个返回值为正1[大数在后],第一个小于第二个返回值为负数1[大数在前]
   */
    function compare(val1,val2){
        if(val1 > val2){
             return 1;
           }else if(val1 < val2){
                return -1;
         }else{
                 return 0;
          }
    }


  • 数组拼接


/*
      数组有两个拼接函数,一个是concat[可以关联拼接多个数组]  -- 得到还是一个数组
      一个是join[通过传入分隔符]  -- 得到是一个字符串
    */
    var arr = [1,2,"3"];
    var arr1 = [{"test":"fs"},[1,2],9];
    arr.concat(arr1);   //返回值 :  [1, 2, "3", Object, Array[2], 9]
   arr.join(":") ;    //返回值: "1:2:3";复制代码


经过测试,,参数里面的index,array可以不带..只要带执行的值即可生效;


Date


日期的使用随处可见,大多数编程语言的计时都是从1970/1/1开始


/*
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
  */
  var d = new Date(); //声明日期对象,里面可以参数,也可以不带参数,也可以带格式的参数     
  //这货实在没啥好说的..具体看链接把[MDN是一个知识宝库]~~~
  // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date复制代码


目录
相关文章
|
12天前
|
JavaScript 前端开发
js的作用域作用域链
【10月更文挑战第29天】理解JavaScript的作用域和作用域链对于正确理解变量的访问和生命周期、避免变量命名冲突以及编写高质量的JavaScript代码都具有重要意义。在实际开发中,需要合理地利用作用域和作用域链来组织代码结构,提高代码的可读性和可维护性。
|
11天前
|
自然语言处理 JavaScript 前端开发
[JS]作用域的“生产者”——词法作用域
本文介绍了JavaScript中的作用域模型与作用域,包括词法作用域和动态作用域的区别,以及全局作用域、函数作用域和块级作用域的特点。通过具体示例详细解析了变量提升、块级作用域中的暂时性死区等问题,并探讨了如何在循环中使用`var`和`let`的不同效果。最后,介绍了两种可以“欺骗”词法作用域的方法:`eval(str)`和`with(obj)`。文章结合了多位博主的总结,帮助读者更快速、便捷地掌握这些知识点。
23 2
[JS]作用域的“生产者”——词法作用域
|
3月前
|
JavaScript 前端开发
浅谈js作用域
浅谈js作用域
32 0
|
13天前
|
前端开发 JavaScript 数据处理
CSS 变量的作用域和 JavaScript 变量的作用域有什么不同?
【10月更文挑战第28天】CSS变量和JavaScript变量虽然都有各自的作用域概念,但由于它们所属的语言和应用场景不同,其作用域的定义、范围、覆盖规则以及与其他语言特性的交互方式等方面都存在明显的差异。理解这些差异有助于更好地在Web开发中分别运用它们来实现预期的页面效果和功能逻辑。
|
12天前
|
JavaScript 前端开发
如何在 JavaScript 中实现块级作用域?
【10月更文挑战第29天】通过使用 `let`、`const` 关键字、立即执行函数表达式以及模块模式等方法,可以在JavaScript中有效地实现块级作用域,更好地控制变量的生命周期和访问权限,提高代码的可维护性和可读性。
|
20天前
|
JavaScript 前端开发
javascript的作用域
【10月更文挑战第19天javascript的作用域
|
12天前
|
存储 JavaScript 前端开发
js的基础类型和引用类型
【10月更文挑战第29天】理解 JavaScript 中的基础类型和引用类型的区别对于正确地编写代码和理解程序的行为非常重要。在实际开发中,需要根据具体的需求合理地选择和使用不同的数据类型,以避免出现一些意想不到的错误和问题。同时,在处理引用类型数据时,要特别注意对象的引用关系,避免因共享引用而导致的数据不一致等问题。
|
25天前
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域是指程序中可访问的变量、对象和函数的集合。它分为函数作用域和局部作用域。函数作用域内的变量仅在函数内部可见,而全局作用域的变量在整个网页中均可访问。局部变量在函数执行完毕后会被销毁,而全局变量则在整个脚本生命周期中都存在。未使用 `var` 关键字声明的变量默认为全局变量。
|
29天前
|
存储 JavaScript 前端开发
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
JavaScript 数据类型分为基本数据类型和引用数据类型。基本数据类型(如 string、number 等)具有不可变性,按值访问,存储在栈内存中。引用数据类型(如 Object、Array 等)存储在堆内存中,按引用访问,值是可变的。本文深入探讨了这两种数据类型的特性、存储方式、以及检测数据类型的两种常用方法——typeof 和 instanceof,帮助开发者更好地理解 JavaScript 内存模型和类型检测机制。
68 0
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
|
1月前
|
JavaScript 前端开发
js作用域
js作用域
16 1