zhangdong@tedu.cn
JS 基础语法
1、使用JS
1、浏览器内核
    内核主要负责页面的渲染
    内核主要由两部分组成
        1、内容排版引擎
            解析HTML/CSS
        2、脚本解释引擎
            解释JS

    浏览器    内核     排版引擎      解释引擎
    IE        Trident     -          Chakra
    Firefox   Gecko       -          Monkey系列
    Safari    Webkit    Webcore      Nitro
    Chrome    Webkit    Webcore      V8
    Opera     Presto      -          Carakan
    Opera     Webkit    Webcore      V8
    (2013~)   
2、搭建JS运行环境
    1、独立安装的JS解释器
            要求:安装NodeJS
            开始-> 搜索输入 cmd
            操作:向控制台中输出一句话
            console.log("你好世界!");
        console.log('Hello World');
   2、嵌入在浏览器内核中的JS解释器
    1、直接在浏览器Console中输入脚本并执行
    2、将JS脚本嵌入在HTML页面中执行
        1、通过 html 元素事件
         onclick 事件 :在鼠标单击时要执行的操作
         <button οnclick="JS脚本"></button>
         <div οnclick="JS脚本"></div>
         ...
         <ANY 事件名称="JS脚本"></ANY>
        2、在<script>标记中 编写JS脚本
            <script>
                document.write("<h1>Hello</h1>");
            </script>
        
        3、使用外部脚本文件,编写JS脚本
            1、创建脚本文件
                ***.js
                编写JS脚本
            2、在使用的页面中引入JS文件
                    <script src="文件URL"></script>
    3、JS调试
        代码出现问题,结束本块运行,但不会影响后续块
2、语法规范
    1、语句-会被JS解释器所执行的代码
        由表达式、关键字、运算符组成
        严格区分大小写(重要)
        每条语句都由 ; 表示结束
        中英文符号:
            1、, 和 ,
            2、. 和 。
            3、; 和 ;
            4、: 和 :
            5、" 和 “
            6、() 和 ()
    2、注释
        单行注释:只能注释一行内容
            语法://
        多行数值:一次性注释多行内容
            语法:/* */
3、变量 和 常量
1、变量
1、什么是变量
    内存:保存程序运行过程中所需要用到的"数据"
        空间:
            位 :bit     8bit = 1byte
            字节:byte   1024byte = 1kb
            千字节:kb   1024kb = 1mb
            兆字节:mb   1024mb = 1gb
            G : gb       1024gb = 1tb
            T : tb

        变量:表示的就是内存中的一段存储空间
            生活中:
                1、宾馆的房间
                2、超市储藏箱
        变量值:保存在变量中的数据
        变量名:标识数据在内存中的名字
        
2、变量的声明
到内存中 声明一段空间,并且起个别名再保存数据
语法:
    1、声明变量
        var 变量名; 
    2、为变量赋值
        变量名=值;
    
    简写:
        var 变量名=值;
    3、一条语句声明多个变量
        var 名1,名2,...,名n;
        ex:
            var stuName="张三丰",age=18,gender,score;
3、变量名的规范
    1、不允许使用JS的关键字或保留关键字
    2、允许包含字母、数字、下划线(_)以及$
        var stuName;正确
        var $stuName;正确
        var stu-name;错误,不能出现 -
    3、不能以数字开头
        var 1name;错误
        var name1;正确
    4、不能重复
    5、尽量见名知意
        var a;
        var b,c,d,e,f,g;

        var studentName;
    6、推荐使用 "匈牙利命名法","驼峰命名法","下划线命名法"
        驼峰命名法:
            1、变量名由一个单词组成,采用全小写
            2、变量名由多个单词组成,第一个单词采用全小写,
            其余的每个单词首字符变大写

            var studentName;
4、变量的使用
    1、未经初始化的变量
        1、变量声明之后,没有被赋值就直接使用
            var stuName;
            console.log(stuName);
            结果为:undefined
        2、变量未被声明过,而直接使用
            console.log(stuAge);
    2、声明变量不使用var
        在JS中,允许声明变量时不使用var关键字
        如果省略var关键字,声明的就是"全局变量"
        但,并不推荐此写法
        stuGender="男";
        console.log(stuGender);
    3、可以对变量进行存取操作
        1、设置变量的值-存值操作(SET操作)
            将数据保存在变量中
            特点:只要变量出现在赋值符号(=)的左边,一律是存执操作
                var stuName="张三丰";
                stuName="张无忌";
                var newName=stuName;
        2、获取变量的值-取值操作(GET操作)
            将数据从变量中取出来使用
            特点:只要变量"没"出现在赋值符号的左边,一律都是取值操作
                var stuAge=18;//存值操作
                console.log(stuAge);//在控制台上打印输出stuAge的值
                document.write(stuAge);//在页面上打印输出stuAge的值
                var newAge = stuAge;
                    针对newAge 是存值操作
                    针对stuAge 是取值操作
                stuAge = stuAge + 10;
                 存值     取值

                套餐名:香辣鸡腿堡套餐
                汉堡:香辣鸡腿堡
                配餐:烤翅
                饮料:可乐
2、常量
    1、变量与常量
        变量:是一个可以变化的数据
        常量:是一个不能变化的数据
        常量的特点:
            在程序中,一旦被声明好,在程序运行过程中就不允许被修改
    2、语法
        const 常量名=值;
        注意:
            1、声明常量时必须赋值
            2、通常,常量名称采用全大写形式(规范)
    3、练习
        声明一个变量 用来 保存一个圆的 半径值
        计算 该圆的周长,并打印输出 2*π*半径
        计算 该圆的面积,并打印输出 π*半径*半径
4、数据类型
1、作用
    决定了数据在内存中所占的空间大小
2、数据类型分类
   1、原始类型(基本类型)
     1、number类型
       数字类型
       可以表示32位的整数,也可以表示64位的浮点数
       整数:32位空间(4字节)
       浮点数:小数,64位空间(8字节)

      整数:
    1、保存十进制数字
        由0-9共10个数字组成,逢10进1
        var age = 35;
    2、保存八进制数字
        由0-7共8个数字组成,逢8进1
        JS中,八进制数字值,由0开始
            var num=010;
        3、保存十六进制数字
            由0-9,A-F 共 16个数字组成,逢16进1
            JS中,十六进制数字,由0x开始
            var num=0x10;
       浮点数:
        小数
        支持小数点计数法:35.5,76.8,31.00004
        支持指数记录法:4.3e2
      2、string类型
    字符串类型
    表示一系列的文本字符
    由Unicode字符,数字,标点符号组成的序列
       Unicode : 编码方式之一,
         可以由一组十六进制的数字(Unicode码)来表示一个字符。
    每个字符在计算机内存中,占2个字节

    如何查看字符的Unicode码???
    字符.charCodeAt(); 十进制表示方式
    字符.charCodeAt().toString(2); 二进制
    字符.charCodeAt().toString(16);十六进制
    张:24352(十进制)
    张:0101111100100000(二进制)
    张:5f20(十六进制)

    如何将 Unicode码 转换为字符???
    使用 \u 将 十六进制的Unicode码转换为字符
    var str = "\u5f20";

    中文汉字的范围:
    从 \u4e00 开始  到  \u9fa5 结束 

    string在声明的时候需要使用"" 或 '' 引起来
        var num1 = 456;//number
        var num2 = "456";//string

    特殊字符需要转义:
        ex:
            想在字符串中 打印输出 ""
        \n : 换行
        \t : 一个制表符
        \" : "
        \' : '
        \\ : \
    3、boolean类型
        布尔类型
        在程序中只表示真 或 假 的状态值(条件中用的多)
        该类型 仅有两个值 
            true :真
            false :假
        在实际运算中true当做1运算,false当做0运算
    4、undefined
        语义:访问的数据不存在
    2、引用类型
js是解释执行
js两大类型:原始类型和引用类型
所有的var 都会提前到当前script中最前端

1、隐式转换:
      规律:1、默认一切转数字类型,做算术计算。
               boolean类型 true--> 1 false--> 2
        2、+法中,只要有一个是字符串,都转为字符串,
           +变为字符串拼接
           其他类型转字符串,在字符串前后直接加引号
      表达式:有数据、变量和运算符组成的公式
               *默认,从左到右,两两计算

        NaN:  不是一个数字 的  数字
            意义          类型
        Not a Number
     何时遇到:当无法转为数字是,或无法正常计算时
                undefine和任何数计算,结果为NaN
     特点:    和任何数据做计算,结果永远为NaN
               加法技术中,碰上字符串,也会转为NaN
     typeof(x):返回x的数据类型名称:Number string boolean 
                                       undefined
2、强制转换:程序员主动调用专门函数完成的转换
     1、任意 to String:2种
     var str = x.toString();
     var str = String(x)---->相当于隐式转换
     ***String(x)万能

     x.toString:   null和undefined转不了
     何时使用:通常都在js需要时,自动调用
     
     2、***任意 to Number 3种
       1、任意 to Number ;var n = Number(x)--> 隐式
            何时使用:将非字符串类型转为数字时使用
                  将纯数字组成的字符串转为数字类型
    
       2、String to Number:
          1  to 整数 var n=parseInt(string)
      何时使用:将*字符串*转为整数时使用
      如果传入的不是字符串,则先隐式转为String
      原理: 从头开始读取字符串中的每个字符
             跳过开头的空字符
         只读取数字字符
         只要碰到第一个不是数字的字符,就退出
         不认识小数点

          Number vs  parseInt
      Number 只认识纯数字组成的字符串
        Number却可转boolean类型
      parseInt(str)认识包含非数字字符的字符串开头位置的数字
            parseInt转不了boolean       

           2、String to 浮点数:var n=parseFloat(str);
        何时使用:只要将字符串转为小数时
        用法和parseInt用法完全一样
        只认第一个碰到的小数点。

  3、任意类型 to Boolean :var bool = Boolean(x);
       "" 0 NaN  undefined  null --->false
       其余都是true;
      
    3、条件运算符(三目运算符)
        目:操作数
            单目运算符:只有一个操作数,++,--,!
            双目运算符:有两个操作数,+,-,*,...
            三目运算符:要求有三个操作数

        条件运算符:
            ? :
            表达式1 ? 表达式2 : 表达式3;
            表达式1 :是一个条件,结果为boolean类型
            如果表达式1的值为true,则执行表达式2
            如果表达式1的值为false,则执行表达式3

        输入一个考试成绩,如果成绩大于60分,输出及格,否则输出 不及格

        练习:输入一个年龄,如果年龄大于等于 18岁,打印输出 "你已成年",
               否则,打印输出,"还未成年"

        条件运算符的嵌套:
            表达式2, 表达式3的位置处分别可以再嵌套一个条件表达式
            ex : 根据成绩 输出成绩 等级
                成绩100 输出 A
                90 ~ 100 输出 B
                80 ~ 90 输出 C
                60 ~ 80 输出 D
                60以下 输出 E


课堂练习:获取用户输入,保存在变量input中
    var input = [window.]prompt("输入提示");
    ****凡是从页面上进来的,都是字符串***


算数运算符:+ - * / % ++ -- 都带隐式转换
      返回值:只能是number,如果运算无效,返回NaN
      隐式转换:默认转Number
                +法中,碰到字符串,都转字符串,再拼接;
     %膜运算(取余数):m%n:m/n取除不尽的余数部分
     何时使用:1、判定能否整除:
               比如:判定奇偶数:
           m%2等于0,说明m是偶数
           m%2不等于0,说明m是奇数
          2、限制计算结果,永远小于除数


   ***递增、递减运算:++ --
      n++: n=n+1;讲n中的值加1,后在保存回n中
      2种情况:
         ++n:前++ ,返回*新*值
     n++:后++ ,返回*旧*值

     ++n或n++单独使用,无影响
     如果参与其他表达式中,会影响执行结果。

关系运算:
      做比较,比大小
      返回值:true、false
      隐式转换:默认都转为数字再比较
                如果两个都是字符串,则按位pk每个字符的unicode

      特殊情况:
             1、如果无法转为数字,转为NaN
         NaN不等于,不大于,不小于任何值,甚至自己
         NaN !=x --->true
         isNaN(num):专门判定一个num数值是否为NaN
               如果是NaN,就返回true,否则返回false
              何时使用:只要判断一个数字无效,就用isNaN
          开发中何时使用,反着用
              用isNAN判断一个num是不是数字,或是否能被
          隐式转为数字使用
         !isNaN(num):返回ture--->num是数字
                       返回false---->num不是数字

            2、如果两个都是字符串,则按位pk每个字符的unicode号

                undefine vs null
        undefine:所有变量的默认初始值,自动赋值
        null:主动清空一个变量,释放一个变量
        typeof的监测结果:
        typeof(undefined)--->undefined
        typeof(null)--->object
         ===:全等,首先类型必须相同,其次值相同
             全等不带隐式转换
        何时使用:要求类型相同,且值相等时。
     
          3、如果参入比较的两个值都是字符串类型
           不再转数字,而是pk每个字符的unicode号
       总结:凡是条件:一般都是关系运算或是逻辑运算

***逻辑运算:多个条件(关系运算),综合得出最后的结论
              只可能返回true/false
    隐式转换:默认转换为boolean类型:boolean(x)
    何时使用:只要综合多个条件,得出最终结论
    如何使用:3种
         &&:读作且,程序总称为“逻辑与”
          条件1&&条件2:必须条件1和条件2都为true,
          结果为true,只要任意一个为false,结果为false

     ||:读作与,程序总称为“逻辑或”


     !:读作与,程序总称为“非”
        !条件:颠倒条件的true/false结果


***短路逻辑:逻辑运算中,如果前一个条件已经可以得出结论
    则后续所有条件不再执行!
    利用短路逻辑筛选按条件执行语句
    条件&&操作:如果满足条件,才执行操作
            否则,什么也不做

***函数:封装一项任务的步骤清单的代码段,再起一个任务名
    函数是一个引用类型的对象
    对象:内存中同时存储多个值的空间
    何时使用:发现一项任务,被反复调用,要先将任务步骤封装
    为一个函数,再反复调用
    如果声明函数:
          function 函数名([参数变量列表]){
            步骤清单代码段
            [return返回值]
        
          }    

    如何调用函数:函数名([参数变量列表]);
    强调:1、函数只有被调用时,才会执行!
          2、函数可被反复调用!----代码重用
    
    参数变量:专门接受方法执行所必须的数据的变量
    何时使用:如果一个函数,必须提供指定数据,才能正常执行时,
            需要提供几个数据,就定义几个参数接收
    如何定义参数:不需要var,直接在函数名后的括号中定义参数名
             每个参数名直接用逗号分隔
    何时,如何转入参数值:调用时,按照参数定义的个数和顺序传入
    为什么使用参数:参数可以让方法变的更灵活。

***内存中函数生命周期:
    1、定义时:将函数封装在一个对象中保存---函数对象
          函数名,其实是指向函数对象的一个变量
          ***定义时,不会读取函数的内容
    2、调用时:在执行环境中增加一个档期函数的执行环境对象
         才会逐行读取病执行函数的内容
    3、调用后:函数的执行环境弹出,活动对象被释放

***作用域:一个变量的可用范围
    本质其实是一个存储多个变量的对象
    2、1.全局作用域:专门保存全局变量的对象
    全局变量:在任何时候,任何位置都可被访问
       2.函数作用域:专门保存函数内部的局部变量的对象
             ------活动对象
        局部变量:2类:1、参数变量  2.在函数内声明的
                 值在函数调用是的函数内部才可以使用

    return返回值:函数调用的执行结果
    何时使用:只要函数的执行,需要有明确的返回结果时
        要看调用者是否需要获得执行结果
    如何定义返回值:在函数定义结尾:return返回值
    何时如何获得返回值:调用时:
        var 变量=函数名(XXX);

***按值传递:两变量间赋值或想函数中传递参数时
        都是将原变量中的值复制一个副本给对方
        修改一方,另一方不受影响

        function buy(card){
            card-=3;
            console.log("余额"+card);        
        }
        var card=10;
        buy(card);//输出7
        console.log("余额"+card);//输出10


***声明提前:在正式执行程序前,都会先预读所有var声明的变量
    和function声明的函数,集中到当前作用域的顶部集中声明
    ***赋值留在原地***
       
    function fun(){
        return 1;
    }

    console.log(fun());//输出2
    
    function fun(){
        return 2;
    }

    console.log(fun());//输出2

    var fun=100;

    console.log(fun());//报错

定义函数的第二种方法:
    var 函数名=functon(参数){函数体;return 返回值};

    vs 声明函数
       第二种方法,函数定义不会被提前,仅函数名提前
       声明函数,整体(函数名+函数定义)提前

         问题1:如果一个表达式或函数有结果,就可至今当一个值用
     问题2:如果传入参数个数不符,不会报错:
            个数超了,多出的没用
        个数不够,未接到值的参数变量,默认值undefine
    问题3:在函数内,为没用声明过的变量赋值,
               变量会被自动创建在全局--->危险
           强烈建议:所有变量使用前,必须用var声明。
           function max(a,b,c){
        var max=a;
        b>max && max=b;//利用短路逻辑
        c>max && max = c;
        return
       }
      console.log(max(5,4,6));

全局函数
  手册中:课程表--JavaScript--javascript对象---js functions
     干扰项:BOM,凡是在BOM阶段交的都不是全局函数。


   编码解码:
    encodeURL:对包含多字节字符的url字符串编码为单字节字符组成
    decodeURL:键encodeURL编码后的字符串,解码为原文
    为什么:url不允许包含多字节字符:比如汉字
             www.baidu.com/s?kw=张东
                           %E5%BC%AO%E4%B8%9C

    问题:url还不允许包含保留的特殊符号。比如:/
    解决:encodeURLComponent/decodeURLComponent
    
   eval:专门执行字符串格式的js语句
       还可计算字符串格式的表达式的值

   除数为0:js中除数可以为0,结果为:infinity
     Infinity,可参与关系运算
     isFinite(num):专门判断一个数组是否在有限范围内

*分支结构:
    程序3中结构:顺序  分支 循环
    顺序:除去声明提前,其余代码默认都从上向下顺序执行
    分支:根据不同的条件,执行不同的代码
    循环:让程序反正执行一段相同代码

*分支:3种
   1、一个条件,一件事。满足条件就做(,不满足就不做)
     如果操作简单:利用短路:条件&&(操作1,操作1,...)
     如果操作复杂:
   2、一个条件,两件事,满足条件做第一季,不满足做另一件
     如果操作简单:三目:条件?操作1:操作2;

   3、多个条件,多件市,多选一执行,可一件不执行
      如果操作简单:三目:条件1?操作1:
                          条件2?操作2:
              .....? ....:
              默认操作;//不能省略

第一个汉字的uncode编码为 "\u4e00"
最后一个汉字的UNcode编码为"\u9fa5"

***for**循环
   
   语法:
       for(var 循环变量=初始值;循环条件;迭代编号循环变量){
          循环体;
       }

   特殊写法:
        1、for中第一部分,可同时声明并初始化多个变量
    2、for中的第三部分,可同时执行多个小操作
    3、for循环条件可省略,省略后是死循环
         比如:for(;;)代替while(true)

***数组:多个变量的集合,起一个统一的名字---用法
        连续保存多个数据的引用类型的对象---存储
    为什么使用数组:
         程序=数据结构+算法
              好的数据结构可以极大提高程序的执行效率!
   何时使用:程序中都是用数组集中管理多个数据
如果使用:创建  赋值   取值
   1、创建:4种
      1、创建空数组:var 数组名=[];---js中见到[],就是数组
      2、创建数组同事,初始化数组中的每个元素:
       var 数组名=[值1,值2,值3,...]
       内存中的数组:引用类型的对象
             每个值相当于一个元素
             每个元素都有个下标
             下标从0开始,每次增1,到个数-1结束
        数组对象的个数:arr.length
                arr.length用于等于最大一个下标+1;

      3、创建空数组:var 数组名=new Array([n]);
              new创建一个新对象
              Array数字类型
              n标识初始元素的格式,省略则创建空数组

      4、创建数组同时初始化数组元素:
            var 数组名=new Array(值1,值2,值3,...);
            new Array的歧义:new Array(7);
         
        如何使用数组中每个元素:数组名[i]
           数组名[i]的用法和普通的变量完全相同!
    
      赋值:数组名[i]=值
      取值:任何位置使用数组名[i],等效于直接使用数组名[i]中的值

   数组是引用类型对象:按值传递
       原始类型的值,赋值后,相互不影响
       引用类型的对象,赋值后,依然引用同一个对象
                     任何修改,都会影响对方
          
       null:主动释放一个对象
         垃圾回收器:专门释放内存中不再被引用的对象的小程序
                 伴随主程序执行
    什么是: js引擎会自动释放不再被任何变量引用的存储空间

         每个对象都有一个引用计数器,增加引用+1,减少引用-1
     一个对象,应用计数器为0,不在被任何变量引用,被回收
      建议:使用完较大的对象后,都要主动释放

      数组的length熟悉固定套路:2个
        1、获得最后一个元素值:arr[arr.length-1]
    2、想数组未尾追加一个新元素:arr[arr.length]=新值;

    遍历数组:依次对数组中每个元素执行相同操作
     //三要素
      1、条件:小标i<数组长度
      2、变量:下标i从0开始,每次++
          for(var i=0;i<arr.length;i++){
          当前元素:arr[i]
      }
     chrome中的console.log有时是异步执行,伴随住程序同时执行

关联数组: 
什么是关联数组: 可自定义下标名称的数组
  vs索引数组: 下标都是数字的数组
为什么: 索引数组中的下标都是无意义的数字,不便于查找
何时: 只要希望在数组中按照意义快速定位一个元素时
如何: 
  创建: 2步:
    1. 创建空数组: var ym=[];
    2. 向空数组中添加新元素,使用自定义的下标名称
      ym["name"]="杨幂";
      ym["math"]=81;
      ym["chs"]=53;
      ym["eng"]=89;
  访问: ym["下标名"]——用法同普通变量
  强调:key必须是字符串
  特点: ***length属性失效,永远为0***
 
  如果遍历hash数组: 
     for( var key in ym){
    //in依次取出ym数组中的下标名保存到key中
    //key仅获得下标名
    //ym[key]获得当前元素的值。
    //强调: key不加"",因为key是变量,不断变化
  
      }

      关联数组中的key不能重复
      所以数组如果访问不存在的下标位置,不会保存
      会返回undefined9

  原理: 
   索引数组的问题: 查找只能靠遍历
   结果: 查找速度受存储位置和元素总数的影响极大
   
   关联数组解决: 
      hash算法: 
         根据一个字符串,计算出一个尽量不重复的序号
      添加元素: 
       将自定义的下标名交给hash算法计算出不重复的序号,
         将元素保存到序号位置
      取值时: 
      将自定义的下标名较为hash算法,计算出和存入时相同
         的序号,直接去序号位置获取元素值
      优点: 
     无需遍历, 查找速度和存储位置以及元素总数无关
  
    今后:只要遍历索引数组,选普通for循环
     只要遍历关联数组,值能用for in 循环
     
  indexOf 接收一个数组和一个值,
     返回值在数组中的下标位置i
     只找第一个,然后就退出
     如果没找到,就返回-1

2、数组API:浏览器场所已经实现的方法
    开发人员直接调用,不需要了解具体实现。

    将数组转为字符串:2个
      var str =arr.toString();返回数组中元素的内容,用逗号分隔
      var str = arr.join("连接符");***可自定义连接符***
    固定套路:
    1、无缝拼接数组每个元素:var str = arr.join("")
         如果不加"",等效于toString,用逗号
            var chars=["h","e","l","l","o"];
            var word = chars.join("");
            console.log(word);//hello

     2、将单词拼接为句子:var str = arr.join(" ")
         var words =["no","zuo","no","die","!"];
        var stmt =  words.join(" ");
        console.log(stmt);//no zuo no die !

     3、将数组拼接为html元素
        var provs = ["北京市","天津市","河北省","河南省"];
        var  html = "<select><option>" +
               provs.join("</option><option>")
            +"</option></select>";
        document.write(html);//输入在页面上为下拉列表

      优化:数组的拼接比字符串拼接效率更高
      建议:今后凡是频繁的字符串拼接,都要2步:
         1、先将要拼接的子字符串放入一个数组中用
         2、利用数组的join方法,一次性生成结果字符串
         
 拼接数组:var newArr = arr1.concat(arr2,值1,值2)
 强调:concat不能修改原数组,总是返回一个新数组

 获取子数组:var subArr = arr.slice(stati,endi+1)

 starti:开始获取下标位置
 endi:表示获取到的下标位置
     ***含头不含尾**
 slice方法支持倒数参数:其实负数下标不存在
            假定的负数下标从-1开始
splice:删除  插入  替换
    1、删除:arr.splice(starti,n)
    从starti位置开始,删除n个元素

    2、插入:arr。splice(starti,0,新值1,新值2,....)
     在starti位置插入新值1,新值2...
     原starti位置及其之后的元素,被向后顺移
    3、替换:arr.splice(starti,n,新值1,新值2,...)
     新元素的个数和n不一定相等
     数组会自动调整元素的位置和长度
       
       颠倒数组中所以元素的位置:arr.reverse();

数组的sort方法:arr.sort();
   特点:默认按升序排列
     默认一切都转为字符串,再按字符串比大小

 自定义排序规则:2步
      1、定义比较器函数:专门比较任意两数大小的函数
      规定:两个参数(a,b)
        必须返回数组:如果a>b,就要返回正数
                  如果a<b,就要返回负数
                  如果a=b,就要返回0
       2、将比较器函数做完参数传入sort方法中
       arr.sort(比较器函数名);//函数名不加圆括号 
 函数 vs 方法:
     都是function
     不属于任何对象的叫函数(不需要通过.访问)
     属于特定对象的函数叫方法(需要通过对象.才可访问)

  ***函数也是引用类型的对象
  ***给升序改降序,只要给比较器的逻辑*-1; 
 
数组API
 *栈和队列:其实都是数字,只不过使用了不同的方法
  栈:一端封闭,只能从另一端进出的*数组*
  何时使用栈:只能从数组一端进出
  LIFO
  结尾出入栈:
      入栈:arr.push(新值);==》arr[arr.length]=新值
      出栈:var last = arr.pop();
  开头出入栈:
       入栈:arr.unshift(新值);
       出栈:var first =  arr.shift();
       每次出入栈都会影响所有剩余元素的位置发生顺移---低

   队列:只能从一端进入,必须从另一端出
   何时使用:只要先到的先得


   2****二维数组:数组的元素又引用了另一个子数组
         何时使用:保存横行竖列的二维数据
     保存上下级关系的数据
     如何创建:2步
       1、创建一个空数组:var data =[]
       2、设置数组中每个元素再引用另一个小数组
                   data[0] = [0,0,0,0];
              访问二维数组中任意位置的元素:data[r][c]
              二维数组行下标r不能越界,越界就报错

         遍历二维数组:固定套路
     外层循环遍历行,内层循环遍历当前行的中的列
     for(var r =0;r<data.length;r++){
        for(var c=0;c<data[r].length;c++){
            当前元素:data[r][c]
            }
    }

***字符串对象:对个字符组成的只能*数组*
     和数组相同的API
        访问字符串中任意一个字符:str[i]
    字符串的长度:str.length
      凡是不直接修改原数组的API,字符串都能用
         比如:var substr = str.slice(starti,endi+1)
               var newstr = str.concat(otherstr);
         不能用:reverse() push() str[i]=‘字符’
笔试题:
内置对象:11个
     ES标准已经规定好,有浏览器厂商已经实现的对象
     开发人员直接使用,不必关系具体实现
     String  Number  Boolean  ----包装类型
     Array   Date RegExp  Math
     Error
     Function Object
     Global----->window
   ***包装类型: 专门封装原始类型的数据,
              并提供对原始类型数据操作方法的对象
    
   何时使用: 试图用原始类型的值调用方法时自动创建
              用完自动释放
              具体创建何种包装类型,要看值的类型

   为什么有包装类型:原始类型的值没有任何方法


new String(xxx) vs  String(xxx)
String(xxx):隐式类型转换为字符串,返回原始类型的字符串值
new String(xxx):创建一个String包装类型的对象
                返回String包装类型的对象


转义字符:如果字符串内包含与预防冲突的特殊符号
          可用转义字符将特殊符号标记为普通字符
     比如:"-->\"   '-->\'  

String API:所有API都无法修改原字符串,必定返回新字符串
1、大小写转换
      var newStr = str.toLowerCase();//全部转小写
      var newStr = str.toUpperCase();//全部转大写
      何时使用:只要不区分大小写
2、获取指定位置的字符或unicode
       var char =str[i]
                  str.charAt(i);
       var unicode = str.charCodeAt(i);


3、查找关键字的位置:2个API,返回的都是关键字的位置下标
        找下一个匹配的关键字位置:var i = str.indexOf("kword",starti)
                       如果省略starti,从0开始
    找前一个匹配的关键字位置:
       var i = str.lastIndexOf("kword",starti)
       如果省略starti,从最后一位开始
    strarti:开始查找的位置
    如果没找到,都返回-1;

   获取指定位置的字符: 
     str.charAt(i) => str[i]
   获取指定位置的字符的unicode号
      str.charCodeAt(i) 获得str中i位置的字符的unicode号
   将unicode号反向转为正文:
        String.fromCharCode(unicode);
获取子字符串: 
     str.substring(starti,endi+1) =>str.slice(starti,endi+1)
         强调: substring不支持负数参数!
         解决: length-n 表示倒数第n个
     str.substr(starti,n) 获取str中starti开始的n个字符
        相当于: str.substring(starti,starti+n)
        强调: 不考虑含头不含尾



****正则表达式:
   什么是: 规定一个字符串中字符出现规律的表达式
     何时: 2种: 
        1. 按照规则模糊匹配多种关键词
        2. 按照规则验证字符串格式时
如何: 
 1. 关键词的原文就是最简单的正则表达式
 2. 字符集:
    什么是: 规定一位字符可选字符列表的集合
    何时: 如果一位字符,有多种备选字时
    如何: [备选字符列表]
    强调: 一个字符集只能匹配1位
    简写: 如果备选字符列表中字符是连续的,可用-省略中间的字符
    比如:1位数字: [0-9]
         1位小写字母: [a-z]
         1位大写字母: [A-Z]
         1位字母:[A-Za-z]
         1 位汉字: [\u4e00-\u9fa5]
    特殊: 除了XXX  [^字符列表]

 3. 预定义字符集: 
  什么是: 对常用字符集的简化写法

  包括: 一位数字: \d    [0-9]
        一位字母,数字或下划线: \w  [0-9A-Za-z_]
        一位空字符: \s  空格,制表符等空字符
          通配符:  .  任意字符

  强调: 只有在规则完全匹配时才能使用预定义字符集
  问题: 无法匹配字符出现的个数
  解决: 量词

 4. 量词:
  什么是: 规定一位字符集出现次数的规则
  何时: 只要规定一位字符集出现的次数
  如何: 
   强调: 总是跟在字符集之后
   1. 有明确范围的: 
     6~8位    {6,8}
     6位以上   {6,}
     必须6位   {6}
   2. 没有明确范围:
     ?    可有可无,最多一个
     *    可有可无,多了不限
     +   最少一个,多了不限
 5. 选择和分组: 
      选择:或|
      分组:()
     
 6. 指定匹配位置: 
      ^ 匹配字符串开头
      $ 匹配字符串结尾
       比如: 仅匹配开头的空字符: ^\s+
         仅匹配结尾的空字符: \s+$
         同时匹配开头或结尾的空字符: ^\s+|\s+$
      \b 匹配单词边界: 开头 结尾 标点 空字符

 7.转义:\
    
 8.预判:在正式匹配前,先大概预判整个字符串的规则
          多用于排除法
      比如:密码强度:6-8位字母、数字或下划线字符
             必须包含一个大写和一个数字

        
           所有字符:4大类:数字,小写字母,大写字母,特殊符号
          1、排除:不全由数字和小写字母组成
           (?![0-9a-z]+$)
      2、排除:不全由大写字母和小写字母组成
           (?![a-zA-Z]+$)
      3、只能有字母或数字、_组成----
            \w{6,8}

           最终: (?![0-9a-z]+$)(?![a-zA-Z]+$)\w{6,8}
         



使用正则判断是否包含符合规则的关键词:
     var i=str.search(/正则/i)
     在str中查找符合正则要求的关键词,返回其位置
     如果找不到,返回-1
    问题1: 所有正则,默认都区分大小写
     解决: 加后缀i  表示忽略大小写

    问题: 1. 只能获得位置,无法获得内容
          2. 只能找第一个。
    解决: match方法

 3. 查找所有关键词的内容
     var kwords=str.match(/正则/ig)
     查找str中所有符合正则要求的关键词,保存在结果数组kwords中
      ***如果找不到,返回null! 
     强调: 只要API的返回可能是null,就必须先验证不是null,再使用!
     问题: 所有正则,默认仅匹配第一个关键词
     解决: 加后缀g  表示查找全部
     问题: 只能返回所有关键词的内容,无法返回每个关键词的位置。
 
 4. 即查找每个关键词的内容,又查找每个关键词的位置 ?

   替换: 将字符串中找到的敏感词替换为新内容
   简单: 将所有敏感词替换为一个统一的新值
          str=str.replace(/正则/ig,"新值");
        高级: 根据不同的敏感词,动态选择要替换的新值
           str=str.replace(/正则/ig,function(kword){
                 return 根据kword动态选择不同的替换值返回
            })
       其中: replace会在每个找到的关键词上执行function
       每次执行,都会将本次找到的敏感词自动赋值给kword参数变量。


 替换或删除子字符串:
       var nweStr = str.replace(reg,"替换字符");
       格式化字符串:
             正则表达式中的每个(),都是一个字表达式
         每个字表达式都会自动获得一个从1开始的编号
        替换时,可用$n,指代本次匹配中第n个子表达式的对应内容
           
  
分隔字符串:
   var subs=str.split(reg,[count]);
       reg:正则表达式
      [count]可有可无,从0开始,代表切割的第几个
      例如:var mail=zhangdong@dane.com;
             var arr = mail.split(/@/);
         console.log(arr[0])输出zhangdong
   

String API:
   获取子字符串:3种
       var sub = str.slice(starti,endi+1)
                 str.substring(starti,endi+1)//不支持负数参数
         str.substr(starti,n);//获取多少个

查找:4种
   1、查找固定关键字,仅返回位置,可指定开始位置
           var i =str.indexOf("kword"[,starti]);
              str.lastIndexOf("kword"[,starti]);
           何时使用:关键字确定
                 通过循环,反复获得每个关键字的位置


  2、只判断有没有:var i=str.search(reg);
      返回值:找到返回i,没找到返回-1;

  3、获取所以关键字的内容:var kwords=str.match(reg);
          g
      返回值:找到返回所以关键字内容的数组
               没找到返回null,必须先判断不是null,再使用

   4、即获得每个关键字的内容,又获得每个关键字的位置:
       var arr = reg.exec(str);
       特点:1、每次只返回一个关键字的内容,存在arr的[0]
                  如果找不到了,返回null
             2、将本次找到的关键字的位置保存在arr.index
         3、自动调整reg.lastIndex属性为下次开始的位置

  课堂练习:网络爬虫
      正则:<a[^>]*href=['"][^'"]*['"][^>]*>.*</a>
      默认贪婪模式:尽量匹配最差的符合条件的子内容
      懒惰模式:只匹配最短的符合条件的子内容
             贪婪改懒惰:.*---->  (.*?)

      RegExp.$n:获得本次匹配中第n个子表达式匹配的内容

      替换:str=str.replace(reg."替换值");
            如果reg中没有g,只替换第一个匹配的

验证:
     var bool = reg.test(str);
     如果str符合reg的要求,返回true,说明验证通过
                       否则返回false,说明验证未通过
    ***强调
         凡是验证,前加^后加$;
     如果不加,只要局部匹配,就通过



Math:封装了数学计算的常量值和方法
     ***不能实例化对象
        实例化:用new创建一个指定类型的具体对象---实例 
                                            instance
    Math常用API
     取整:3种
            上取整       下取整         四舍五入取整
     Math.cei(n)    Math.floor(n)  Math.round(n)

   n.toFixed(d) VS Math.round(n)
     n.toFixed(d):指定d位小数四舍五入,*返回字符串*
     Math.round(n):不能指定小数位数,只能取整
                      *返回number*
  


    乘法和开平方
      乘法:Math.pow(底数,幂)
      开平方:Math.sqrt(n);

 最大值和最小值
         var max = Math.max(值1,值2,...);
               //默认不支持数组;
   固定套路:获取数组中的最大值和最小值:
         var max =Math.max.apply(Math,[值1,值2,...])

随机数:Math.random()  0<=r<1;
      公式:min -max取随机整数
      Math.floor(Math.random()*(max-min+1)+min)
  

  
Date:封装了1970年1月1日0点至今的毫秒数
创建:4种
  1、创建日期对象,同时获得客户端*当前时间*
         var now = new Date();

  2、自定义任意时间点
         var date = new Date("xxxx/xx/xx[xx:xx:xx]");

  3、自定义任意时间点
          var date = new Date(xxxx,xx,xx[,xx,xx,xx]");
                                月,都要-1修正。

  4、复制一个日期对象:
        何时使用:日期API都至今修改原日期对象
         如果希望留住旧日期对象,就需要先复制,再修改副本

        如果复制:var old= new Date("XXX");
              var target=new Date(old.getTime());
             其中:old.getTime()返回旧时间中的毫秒数

       Date对象API:
              分量:  年         月      日       星期
               FullYear    Month     Date      Day

                  时         分      秒        毫秒
            Hours     Minutes   Seconds    Milliseconds
            
          1、每个分量都有一对儿get/set方法
             getXXX获得分量的值
         setXXX(n)设置分量的值,Day没有set
      2、命名:年月日星期,没有s结尾
               时分秒毫秒,都有s结尾

          3、返回值:除Date外,其余都是从0开始,进制-1结束
            强调:只有month需要修正,其余都正常
              
          4、日期转字符串:
            var str= date.toLocaleString();//日期+时间
        var str = date.toLocaleDateString()//日期
        var str = date.toLocaleTimeString()//时间
     Date的计算:2种
      1、两日期对象可相减,结果是毫秒差
      2、对日期任意分量做加减:3步,取分量,做加减,set回去
              set方法自动调整进制
          固定套路:date.setXXX(date.getXXX()+/-n);
     



错误处理:即使程序出错,也要保证程序不退出的机制
Error对象:在错误发生时,自动创建的封装错误信息的对象
属性:err.name:错误类型:6种
    SyntaxError:语法错误
    ReferenceError:引用错误,找不到对象或变量时;
    TypeError:类型错误,错误的使用了对象的"方法"
    RangeError:范围错误,参数超范围
    EvalError:Eval错误,错误的使用了eval函数
    URlError:URL错误

如何错误处理:
    语法:try{
             可能出错的语句;
      }cathc(err){
          一旦出错,执行的错误处理代码;
       
      }[finally{
         无论是否出错,都要执行的代码
      }]

 建议:能用if屏蔽的问题,优先选择if
        大多说try catch都可提前预防

笔试题:js中如何解决浏览器兼容性问题:3种
       1、不兼容的类型或方法:2种
           if else
       try   catch

       2、不兼容的值,短路逻辑中的||
           值1||值2


***错误处理中的return
 1、finally中的return,会替换try catch中的return
 2、即使finally中没有return,finally中的代码一定会再return钱
 执行,但无法影响已确定的return结果




*****函数对象
    执行环境栈:ESC,保存全局已经每个函数的执行环境的栈结构
    执行环境:EC,调用函数是,创建的引用函数资源的对象
       窗口一打开,默认ESC中压入一个全局EC
                         全局EC引用了window对象VO
               window对象中的变量都是全局变量

    变量对象VO,专门存储变量的对象
    函数声明周期
        定义时:仅创建一个函数对象,封装了函数的定义
             不会读取函数的内容

    调用时:创建函数的EC对象压入ESC中
              函数的EC对象引用了,当前函数的活动对象的AO
            活动对象:AO:专门保存本次函数调用是的局部变量
                  AO中有一个属性始终指向window对象
            变量使用规则:优先在AO中找
                      找不到,才去window对象找

    调用后:函数的EC对象出栈,AO对象失去引用,被回收
                      AO对象中的局部变量一起被释放


***重载:overload
      相同名称,不同参数列表的多个函数
      在调用是,可根据传入参数的不同,动态选择对应的函数执行
  
  js语法默认不支持重载,但可用arguments对象模拟重载的效果
  arguments对象:调用时,自动创建并接收所有传入的参数值
                  类(like)数组(的)对象
          2点:1、arguments[i];
               2、arguments.length;

   何时使用:今后只要多个操作,共用同一个函数名时,

   ***类数组对象  VS  数组对象:
       类型不同:类数组对象的父类型是Object
                 数组对象的父类型是Array
             导致类数组对象无法使用数组类型的方法

     类数组对象转为数组对象 固定套路:
         var arr = Array.prototype.slice.apply(arguments);
                                     call
     总结:今后大部分方法依然要定义参数
            只有不确定传入参数的个数时,才省略参数,用arguments


****匿名函数:定义时,不用任何变量引用的函数,
     何时使用:2种情况:
     1、如果一个函数只执行一次----匿名函数自调
     2、如果一个函数作为对象教给其他函数使用时---回调
         
     创建一个比较器函数:3种
        1、声明方式定义函数:funciton compare(a,b){return a-b}
            只有声明方式定义的函数才能被声明提前

                 ***以下两种方式定义的函数,不能被提前

        2、函数直接量方式定义
              var compare = funciton(a,b){return a -b}
        3、使用new关键字:
           var compare = new Function("a","b","return a -b")
                                      //括号中的引号必须要加
  
  
        匿名函数的优点:节约内存空间
            调用前和调用后,内存中不创建任何函数对象
         总结:arr.sort(function(a,b)(return a-b));


****作用域与作用链
 作用域:一个变量的可用范围,其实就是变量的实际存储位置
         只可能是window中或AO中
     window:全局作用域--全局变量
     AO:函数作用域---局部变量
     本质:EC对象的一个scope属性
         引用了window或AO对象
     
  作用域链:以当前EC的scope属性为气垫一次引用每个AO,直到
            window结束,形成的多级引用关系

       只要在作用域链上存在的变量,当前函数都可使用


*****闭包:
      问题:全局变量 VS 局部变量
         全局变量:优:反复使用,且共享使用
               缺:可能随时在任意位置被篡改---全局污染
                   建议:尽量避免使用全局变量
          局部变量:不可反复使用!方法调用完自动释放
      解决:闭包:反复使用一个局部变量,且不会被污染

      何时使用:想反复使用一个局部变量,且不希望被污染时,
                就要用闭包结构包含局部变量
 
      如何使用:1、定义外层函数(工厂函数)
              特点:2个
            1、定义了受保存都局部变量
            2、返回一个专门操作局部变量的内部函数对象
                2、调用外层函数(工厂函数),获得返回的内部函数对象
        3、使用获得的内部函数对象,操作受保护的局部变量---唯一途径
      缺点:比普通函数占用更多的内存空间(外层函数的AO)   

      判断闭包输出结果:
         1、找受保护的局部变量
         2、外层函数被调用几次,就创建了几个受保护的变量副本
     3、同一次外层函数调用返回的内层函数,永远使用统一个变量


*****面向对象:
  对象:程序中描述现实中一个具体属性的方法的结构
        内存中保存多个属性和方法的一块存储空间

  面向对象:OOP程序中,描述一个具体事务都要用对象来封装事物
            的属性和功能

   写任何程序,都要先找对象
   再识别对象的属性和功能
    
  封装:将描述一个事务的属性和方法集中定义在一个对象中

 2、创建对象:3种
     1、仅创建一个对象:2种
         1、var obj={"属性名":值,"属性名":值,....};
        对象 vs 关联数组
        ***js中一切对象底层都是关联数组;
           每个属性可用["属性名"]访问
           遍历一个对象中所有属性,也用for in
           也可以在任何时候动态添加新属性
           强行访问没有的属性返回undefined
          方法其实就是属性引用了一个函数对象而已
       
      2、 var obj=new Object();//创建一个空对象
              约等于{};
          obj.属性名=值  <==> obj["属性名"]=值;
           ......
******this关键字:存在EC中,保存正在调用当前方法的对象
                 默认this--->window

       对象中的方法,要使用对象内部的属性是,必须用this引用
            不用this:默认在作用域链(AO和window)中找
        加this:在this应用的当前对象中找
        *****this和定义在哪儿无关
              只和调用时使用的对象有关
        没有用任何对象,就直接调用的函数,this默认值window
   
      
      2、反复创建多个相同结构的对象时,2步
         
      1、创建构造函数:规定一类对象,统一属性的函数
          function 类型名(属性参数列表){
           this.属性名=参数值;
           this.属性名=参数值;
           ... ...
           this.方法名=function(){

           }...
        }


       2、用new调用构造函数,装饰一个新创建的对象
         var obj=new 类型名(属性值,...);
         new:1、先创建空对象,相当于{};
              2、用空对象调用构造函数,this-->正在创建的空对象
              按照构造函数的定义,为空对象添加属性和方法
              3、将新创建对象的_proto_属性指向构造函数的
              Prototype对象
              4、将空对象的地址,保存到等号左边的变量中

***原型和原型链
    原型:prototype 保存所有子对象共有属性值的父对象
          每个(构造)函数都自带一个prototype对象
      所有被构造函数创建的字对象都有一个_proto_属性
      指向构造函数的prototype对象

   什么东西放在构造函数的prototype中?
       所有子对象共用的属性值和方法---只在读取时共享
   
   特殊情况:修改prototype中共有属性,必须只能用prototype对象
              不能用子对象
             如果用子对象修改共有属性,会在子对象创建创建共有属性副本



   原型链:由各级子对象的_proto_属性连续引用形成的结构
           所有对象都有_proto_
           所有对象原型链的顶部都是Object.prototype
       .运算符:访问一个对象的属性,只要在原型链上有的,
                都可以访问

   重写:如果字对象觉得父对象的方法不好用,可在子对象定义同名
         方法,就会覆盖父对象中的同名方法


   原型相关API
      1、判断对象的属性是自有,还是共有
         自有属性:在当前对象本地保存的属性
     共有属性:从原型链中继承来的属性

      如何判断自有:obj.hasOwnProperty("属性名")
           如果返回false,不一定说明共有,也可能没有!

      如何判断在原型链上有没有:2种
           1、"属性名" in 对象
           2、if(obj["属性名"])如果有效
          可能被干扰:如果属性值刚好为0,NaN,null,""

      如何判断共有:固定套路
       if(obj.hasOwnProperty("属性名")){
            console.log("是自有属性")
 
       }else if("属性名" in obj){
        console.log("是共有属性")
    
       }else{
        console.log("没有属性")
       }


2、获得任意子对象的原型(父对象):
    obj._proto_
    var prototype=Object.getPrototypeOf(子对象);
    何时使用:无法获得构造函数时,又希望设置子对象的公有
    属性

3、判断父对象是否在子对象的原型链上
    上级对象.isPrototypeOf(子对象)
    强调:isPrototypeOf不仅找直接父级,而是找整个原型链

*****/*笔试题*/
    如果判断一个对象是数组类型:typeof失效
       1、if(Array.prototype.isPrototypeOf(obj)){
        obj是数组类型
       }
       
       2、其实构造函数的prototype指向原型对象
             同时,原型对象有constructor指向构造函数对象
          if(obj.constructor==Array){
         obj是数组类型
      }
       3、判断子对象是否是指定构造函数的实例instanceof
           if(子对象 instanceof 构造函数名){}
         instanceof也是查找挣够原型链

       4、if(Object.getPrototypeOf(obj)==Array.prototype){}
      
       5、call和apply
             call和apply:在调用方法时,修改EC中的this
      
              Object.prototype.toString.call(arr)=="[object Array]"
        
          执行的一刹那,相当于arr.toString();
                      apply(arr)
        call VS  apply:      
            1、都是,在调用方法时,修改当前调用方法的对象
          差别:传入参数的形式:
           xxx.call(obj,值1,值2,值3...)
           xxx.apply(obj,[值1,值2,值3...]);


         6、ES5中新函数:Array.isArray(obj)



继承:父对象中的属性和方法,子对象可直接使用
   为什么继承:代码重用!节约内存空间!便于维护
   js中的继承都是用_proto_

   1、直接继承对象:修改对象的_proto_
        3种:
    1、仅修改一个对象的_proto_
        Object.setPrototypeOf(子对象,父对象)
    2、通过修改构造函数的原型对象,实现批量修改后续子对象
          的继承关系
          构造函数.prototype=父对象
        强调:仅影响之后创建的对象的继承关系
              之前创建的对象依然继承旧构造函数.prototype

    3、Object.create(父对象[,{属性列表}])
       创建一个空对象
       继承父对象中的属性
       继承同时可再扩展属性和方法

   2、仅继承机构:模拟java中的继承。
       function 父类型构造函数(属性参数1,属性参数2){
             this.属性1=属性参数1;
         this.属性2=属性参数2;

       }
       function 子类型构造函数(属性参数1,属性参数2,属性参数3){
        父类型构造函数.call(this,属性参数1,属性参数2)
        this.属性3=属性参数3;

       }
       var obj=new 子类型构造函数(值1,值2,值3)


总结:面向对象:封装  继承  多态(重载和重写)
    多态:同一个东西在不同情况下,表现不同的状态