前言
上一节我们说了那些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复制代码