JS,,,

handler发送消息和接收消息异步处理:发送消息的函数即刻返回,另一部分在消息队列中逐一等待被处理
数据类型小写,构造函数首字母大写
不声明就会报错!
函数执行return后,后面的代码不会再执行
Arguments是类数组对象,具备数组相同的访问性质及方法,能由arguments[n]访问对应单个参数的值,并拥有数组长度属性length,arguments存储的是实参

window.onload=function(){}   //(延迟加载,先加载dom树,再执行当前函数)
       load事件绑定给window对象

JS中的内置对象/内置函数:
Object
Function
Array
Date
Regexp
Math(说内置函数要去掉)

Number 
Boolean
String

回调函数:通过函数指针调用的函数
如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数

split:字符串->字符串数组
str.split(字符串/正则表达式,最大返回数组长度)

获取原型对象的方式:
obj.__proto__:获取到的是obj实例的构造函数的原型对象
obj.constructor.prototype

JS异常:try…catch必须成对出现
       catch语句在try代码块发生错误时执行

判断正则表达式的方法:test(str);

浅谈javascript的Array.prototype.slice.call
js中的内置对象(详细篇)

JS:动态效果设置

一、JS的由来

最初研发:网景公司(浏览器公司)——livescript
整合:javascript

MySQL:一个关系型数据库管理系统的应用软件,将数据保存在不同的大仓库中,增加了速度,提高了灵活性
所使用的SQL语言(结构化查询语言,编程语言)是用于访问数据库的最常用标准化语言
在这里插入图片描述

二、语法

变量的声明,注释
1.标识符、变量的声明(尽量语义化)

1>标识符的声明(相当于属性名)
  a.由字母、数字、下划线、$组成,且不能以数字开头	
  b.建议使用驼峰式命名(第二个单词开始,首字母大写)
	var firstnameandlastname='zhangsan';    不好
	var firstNameAndLastName='zhangsan';    推荐!
  c.不能使用关键字和保留字
	关键字:在js中具有特殊意义的字符
	保留字:未来有可能成为关键字的字符	
	
2>变量的声明
  ES5:var(可重复声明)
     //先声明,后赋值
	  var a;          //声明一个a变量,但不赋值——值为undefined
	  a="hello";      //获取a变量并赋值hello
	  
	 //声明并赋值
	  var a="hello"; 
	  a='hello';     (省去了var就必须给变量赋值)

     //同时声明多个变量
	  var a=2,b=3,c=4;
	  想让它输出时,console.log(a,b,c);
	  
  ES6:也可以使用var声明变量(向下兼容)
      let和const(只能声明一次,不能重复声明)
                (都是局部变量)
                不能变量声明提升(三、4>)
	  let:声明变量(不是程序员想改,是用户想改)
	  const:声明常量(一旦声明不可修改)
	         例子:const person={  //存到计算机里,计算机会自动分配一个引用地址,person所在的地址
						  name:'lisi',
						  age
					  	  gender
					  	  ....
				       	 }
		          console.log(person);
		          结果:Object { name: 'lisi' 。。。}
		    
			如果常量值为引用数据类型,只要引用地址不变,可以修改内部属性	
			例子:const person={
		                  name:'lisi'
                          };
                  person.name='tom';
                  console.log(person);
                  结果:Object { name: "tom" }      					    			    
           
            		    		    		
		    例子:var a=10;
		       	 function say(){
		            console.log(a);
			        var b=20;
		            console.log(b);
			     }
		         say();
		        //解析顺序:function say(){};
		                  var a;
		                  a=10;
		                  function say(){
		                     var b;
		                     console.log(a);
			                 b=20;
		                     console.log(b);
			              };
			              say();			         
			              结果:10
			                   20
		               		    		 				
	 	     例子:let a=20;
				  function say(){        
				       console.log(a);
				   }
				  say();				       
		          结果是:20

在这里插入图片描述
2.注释

单行注释(可嵌套使用)://内容
多行注释(不能嵌套使用):/*内容*/

三、使用

浏览器端、node环境——都内置了Js解析器
全局对象

1>浏览器端
  全局变量window(页面中最大对象)
  window只能在浏览器端使用(因为一个文档开一个窗口,一个窗口里包含一个window对象)
  window对象:浏览器中打开的窗口
  onload方法:遇到function关键字声明一个函数,就会在内存中开辟一个新的内存空间,方便后续调用
             当遇到window.onload时,整个页面(dom树)加载完才声明这个函数
             当js代码需要获取页面中元素时,如果script标签在元素前面,就需要加

2>node环境
  全局变量global(最大对象)
  node端无窗口——>无window对象

可写在html的任意位置,但建议写在head中在这里插入图片描述
1.浏览器端(核心js、dom、bom都可运行)

1.嵌入html标签中(script标签 type属性)(直接写js代码)
  <script type="text/javascript"></script>      
   
2.外部引入脚本,把js写在另一个文件里(script标签 src属性)——内部代码会被解析器忽略 
  <script src="./文件名.js"></script>

2.node环境 node.js(只能运行核心js)

node:JS运行环境,相当于封装了js解析器(谷歌V8引擎),能够使js脱离浏览器运行
node安装在云端(node --version检测node版本号,即检测是否安装成功)
两种运行方式:1>repl环境(临时环境,一般做测试时用)
              r:read
			  e:eval     执行
		      p:print    打印
			  l:loop     循环(再次从r开始)
              
              node,回车,进入repl环境——在repl环境输入一行代码,读取、执行、打印、循环
              例子:xshell里node(下一行光标有>,说明已经进入repl环境中)
                   >1+1    
	               2            p阶段,把执行结果打印出来
			                   
                   >console.log(1+1);  
                   2            e阶段,输出2
                   undefined    p阶段,打印的返回值
                   退出:Ctrl D 或 2次Ctrl C

             2>node命令:(Linux里的程序,通过第三方软件安装相当于装了一个node程序)——真正项目开发时使用
               1)创建:vi 文件名.js
               2)执行:node 文件名.js

六、局部变量和全局变量(先声明)

1、全局变量:在整个作用域内都能被访问的变量
          没var操作符
2、局部变量:只在声明的代码块内能够被访问
           let,const
           使用var并声明在函数内部   

七、数据类型(6种)

1.五种基本数据类型(简单数据类型)
undefined,null,number,boolean,string

//测试数据类型的方法:typeof (a);
                   typeof a;
typeof测数据类型(调用typeof的结果):undefined,object(null+object),number,boolean,string,function
例子:var a=Object;
     console.log(a);
     console.log(typeof a);
     结果:function Object()  //构造函数Object
          function  //函数类型
          
typeof的返回值类型:string
1>undefined:未定义,派生自null
 (1)声明一个变量而不赋值——值和数据类型都为undefined  
  例子:var a;
      console.log(a);
      console.log(typeof a);    
      结果:undefined
           undefined                  
 (2)直接赋值undefined)——值和数据类型都为undefined  
  例子:var a=undefined;
      console.log(a);
      console.log(typeof a);      
      结果:undefined
           undefined       
 (3)既不声明也不赋值——没值(报错),数据类型为undefined
    console.log(a);   
    结果:没值,报错
    console.log(typeof a);
    结果:undefined
    
2>null:空引用数据类型(返回值——null,返回值类型——object)
  即将指向堆区,但此时没有指向(还没引用)
  var a=null;  
  console.log(a);
  console.log(typeof a);
  结果:null
       object

  null==undefined   //true,因为undefined派生自null
  null===undefined  //false

3>number
  小数,整数,011(二进制),0xa(x:十六进制)(o:八进制)
  NAN(not a number的缩写)
  infinity(无穷大或小,正或负都可)
  
 (1)方法:isNAN(a):a是不是 不是一个数   // 不是数,返回true 
    var a=10;       
    console.log("hello"/a);           
    console.log(typeof ("hello"/a));  
    结果:NAN
         number

 (2)方法:isFinite(a):a是否为无穷数   //是无穷数,返回true     
    console.log(10/0);  
    console.log(isFinite(10/0));
    结果:Infinity  
         false
     
4>boolean:结果是true和false
  例子:var a=true;
       console.log(a);
       console.log(typeof a);
       结果:true
            boolean
           
5>string:用“”或‘’包裹的字符
  字符串拼接:``反引号(忽略格式,可以换行)
  例子:console.log('null');  
       console.log(typeof 'null');
       结果:null   
            string

  json(字符串类型):前后台交互常用
   接收一个对象:{    
               “name":"lisi",   //属性名一定加引号
               "age":10,
               }
   多个对象:【{
              “name”:
              "age":
              },
              {},
              {}】

在这里插入图片描述
2>null:空引用数据类型
在这里插入图片描述
2.引用数据类型(复杂数据类型)——最大父类(js中所有对象的数据类型):object类

object:function
        array 
        date
        正则
        ...//不是基本数据类型,其余的就是object类型里的子类
object是动物
剩下三个是人,猫,狗
每个里面又会有实例对象
     
object的公有属性和方法:constructor:构造者
                     //每种子类调用这两种方法的的返回值不一定
                     toString():调用后的数据类型是string
                     valueOf():返回——对象本身、变量原始值                                                                                                                            

八、数据类型转换

基本数据类型和引用数据类型之间基本不做转换(引用地址变了,但原来的不用了还没销毁)
undefined和null是向其他类型转换
1.number

1>Number转换函数:Number(a);   
——undefined和非空字符串——>NaN
             "hello"、"10l"、"a10":NaN——带字母的字符串不能转换,是NaN
  
  null、false、"":0
  true:1
  "10":10
  "10.3":10.3
  "+10":10
             
2>parseInt(a): 
  null:NaN(null,object,NAN,number)
  true:NaN
  false:NaN
  "":NaN 
  "10l":10(10l,string,10,number)  //从前到后解析
  "10.3":10(直接取整,不是四舍五入)
  
3>parseFloat(a)
 "10.3":10.3	  

4>一元操作符+或-(-)
  +a:相当于调用了Number(a)
  -(-)a:相当于调用了--Number(a)

2.boolean

*->boolean
   1>Boolean转换函数:Boolean(a)——存在true,不存在false
     null:false
     undefined:false
     0:false
     非0:true
     "":false        
     "...":true     

2>两次逻辑非!(两次取反)
  一个变量连用两次逻辑非,相当于将当前变量转换为boolean类型
  !!null——false

3.string
String转换函数:String(a)
toString()

*->String
1>String转换函数:String(a)
  直接在变量值之外添加""或''
  undefined和null只能通过String转换函数

2>toString方法:toString((num:几进制)   
  undefined和null没有toString() 

——————对象的toString
      var obj={            
        name:'lisi',
        age:20
        }
      console.log(obj.toString());
     结果:[object Object]   //[数据类型 对象]——object类型的对象

——————函数的toString
      function say(){}     
      console.log(say.toString());
      结果:function say(){}
          
——————数组的toString
      var arr1=new Array();   //声明了一个空数组
      var arr2=new Array('hello','world');   
      console.log(arr1.toString());
      console.log(arr2.toString());
      结果:<empty string>  //浏览器端               
           hello,world            
                                            
//valueOf方法:返回——对象本身、变量原始值
例子:var obj={
       name:'lisi'
     };
     console.log(obj.valueOf());    
     function say(){}
     console.log(say.valueOf());
     结果:Object { name: "lisi" }
          function say()
  
  a.toString(2)   //先将当前a变量转换成对应的二进制number值,再加“”
  true.toString():"true"
  10.toString():"10"
  例子:var a=true;
       console.log(a.toString());       
       console.log(typeof a.toString());  
       结果:true
            string 

九、值传递问题

基本数据类型在值传递时,传递的是值
引用数据类型在值传递时,传递的是引用地址

1>基本数据类型
  var a=10;  
  b=a;       
  b=b+1;
  console.log(a);
  console.log(b);
  结果:10      
	   11
2>引用数据类型
  var obj={             
		   name:'lisi',   //字符串类型的属性值加''
		   age:20,
		   gender:'men'
		}
  //var obj在栈区存储,{}在堆区存储

问题:
	var obj1={
			 name:'lisi',
			 age:20
		     }
	obj2=obj1;            //obj2拿到了obj1的内存地址
	obj2.name='terry';    //修改obj2的name,实际上修改的是obj1的name//不管obj1还是obj2修改的是同一个内存地址
	console.log(obj1.name);
	console.log(obj2.name);
	结果:terry  
	     terry

在这里插入图片描述

十、操作符

算数操作符:=,+和+=,-和-=,*和 *=,/和/=,%和%= (赋值,加减乘除,取余)
比较操作符(返回值都是布尔值)(会做数据类型转换):>,>=,<,<=,==和全等操作符
逻辑操作符:&&(逻辑与),||(逻辑或),!(逻辑非)
三目运算符(代码少)、条件分支语句
一元运算符(写在变量前面):+,-,++,–
位运算符:原码、反码、补码
1.算数操作符(至少两个运算符进行加减操作)

=:赋值操作符(从右向左赋值)
   var a=10;

1、+和+=
   +(a+b):1>number类型,直接相加
		  2>number+非number(转换为number)
		  3>undefined null boolean类型(以Number转换函数->number类型)
			例子:var a=null;
			     var b=false;
			     var sum=a+b;
			     console.log(sum);
			     结果:0
		     
		    对象调用toString方法,返回[object Object]   
		    var obj={};
		    console.log(obj.toString());
		    结果:[object Object]	  //object类型的对象
		  4>string+将另一个变量转换为string类型,拼接  		
			例子1:"10"+{}=10[object Object]  			     
			例子2:10+"10"=1010
			
		  5>非string类型+object类型
			10+{}=10[object Object] 
		  5.1>只重写了toString():调用toString()
		      例子:var obj={
                       toString:function(){    //相当于重写父类的toString方法
                           return 10
                        }
                    }
                    var a=10;    
                    var sum=a+obj;   //有自己的toString
                    console.log(sum);
                    结果:20
		  5.2>只重写valueof():调用valueof()
		      例子:var obj={
                       valueOf:function(){
                           return 1
                       }
                   }
                   var a=10;   
                   var sum=a+obj;   
                   console.log(sum);
                   结果:11
		  5.3>既重写toString()又重写valueof():调用valueof()	
			   例子:var obj={
                        toString:function(){
                           return 10
                         },   
                        valueOf:function(){
                           return 1
                          }
                     }
                    var a=10;
                    var sum=a+obj;
                    console.log(sum);
                    结果:11	    
   +=:a+=2;——>a=a+2;
2、-和-=
3、*和*=
4、/ 和/=
5、%和%=

2.比较操作符(6个,返回值均为boolean)(会做数据类型转换)

>:(a>b)
  num:num——直接比较
  num:非num但不为string——将非number转换为number再比较  (“hello”转不了,比较结果返回false),但'10'可以]
           例子:var a=null;  //计算时把null转换成number了
                var b=10;
                console.log(a>b);
                console.log(a<b);
                结果:false   
                     true                                                                            
  非num:非num——转为number
               例子:var a=null;
                    var b=true;
                    console.log(a<b);
                    结果:true
  string:string——比较字符编码
                  例子:var a='a';
                       var b='b';
                       console.log(a<b);
                       结果:true
  num:obj——默认情况下调用tostring()
           如果只toString(),调用toString()
           如果只valueOf(),调用valueOf()
           如果既重写了toString,又重写了valueOf,调用valueOf()
<
>=
<=
==:(a==b)   ——先数据类型转换,再比较  
    undefined==null,返回值为true
    NaN==NaN,返回值为false     //"hello"和"world"可不相等啊
    "10"==10,返回true		//“10”转换成了10(非number转为number)
===:全等操作符——返回值是true或false
     先比较数据类型,数据类型相同,再比较值
			      数据类型不同,返回false
     obj===obj——比较引用地址
     例子1:object类型(引用地址相同和不同的比较)
     例子1.1:var o1={
               name:'lisi'
             }
             o2=o1;
             o2.name='terry';
             console.log(o1===o2);
             结果:true
      例子1.2:var o1={
                name:'lisi'
              }
              var o3={
                name:'lisi'
              }
              console.log(o1===o3);  //虽然{}里内容一样,但引用地址不一样
              结果:false

3.逻辑操作符

&&:逻辑与(第一个数是false,返回第一个数)
    a&&b 
    结果:返回值要么是a,要么是b
	1>如果第一个数为undefined、null、NaN、false、""能够转换为false的值,返回第一个数
	2>如果第一个数不是,返回第二个数
	例子1:console.log("hello"&&"world");
	      结果:world
    例子2:console.log(""&&"world");
	      结果:<empty string>
    例子3:console.log(null&&"world");
	      结果:null
||:逻辑或
    1>如果第一个数为undefined、null、NaN、false、""能够转换为false的值,返回第二个数
	2>如果第一个数不是,返回第一个数
	例子1:console.log(null||false);
         结果:false
    例子2:console.log(“hello”||false);
          结果:hello
!:逻辑非(结果一定为boolean类型)
   !null
   1>用Boolean()转换函数转为boolean类型
   2>取反		
   
   一个变量连用两次逻辑非,相当于将当前变量转换为boolean类型,相当于直接调用Boolean()转换函数
   !!null:false
   例子:console.log(Boolean(null));   
        console.log(!null);
        结果:false   
             true        

4.三目运算符(代码少)
1>和2>是等价的

1>三目运算符(代码少)
  a>b?console.log(a):console.log(b) 
  表达式?成立:不成立
  例子:var a=10;
       var b=20;
       a>b?console.log("a大”):console.log("b大”);
       结果:b大

2>条件分支语句
  if(a>b){
  }
  else{
  }

5.一元运算符(写变量前面)

+:(+a),相当于调用了Number(a)转换函数
   例子1:var a=null;        
        console.log(+a);	
        结果:0			
   例子2:var a=undefined;
         console.log(+a);	
         结果:NaN     
   例子3:var a=true;       
         console.log(+a);	
         结果:1    
-:-a:-Number(a)
++:
   1>a++:a=a+1
	 先变量操作,后++
   2>++a:a=a+1
	 先++,后变量操作
   例子1:var a=10;
        console.log(a);
        console.log(a++);
        console.log(a);
        结果:10
             10
             11
   例子2:var a=10;
         console.log(a);
         console.log(++a);
         console.log(a);
         结果:10
              11
              11      
--

6.位运算符

(二进制)原码——>反码——>补码(用补码进行操作)——再转为原码
js中32位2进制
...128 64 32 16 8 4 2 1
正数:原码=反码=补码
负数:原码		
	 反码=符号位不变,其他位取反
	 补码=反码+1
符号位:0表示正数,1表示负数
例子:-3+4:二进制是1
	 -3:原码:1000 0011
         反码:1111 1100   //负数取反码时,符号位不变
				      1
		     ------------
		 补码:1111 1101
	  4:原码=补码:0000 0100
	  sum:(补码之间做加运算)
		   1111 1101
		   0000 0100
		  -----------
	  结论的补码:0000 0001(一共九位,超出位数不要了)
&   AND  都1——1
|   OR   有1——1
^   XOR  只有一个是1——1
~   NOT  反转
<<  
>>
>>>
计算机底层对float型数据存储可能会出现一些问题——把float型转换成int型
例子:console.log(0.1+0.2);
     console.log((0.1*10+0.2*10)/10);
     结果:0.30000000000000004
          0.3

十一、条件分支语句

if else语句
switch case语句

1>if(a>b){		 //表达式的结果是布尔值,不是布尔值也会转换成布尔值
  }
  else{	
  }

  if(){
  }
  else if(){
  }
  else if(){
  }
  else{   //最后一个写成else 
  }
例子:var today=7;
     if(today==1){
        console.log("星期一");
     }
     else if(today==2){
        console.log("星期二");
      }
      else if(today==3){
         console.log("星期三");
      }
      else{     //当不满足上面条件时,也不会报错
         console.log("星期日");
      }
      结果:星期日

2>switch case语句
  switch(变量/表达式){  ()里和下一行的key==比较
	 	case key:语句;break;   //匹配成功,执行后面语句			
		case key:语句;break;    			
		default:语句;      //上面的都不满足就执行默认代码
			              //如果写在第一行,一定要加break,写在最后一行可以不加break
	}
  例子:var today=1;
       switch(today){
          case 1:console.log(111);break;
          case 2:console.log(222);break;
          default:console.log('week');
        }
        结果:111
        
break:跳出循环体	
continue:跳出本次循环,继续进行下一次循环

十二、循环语句

前置、后置条件循环语句,增强for循环(JS特有):for(var key in obj){},(with语句)

循环三要素:初始条件;结束条件;迭代(循环)条件

1>前置条件循环语句(先判断条件)
  (1)for(初始条件;结束条件;迭代条件){
			循环体
     }
     死循环:for(;;){}
		
     label语句:标识循环的名称
               for循环前面起个名字(名字:for循环)
               例子:outer:for(){
                      inner:for(){}
                      break outer; //出了这整个循环了
                    }
  (2)初始条件;    //初始条件写在外面
	 while(结束条件){
		循环体;
		迭代条件;
	  }
	 死循环:while(true){}
	 例子:var i=1;
          while(i<10){
              console.log(i);
              i++;
           }              
          结果(控制台):1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      
2>后置条件循环语句
  初始条件;
  do{
	  //循环体     //循环体至少执行一次
	  //迭代条件
   }while(结束条件)
		                         
3>js特有,打印属性名和属性值(主要用来循环对象)
  增强for循环(for in循环)——for(var key in obj)
  例子:var obj={
	     name:'lisi',
	     age:20,
	     gender:'men'
	   }
	   //{}里有几个变量就循环几次,每次都会把name,age,gender分别赋值给key
	   for(var key in obj){   //key和obj可变
		    key:     obj中所有属性的属性名    
			obj[key]:     所有属性的属性值
		}
		例子:var obj={
		       name:'lisi',
		       age:20,
		       gender:'men'
             }
             for(var key in obj){   
                console.log(key);
                console.log(obj[key]);
             }
             结果:name
                  lisi
                  age
                  20
                  gender
                  men

with语句:with(作用域){里访问的变量都是obj里的变量}   //使用频率低
例子:var obj={
        name:'lisi',
        age:20,
        gender:'men'
     }
     console.log(obj.name);  //可以合并成一句啊
     console.log(obj.age);
     console.log(obj.gender);

     with(obj){
        console.log(name);
        console.log(age);
        console.log(gender);
      }     
     结果:lisi
          20
          men

例子1:
在这里插入图片描述
在这里插入图片描述
例子2:内层循环说只要k=3了,连k=3都不打印,直接跳出整个循环——外层循环只经历了一次
在这里插入图片描述
在这里插入图片描述
例子3:九九乘法表
document.write(内容);——(在document文档中输出)
document.writeln();——到了一行的末尾会自动换行

for(var i=1;i<=9;i++){
    for(var k=1;k<=i;k++){
         document.write(i+"*"+k+"="+(i*k));
     }
}
结果:九九乘法表一行
for(var i=1;i<=9;i++){
     for(var k=1;k<=i;k++){
          document.write(i+"*"+k+"="+(i*k));
     }
     document.write("</br>");   //每次内层执行完后/br换行
}
结果:左下位置的九九乘法表
for(var i=1;i<=9;i++){
     for(var k=1;k<=i;k++){
          document.write(i+"*"+k+"="+(i*k)+"&nbsp;");   //每个式子输出后都有一个空格
     }
     document.write("</br>");  
}
结果:左下位置的九九乘法表(每个式子后有一个位置的空格)
var space="&nbsp;"      //空间
for(var i=1;i<=9;i++){
     for(var k=1;k<=i;k++){
         var sp;          //每个式子输出后空的格数
         if(i*k<10){      //个位数空三格
             sp=space+space+space;    
         }    
         else{            //两位数空一格
             sp=space;
         }            
         document.write(i+"*"+k+"="+(i*k)+sp);
     }
     document.write("</br>");   
}
结果:左下位置的九九乘法表(结果:个位数空三格,两位数空一格)

十三、对象(一组属性和方法的集合)

Object{ } //不能操作类,但是能操作类的实例对象
创建实例对象,访问、删除、检测属性,对象序列化,方法
1.创建实例对象

1>对象字面量
  var obj={    
	  name:'lisi',
	  age:20 
  }
2>构造函数方式
  var obj=new Object();  //构造函数的首字母一定大写,一见到new相当于在堆区中新开辟一块内存空间
  obj.name='lisi';
  obj.age=20;

2.访问属性
访问一个属性:点操作符,属性名是变量/特殊字符
访问多个属性:for(var key in obj){ }

1>点操作符
  var obj={      
	  name:'lisi',
	  age:20
   }
  obj.name='terry';    
  console.log(obj.name);
  结果:terry
  
2>属性名是——变量/"特殊字符"——(用[""]访问) 
  1.变量
  2.obj={
		'name-first':'lisi',  //特殊属性名需加" "
	 	 age:20
	 }
	console.log(obj['name-first']);
	console.log(obj.age);
	console.log(obj);
	结果:lisi
      	 20
      	 Object { "name-first": "lisi", age: 20 } 
      	 
——循环数组对象元素,获取多个属性
  //for(var key in obj){}方法
  例子:var obj={
          name:'lisi',
          age:20,
          gender:'men'
       }
       for(var key in obj){
           console.log(key);
        }
       for(var key in obj){
           console.log(obj.key);  //到obj中找key变量(是变量,不能用.操作符)
        }
       for(var key in obj){
           console.log(typeof key);
           console.log(obj[key]);
        }
        结果:
             //第一个for循环结果
             name
             age
             gender
             
             //第二个for循环结果
             undefined    
             undefined
             undefined

             //第三个for循环结果
             string 
             lisi
             string
             20
             string
             men           

3.删除属性

delete 想要删除属性的属性名
delete obj.name
delete obj["name"]

例子:var obj={
        name:'lisi',
        age:20,
        gender:'men'
     }
     console.log(obj);
     delete obj.name;
     console.log(obj);
     结果:Object { name: 'lisi', age: 20, gender: 'men' }
          Object { age: 20, gender: 'men' }

4.检测属性(两种)
继承属性/私有属性,私有属性hasOwnProperty(“属性”)

1>继承属性/私有属性——返回true
  "name" in obj   	
  例子:var obj={
          name:'lisi',
          age:20,
          gender:'men'
       }
       console.log('length' in obj);     //既不是私有属性,也不是继承属性
       console.log('name' in obj);       //私有属性
       console.log('toString' in obj);   //继承属性
       结果:false   
            true  
            true          

2>私有属性,返回true;继承属性,返回false
  obj.hasOwnProperty('name')  
  
  例子1:var obj={
          name:'lisi',
          age:20,
          gender:'men'
         }
        console.log(obj.hasOwnProperty('name'));
        console.log(obj.hasOwnProperty("toString"));
        console.log(obj.hasOwnProperty('length'));
        结果:true
             false
             false
  例子2:var obj={
          name:'lisi',
          age:20,
          gender:'men',
          toString:function(){    // 重写toString方法
               return 10
          }   
        }
        console.log(obj.hasOwnProperty('name'));
        console.log(obj.hasOwnProperty("toString"));
        console.log(obj.hasOwnProperty('length'));
        结果:true
             true   //重写toString方法后,属于自己的属性
             false

5.对象序列化
前后台交互主要用json字符串格式——通用

object->json字符串——JSON.stringify(obj)  
json字符串->object——JSON.parse(json)

例子: var obj={
          name:'lisi',
          age:20,
          gender:'men'
       }
      var str=JSON.stringify(obj); //Object {"name":"lisi","age":20,"gender":"men"}
      var obj1=JSON.parse(str); //Object { name: 'lisi', age: 20, gender: 'men' }  //转回去了,和obj相同 
      
      console.log(obj==obj1);   //false 转换后内存地址变了                     

6.方法
静态方法:声明在函数内部,只能函数本身调用
非静态方法:声明在函数的原型对象中,函数的原型、实例对象均可调用

每个对象都有一个构造者(constructor)
每个函数都有一个原型对象(prototype)//写一个函数后,会瞬间开辟出两块内存空间保存一个函数,函数(本身+原型对象)

1>静态方法:
  调用:Object.关键字()
  Object.assign(obj1,obj2)——对象合并,右边覆盖左边,结果:左边
  Object.keys(obj):返回数组类型的所有属性名
  Object.values(obj):返回数组类型的所有属性值
  Object.defineProperty(obj,'key',{}):定义属性:哪个对象,哪个属性,属性值、属性配置(是否可修改等)
                                       不可重复定义
                                  {}里:直接写参数
                                       {value:属性值是多少	            
						                writable:是否可修改   //返回值是布尔类型
						                enumerable:是否可遍历
						                configurable:是否可删除/配置}		
                                  set/get方法(不能和第一种方式同时使用):set设置属性值,get获取属性值
         
  例子assign:var obj1={
                name:'lisi'
             }
             var obj2={
                name:'terry',
                age:20
             }
             var result=Object.assign(obj1,obj2); //Object{name:"terry",age:20}——result、obj1、obj2一个结果
       
             console.log(Object.keys(obj2));    //Array['name','age'] 
             console.log(Object.values(obj2));  //Array["terry",20]
                           
             console.log(obj1==result); //true
             console.log(obj2==result); //false                        
                                
  例子defineProperty(obj,'属性名',{})         
		                   {}里1>直接写参数			                        				             
                                 例子:var obj={
                                         name:"lisi",
                                         gender:'men',
                                      }
                                      Object.defineProperty(obj,'age',{
                                         value:20,
                                         writable:true,     
                                         enumerable:true,
                                         configurable:true  
                                      });
                                      console.log(obj.age);    //原来的年龄
                                      obj.age=30;
                                      console.log(obj.age);    //修改后的年龄
                                      
                                      for(var key in obj){
                                          console.log(key);   //年龄可被遍历,遍历属性名
                                      }
                                                                                                                                                     
                                      delete obj.age;                             
                                      for(var key in obj){     
                                            console.log(key);         //年龄可被遍历,被删除后,遍历属性名                                       
                                      }                                       
                                      结果:20
                                           30
                                           
                                           name
                                           gender
                                           age
                                                                                                                             
                                           name
                                           gender
                                                                                                                                                                                                                                                                                   
			 	              2>set/get方法(不能和第一种方式同时使用)
				                Object.defineProperty(obj,'age',{
						            set:function(v){				
							             this._age=v;   //内部设置方式
						            },
						            get:function(){    //获取属性过程							
							             return this._age;
					            	}
					            }			        
			                    例子:var obj={
                                         name:'lisi'
                                     }
                                     Object.defineProperty(obj,'age',{
                                         set:function(n){
                                            console.log("开始设置age啦----");
                                            this._age=n;
                                            console.log("设置完成啦");
                                         },
                                         get:function(){
                                            console.log('开始获取啦----');
                                            return this._age;
                                         }
                                     })
                                     obj.age=20;
                                     console.log(obj.age);
                                     结果:开始设置age啦----
                                          设置完成啦
                                          开始获取age啦----
                                          20

在这里插入图片描述
在这里插入图片描述函数里(静态方法):Object.assign(),Object.keys(),Object.values(),Object.defineProperty(obj,‘key’,{})
属性:prototype,length(形参个数)
调用:Object.关键字()

原型对象里(非静态方法):toString(),valueOf(),mytest()
属性:constructor

原型对象里,1003.toString()或1002.toString()或Object.prototype.toString()
原型对象的构造者:Object.prototype.constructor是Object1001

十四、(object)的常用子类(函数、数组、日期、正则)

(包装器函数、Math对象、前世今生小游戏)
1.函数
创建、调用、参数、内部属性、属性、作为值和返回值的函数

1>创建(函数字面量、函数声明、对象中)
  1)函数字面量  var say=function(){}; 表达式可以存储在变量或对象属性里
  2)函数声明   function say(){};         
  3)对象中
		var obj={
			name:'lisi',
			say:function(){}
		}
		obj.name
		obj.say()
		obj["say"]()

js解析器优先解析——函数声明(第二种)(遇到函数调用执行)
                解析用var操作符声明的变量,但不赋值(遇到赋值代码赋值)

js中没有重载概念,函数名相同,即为重写 
例子:function say(a){
	      console.log('a:',a);
     }
     function say(a,b){
          console.log('a+b',a,b);
     }
     say(10);
     结果:a+b  10  undefined   
	 
例子:function say(){
         a=10;
     }
     console.log(a);
     say();
     结果:报错  
2>函数的调用
  函数名(实参):  //只是让函数执行一遍,相当于window调用
  new 函数名();    //在堆区中有新的内存空间出现,相当于new调用,一定返回实例对象Object{  } 
  ——如果不需要新的内存空间,就用第一种方法

  //用函数的属性调用——通过call和apply改变函数体内this值的指向
  //this写的是谁就永远是谁,不需要再判断了,是this还得再判断一下
  函数名.call(this,参数列表)
  函数名.apply(this,[参数列表])
  
  例子1:function say(a,b){
           console.log(this)
       }
       new say();
       结果:Object{  }   //指向new出的内存空间,堆区中新的内存空间就是Object
       
 //测试call()
  例子2:function say(a,b){
           console.log(this);
           console.log(a,b);
       }
       say.call(this,10,20,30);  
       结果:Window
            10 20

  例子3:function say(a,b){
           console.log(this);
           console.log(a,b);
       }
       say.call([],10,20,30);  
       结果:Array[]
            10 20

  例子4:function say(a,b){
           console.log(this);
           console.log(a,b);
        }
        say.call({name:'lisi'},10,20,30);
        结果:Object { name: "lisi" }
             10 20
             
 //测试apply()
  例子:function say(a,b){
           console.log(this);
           console.log(a,b);
        }
        say.apply({},[1,2,3,4]);  
        结果:Object {  }
             1  2  
3>函数的参数
  形式参数:函数需要的参数
  实际参数:实际调用时传递的参数
  var say=function(形参){}   
  function say(形参){}
  say(实参);

  形参和实参的个数可以不一致,且数据类型不限
  1、有几个形参,就声明几个形参;
  2、有几个实参,就给arguments就赋几个实参
  3、将arguments里的数组元素全部赋给形参,如果没那么多形参,就放在arguments里内部保存着
  function say(a,b,c){
        //内部做的操作
		//var a;var b;var c;      
		//10给a;20给b		
		console.log(a,b,c);
   }
   say(10,20);
   结果:10 20 undefined
4>函数的内部属性(arguments的length和callee,this)(每个函数都有自己的arguments和this)
  arguments:类数组对象,保存实参   
  arguments[下标]
  
  arguments的属性——length:返回实参个数
  例子:function say(a,b){
          console.log(arguments);
          console.log(arguments.length);
          //var a;var b;
          //10给arguments[0],20给arguments[1],30给arguments[2]
          //arguments[0]给a,arguments[1]给b        
          console.log(arguments[2]);
       }
       say(10,20,30);
       结果:Arguments{0:10,1:20,2:30}    
            3  
            30
       
  arguments的属性——callee(例子:阶乘):从函数内部 指向当前拥有arguments的函数
  例子:计算一个数的阶乘          
       function jiecheng(num){   
            if(num<=1){
                return 1;
            }
            else{
                return num*jiecheng(num-1);  //jiecheng可换成arguments.callee  在函数内部找,留下电话方式了
            }
        }
       var result=jiecheng(3);
       console.log(result);
       结果:6
  例子:计算阶乘的和(1!+2!+3!+...+10!=?)
       后面再加:
       var sum=0;
       for(var i=1;i<=10;i++){
           sum+=jiecheng(i)
       }
       console.log(sum);
       
       
  this:指向函数赖以生存的环境对象  (简化:this指向对象)
  什么时候确定?指向谁?——当前拥有this的函数 被调用时确定//被谁调用就指向谁
  对象里的this就在对象里看
  //this的指向
  say();      //默认是window.say 
  obj.say();  //obj
  new say();  //new
  arr[0]();   //arr  函数内部的this值指向arr
  例子:function say(){  
           console.log(this);
       }
       say();
       结果:Window   //被Window调用,指向Window
       
  当全局声明一个变量时,var a=10;  //window.a
                    console.log(a);  //其实是window.a

  例子1:var length=10;
       function say(){
           alert(this.length);  //整个代码相当于弹出window.length
       }
       say();   //被window调用
       结果:弹框里是10
   
  例子2:var length=10;
        function say(){
           length=30;
           alert(this.length);   //整个代码相当于弹出window.length  //值随解析顺序发生变化
         }
        say(); 
        结果:弹框里是30
       
  例子3:var length=10;  
        function say(){
           alert(this.length);   //整个代码相当于弹出obj.length
         }
        var obj={
           length:20,
           say:say            
         }
        obj.say();   
        结果:弹框里是20

  例子4:var length=10;
        function say(){   
           alert(this.length);   
        }
        var obj={
           length:20,
           say:say,     
           run:function(handler){ 
               handler();    //相当于window.say()
               alert(this.length);    // 变成了obj.length,obj.length是20
           }
        }
        obj.run(say);  
        结果:弹框里是10  //只管当前函数是被谁调用的
             弹框里是20

  例子b:var length=10;  //全局声明了一个length属性
       function handler(){  //声明一个函数
           length=20;
       }
       function  say(){
           alert(this.length);  //this指向window,相当于window.length是多少
       }    
       say();   
       handler();  // 执行handler函数时,会全局声明一个length变量
       say();    
       结果:弹框里是10     //两个弹框,因为say函数内才有弹框
            弹框里是20

  例子c:var length=10;  //全局声明了一个length属性
       function handler(){  //声明一个函数
           length=20;
       }
       function  say(){
           alert(this.length);  
       }
       var arr=[say,say,say];
       var obj2={
           length:40,
           handler:function(){
               alert(this.length);
           }             
       }
       var obj={
           length:30,
           say:say,
           handler:function(h,o){
               h();   
               o.handler();  
           }
       }
       obj.handler(say,obj2);
       结果:弹框里是10   
            弹框里是40

  例子d:var length=10;  
       function  say(){
           alert(this.length);  
       }
       new say();  //this指向新创建的内存空间
       结果:弹框里是undefined

  例子e:var length=10;     
       function  say(){
           alert(this.length);   //相当于arr.length
       }
       var arr=[say,say,say];    //arr.length是数组长度是多少,是3 
       arr[0]();   //say(); 相当于arr.say();
       结果:弹框里是3           
5>函数的属性(把函数当做一个普通的对象)
 prototype,length(形参个数)

 prototype:原型对象——存储非静态方法/公有属性和方法		  
  
 length:say.length——返回形参个数
	     例子:function say(a,b){
	              console.log(a,b);
	              console.log(arguments.length);  //实参个数
               }
               say(10,20,30);
               console.log(say.length);
               结果:10 20
                    3 
                    2	 	  	
6>作为值和返回值的函数
  值:function say(){};
	  var handler=say;
	  handler();   //相当于say(),调用了第一行的函数
	  
	  function run(h){  //实参say传给了形参h
		 h();
	  }
	  run(say);
	  
  返回值:所有的返回值要使用return关键字——在函数外部想使用局部变量                 

  例子1:function say(){
           var a=10;
           return a;   //根据当前方法的用途设定是否需要
                       //在函数外使用局部变量,相当于say返回a
        }  
        var result=say();  //声明一个全新的变量去接收say的返回值
        console.log(result);
        结果:10

  例子2:var length=10;
        function say(){
            return  function(){  
                alert(this.length);   //整个代码相当于返回window.length
            }
         }
        var result=say();   //result是函数
        result();    
        结果:弹框里是10
           
  例子3:function say(){
           var a=10;
           function inner(){  
               console.log(a);
           }
           return inner;  //返回inner函数
        }
        var result=say();
        result();        //相当于调用say里边的inner函数
        结果:10

  例子5:链式作用域——先在自己的作用域内找,再逐级向上找
        var a=0;
        function say(){
           var a=10;
           function inner(){  
               var a=20;
               console.log(a);
           }
           return inner;  
        }
        var result=say();
        result();      
        结果:控制台:20

2.数组
创建、访问数组元素、检测数组、数组转换、方法

每个数组元素的数据类型任意,数组长度可动态修改

Array.prototype.slice.call():改变数组的slice方法的作用域——在特定作用域调用slice方法
                call()方法的第二个参数:传递给slice的参数(截取数组的起始位置)               
1>创建(数组字面量,构造函数)
  1)数组字面量
	var arr=[];   //空数组
	var arr=[null,undefiend,false,"",function(){},{}];  
	例子:var arr=[];
	     console.log(arr);
	     console.log(typeof arr);
	     结果:Array []
	          object
	          
  2)构造函数(一般用new关键字调用)
    var arr=new Array();    //空数组   
	var arr=new Array("hello",false);   //创建数组长度为2的数组,Array [ "hello", false ]
	var arr=new Array(10);    //创建一个数组长度为10的数组,打印时默认都为undefined
	如果是1个number类型的参数,相当于创建一个number长度的数组
	其他情况,相当于将参数作为数组元素创建数组

	function Array(){
		if(arguments.length==1){     //长度=1
			if(typeof arguments[0]== 'number'){
			    //判断这个唯一的参数是不是number类型,右边是字符串类型, 因为==会做数据类型转换			     	
			}
			else{
				//底层:创建一个以1为长度的数组,数组元素为arguments[0]
			}
		}
		else if(argumnets.length==0){
			//创建一个以0为长度的数组
		}
		else if(arguments.length>1){
		}
	}
2>访问数组元素
  每个数组元素都对应一个从0开始的数组下标(属性名)
  
  arr[index]:访问+设置(可以增加数组元素)
  arr[index]=10:给arr index位置的数组元素设置值为10
                 //存在——做替换
                 //不存在——数组长度扩展到index的长度,再设置值为10

  length:改变数组长度——增加/删除数组元素		  
  例子:var arr=["hello",false,null,true];
       arr.length=2;
       console.log(arr.length);
       console.log(arr);
       结果:2
            Array [ "hello", false ]
3>检测数组:判断arr是否为Array类型	
  Array.isArray(arr)方法   	
    例子:var arr=["hello",false,null,true]
         console.log(Array.isArray(arr));
         结果:true

  判断arr的构造函数是否为Array
  arr.constructor==Array;
4>数组转换(将数组转换成字符串类型)
  toString()  //每种子类调用toString方法,返回值不一定
              //看子类是否重写了父类型的toString,如果重写了就返回子类型的toString返回值
                                            //如果没重写,返回父类型的返回值,为[object Object](对象的toString()返回值)
  join("-");   //以什么形式来连接一个数组项
  例子:console.log(arr.join('-'));

——————数组的toString
      var arr1=new Array();   //声明了一个空数组
      var arr2=new Array('hello','world');   
      console.log(arr1.toString());
      console.log(arr2.toString());
      结果:<empty string>                   
           hello,world            
学习新方法时,参数,返回值(作用是什么)
5>方法——(添删4个,排序2,拼接1     切割2,查找2,迭代5——几乎都是非静态方法
  1)添加/删除数组元素
	栈方法:pop():删除最后一个数组元素  			    
			  	 返回值:删除的数组元素
		  push(添加的数组元素):添加				
				  返回值:添加后的数组长度
	      例子pop:var arr=[10,"hello",false,function(){},true,null];
	              var result=arr.pop();
	              console.log(result);
	              结果:null   //删除的数组元素是null
	      例子push:var arr=[10,"hello",false,function(){},true,null];
	               var result=arr.push(20,{});
	               console.log(result);
	               console.log(arr);
	               结果:8    
	                    Array(8) [ 10, "hello", false, arr(),true, null, 20, {} ]
	队列方法:shift():删除第一个数组元素 
					 返回值:删除的数组元素
		    unshift(添加的数组元素):添加
					   返回值:添加后的数组长度		
					   
  2)排序:(reverse,sort)——返回在原数组基础上排序后的新数组
	     reverse:数组反转						
	     sort(无/回调函数):默认数组升序
				参数(个数): 0:默认调用toString()后,字符编码排序				      				                  	           
			               1:回调函数sort(function(a,b){   //a和b:每次比较的两个数组元素
					                if(a>b){    //比较操作符,会做数据类型转换
						              return 正数:第一个数放后边					             
						              return  0:不排序,不比较
					                }
			                       })		
			                       回调函数:根据不同情况,返回不同的值
			     //降序排列:改符号/返回值
			
			    升序排列例子:var arr=[1,4,6,2,9,3,11];
			                var result=arr.sort(function(a,b){
			                    if(a>b){   
			                        return 1;   
			                    }
			                    else{
			                        return -1;   
                                }
                             });	  
                            console.log(arr);        
			                console.log(result);
			                console.log(arr==result);
			                结果:Array [ 1, 2, 3, 4, 6, 9, 11 ]
                                 Array [ 1, 2, 3, 4, 6, 9, 11 ]
			                     true
   例子://随意切换比较参数,得到比较结果
        	var arr=[{
			name:'a',
			age:20,
			salary:1000
		},
		{
			name:'d',
			age:10,
			salary:100
		},
		{
			name:'c',
			age:33,
			salary:800
		},
		{
			name:'b',
			age:15,
			salary:1500
		}];
		var result=arr.sort(handler("salary"));  //sort的参数是回调函数
		function handler(key){   //此时参数是salary
			return function(a,b){   //a,b每次比较的两个数组元素
				var c=a[key];
				var d=b[key];
				if(c>d){    //按工资升序排序
					return 1
				}
				else{
					return -1
				}
			}
		}
        console.log(result);	
        结果:0: Object { name: "d", age: 10, salary: 100 }
​             1: Object { name: "c", age: 33, salary: 800 }
             2: Object { name: "a", age: 20, salary: 1000 }
​             3: Object { name: "b", age: 15, salary: 1500 }

  3)操作方法(拼接concat,切割slice splice,
            查找数组元素indexOf lastIndexOf)——只有splice旧数组变了
    concat(想要拼接的数组):数组拼接——返回拼接后的新数组		   
		    例子:var arr=[1,2,3,4,5];
		         var arr1=[10,11,12];
		         var result=arr.concat(arr,arr1); //在调用的数组后再添加新数组  //改slice()  
		         console.log("原数组:",arr);
		         console.log("新数组:",result);
		         结果:原数组:Array(5) [ 1, 2, 3, 4, 5 ]
		              新数组:Array(8) [ 1, 2, 3, 4, 5, 1, 2, 3, 4, 5,10, 11, 12 ]		        
		               
    slice():数组切割
		 参数个数:0:返回旧数组	   
				  1:当前到末尾(不含)								 
				  2:开始到结束(不含)					
    splice():数组切割——返回切割后(旧数组:剩下的,含content)
         参数个数:0:返回空数组
                 1:		        
                 2:begin number(多了也不显示)					    
                 3:begin number "content"——新数组:被替换原来的
			        替换/插入:begin number 'content'
			 	              删除number个,在begin插入content
			      	     
	//查找数组元素,通过===进行比较
    indexOf(内容):默认从前向后,找到一个满足条件的元素返回
    lastIndexOf(内容):默认从后向前  
	返回值:找到——返回下标
		   找不到——返回-1
	例子:var arr=[1,2,3,4,2,5];	
	     var result1=arr.indexOf(2); 
		 var result2=arr.lastIndexOf(2);   	
		 console.log("新数组1:",result1);
		 console.log("新数组2:",result2);	
		 结果:新数组1: 1
		      新数组2: 4		   
		       		                        
  4)迭代方法(循环)——有几个数组元素就执行几次
     var arr=[11,2,13,4,5];
	 for(var i=0;i<arr.length;i++){  //底层循环
	     console.log(arr[i]);
	  }
	 
	 //函数的参数都一样	
	 参数:回调函数(数组元素 下标  数组)   this:回调函数中this的指向(可选,想让它指向谁就写谁)	
 	
	 every():每个数组元素都满足条件,返回true
	 some():只要有一个数组元素满足条件,返回true
	 //返回新数组
     map():对每个数组元素进行操作     
	 filter():数组过滤——回调函数里是筛选条件
	 forEach():相当于对底层for循环进行了封装——无返回值  	 		                    		                               			 		
			    例子:arr=["yi","er","san","si"];
			         var result=arr.forEach(function(item,index,arr){
			                   console.log(item,index,arr);},
			                   {});			         
			         console.log(result);   //undefined  因为forEach无返回值
			         结果:yi 0 Array(4) [ "yi", "er", "san", "si" ]
			              er 1 Array(4) [ "yi", "er", "san", "si" ]
			              san 2 Array(4) [ "yi", "er", "san", "si" ]
			              si 3  Array(4) [ "yi", "er", "san", "si" ]                   			    			
        
      例子every:var arr1=[1,2,3,4,5,6,7];
                var result=arr1.every(function(item,index,arr){return item>4});
                console.log(result);
                结果:false   //不是每个都大于4
      例子map:var arr1=[1,2,3,4,5,6,7];
              var result=arr1.map(function(item,index,arr){return item+10});
              console.log(result);
              结果:Array(7) [ 11, 12, 13, 14, 15, 16, 17 ]
      例子filter:var arr1=[1,2,3,4,5,6,7];
                 var result=arr1.filter(function(item,index,arr){return item>3});
                 console.log(arr1);
                 console.log(result);
                 结果:Array(7) [ 1, 2, 3, 4, 5, 6, 7 ]
                      Array(4) [ 4, 5, 6, 7 ]
      例子forEach:var arr=["hello","world",20,false];
                  arr.forEach(function(item,index,arr){console.log(item,index)});  
                  结果:hello 0 
                       world 1
                       20    2 
                       false 3       
                      
      //自己写myForEach()须知:声明位置
                             参数个数、类型
                             如何循环执行回调函数
                             回调函数中的this值指向
      分析:调用:arr.myForEach(function(item,index,arr){},this);   
      var arr=[1,2,3,4];
      var arr1=[1,2];
      //声明在原型对象中
      Array.prototype.myForEach=function(){ 
          //只有一个参数,且是函数类型
          if(arguments.length==1&&typeof arguments[0]=='function'){    
              //如何循环执行回调函数         
              for(var i=0;i<this.length;i++){
                  arguments[0].call(window,this[i],i,this);   
              }             
          }   
          //有两个参数 
          else if(arguments.length==2){
               //如何循环执行回调函数 
               for(var i=0;i<this.length,i++){
                  arguments[0].call(arguments[1],this[i],i,this);
               }
          }
      }; 
      //函数的调用
      arr.myForEach(function(item,index,arr){
        console.log(item);
        console.log(this);},  this);        
      console.log(this);
      console.log(item,index,arr);

---------------用foreach修改数组内元素,需首先判断是基本数据类型还是引用数据类型
什么鬼这是!?不懂!?
用map方法不用考虑这些
    //基本数据类型
    var arr=[1, 2, 3, 4, 5];   
    arr.forEach(function(item,index){
      //无效
      //item=item+1;
      //有效
      //arr[index]=item+1;  //Array(5)[2,3,4,5,6]    
    })
    console.log(arr);

    //引用数据类型
    var arr = [{}, {}, {}, {}, {}];
    arr.forEach(function(item,index){
      //item.name='zhangsan';  //每个元素都有name属性
      arr[index]=[1,2];  //Array(5)[[1,2][1,2],[1,2],[1,2],[1,2]]
    })
    console.log(arr);

      ES6中:用reduce实现map
      没有第二个参数循环会少执行一次!
      reduce(function(pre,item,index,arr),this)——参数多了一个pre         
                     pre:上一次回调函数执行的返回值
                          第一次执行时,this存在,pre就是this                                               
                                      this不存在,pre就是第一个数组元素
                                            直接从第二个数组元素开始执行,循环会少一次
                                                     
                     this:指向回调函数的返回值,根据第二个参数是否存在,改变回调函数的参数        
      例子:var arr=[11,12,13,14,15];       
           var result=arr.reduce(function(pre,item,index,arr){   //回调函数的第一个参数
                          console.log(pre,item,index,arr);   
                          return index+10;},   //return作用:下一次pre,result最后值
                       {});        //回调函数的第二个参数
                       console.log(result);  //最后一次的指数4+10
           结果:见下图             
           分析:第一次执行时,reduce设置了第二个参数空对象,第一次的pre是第二个参数空对象

在这里插入图片描述

第一次执行时,reduce没第二个参数时,pre为数组第一个元素11,所以从12开始执行
结果:

在这里插入图片描述
reduce的例子:用JS编写,使用一次array的reduce方法,给定一个数组:var a=[1,2,3,4,5,6,7…],请写一个函数可以返回一个数组,形式如下:var b=[[1,2,3,4,5],[6,7,8,9,10]…],即5个一组分割成数组再组成一个更大的数组;最后一个数组如果不足5个,实际剩几个就包含几个,但不得为空
代码:slice方法

var arr=[1,2,3,4,5,6,7];
var newArr=arr.reduce(function(pre,item,index,arr){
     var begin=index*5;  
     var end=begin+5;
     var result=arr.slice(begin,end);  //result是小数组   
     if(result.length){    
           pre.push(result);   //只要小数组存在,就给pre大数组                    
      }   
     return pre;   //后来的pre是上一次切割后带有结果的数组
},[]);    //第一次的pre是空数组
console.log(newArr);
结果:Array [[1,2,3,4,5],[6,7]]

splice方法:修改原数组了,考虑的东西会更多一些
。。。
。。。
。。。
3.日期(C++,java中都有)——JS中的内置对象

1、创建日期类型:new Date();  //(年,月,日,时,分)可加参数,从0月开始算,0~11月
                           //字符串形式("年/月/日")或("年-月-日"),无月份问题
例子:var date=new Date();   
     console.log(date);
     结果:现在的时间   
2、设置日期
   setDay()
   setDate()
3、获取日期
   new Date().getTime()    //返回当前日期的毫秒数

4.正则表达式(C++,java中都有)——JS中的内置(描述字符模式的)对象

表单验证大部分用的是正则表达式——匹配一段字符串
字符串调用字符串方法进行匹配/正则调用正则方法和字符串进行匹配
不用正则表达式,默认只匹配一个(search只能找到一个)

在表达式内容里写:
[]:把里面看做每一个字符进行匹配
[]{1,2}:1~2个字符,贪婪模式下最多放一起的字符  
^:不在[]内的任意字符

\w:任何ASCII字符,等价于[a-zA-Z0-9]+_
\W:任何非ASCII字符组成,等价于[^a-zA-Z0-9]
?:等价于{0,1}
+:等价于{1,}
*:等价于{0,} 更多
|:或者
^:匹配字符串的开头,多行检索时,匹配一行的开头
$:匹配字符串的结尾,多行检索时,匹配一行的结尾

两种模式:贪婪模式(默认),非贪婪模式

1.创建表达式
  1)字面量  var p=/表达式内容/gi;  (g:全局搜索)(i:忽略大小写)
  2)构造函数  var p=new RegExp("表达式内容","gi") 
例子:var str='hello world Hello HELLO,javascript is very easy than java';
     //第一种创建方式
     var  p=/hello/;
     //第二种创建方式
     var p=new RegExp("hello","ig");  
--------------------------------------------------------     
     var result=str.search(p);  //字符串调用方法,在字符串里找和p匹配的
     console.log(result);
     结果:0  
          Array(3) [ "hello", "Hello", "HELLO" ]  //如果是match的话
     
     //p里的test方法/esec方法,测试str是否符合正则表达式的规则
     var result=p.test(str);  
     console.log(result);   
     结果:true

----------包装器函数(可进行基本数据类型的封装)(构造函数)——和转换函数区分
返回首字母大写类型的对象object类型

使用new关键字调用,才能得到实例对象 num=new Number()
Number.prototype.×××(所能调用的方法都在Number.prototype里)

var num=10;
num.toString();
    //num->new Number(num)的实例对象中——自动装箱过程,object类型
    //new Number(num).×××——实例对象调用实例对象中的属性和方法
    //console.log(num);   变成了基本数据类型number类型——自动拆箱过程
第一种:Number()
       new Number();  //包装器函数,返回object类型的Object
       Number();      //转换函数,返回值类型是number
例子:var num=10;
     var a=Number(num);
     var b=new Number(num);
     console.log(a);
     console.log(typeof a);
     console.log(b);
     console.log(typeof b);
     结果:10
          number
          Number { 10 }
          object
Boolean()
String()
String包装器:声明在String.prototype.xxx——研究实例对象的公有方法
用str.×××调用就行
length,concat,slice,substr,substring,toUpperCase,toLowerCase
indexOf,lastIndexOf,trim,search,match,replace,split,charAt,charCodeAt
length:返回字符串长度
        例子:var str="hello";
		     console.log(str.length);  
		     结果:5
concat():字符串拼接		
slice():字符串切割			
		 2:begin end   end为-1:倒数第一个字符(不包含),-2:倒数第二个字符	
substr():字符串切割——不修改原字符串   
		  0:原字符串	
		  2:begin number  
		  例子:var str="hello";		      		   
		       console.log(str.substr());
		       console.log(str.substr(1,2));
		       结果:hello	           		   
		            el
substring():字符串切割
		     0:原字符串	   	    
	     	 2:begin end(不管负几,改变切割方向,不含末尾)  			   
			 例子:var str="hello";		      	
			      var result=str.substring(1,3);		       
		          console.log(result);
		          console.log(str.substring(1,-1));
		          console.log(str.substring(4,-1));
		          结果:el		
		               h        
		               hell
toUpperCase():小写—>大写
toLowerCase():大写—>小写
               例子:var str="hello";
                   var result=str.toUpperCase(只要是数字就行);
                   console.log(result);             
                   例子:HELLO  
indexOf()
           例子:var str="hello";
                  var result=str.indexOf('o');
                  console.log(result);
                  结果:4
lastIndexOf()
trim():除字符串前后空格(注意是前后的空格)
search("str"/正则表达式):搜索字符串,只匹配一个满足条件的字符——返回下标		                        
		                例子:var str="hello";
		                    var result=str.search("h");
		                    console.log(result);	          
		                    结果:0          
match(key/正则):匹配字符串——返回匹配字符组成的数组
	   	        例子:var str="hello";
		             var result=str.match('he');		                  
		             console.log(result);	
		             结果:Array [ "he" ]
replace('old'/正则,'new'):替换字符串
split(""/正则):切割,字符串转数组——返回切割后的新数组
                例子:var str="hello world";
                     var result1=str.split("l");   //把l去掉,根据l进行切割                   
                     console.log(result1);
                     var result2=str.split("o");   //把o去掉,根据o进行切割                   
                     console.log(result2);                     
                     console.log(str.split(""));  //每个字符代表一个数组元素
                     结果:Array(4) [ "he", "", "o wor", "d" ]   //两个l的话是空字符串
                          Array(3) [ "hell", " w", "rld" ]      
                          Array(11) [ "h", "e", "l", "l", "o", " ", "w", "o", "r", "l","d" ]                                     
charAt():返回指定位置的字符
charCodeAt():返回指定位置的字符编码
              1)例子:console.log("a".charCodeAt());
                   结果:97
              2)也可以返回一个字符串中一个字符的编码
var num=10;
console.log(num);
console.log(typeof num);
console.log(num.toString());  
   //自动装箱      new Number(num);
   //调用属性和方法 new Number(num).toString();
   //自动拆箱      typeof num:number
console.log(typeof num.toString());
结果:10
     number
     10
     string

----------Math对象,不是构造函数(new Math:错误!)

     Math.min():返回一组数的最小值
	 Math.max():返回一组数的最大值
	 例子:console.log(Math.min(1,2,3,4,5,6));
	      结果:1
取整:Math.ceil():向上取整
  	 Math.floor():向下取整(去掉小数点)
	 Math.round():四舍五入
随机数:Math.random():返回0-1之间的随机数,不包含1
       例子1:console.log(Math.random());
       例子2:var arr=["hello","world","h",1,2,3];
             console.log(arr[Math.floor(Math.random()*6)]); //[]里是数组下标,0~5
             结果:随机数组元素
其他:Math.abs():绝对值
	      sin()
	      cos()
	      log()

例子:----------前世今生小游戏

写旧名字数组,里面是对象
获取用户输入的名字  //prompt:显示提示对话框
分情况讨论:2/3~4/大于5,请输入正确的格式
          获取新姓
          通过新姓获取旧名数组(如果旧名数组存在,如果不存在弹出没有匹配的旧名)
          从旧名数组随机选一个
          拼起来,弹框弹出
函数——通过姓找名               
//firstName:旧姓
//lastName:旧名  lastNames:旧名集合
//nowFirstName:新姓
老师的:
var  nameArr=[{
			firstName:'王',
			lastName:["安石",'昭君','羲之','维']
		},{
			firstName:'李',
			lastName:["白",'世民','元霸','清照']
		},{
			firstName:'张',
			lastName:["三丰",'无忌','飞','良']
		},{
			firstName:'欧阳',
			lastName:["修",'峰','克','娜娜']
		}];

		//1.获取用户所输入的名字
		var nowName=prompt("请输入您的今生姓名:");
		//控制台:确认:输入的内容
	             取消:null	
		if(nowName){
			if(nowName.length<=3){
				//2.获取新姓
				var nowFirstName=nowName.substr(0,1);
				//3.获取旧名数组
				var lastNames=findLastNameByFirstName(nowFirstName); 	
				if(lastNames){
				    //4.随机选一个旧名
				    var index=Math.floor(Math.random()*lastNames.length);
			      	alert("您前世的姓名为:"+nowFirstName+lastNames[index]);
		     	}
		     	else{
		     	    alert("没有匹配您的前世姓名");		     	  
		     	}
		     }
			else if(nowName.length>3 && nowName.length<6){				
				var nowFirstName=nowName.substr(0,2);
				var lastNames=findLastNameByFirstName(nowFirstName);
				if(lastNames){
					var index=Math.floor(Math.random()*lastNames.length);
				    alert("您前世的姓名为:"+nowFirstName+lastNames[index]);
				}
				else{  
					alert("没有匹配您的前世姓名");
				}					
			}
			else{   //如果长度大于6
				alert("请输入正确格式的姓名");
			}
		}

	function findLastNameByFirstName(firstName){  //通过姓找名函数
		newArr=nameArr.filter(function(item,index,nameArr){  //新数组=旧名字库筛选(只剩下合适的)
			return item.firstName==firstName});   //如果旧名字库的姓==姓,就返回
		return newArr[0].lastName;  //新数组里只有一个对象所以是0,返回这个对象里所有的旧名
	}

十五、面向对象——实现多个对象的集合

基础模式
工厂模式(创建对象的过程放工厂)
构造函数模式(对象细分)
原型模式(公有属性&方法放在原型对象中)
继承()
借用构造函数(封装)
1.基础模式

每个对象{}都是一个new Object()
var web2101=[{
			name:'',
			age:20,
			gender:'men',
			tel:xxxx,
			address:'',
			专业:xxx
		},
		{
			name:'',
			age:20,
			gender:'men',
			tel:xxxx,
			address:'',
			专业:xxx
		},
		{
			name:'',
			age:20,
			gender:'men',
			tel:xxxx,
			address:'',
			专业:xxx
		 },....];

2.工厂模式
属性名没改,属性值改了

优点:创建对象过程放工厂,不用new Object,只需调用工厂函数(调用时执行,执行时new一个Object)
缺点:对象不能细分;浪费内存(内置函数)	
解决2的问题:将共有函数声明在工厂函数外部,在函数内部将指针指向共有函数(缺点:外部其它函数也能调用)
           say方法在构造函数外部,也是双向指向的过程
function createStudent(name,age,gender){			
	var obj=new Object();   //创建一个新的Object类的对象
	obj.say=function(){};   //共有的属性
	obj.name=name;      //=传进来的name属性
	obj.age=age;
	obj.gender=gender;
	return obj;
}
var stu1=createStudent("lisi",20,'men');    //把具体的值给了obj对象
var stu2=createStudent('tom',30,'women');

例子:可以把say方法声明在工厂外部,工厂内的say方法指针指向外部函数
//解决方法:工厂外部:function say(){alert("say----");};
      function createStudent(name,age,gender){
         var obj=new Object();  //1001       //1002
         obj.say=function(){    //1001.say   //1002.say
            alert("say----");      //解决方法:把say声明在外部后(去掉里面的say):obj.say=say;
         }
         obj.name=name;
         obj.age=age;
         obj.gender=gender;
         return obj;       
      }
      var stu1=createStudent("lisi",20,"men");  //虽然调用的都是say方法,但是在不同的内存地址
      var stu2=createStudent("tom",25,"men");
      console.log(stu1);
      console.log(stu2);
      console.log(stu1.say==stu2.say);
      结果:见下图
           false(不是同一个引用地址)    //解决方法:true

工厂里:obj.clazz="web2101";   //比较的是字符串类型,保存的地址在栈区里
       obj.say=function(){};  //引用数据类型,每个函数在堆区中有2个内存空间,stu1和stu2的内存空间(浪费)
       stu1.clazz==stu2.clazz;  //true
       stu1.say==stu2.say;      //false

例子的结果:
在这里插入图片描述
3.构造函数模式(对象细分)

缺点:公有属性/方法 外置——除了工厂函数可调用,其他也能调用
new Object()   
new Array()
new Date()
function Student(name,age,gender){   //Student构造函数		
	this.name=name;   //此时this被new调用,想往new里放属性=向this里放属性
    this.age=age;   
	this.gender=gender;  //不用return,通过new关键字创建,会自动将this值指向创建出来的内存空间
}    //--------------开头的new不用写,结尾的return不用写
var stu1=new Student('lisi',20,'men');   

例子:function Student(name,age,gender){
           this.name=name;   //传进来的参数
           this.age=age;
           this.gender=gender;        
     }
     var stu1=new Student("lisi",20,"man");
     console.log(stu1);
     console.log(stu1.constructor);     //细分实例对象的结果
     结果:见下图

在这里插入图片描述

缺点:
例子:function Student(name,age,gender){
           this.name=name;   //传进来的参数
           this.age=age;
           this.gender=gender;
           this.say=function(){   //say给了this,this也是new来的
              alert("say---");
           }
      }
     var stu1=new Student("lisi",20,"man");  //第一次new有一个新的内存空间,给了function里的this
     var stu2=new Student("tom",21,"woman");  
     stu1.say();
     stu2.say();
     console.log(stu1.say==stu2.say);  //实例对象的构建改成构造函数模式
     结果:弹框say---
          弹框say---
          false  //把say放外边才能为true

解决方法:function say(){
            alert("say---");
         }
         function Student(name,age,gender){
           this.name=name;   //传进来的参数
           this.age=age;
           this.gender=gender;
           this.say=say;
         }
         var stu1=new Student("lisi",20,"man");  //第一次new有一个新的内存空间,给了function里的this
         var stu2=new Student("tom",21,"woman");  
         stu1.say();
         stu2.say();
         console.log(stu1.say==stu2.say);  //实例对象的构建改成构造函数模式
         结果:弹框say---
              弹框say---
              true  //把say放外边才能为true       

4.原型模式(公有属性&方法放在原型对象中)

例子:
function Student(name,age,gender){
	this.name=name;
	this.age=age;
	this.gender=gender;
}
Student.prototype.say=function(){    //把say方法声明到了原型对象中
	alert("say---");
}
var stu1=new Student("lisi",20,"man");
var stu2=new Student('tom',21,"woman");
stu1.say();
stu2.say();
console.log(stu1.say==stu2.say);
结果:弹框say---
     弹框say---
     true

例子1:function Student(name,age){
         this.name-name;
         this.age=age;
       }
       var stu1=new Student("lisi",20);
       console.log(stu1.constructor);
       结果:function Student(name, age)
例子2:function Student(name,age){
         this.name-name;
         this.age=age;
       }
       Student.prototype.money="money";
       Student.prototype.work=function(){
            alert("work---");
       };
       var stu1=new Student("lisi",20);
       stu1.work();   
       console.log(stu1.money);
       console.log(stu1.constructor);
       结果:弹框work---
            money
            function Student(name, age)   
例子3:function Student(name,age){
         this.name=name;
         this.age=age;
       }
       Student.prototype.money="money";
       Student.prototype.work=function(){
            alert("work---");
       };
       Student.prototype={
           constructor:Student,
           enjoy:function(){
              alert("enjoy---");
           },
           color:"red"
        }
       var stu1=new Student("lisi",20);
       
       console.log(stu1.constructor);  //指向Object       
       结果:function Student(name, age)

5.继承

子类的原型对象指向父类的实例对象
父类的实例对象指向子类的构造函数——使子类的constructor属性指向子类的构造函数
Poor.prototype=new Rich();
Poor.prototype.constructor=Poor;

例子:function Rich(name,age){  //先创建了Rich构造函数
        this.name=name;
        this.age=age;
      }
      Rich.prototype.enjoy=function(){   //Rich的原型对象中有enjoy属性
          alert("enjoy---");
      }
      Rich.prototype.money=["card1","card2"," card3"];   //Rich的原型对象中有money属性
      var r1=new Rich("terry",20);   //实例对象r1
      
      function Poor(name,age,gender){  //声明了Poor构造函数
        this.name=name;
        this.age=age;
        this.gender=gender;
      }    
      Poor.prototype=new Rich();   //----------子类的原型对象指向父类的实例对象
      Poor.prototype.constructor=Poor;   //----------父类的实例对象指向子类的构造函数
      Poor.prototype.work=function(){   //Poor的原型对象中有work属性
         alert("work---");
      }           
      var p1=new Poor("lisi",20,"man");   //实例对象p1
      
      //----------------------------------------
      console.log(p1.money);     //穷人家孩子能不能拿到钱
      console.log(p1.constructor);    //穷人家孩子的爸爸是谁
      
      console.log(r1.money);    //富人家孩子能不能拿到钱
      console.log(r1.enjoy);   //富人家孩子还能不能有enjoy属性
      console.log(r1.constructor); 
      结果:见下图

在这里插入图片描述
在这里插入图片描述
6.借用构造函数

同样的代码写两遍最好进行封装——借用父类构造函数
声明Rich和Poor函数时,同样的d代码写了两遍

Rich.call(this,name,age);
Person
	Student
	Teacher

例子:
function Rich(name,age){  
        this.name=name;
        this.age=age;
      }
Rich.prototype.enjoy=function(){ 
          alert("enjoy---");
      }
Rich.prototype.money=["card1","card2"," card3"];  
      var r1=new Rich("terry",20);   
      
function Poor(name,age,gender){  
        /*this.name=name;
        this.age=age;*/
        Rich(name,age);    //调用new Poor()时传进来的name,age   //要看Rich是被谁调用的,被window调用,此时name和age赋给了window
        //-----------所以写成Rich.call(this,name,age);  //所有的this指向new Poor()里的new
        this.gender=gender;    //这个this指向new出来的新空间
}    
Poor.prototype=new Rich(); 
Poor.prototype.constructor=Poor;  
Poor.prototype.work=function(){ 
         alert("work---");
}           
var p1=new Poor("lisi",20,"man");     //调用new Poor()   //Poor里的this值指向new
//----------------------------------------
console.log(p1);    
结果:Object { gender: "man" }    //name和age赋给了window,所以p1里只有gender

结果:Object { name: "lisi", age: 20, gender: "man" }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值