js核心

96 阅读13分钟

数据类型的转换: 1、强制类转换:3类; 1、转字符串: 1.X.toString();//x不能是null和undefined;不能用做操作; 2、String(x);//此方法是万能的,任何类型都可以转为字符串,完全相当于隐式转换,绝对不要手动使用此方法;还不如:+""; 不重要:页面上一切数据默认都是字符串类型; 2、*转数字: 1、parselnt/Float(str);//专门为字符串转字符准备的 原理:从左到右,依次读取每个字符,碰到非数字字符则停止,则为NAN,Float认识第一个小数点; 2、Number(x);//此方法万能的,任何类型都可以转为数字,完全相当于隐式转换,绝对不要手动使用此方法,还不吐:-0,*1,、1,%1; 3、转布尔: Boolean(x);//此方法是万能的,任何类型都可以转为布尔,完全相当于隐式转换,绝对不要手动使用此方法,还不如!!x

***大部分情况都为true,只有6个为false0""undefined,null,NaN,false;
在分支,循环的【条件】之中,不管写什么,都会悄悄咪咪的转为一个布尔值,只需要知道为不为这6个,不为这6个说是true

2、隐式转换:都出现在运算符之中; 二、***运算符和表达式:

    1*算数运算符:+ - * / %;
 特殊:1% 取余 俗称模,判断奇偶性;
   2、隐式转换:默认转为数字,在运算:
  true-----1
  false----0
  undefined------nan
  null--------0
  特殊:1+运算,碰上一个字符串,变拼接操作
  2- * / % 字符串也可转为一个数字,前题是纯数字组成,但凡包含一个非数字字符则为 "NAN",NAN参与任何运算结果都为  NAN;

2、*比较运算符:>< >= <= == != === !==

  结果:布尔值;
 隐式转换:默认,转为数字,在比较大小;
 特殊 :
 1、如果参与比较的左右两边都为字符串,则按位PK每个字符的十六进制unicode号(十进制ascii码)
    0-9<A-Z<a-z<汉字
2NAN参与任何比较运算结果都为false,解决:!NAN(x);
3undefined==null;//true;
区分:undefined===null;
   
   ===!==:不带隐式转换的值比较和不等比较,要求数值相同,并且数据类型也要相同function String(x){
        if(x===null){
                  return"null";
                  }else if(x===undefined){
                  return"undefined";
                  }else{
                    return: x.String0;
                    }
                    }
       3*逻辑运算符:
       &&:全部为true,才能为true;
           一个为false,则为false;
         ||:全部为false,才为false;
            一个为true,则为true;
            !:颠倒布尔值;
             
                 特殊:短路逻辑:如果前一个条件,已经能够得出最终结论了,则不看后续
                 &&短路:如果一个条件满足;则后一个操作执行,如果前一个条件不满足,则后一个条件不执行;
 目的:简化的【简单的】if分支:1、一个条件一件事;满足就做不满足就不做,2、操作只有一句话;
 简化:条件&&(操作)
 原来:if(total|>=500){
              total*=0.8
              }
    现在:total>=500&&{
                      total*=0.8
                      }
   ||短路:如果前一个为true,后一个不看,实现浏览器的兼容性,二选一操作;
   e=e||window.event4、赋值运算符: ++ -= *= %=
   一个操作完成两件事,先计算,在赋值回去
  i++;//递增,每回固定只会+1【
  i+=1//累加,每次+几由我们程序员自己决定
  i=i+1//最low的写法;
  

*****笔试题

 ++ii++的区别?
 单独使用两者没区别
 如果参与了表达式,变量中的值都会+1;
 前++,返回的是加了过后的新值
 后++,返回的是加了之前的旧值;

5、三目运算:简化if...else 语法: 1、条件?操作1:默认操作; 2条件1?操作1:条件2?操作2:默认操作;

 特殊:1、默认操作不能省略;
      2、只能简化【简单的分支】  操作只能有一句话;

汇总:if(){}====>&&短路 if(){}====>三目运算 if...else if...else =====> 三目运算

 扩展:1、计算机很笨,虽然计算能力很强(机械硬盘(永久保存)/固态硬盘(有效期10年));计算机有摄入误差,解决:num.toFixed(d);//d代表保留的小数位数,会四舍五入的功能,
 缺陷:搭配上一个parseFloat()使用最好,返回的结果都是一个字符串
 2、获取计算机字符串中的第一个字符的ascii码:str.charCodeAt(0);
数字:48-57;
 大写字母:65-90;
小写字母:97-122;
汉字:199684e00)-40869(9fa5)

 
 

函数

  ***自定义函数function:函数,也称之为方法,是需要提前预定义好的,以后可以反复使用的代码段
  1、创建函数的方式:2种;
  1、声明方式:function函数名(行参列表){
  不是人人都有声明方式,但是有声明方式的人一定优先用声明方式,因为最简单,只有三个人有声明方式:变量、常量、函数;
  函数体;
  return 返回值;
  }
  2、直接量方式:大部分人直接量就是最简单的创建方式
  var 函数名=function(形参列表){
  //通过函数此处看出函数名其实也是一个变量,衍生出,elem.on事件名这一部分就是函数名,
  函数体;
  return 返回值;
  }
  return的本意,退出函数的意思
  

只不过如果return后面跟着一个数据,会顺便将其返回到全局作用域中,但是只负责返回不负责保存 所以在调用函数时,如果有retuen,记得拿一个变量接住它 调用函数: var reult=函数名(实参列表)

 2、***作用域:2种;
   1、全局作用域:成品:全局变量和全局函数,在任何地方都可以访问使用;
 2、函数局部作用域:成员:局部变量和局部函数,只能在【函数调用时内部可用】
 带来了变量使用规则:优先使用局部,局部没有就找全局,全局没有就报错;

特殊:

 1、千万不要对着未声明的变量在赋值:a=1;会导致全局污染,全局本来就没有,突然就被添加上了一坨内存,建议任何变量使用之前一定先"var";
 2、局部的东西不能全局使用;
 3、哪怕没有写return,其实也会悄悄给你return一个undefinedn,默认;
 4return一般只会出现在函数的最后,而且只能出现一次;
 5、其实前辈给我们的提供的方法,大部分都有return操作,因为前辈们考虑到了,调用了这个方法过后得到的结果可能对我们以后有用;
 

笔试题

声明提前: 在程序执行之前 会将var声明的变量和function声明的函数 集中提前到当前作用域的顶部,但是赋值留在了原地 变量比函数轻, 遵守规则: 1、先创建后使用 2、变量名和函数名尽量不要重复; 只会在笔试中碰到:如果以后碰到,先使用后创建,多半都是声明提前;

4***按值传递:

如果传递的时【原始类型的值】 修改一个变量,另一个变量是不会受到影响的,其实就是复制了一个【副本】给对方; 如果传递的是【引用类型的对象】:Array、Function 修改一个变量,另一个变量是会受到影响的,因为两者使用的是【同一个地址值】--浅拷贝:好像复制了 但是复制的不全;

二、预定义全局函数:前辈们提前创建好的,我们可以直接使用,在哪里都可以使用;

1、编码和解码: 问题:url中不允许出现多字节字符,如果出现会乱码; utf-8编码格式下,一个汉字,占三个字节; 解决:在发送前,前端将用户输入的多节字符编码为单字节字符(符号、字号) 发送后,后端将单字节字符解码为多字节原文

  编码:var code=encodeURIComponent("原文“)
  解码:var 原文=decodeURIComponent(code);
  其实百度没有这种操作,这种在浏览器更新后就自带此功能淘汰了;
  2、isFinite(num);判断num是不是无穷大,turn--有效数字  false-----无穷大 
  那些为false:NAN,分母为0(Java就会报错),infinity
  3、牛逼的:parselnt/Float/isNaN/eval();
  

3分支结构:根据条件,选择一部分条件执行; switch分支if分支 语法: switch(变量/表达式){ case值1: 操作1 case值2 操作2 default: 默认操作 }

 特殊:

  1case的比较不带隐式转换;
  2问题:默认只要一个case满足后,会将后面所有的操作全部做完;
  解决:break;
  建议:每一个case的操作后都跟上一个break;
  有的地方也可以不加break1、最后一个操作default可以省略break2如果中间多个操作做的事是一样,可以省略中间部分;

3、default可以省略不写,但如果条件都不满足,则什么都不执行;

面试题

 if vs switch区别
 1switch...case...,
 缺点:必须要知道最后的结果是什么才可以使用,在case中不能做范围判断,只能做等值判断;
 优点:执行效率相对比较高;
 2if:
 缺点:执行率相对较低;
 优点:可以随意的做范围判断;
 建议:代码优化时;要尽量将所有的if...else换成switch...case...
 

**#

循环结构***

 1、*var 变量=几;while(循环条件){
              循环体;变量变化;
                  }
   2 var 变量=几;
 do{
循环体;
 变量的变化
 }while(循环条件)
面试题:
     whiledo....while的区别?
     只看第一次,如果条件都满足,则没区别
       如果条件不满足,则while一次都不会执行,do....while至少会执行一次;

3、for (var 变量=几;循环条件;变量变化){ 循环体; } 4、退出循环:

      break--退出整个循环;
      continue--退出本次循环;

5、死循环:

         while(1){
         
         }
         for(;;){
         }

2、*****数组的基础

    1、概念:什么是数组:一个内存(变量)中保存多个数据的一个结合结构
    何时:只要储存的多个相关的数据,都要用数组集中保存;
    为什么:一个好的数据结构,可以极大的提升程序员的开发效率

2、创建:2种;

       *直接量:var arr=[值1,.....]
       构造函数:var arr=new Array(值1,....)
      有一个坑 newArr(num);//创建了一个长度num的空数组;
      

3、访问:数组名[i]---当前元素,添加/修改:数组名[i]=新值 特殊:读取元素,下标越界--返回undefined 添加元素,下标越界--下标不在连续,导致变成一个稀疏数组;

4、数组的三大不限制:长度;类型;下标越界(不好);

5、数组的唯一属性:长度:arr.length

        三个固定套路:
        1、向末尾添加:arr[arr.lenght]=新值;
        2、获取倒数第n个:arr[arr.length-n];
        3、缩容: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;

遍历数组,不能在使用for循环,必须使用for in循环 -纯自动循环、【专为遍历数组准备的】;

for (var i in 数组名) { i;//自动得到下标; 数组名[i];//得到的当前次元素; }

很棒:不光遍历数组hash数组,还可以遍历索引数组;

个人:遍历索引数组使用for循环,遍历hash数组在使用for in;

4、hash数组的原理

hash算法:将字符串,计算出一个尽量不重复的数字(地址值);

 字符串的内容相同,则计算出来的数字也是相同的;
  添加元素:将自定义下标交给hash算法,得到一个数字(地址值);直接将你要保存的数据放到此地址;
   获取元素:将指定的自定义下标交给hash算法,得到一个和当初添加上完全相同的数字(地址值),通过地址值就可以找到当初保存的数据;

5、***js里万物皆对象(除undefined和null) [一切对象的底层都是hash数组】

3、*****数组的API:数组其实就属于我们11个引用对象之一,对象就会有属性和方法,数组有很多很多API(数组的专属方法)等待我们学习;

1、*****数组转为字符串

    var str=arr.join("自定义连接符“);
 

固定套路:2个

笔试题:

1、将数组里面的内容拼接为一句话/单词,无缝拼接;
arr.jion(" ");
2、将数组里面的数据拼接为DOM页面元素
//数据
var arr=["-请选择-""",""]
//将数组转为字符串,只不过是拼接了标签
 var str="<h1>"+arr.join("</h1><h1>")+"</h1>";
 //渲染到DOM树上,
 bd.innerHTML=str;

2*拼接数组:添加元素的新方式

//根据传入的实参全部拼接到数组的末尾

var newArr=arr.concat(新值1,....);

特殊:

    1、不修改原数组,只会返回一个拼接后的新数组;
    2支持传入一个数组参数进行拼接,悄悄的将你的数组打散放入;
    

3、*截取子数组: //根据传入的开始下标一直截取到结束下标

 var subArr=arr.slice(starti.endi+1);
 特殊:
 1、不修改原数组,只返回一个截取后的新数组,
 2、含头不含尾
 3、endi可以省略不写,会从starti一直截取到末尾;
4、两个实参都可以省略,从到截到尾,复制了一份(深拷贝--两者互不影响)
5、支持负数参数,-1代表最后一个;

----------以上api不会修改原数组---------

-----------以下api都会修改原数组-----------

4、*删插替:

 删除:var dels=arr.splice(starti,n)//n代表删除的个数;
 插入:arr.splice(starti,0,新值1....);
 替换: var dels=arr.splice(starti,n,新值1,....)
 特殊:插入的个数和删除数不必相等;
 

5、反转数组:arr.reverse();

******数组的API

1、*****排序:2种

   1.笔试题
   鄙视题:手写冒泡排序:从第一个元素开始,依次比较相邻的两个元素,如果前一个>后一个,两者就要交换位置
		公式:
		for(var j=1;j<arr.length;j++){
			for(var i=0;i<arr.length-j;i++){
				console.log(1);
				if(arr[i]>arr[i+1]){
					var m=arr[i];
					arr[i]=arr[i+1];
					arr[i+1]=m;
				}
			}
		}
   

2、正式开发中:数组提供的排序API: arr.sort();

问题1:默认会将元素们转为字符串,按位pk每个字符unicode(ascii),如果希望按数字排序?

解决:

arr.sort(function(a,b){//sort传了一个实参:比较奇怪是一种匿名回调函数,不需要程序员自己调用,前辈们已经帮我们调好了,而且我们不需要管前辈们怎么创建的,只需要记忆固定用法即可;
console.log(a)://后一个数字
console.log(b);//前一个数字
return a-b;//如果return是一个正数;说明后一个数>前一个数
//如果return是一个负数,说明后一个数<前一个数
//如果return是一个0;说明后一个数==前一个数
//而sort方法会跟据你return的正/负数,来进行排序操作;
})

问题2:希望降序排列 arr.sort(function(a,b){ return b-a; })

强调:排序非常重要,记住:只要以后页面中有排序功能,说明他的底层一定是一个数组,因为js中只有数组才可以排序;

2、栈和队列:

栈:其实就是数组,只不过要求是一段封闭,只能从另一端进出的数组

何时:希望优先使用最新数据时

如何使用:

      开头进:arr.unshift(新值1,....)//添加元素的新方式,缺陷:导致其余元素的下标发生变化;
      开头出:var first=arr.shift();//一次只能删除一个,删除元素的新方式,可以接住你删除的元素,缺陷:导致其余元素的下标发生变化
      结尾进:arr.push(新值1,....)//添加元素的新方式;
      结尾出:var last=arr.pop();//一次只能删除一个,删除元素的新方式,可以接住你删除的元素;
      队列:其实就是数组,只不过要求是一端进,另一端出;
      何时:希望按照先来后到的顺序使用数据时;
      开头进:arr.unshift(新值1,....)
      结尾出:var last=arr.pop();
      结尾进:arr.push(新值1,....)
      结尾出:var first=arr.shift();
      
      

2*二维数组:数组的元素,又引用着另一个数组;

 何时:在一个数组内,希望在次细分每个分类;

 创建:

 var arr=[[" "] [ " " ]];
 访问:arr[行下标][列下标]
 特殊:
 列下标越界,会报错,因为只有数组才可以用[下标]。行下标,越界已经得到undefined,没有资格在加下标;

遍历二维数组:必然需要两层循环,外层循环控制行,内层循环控制列--

       公式:for( var r=0;r<arr.length;r++){
       for (var c=0;c<arr[r].length;c++){
       console.log(arr[r][c])
          }
       }

3、*****String的概念:

1、什么是字符串:多个字符串组成的【只读】字符【数组】和数组有相同的点:

1、字符串中个数(长度):str.length
2、获取字符串中的某个字符:str[i];
3、遍历字符串;
4、所有数组不修改原数组的API,字符串都可以使用(concat、slice)

和数组也有很多不同的地方: 所有的数值直接修改原数组的API,字符串都不可以使用;比如只有数组可以使用,但是字符串也有很多很多属于自己的API

2、***引用/对象类型;11个;

*String Number Boolean -->为什么这三个既是原始类型又是引用类型?原因是他们三个具有包装类型;
*Array *Function Date(日期) Math(数学)*RegExp(正则-->表单的验证)
Error(错误)
*Obiect(面向对象开发方式)
Global (全局对像)-->特殊:再浏览器中没有globalwindow(全局对象:保存着全局变量和全局函数)给代替了,只不过window可以省略不写;
只有JavaScriptglobal才被代替为了window,而且node.js后端语言中!全局对象就叫global

3、面试题:什么是包装类型

 包装类型:专门将原始类型的值封装为一个引用类型的对象
	    为什么:原始类型的值原本是没有任何属性和方法的,意味着原始类型本身就是不支持.做操作的
		  但是前辈们发现字符串经常会被我们程序员所使用/操作
		  为了方便我们程序员为这三个人提供了包装类型,从值->对象(提供了很多属性和方法)
	何时使用:只要你试图用原始类型的变量去调用属性或方法时,自动包装
	何时释放:方法调用完毕后,包装类型就会自动释放,又变回了一个原始类型的值

	为什么undefinednull不能使用. - 没有包装类型

 

只读: 1、StringAPI:只有字符串可以使用的方法,无需创建,直接使用。 1、转义字符:
作用: 1、将字符串和程序冲突的字符转为原文 """

		2、包含特殊功能的符号
			\n -> js字符串换行
			\t  -> js字符串中的制表符,就是你平时敲键盘的tab键,大空格

		3、输出unicode编码的字符
			\uXXXX:第一个汉字:4e00		->ascii:19968
				最后一个汉字:9fa5		->ascii:   40869

2、*大小写转换:将字符串中的每个英文字符统一的转为大写或小写
	 何时:只要程序不区分大小写,就要【先统一】的转为 大写 或 小写,再比较(验证码)
	 如何:
		大写:var upper=str.toUpperCase();
		小写:var lower=str.toLowerCase();

3、获取字符串中指定位置的字符:str.charAt(i); === 还不如str[i]

4、*获取字符串中指定位置的字符的ASCII码:
	var ascii=str.charCodeAt(i);
      *通过ascii码转回原文
	var 原文=String.fromCharCode(ascii);

5、***检索字符串:检查索引:获取关键字的下标
	var i=str/arr.indexOf("关键字",starti);
	starti可以省略,如果省略了,从下标0开始向右查找
	返回值:找到了,返回的是第一个关键字的第一个字符的下标
	              *没找到,返回-1,我们不关心下标为多少,我们只关心下标为不为-1
	作用:判断有没有
	强调:不光字符串可用,数组也可用!老IE的数组是没有此方法的
	鄙视题:此方法默认只能找到第一个关键字的下标,找到所有关键字的下标,如何完成?
	var str="no zuo no die no can no bibi";
	var index=-1;//开始位置 -1
	while((index=str.indexOf("no",index+1))!=-1){
		console.log(index);
	}

6、*截取字符串:3个
              *var subStr=str/arr.slice(starti,endi+1);//用法和数组一摸一样
		   str.substring(starti,endi+1);//垃圾:用法几乎和slice一致,但是不支持负数参数,而且只有字符串可用   
		   str.substr(starti,n);//n代表截取的个数,不再需要考虑含头不含尾,也支持负数下标

7、拼接字符串:var newStr=str.concat(新字符串,...);//还不如+运算

8、*替换字符串:本身这个方法非常强大,但是由于我们现在暂时不会正则表达式,所以只能替换固定的关键字(下周一就牛逼了)
	var newStr=str.replace("关键字"/正则表达式,"新内容");

9、*****切割/分割字符串:
	作用:str<=>arr
	var arr=str.split("自定义切割符");
	特殊:1、切割后,切割符就不存在了,转为一个数组
	          2、切割符"",切散每一个字符

扩展: 1、JS创建空标签: var elem=document.createElement("标签名");

2、为其设置必要的属性和事件
	elem.属性名="属性值";
	elem.on事件名=function(){操作}

3、上树
	父元素.appendChild(elem);