数据类型转换:
1.强势类型转换: 1、转字符串:2种 1、x.toString();//undefined和null不能使用,不能用.调用方法 2、String(x);//万能的,但是没什么用,千万不要手动使用,完全相当于隐式转换,还不如+""
2、*转数字: 1、*parseInt(str/num) - 专门用于将字符串转为整数的 执行原理:从左向右依次读取每个字符,碰到非数字字符则停止,一来就不认识则为NaN 2、*parseFloat(str); - 专门用于将字符串转为浮点数的 执行原理:几乎和parseInt一致,但是认识第一个小数点 3、Number(x);//万能的,但是没什么用,千万不要手动使用,完全相当于隐式转换,还不如-0 *1 /1
3、转布尔:Boolean(x);//万能的,但是没什么用,千万不要手动使用,完全相当于隐式转换,还不如!!x 转为false?6个:0,"",undefined,null,NaN,false,其余的全部都为true
2.隐式类型转换:都出现在运算符之中
运算符和表达式:
1、*算术运算:+ - * / % 隐式转换:默认,转为数字,再运算 特殊:1、+运算,只要碰上一个字符串,则变为拼接 2、- * / %,纯数字组成的字符串也可以转为数字,但是非纯数字字符串则为NaN NaN参与任何算术运算结果都为NaN
2、*比较运算:> < >= <= == != === !== 结果:布尔值 隐式转换:默认,左右两边都会悄悄的转换数字,再比较 特殊:1、如果左右【两边】参与比较的都是字符串,则是按位PK每个字符的十六进制的 unicode号(十进制ascii码);不需要记忆,但是要知道常识:0-9<A-Z<a-z<汉字 2、NaN参与任何比较运算结果都为false,甚至不认识自己,解决:!isNaN(x); true->有效数字 false->NaN 3、undefined==null; 问题:==区分不开undefined和null,怎么才能区分开? 全等:===,要求值和数据类型都要相同,换句话说,就是不再带有隐式转换的比较运算 !==,不带有隐式转换的不等比较
3、逻辑运算符: 隐式转式:悄悄的都变为布尔值,然后再综合比较 &&:全部条件都满足,结果为true 只要一个条件不满足,则为false ||:全部条件都不满足,结果为false 只要一个条件满足,则为true !:颠倒布尔值 特殊:用法 短路逻辑:只要前一个条件已经可以得出最后结论,则后续条件不在执行: &&短路:如果前一个条件为true,则后一个操作才执行 如果前一个条件为false,则后一个操作不执行 简化【简单的】分支:if(条件){操作} 语法:条件&&(操作); 举例:曾经:if(total>=500){total=0.8} 现在:total>=500&&(total*=0.8); 特殊:1、【简单的】->操作只能有一句话 建议:简单的操作可用&&短路代替,但是操作如果复杂了还是建议使用if结构 ||短路:如果前一个条件为true,则后一个不看 如果前一个条件为false,则后一个才看 使用场景:两个值二选一 - 后期做浏览器的兼容性问题的 e=e||window.event; - 见小案例,bom部分
4、位运算:垃圾 左移:m<<n,读作m左移了n位,相当于m*2的n次方 右移:m>>n,读作m右移了n位,相当于m/2的n次方 缺点:底数永远只能是2 5、*赋值运算:一句话执行了两个操作,先运算,再赋值 += -= *= /= %= ++ --; 何时使用:只要取出变量中的值,在做运算,之后还要在保存回去时,就是用它 i=i+1;//比较low的写法 推荐: i+=1 或者 i++;
递增:i++; 每次只能+1 累加:i+=n; 每次想加几,随便你 ++分为 ++i 和 i++ 1、单独使用时,没有参与别的表达式,放前放后都一样 2、如果参与了别的表达式: 变量中的值其实都会+1 ++i,返回的是递增后的【新值】 i++,返回的是递增前的【旧值】 6、*三目运算:简化了if(){}else if(){}else if(){}else 语法: 1、条件?操作1:默认操作; 2、条件1?操作1:条件2?操作2:默认操作; 问题:1、只能简化简单的分支结构 - 三木操作也只能有一句话,不怕,其实以后你会发现很多if结果中操作恰巧只有一句话 2、默认操作是不能省略的 - 哪怕条件都不满足,至少还要做一件事 总结: if(){} == &&短路 if(){}else == 三目 if(){}else if(){}else == 三目
1、舍入误差:方法:num.toFixed(n);//n代表保留的小数位数,根据你放入的小数位数自动四舍五入 //此方法有一个小缺陷:结果会变成一个字符串,建议搭配上parseFloat使用 2、获取第一个字符的ascii码: var ascii=str.charCodeAt(0);
自定义Function
什么是函数:需要先定义好,可以反复调用的一个代码段 何时使用:1、不希望打开页面立刻执行 2、以后可以反复的使用 3、希望绑定在页面元素上 1、如何使用: 1、创建:2种 *1、【声明方式】创建函数: function 函数名(形参,...){ 函数体; return 返回值; } 2、【直接量方式】创建函数: var 函数名=function(形参,...){ 函数体; return 返回值; } //通过此方法看出函数名其实就是一个变量名 2、调用: var 接住返回的结果=函数名(实参,...); //return的本意其实是退出函数,但如果return后面跟着一个数据 //顺便将数据返回到函数作用域的外部,但是return只负责返回,不负责保存 //就算你省略return,默认也会return undefined; //具体要不要return,全看你需要不需要获得函数的结果 //往往前辈们提供的预定义函数底层都有一句return操作 2、作用域:2种 1、全局作用域:全局变量 和 全局函数,特点:在页面的任何位置都可以使用 2、函数/局部作用域:局部变量 和 局部函数,特点:在【当前函数调用时内部可用】 导致变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错 特殊:缺点: 1、千万不要在函数中对未声明的变量直接赋值 - 导致全局污染,解决:尽量变量使用前都要记得先var一下 2、局部可用全局的,但是全局不能用到局部的 - 解决:看上面,搭配上return
3、声明提前:- 鄙视时 在程序正式执行之前 将var声明的变量(轻)和function【声明的】函数(重) 都会悄悄的集中定义在当前作用域的顶部 但是赋值留在原地 声明方式创建的函数会完整的提前(第一种) 直接量方式创建的函数不会完整的提前,只有变量部分会提前(第二种) 何时使用:永远不会自己使用,垃圾干扰我们的判断 - 只会在鄙视中遇到 只要你遵守以下规则: 1、变量名和函数名尽量不要重复 2、先创建后使用 3、如果鄙视时,遇到先使用后创建,多半都是在考你声明提前,先转换为我们认识的代码,再去判断. 4、按值传递:两个变量之间进行赋值 如果传递的是【原始类型】的值: 修改一个变量,另一个变量是不会受到影响的,其实是复制了一个副本给对方 如果传递的是【引用类型】的对象: 修改一个变量,另一个变量就会收到影响了,两者使用的是同一个地址值(浅拷贝) 2、预定义全局函数 1、编码和解码: 编码:var code=encodeURIComponent(str); 解码:var 原文=decodeURIComponent(code) 2、isFinite(num):判断num是不是无穷大:true->有效数字 false->无穷大 哪些会为false:NaN、Infinity、分母为0 3、:parseInt/parseFloat/eval/isNaN 3、分支结构:根据条件选择部分代码执行:if分支 switch分支 语法: switch(变量/表达式){ case 值1: 操作1; break; case 值2: 操作2; break; default: 默认操作; } 特殊:1、case的比较不带隐式转换的 2、问题:默认只要一个case满足后,会将后面所有的操作全部做完 解决:break; 建议:每一个case的操作后都跟上一个break 有的地方可以不加break: 1、最后的一个操作default可以省略break 2、如果中间多个条件,做的操作是一样的,也不需要 3、default可以省略,如果条件都不满足的话,什么事都不会做到 *面试题:if vs switch 1、switch...case:缺点:必须要知道结果才能使用,不能做范围判断 优点:执行效率相对较高 2、if...else:缺点:执行效率相对较低 优点:能做范围判断
循环结构:反复执行 相同 或 相似的操作:
1、while(循环条件){循环体;变量变化;} - 不确定循环次数的时候 2、do{循环体;变量变化;}while(循环条件) 鄙视/面试中:while 和 do...while的区别 只看第一次:如果第一次大家都满足,两者没有区别 如果第一次都不满足,while什么都不执行,do...while至少会执行一次 3、for(循环变量;循环条件;变量的变化){ - 明确次数 循环体; } 4、*循环流程控制语句:退出循环:break;//退出整个循环 continue;//退出本次循环,根据需求判断自己还需不需要执行后续的循环 后面可能还会学到for in forEach for of各种循环
数组的基础
1、基础概念: 什么是数组:在一个内存(变量)中保存了多个数据的一个集合结构 何时:只要存储多个相关的数据,都要用数组集中保存 为什么:一个好的数据结构,可以极大地提升我们程序员的开发效率
2、创建:2种 1、*直接量:var arr=[值1,...]; 2、构造函数:var arr=new Array(值1,...); - 还有一个坑:var arr2=new Array(5);//创建了一个长度为5的空数组 3、访问:数组名[下标]; -- 当前元素 添加/修改:数组名[下标]=新值; 特殊:读取元素,下标越界 -- 返回undefined 添加元素,下标越界 -- 下标不连续,导致变成一个稀疏数组 4、数组的三大不限制: 1、不限制长度 2、不限制类型 3、不限制下标越界 5、数组唯一的属性:arr.length; 获取到数组的长度 三个固定套路: 1、末尾添加:arr[arr.length]=新值; 2、获取倒数第n个:arr[arr.length-n] 3、删除倒数n个:arr.length-=n 6、遍历数组:对数组中的每个元素执行 相同 或 相似的操作: for(var i=0;i<arr.length;i++){ arr[i];//当前元素 } 7、*如何释放一个引用类型:请你看清楚你的这个引用类型的数据有几个变量引用着,每个变量都要释放后,才能真正的释放干净 建议:我们的代码都要封装到一个函数中,函数中的变量会自动释放 8、索引数组:下标都是数字组成的数组 关联(hash)数组:下标是可以自定义的 为什么:索引数组的下标无具体的意义,不便于查找 如何使用: 1、创建:2步 1、先创建一个空数组:var arr=[]; 2、为数组添加自定义下标并且添加元素值:arr["自定义"]=新值; 2、访问:arr["自定义"] 3、强调:hash数组length永久失效,永远为0! 遍历hash数组:不能使用for循环,必须使用for in循环 - 专门用于遍历hash数组准备的方式,但是代老湿个人不爱称呼他叫做一个循环 for(var i in arr){ arr[i]; } for in虽然不能定义从哪里开始,到哪里结束,专门用于遍历hash数组的 个人推荐:索引数组依然使用for循环,hash数组再用for in 4、hash数组的原理: hash算法:将字符串,计算出一个尽量不重复的数字(地址值) 字符串内容相同,则计算出的数字也一定是相同的 添加元素:将自定义下标交给hash算法,得到一个数字(地址值),把我的元素保存到了这个地址值之中 读取元素:将指定的自定义下标交给hash算法,得到一个和添加时完全相同的数字(地址值),根据地址值找到之前保存的东西 5、js里面一切的东西都是对象:除了undefined和null,【一切对象的底层都是hash数组】
Array的API:
其实就是函数,只不过这些函数是前辈们提前定义好的,我们程序员可以直接使用的,这些方法只有数组可用 1、*arr to string: var str=arr.join("自定义连接符"); 固定套路: 1、鄙视题:将数组中的内容拼接在一起形成一句话/单词; 无缝拼接:var str=arr.join(""); 2、将数组的元素拼接为DOM页面元素 //数据 var arr=["-请选择-","北京","南京","西京","东京","重庆"]; //转为字符串,并且拼接好了标签 var str=""+arr.join("")+""; //渲染到DOM树上 sel.innerHTML=str; 2、*数组拼接:添加新元素的新方式: 根据你传入的实参全部拼接到arr的末尾 var newArr=arr.concat(新值1,...); 特殊:1、不修改原数组,只会返回一个新数组 2、concat支持传入数组参数,悄悄的将你的传入的数组打散为单个元素后在拼接 3、*截取子数组: 根据你传入的开始下标截取到结束下标 var subArr=arr.slice(starti,endi+1); 特殊:1、不修改原数组,只会返回一个新数组 2、含头不含尾 3、endi可以省略不写,会从starti位置一直截取到末尾 4、其实两个实参都可以省略不写:从头截到尾:深拷贝:和以前的按值传递的浅拷贝不同,是复制了一个副本给对方,两者互不影响了
这条线以上的API都不会修改原数组
这条线以下的API都会修改原数组 4、*删除、插入、替换: 删除:var dels=arr.splice(starti,n);//n代表删除的个数 特殊:其实splice也有返回值,返回的是你删除的元素组成的一个新数组 插入:arr.splice(starti,0,值1,....); 特殊:1、插入新的元素会将原有元素和后续元素都推到后面去 2、其实插入也有返回值,只不过没有删除任何元素则为一个空数组 3、千万不要直接插入一个数组,会变成一个部分二维数组 替换:arr.splice(starti,n,值1,...); 特殊:删除的元素个数不必和插入的元素个数一致 5、翻转数组:arr.reverse(); - 以后不会使用