JavaScript第一周总结

222 阅读19分钟

JavaScript介绍

JavaScript是一个运行在 浏览器端解释型弱类型面向对象 脚本语言。

由三部分构成:ECMAScript(核心语法3/5/6/7/8/9/10/11/12) + DOM和网页关联) + BOM(和浏览器关联)

一、概念

1.1 浏览器端:

环境,自带JavaScript解释器——打开浏览器就可以自动运行
在学习Node.js的时候,会安装一个独立的js解释器

1.2 解释型:

在程序执行之前,不需要先检查语法是否正确,直接运行,碰到错误就停止,比如:js、php...
编译型:
在程序执行之前,需要先检查语法是否正确,如果语法错误,则不运行。相对于解释型比较严格,比如:Java、C#...

1.3 弱类型:

变量保存的数据是可以随意的,数据类型由数据来决定,比如:JavaScript
强类型:
变量保存的数据,是由数据的类型决定的,比如:Java

1.4 面向对象:

很难。面向对象式的写法:对象名.属性名;对象名.方法名();

1.5 特点:

  • 可以用一切编辑工具编写JS代码,编辑器的不同并不代表实力的大小
  • 解释型
  • 弱类型
  • 面向对象
  • 可以做一切css完成不了的效果,比如:轮播、选项卡、购物车、验证...

二、如何使用js

2.1 使用方式:(2种)

  1. 在HTML页面上书写一个script标签,然后在里面书写代码 —— 一般不使用此方法
    <script>js代码</script>
  2. 创建一个xx.js的文件,然后在HTML里面引入 —— 正式开发
    <script src='js路径'>此时不能在这里写代码</script>

2.2 输出方式/打桩输出:(3种)

作用:辅助我们检查代码错误

  1. 在控制台输出日志
    console.log(想要输出的内容);//console - 控制台,log - 日志
    推荐:不会影响到页面的内容
  2. 在页面上输出日志:
    document.write(想要输出的内容);//document - 文档,write - 写。
    支持识别标签,但不推荐:如果搭配点击事件,会把页面上原有的东西全部替换
  3. 在弹出框输出日志:
    alert(想要输出的内容);//警告框
    一般般:有时候会卡住整个页面,导致用户只能看到一个白板

2.3 变量:创建后,可以再次修改

  1. 何时使用:反复用到的数据,提前保存到一个变量中,后续使用变量名就相当于在使用变量的值
  2. 语法:var 变量名=值;
  3. 特殊:
    1. 变量名是不可以随意的: a.不能以数字开头 b.建议驼峰命名法 c.命名尽量见文知意:
    2. 如果你的变量名是name,不管你保存的数据类型是什么,都会默认转为一个字符串
    3. 变量名不能是关键字
    4. 变量可以只创建,不赋值,默认值为undefined,undefined不能拿来做任何操作
    5. 如果多个变量连续创建,中间用,隔开;

2.4 常量:创建后,不能修改

  1. 语法:const 常量名=值;
  2. 特殊:见上文变量的特殊

2.5 数据的类型:(两大类)

  1. 原始/基本/值类型:(5个)
    (1)number - 数字:取值有无数个,数字直接写,不需要加任何东西,颜色是蓝色
    (2)string - 字符串:取值有无数个,写的时候需要加英文状态下的单双引号(" "或' '),颜色是黑色
    (3)boolean - 布尔:取值只有2个,true/false - 一般用于当做条件判断,颜色是蓝色
    (4)null - 空,取值只有1个,null,作用是释放变量释放内存,节约空间,提升网页的性能,颜色是灰色
    (5)undefined - 取值只有1个,undefined做任何操作都不行,颜色是灰色
  • 查看数据类型:typeof(变量);
  1. 引用对象类型:(11个)
    可以理解为有11个对象(属性和方法)

2.6 运算符:(6种)

  1. 算术运算符:+ - * / %
    (1)%:取余,俗称模,两数相除,取余数
      作用:a.判断奇偶,任意数%2;
        b.取出某个数字的后n位:1234%10 ==> 4, 1234%100 ==> 34
    (2)带有隐式转换:会默认将数据类型转化为数字再进行运算:
       true => 1,false => 2,undefined => NaN,null => 0
      "10" => 10,"1000px" => NaN,带单位的要用强制转换
    (3)NaN:Not a Number,不是一个数字,但它属于数字类型,不是有效数字
       缺点:a.参与任何算术运算结果为NaN
        b.参与任何比较运算结果都是false
          解决:!isNaN()判断是否是数字,true是数字,false不是数字

  2. 比较运算符:> < >= <= == != === !==
    结果:是布尔值
    带有隐式转换:默认两边转为数字再比较
    undefined==null为true
         === 全等,不带隐式转换的
         !== 不等,不带隐式转换的

  3. 赋值运算符:= += -= *= /= %=
    例如:i+=1 --> i=i+1

  4. 逻辑运算符:|| && !
    或=>|| 与=>&&
    非=>! 颠倒布尔值

  5. 自增自减运算符: ++ --
    i++ ==> i=i+1 ==> i+=1
    前++ 和 后++的区别:
       单独使用没有任何区别
       如果是等式运算,则返回的结果不同:
          前++返回的是加了之后的值
          后++返回的是未加的值

  6. 位运算
    左移:m<<n,读作m左移了n位,m*2的n次方
    左移:m>>n,读作m右移了n位,m/2的n次方
    缺点:底数只能是2

2.7 用户输入框:var 变量=prompt('提示文字');

三、分支结构

通过条件判断,选择部分代码执行

3.1 if...else...

三种写法:
1.一个条件,一件事,满足就做,不满足就不做
    if(条件){
        操作;
      }
2.一个条件,两件事,满足就做第一件,不满足就做第二件
    if(条件){
        操作;
      }else{
        操作;
      }
3.一个条件,多件事,满足哪个条件就做对应的操作
    if(条件){
        操作;
      }else if{
        操作;
      }else if{
        操作;
      }else{
        操作;
      }
  1. else if想写多少就写多少,由程序员决定
  2. else默认操作可以不写,但不建议,如果条件都不满足则什么都没有发生
  3. 分枝走了一条路就不会走其他的路

3.2 switch...case...

switch(变量/表达式){
        case 值:
        case 值:
        case 值:
        操作;
        break;
        case 值:
        操作;
        break;
        default:
        操作;
    }
  1. 默认只要一个case满足后,会将后续所有的操作全部做完。
    解决:在每一个操作后面添加break; default后面不用跟。

  2. default可以不写,但是不推荐不写,如果条件都不满足的时候,则什么都不会发生,什么都不发生就感觉这段代码还不如不写

  3. case在做比较的时候是不带隐式转换的

3.3 if和switch的区别(面试题)

  1. switch...case:
    优点:执行效率高,速度快(case做比较时,case做的不是范围查找,而是等值比较
    缺点:必须要知道最后的结果是什么才可以使用

  2. if...else...:
    优点:可以做范围判断,也可以做等值比较
    缺点:执行效率较慢,速度慢(因为是范围查找)

  • 建议:代码开发结束后,做代码优化,尽量少用if...else...,多用switch...case和三目运算

3.4 三目运算(简化分支)

语法: 条件?操作:默认操作; ==>if...else

  • 条件和操作可以有多个,默认操作只有一个,且默认操作必须写
    比如:条件?操作1:条件?操作2:条件?操作3:默认操作; ==> if...else if...else if...else

  • 如果条件和操作太多,不建议使用三目运算,还是推荐 if 或 switch

  • 注意:默认操作不能省略,省略了会报错的

四、强制转换数据的类型

解决隐式转换解决不了的,例如:"100px"*2=NaN
页面上一切数据,js获取到都是字符串类型

4.1 转数字

  1. parseInt(str/num); 主要用于字符串转整数
      识别规则:从左往右依次识别数字字符,碰到第一个不是数字的字符串就停止,如果第一个不是数字字符串,则为NaN,不认识小数点

  2. parseFloat(str); float浮点数,主要用于字符串转小数
      识别规则:只认识第一个小数点,其余与整数相同

  3. Number(x); 万能公式,任何东西都可转换为数字类型,绝对不要手动转换,等同于隐式转换 -0 *1 /1,减0,乘1,除1

4.2 转字符串

  1. var str=x.toString(); x不能是undefined和null,会报错,他们不是对象,不能使用.做任何操作

  2. var str=String(x); 万能的,绝对不要手动转换,等同于隐式转换 +,加

4.3 转布尔:

  • Boolean(x); 万能的,任何东西都可以转布尔,绝对不要手动转换,完全等同于隐式转换,不如 !!x

  • 只有6个为false:false 0 undefined NaN null 空引号""

  • 除了这6个,剩下的都是true

五、循环结构

循环结构:反复执行相同或相似的操作

循环三要素:
  1、循环条件:开始-结束,循环的次数
  2、循环体:做的操作是什么
  3、循环变量:记录着当前循环到哪一次了,会不断地变化

循环都是一次一次执行的

5.1 for循环

语法:
    for(i=0;i<5;i++){
        console.log(i);
    }

执行原理:与while循环的原理相同
for循环的语法比while循环的语法看上去更简洁,更舒服

5.2 while循环

语法:
    var i=0;
    while(i<5){
        console.log(i);
        i++;
    }
  • 执行原理:首先创建出循环变量,判断循环条件,如果条件满足,则做一次循环体操作,并不会退出循环,而会回过头再次判断循环条件满不满足,如果满足,则做一次循环体操作,...直到条件不满足,才会退出循环
  • while 和 for的区别(面试题):
    while和for在原理上几乎没有区别
    一般来说不确定循环次数的时候,会使用while循环- 死循环
    一般来说确定循环次数的时候,会使用for循环 - 大部分情况

5.3 do...while循环(不常用)

语法:
    var i=0;
    do{
        console.log(i);
        i++;
    }while(i<5)
  • while和do...while的区别(面试题)
      区别只在第一次,如果第一次条件满足,则没有任何区别,但是如果第一次条件不满足,while循环一次都不会做,do...while至少执行一次。根据代码从上到下的运行规则,可以看出,do...while循环是先执行里面的循环体,再判断,而while循环是先判断,再执行。

5.4 死循环

  • while(true){}
  • for(;;){}
  1. 死循环:默认永远不会停下来的循环
     何时使用:不确定循环次数的时候:while(true){死循环}

  2. 让死循环停下来:
     break; - 退出整个循环,大多是用来搭配死循环的
     continue; - 退出本次循环,下一次依然会执行

六、Function函数

Function 称为函数,又称为方法,先预定义好,以后可以反复使用的代码段

6.1、Function基础

6.1.1 如何使用函数:(2步)

  1. 定义/创建/声明:
    function 函数名(){函数体/代码段;}
    注意:函数创建后,不会立即执行,需要调用函数才能执行
  2. 调用函数:(2种)
      (1)在js内部写:函数名(); ——程序员写几次就调用几次
      (2)在HTML上绑定事件:<elem onclick='函数名'></elem>————什么元素都可以绑定事件

6.1.2 何时使用:

  1. 不希望打开页面立刻执行
  2. 希望用户来触发提升用户的体验感
  3. 以后每一个独立的功能都要封装为一个函数
  • 函数在js里的地位极高,函数是js的第一等公民

6.1.3 创建出带有形参的函数:

形参:其实就是一个变量,只不过不需要加var、不需要赋值,所以称之为形式参数 - 简称形参

  1. 语法: function 函数名(形参,...){函数体/代码段;}
  2. 使用带有形参的函数时,必须传入实参 - 实际参数
     调用函数:函数名(实参,...)
    注意:传参时顺序不能乱,必须和形参的顺序一一对应,数量不多不少
  3. 总结:
    a、不带参数的函数:用于执行一些固定操作
    b、带参数的函数:可以根据我们传入的实参的不同,做的略微不同

6.1.4 函数和循环的区别:

  1. 循环:几乎是一瞬间就完毕了
  2. 函数:需要调用后才会执行

6.2 自定义函数Function

函数:需要先定义好,以后可以反复使用的一个代码段

何时使用:不希望打开页面立刻执行,以后可以反复使用,希望用户来触发...

6.2.1 函数的创建:(2种)

  1. 声明方式 创建函数:
    function 函数名(形参列表){代码段;return 返回值/结果;}
  2. 直接量方式 创建函数:--不推荐
    var 函数名=function(形参列表){代码段;return 返回值/结果;}

6.2.2 函数的调用:

var 变量名=函数名(实参列表)

  1. return的本意是退出函数,但是如果return后面跟着一个数据,顺便将数据返回到函数作用域的外部,但是return只负责返回,不负责保存,所以调用函数时要自己拿个变量来接住他

  2. 就算省略return,默认也有,会return一个undefined

  3. 具体需不需要得到函数的结果,看你自己:如果有一天你在全局希望拿着函数的结果去做别的操作,那么记得加return

  4. 前辈们提供的方法,大部分基本上都加了return

6.2.3 作用域:(2种)

  1. 全局作用域:
    全局变量 和 全局函数,在页面的任何一个位置都可以使用

  2. 函数作用域:
    局部变量 和 局部函数,在当前函数调用时,内部可用

  3. 带来了变量的使用规则:
    优先使用局部的,局部没有找全局要,全局也没有那就会报错
    特殊点/缺点:
      1、千万不要在函数中对着未声明的变量直接赋值 - 全局污染:全局本身没有这个东西,但是被函数作用域给添加上了
      2、局部可以使用全局的,但是全局不能使用局部的 - 解决:return

6.2.4 声明提前:(鄙视题)

规则:在程序正式执行之前,将var声明的变量(轻)和function声明的函数(重),都会悄悄的集中定义在当前作用域的顶部,但是赋值留在原地

  • 强调:声明方式创建的函数会完整的提前直接量方式创建的函数不会完整提前,只有变量名部分会提前,赋值留在原地

  • 何时使用:永远不会自己使用,会干扰我们判断 - 只会在笔试中遇到

  • 为什么平时开发不会遇到? 只要你遵守以下规则: 1、变量名和函数名尽量不要重复 2、先创建后使用

6.2.5 重载:

  • 概念:相同的函数名,根据传入的实参的不同,自动选择对应的函数去执行,但是JS不支持,函数名如果重复了,后面的肯定会覆盖掉前面的

  • 目的:减轻我们程序员的压力,记住一个方法就可以执行很多的操作

  • 解决:在【函数内部】自带一个arguments的对象(类似数组对象):不需要我们去创建 - 哪怕没有写任何形参,他也可以接受住所有实参,所以他默认length长度为0
      固定套路: 1、通过下标去获取传入的某一个实参:arguments[i] —— i从0开始。 2、通过length去获取到底传入了几个实参:arguments.length

  • 通过判断传入的实参的不同,在内部去写判断,从而变相的实现重载

七、DOM

Document Object Model:文档对象模型,专门用于操作HTML文档的,提供了一些方法。

7.1 DOM树概念:

  • DOM将HTML看作是一个倒挂的树状结构,但是树根不是html标签,而是document的对象

  • document对象:不需要我们程序员创建,由浏览器的js解释器自动创建,一个页面只有一个document树根
     作用:可以通过树根找到我们想要的任何一个DOM元素/节点/对象(属性和方法)

  • DOM会将页面上的每个元素、属性、文本、注释等等都会被视为一个DOM元素/节点/对象

7.2 查找元素:(两大方面)

7.2.1 直接通过HTML的特点去查找元素

  1. 通过 ID 查找元素:
    var elem=document.getElementById("id值");
    特殊:
      1、返回值,找到了返回当前找到DOM元素,没找到返回的一个null
      2、如果出现多个相同id,只会找到第一个
      3、记住控制台输出的样子,这个样子才叫做一个DOM元素/节点/对象,才可以下午去做操作
      4、忘记此方法,不允许使用,id不好用,一次只能找一个元素。id留给后端用
      5、其实根本不用查找,id直接可用

  2. 通过 标签名 查找元素:
    var elems=document/已经找到的父元素.getElementsByTagName("标签名");
    特殊:
      1、返回值,找到了返回一个类数组DOM集合,没找到得到空集合
      2、js只能直接操作DOM元素,不能直接操作DOM集合,解决:要么下标拿到某一个,要么遍历拿到每一个。
      3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素

  3. 通过 class 查找元素:
    var elems=document/已经找到的父元素.getElementsByClassName("class名");
    特殊:与标签名相同

7.2.2 通过关系去获取元素:

  • 前提条件:必须先找到一个元素才可以使用关系`
  1. 父元素:elem.parentNode; - 单个元素
  2. 子元素:elem.children; - 集合
  3. 第一个子元素:elem.firstElementChild; - 单个元素
  4. 最后一个子元素:elem.lastElementChild; - 单个元素
  5. 前一个兄弟:elem.previousElementSibling; - 单个元素
  6. 后一个兄弟:elem.nextElementSibling; - 单个元素
  • 为什么要通过关系去找元素呢?
    不希望影响到别人,只希望影响到自己的关系网

7.3 操作元素:(3方面)

前提:先找到元素,才能操作元素

7.3.1 操作元素的内容:

  1. elem.innerHTML - 获取和设置开始标签到结束标签之间的内容,支持识别标签的
    获取:elem.innerHTML;
    设置:elem.innerHTML="新内容";

  2. elem.innerText - 获取和设置开始标签到结束标签之间的纯文本,不识别标签的
    获取:elem.innerText;
    设置:elem.innerText="新内容";

  • 以上两个属性都是专门为双标签准备,而有一个单标签也是可以写内容,叫做,我们如何获取?
  1. input.value - 专门获取/设置input里的内容
    获取:input.value;
    设置:input.value="新内容";

7.3.2 操作元素的属性:

获取属性值:elem.getAttribute("属性名");
设置属性值:elem.setAttribute("属性名","属性值");

简化版
  获取属性值:elem.属性名;
  设置属性值:elem.属性名="属性值";
简化版的缺点:
  1、class必须写为className - ES6(2015年)class变成了一个关键字
  2、不能操作自定义属性

7.3.3 操作元素的样式:

使用样式的方式:(3种)
  1、内联样式
  2、内部样式表
  3、外部样式表 - 一阶段做开发用的都是外部样式表

二阶段用js来操作【内联样式
  1、不会牵一发动全身
  2、优先级最高

获取样式:elem.style.css属性名;
设置样式:elem.style.css属性名="css属性值";
特殊点
  1、css属性名,有横线的地方,去掉横线,变为小驼峰命名法:
     border-radius -----> borderRadius
  2、小缺陷:获取时,我们只能获取到内联样式,因为我们目前学的就是内联样式的操作

7.3.4 绑定事件:

elem.on事件名=function(){
        操作;
        关键字this - 这个
                如果单个元素绑定事件,this->这个元素
                如果多个元素绑定事件,this->当前触发事件元素
}
  • 一切的获取,往往都是为了判断
  • 一切的设置,可以说是添加也可以说是修改

八、数组

问题:保存1000个同学的名字?
var name1="钟清翰1";
...
var name1000="钟清翰1000";
不推荐,变量其实就是我们所谓的内存,变量创建的越多,那么我们的内存空间消耗越大,那么网站性能就会越差

解决:数组:创建一个变量可以保存【多个数据】
数组都是线性排列,除了第一个元素,每个元素都有唯一的前驱元素除了最后一个元素,每个元素都有唯一的后继元素

每个元素都有一个自己的位置,称之为叫做下标,下标都是从0开始的,到最大长度-1结束

8.1 创建数组:(2种)

1、直接量方式:
var arr=[];//空数组
var arr=[数据1,...];

2、构造函数方式:
var arr=new Array();//空数组
var arr=new Array(数据1,...);

8.2 获取数组之中的元素:

数组名[i];

8.3 后续添加/替换元素:

数组名[i]=新数据;
如果下标处没人则为添加,如果下标处有人则为替换

8.4 数组具有三大不限制

  1. 不限制元素的类型
  2. 不限制元素的长度
  3. 不限制下标越界 - 不是一个好东西
    如果获取元素时,下标越界,返回的是一个undefined
    如果添加元素时,下标越界,会得到一个稀疏数组,如果我们搭配上我们学过循环去遍历获取每个元素,那么你会得到很多很多undefined

问题:自己数下标,难免会数错,导致我们下标越界

8.5 下标越界的解决:数组中有一个唯一的属性--length

语法:数组名.length
作用:获取到数组的长度,长度是从1开始的

三个固定套路:

  1. 向末尾添加元素:arr[arr.length]=新数据;
  2. 获取数组的倒数第n个元素:arr[arr.length-n];
  3. 缩容:删除倒数n个元素:arr.length-=n;

8.6 遍历数组:

往往很多情况,我们不会拿出某个元素来使用,而是拿出每个元素来进行 相同 或 相似的操作 - 搭配上循环
固定公式:

for(var i=0;i<arr.length;i++){
	arr[i];//当前次元素
}