前言

  • 2020.04.24日,听了两节,课程布局合理,老师幽默风趣,可以作为一个长期课程来听,大概设定时间2月吧,到7月1日截止看学习情况。
  • 2020.05.13日,学习了变量、数据类型、流程控制、数组。
  • 2020.05.22日,昨天还好好的,今天就被删除了,悲伤,只能找其他替代的资料了。
  • 2020.05.26日,对函数、构造函数、对象要进行区别掌握。
  • 2020.06.04日,我已成为 pink老师的忠实粉丝,课讲的明白,人幽默风趣、风骚无比,这老师只应天上有啊。
  • 2020.06.08日,JS 基础课程结束了,用时 45 天。

新知

  • 理解了 for 循环,理解了断点调试,调试 bug,开心(^▽^)
  • 虽然分析(算法)比写代码更重要,但我只要能依葫芦画瓢的写代码就很知足啦!(2020.05.05),结合《心流》一书的理论,这是在给自己定下一个简单的挑战,以免被过高的目标摧毁,不过这样有依有据,太不浪漫,我还是喜欢潜意识里就认定的自己!
  • 流程控制:顺序流程控制,从上到下,从左到右,这是默认的流程,虽然简单但重要且易被忽略。
  • 一种翻译的思想:将项目问题翻译为数学问题和计算机问题。
  • 几种思想:交换变量数值的方法;求最大值的打擂思想;翻转数组的方法;冒泡排序;
  • 字面量:() [] {} , 小括号是运算符,中括号是数组,大括号是对象。
  • 薄弱的地方:对象的概念和操作;作用域的概念和应用;对象的遍历,预解析。

JS 基础

编程基础介绍

  1. 解释型语言:可以即时执行,读一行执行一行,也叫作脚本语言。
  2. 编译型语言:需要将代码全部编译为机器语言才可以运行。
  3. 标识符:开发人员为变量、属性、函数、参数取的名字。
  4. 关键字:JS 本身已经使用了的字,不能再用它们充当变量名、方法名。
  5. 保留字:预留的“关键字”,虽然现在还不是关键字,但未来可能会成为关键字。

初识 JavaScript

  • JS 开始只是为了在本地校验用户填写的表单(账号、密码),以减轻服务器的压力。

浏览器执行 JS 简介

  • 渲染引擎:用来解析 HTML 与 CSS ,俗称内核,比如 Chrome 浏览器的 blink,老版本的webkit。
  • JS 引擎:也称为 JS 解释器。用来读取网页中的 JavaScript 代码,对其处理后运行,比如 Chrome 浏览器的 V8。
  • 浏览器本身并不执行 JS 代码,而是通过内置 JavaScript 引擎(解释器)来执行 JS 代码。JS引擎逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,因为是逐行解释执行的。

JS 的组成

  • ECMAScript:主要是 JavaScript 语法
  • DOM(document object module):页面文档对象模型
  • BOM(Browser Object Module):浏览器对象模型

JS 初体验

  • 行内式的 JS
  • 内嵌式的 JS
  • 外部 JS

JS 命名规范、语法格式

  • 标识符命名规范:变量、函数的命名必须要有意义;变量使用名词,函数使用动词。
  • 操作符规范:操作符的左右两侧各保留一个空格。
  • 单行注释规范:单行注释前面留一个空格。
  • 使用 JS-CSS-HTML Formatter 插件事半功倍。

JS 注释

JS 输入输出语句

VScode 的使用

  • live server 插件
  • JS-HTML-CSS format 插件
  • 一款流程图软件:Diagram Designer

JS 变量

  • 什么是变量?程序在【内存】中申请的一块用来存放数据的【空间】。
  • 变量的使用:1.声明变量 2.赋值;eg:var age; // 声明一个名称为 age 的变量。
  • 变量的初始化:var name = "pink老师"
  • 同时声明多个变量,只需要写一个 var ,多个变量使用 , 隔开,例如:var age = 18, address = "火影村", pay = 2000;

JS 数据类型

  • 为什么需要数据类型?因为不同的数据所占用的存储空间不同,(数据结构也不同)。
  • JavaScript 是一种弱类型或者说动态语言,变量的数据类型是不确定的(根据等号右边的值来确定的),是可变化的。

简单数据类型:Number;Boolean;String;Undefined;Null;

  • Number:

    • 八进制:0 + 0~7
    • 十六进制:0x + 0~9 a~f
    • number.MAX_VALUE
    • infinity
    • NaN:not a number
  • String:'单引号或者双引号'

    • 转义字符:\n \\ \' \" \t \b 英文意思: newline tab blank
    • 重要:转义字符需要放在字符串里
    • length 检测字符串长度的方法:string1.length
    • 字符串拼接:strintj01 + anytypedata \ 拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串。
  • Boolean:true false 1 0
  • Undefined:如果一个变量声明未赋值 就是 undefined,若与数字相运算,结果是 NaN 。
  • Null:空值,与数字相运算是数字本身。
  • 获取变量的数据类型typeof
  • 验证是否是数字:isNaN()
  • 字面量:单纯的字面文本表达的意思。

    • 8 就是数字
    • 'hello world' 就是字符串
    • [ ] 就是数组
    • true 就是布尔值
  • 复杂数据类型:

JS 数据类型的转换

其他类型转换为 字符串类型:

  1. 加号拼接字符串 10 + " " 隐式转换
  2. variable.toString()
  3. String()函数 强制转换

其他类型转换为 数字类型:

  1. parselnt() 函数parseInt(variable) 取得整数且完全向下取整,从左到右依次解析。
  2. parseFloat() 函数parseFloat(variable) 取得浮点数值。
  3. Number() 强制转换函数:
  4. js 隐式转换 ( - * / ):console.log('12'- 0) console.log('13' - '10')+不会隐式转换,因为 + 可以拼接两个字符串。

其他类型转换为 Boolean type:

  1. Boolean() 函数Boolean('true');
  2. '', 0, NaN, null, undefined 空的、否定的值会被转换成 false,其余转换为true

JS 运算符

  • 表达式:由数字、运算符、变量等以能求得【数值】的有意义排列方法所得的组合。简单的说就是由数字、运算符、变量等组成的式子。eg: 1 + 1
  • 返回值:表达式最终都会有一个结果返回给我们,称为返回值。右边的表达式计算完毕把返回值给左边。一般使用一个变量来保存这个值。
  • 运算符(operator) 也被称为操作符,用于实现赋值、比较和执行算术运算等功能的符号。
  • 算术运算符:加,减,乘,除,取余(取模) + - * / %,浮点数的直接运算会有精度的问题。

    • 算术运算符的优先级:先乘除,后加减,有小括号先算小括号里面的。
  • 递增、递减运算符num = num + 1 num = num + 1 -> ++ --

    • 如果需要反复给数字变量添加或减去1,可以使用递增(++)和递减(--)运算符来完成。
    • ++ -- 必须和变量配合使用。
    • 既可以放在变量前面,也可以放在变量后面。放在前面时,称为前置递增(递减)运算符,放在后面时,称为后置递增(递减)运算符。
    • 前置自加:先自+1,再返回原值
    • 后置自加:表达式先返回原值,变量再自+1
    • 在开发时,大多使用后置递增/递减,并且代码独占一行,例如:num++
  • 比较运算符(关系运算符):两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值作为结果。

    • >=
    • <=
    • == // 默认转换数据类型,值相等就可以。
    • === // 严格模式的等于,值和数据类型都要完全相同。
    • !=
    • !== // 严格模式
  • 逻辑运算符:与运算符-&& 或运算符-|| 非运算符-!
  • 短路运算(逻辑中断):当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值。

    • &&:表达式1 && 表达式2;如果第一个表达式的值为真,则返回表达式2console.log(123 && 456);如果第一个表达式的值为假,则返回表达式1console.log(0 && 456)或者console.log(0 && 1 +2 && 456* 567)
    • ||:表达式1 || 表达式2;如果表达式1结果为真,则返回表达式1;如果表达式1结果为假,则返回表达式2。
  • 赋值运算符= += -= *= /= %=

    var num = 10;
    
    num = num + 1; // num += 1; num++
    
    num = num + 2; // num += 2;
    
    num = num - 2; // num -= 2;
  • 运算符优先级:使用小括号来表示优先级,稳妥

    1. 小括号
    2. 一元运算符:++ -- !
    3. 算术运算符:先 * / % 后 + -
    4. 关系运算符:> >= < <=
    5. 相等运算符:== != === !==
    6. 逻辑运算符:先 && 后 ||
    7. 赋值运算符:=
    8. 逗号运算符:,

JS 流程控制

  • 流程控制:控制代码按照什么结构顺序来执行。

    • 在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。
    • 流程控制主要有三种结构:顺序结构、分支结构、循环结构。
  • 顺序流程控制:最简单、最基本的流程控制,按照代码的先后顺序执行。
  • 分支流程控制:由上到下执行代码的过程中,根据不同的条件,执行不同的代码路径(执行代码【多选一】的过程),从而得到不同的结果。
  • 循环流程控制

分支流程控制

if else:

  • if 语句:if (条件表达式) {}
  • if else 语句:
if (条件表达式) {

        // 执行语句1

    } else {

        // 执行语句2

    }

if else if 多分支语句:

if (条件表达式1) {

        // 执行语句1;

    } else if (条件表达式2) {

        // 执行语句2;

    } else if (条件表达式3) {

        // 执行语句3;

    } else {

        // 最后的语句;

    }

三元表达式

  • 一元表达式:++num
  • 二元表达式:3 + 5
  • 三元表达式:条件表达式 ? 表达式1: 表达式2 如果条件表达式结果为真,则返回表达式1的值;如果结果为假,则返回表达式2的值。

switch 语句:它基于不同的条件来执行不同的代码,当要针对【变量】设置一系列的【特定值】的选项时,就可以使用 switch。

  • switch 语法结构:expression 匹配哪个值就执行哪个语句。直接跳转匹配,执行效率较 if 高。
  • 开发里,表达式经常写成变量,灵活复用。
  • num 和 case 的值相匹配的时候是全等,必须是值和数据类型一致才可以。
  • break 不写的话,不会退出 switch ,继续执行下一个 case。
switch(expression) {

    case value1:

        执行语句1;

        break;

    case value2:

        执行语句2;

        break;

    ...

    default:

        执行最后的语句;

}

if 语句 和 switch 语句的区别:

  1. 一般情况下,两个语句可以相互替换。
  2. switch...case 语句通常处理 case 为确定值的情况,而 if ... else ... 语句更加灵活,常用于范围判断(大于、等于某个范围)
  3. switch 语句进行条件判断后直接执行到程序的条件语句,效率更高。而 if ... else 语句有几种条件,就得判断多少次。
  4. 当分支比较少时,if ... else 语句的执行效率比 switch 语句高。
  5. 当分支比较多时,switch 语句的执行效率比较高,而且结构更清晰。

循环流程控制

  • 循环的目的: 重复执行某些代码。
  • JS 中的三种循环:for 循环;while 循环;do...while 循环;
  • 在循环中,一组被重复执行的语句被称为【循环体】,能否继续重复执行,取决于循环的【终止条件】,由循环体及循环的终止条件组成的语句,被称为循环语句。
for 循环

for 循环用于把某些代码循环若干次,通常跟计数有关系。

for 循环的语法结构:

for (初始化变量;condition expression;operation expression) {

    // 循环体

}

 

// 初始化变量:用 var 声明的一个普通变量,通常用于作为计数器使用

// condition expression:用来决定每一次循环是否继续执行,即终止条件

// operation expression:每次循环最后执行的代码,用于更新计数器变量(递增或递减)
// 案例:重复打印 100 次 “hello world”

for (var count = 100; count > 0;count--) {

    console.log('Hello World')

}

for 循环的执行过程:

  1. 首先执行计数器变量 var count = 1,但是这句话在 for 里面只执行一次。
  2. 其次去 条件表达式 去判断是否满足条件,如果满足条件,就执行循环体,不满足条件,就退出循环。
  3. 最后去执行 操作表达式 去更新计数器变量,第一轮循环结束。
  4. 接着去执行 条件表达式 如果满足条件,就执行循环体,不满足…… 第二轮

断点调试(Breakpoints):帮助我们观察程序的运行过程!

  1. Chrome 浏览器 按F12,选择 Source,选择 File,进行调试
  2. 打上断点
  3. 刷新观察
  4. watch:add watch expression
  • for 循环执行相同代码、不同代码、相同操作:
<script>

 

    // 简单的循环语句

 

/*          for (var count = 1; count <= 100;count+=2) {

            console.log('Hello World')

    }  */

 

    // 循环执行相同的代码

 

/*     var num = prompt('请您输入次数:')

    for (var i = 1; i <= num; i++) {

        console.log('你想来这么多次哦')

    } */

 

    // 循环执行不同的代码,使用if语句

 

/*     for (var i = 1;i<=100;i++){

        if(i == 1){

            console.log('the man is 1 years old today,he is born(〃0〃)');

        }else if(i == 100){

            console.log('the man is 100 years old today, he is died o(╥﹏╥)o');

        }else{

            console.log('the man is '+i+'years old this year.');

 

        }

 

    } */

 

    // 循环执行不同的代码,使用switch语句

 

/*     for (var i = 1;i<=100;i++){

        switch(i){

            case 1:

                console.log('the man is 1 years old today,he is born(〃0〃)');

            break;

            case 100:

                console.log('the man is 100 years old today, he is died o(╥﹏╥)o');

                break;

            default:

                console.log('the man is '+i+'years old this year.');

                break;

 

 

        }

 

 

    } */

 

    // 循环执行相同的操作,求1~100之间的整数累加和,涉及简单的算法

 

    var sum = 0;

    for (var i = 1;i<=100;i++){

        // sum =sum+i;

        sum += i;

 

    }

    console.log(sum);

 

    </script>

for 循环案例(课后作业):

  1. 求1-100之间所有数的平均值
  2. 求1-100之间所有偶数和奇数的和
  3. 求1-100之间所有能被3整除的数字的和
  4. 班级学生总成绩和平均分
  5. 打印一行小星星
  6. 打印多行小星星
双重 for 循环:

双重 for 循环的语法结构:

for (外层的初始化变量;外层的条件表达式;外层的操作表达式){

    for (里层的初始化变量;里层的条件表达式;里层的操作表达式){

        // 执行语句;

    }

 

}

    // 1. 可以把里面的循环整体看做是外层循环的语句

    // 2. 外层循环一次,里面的循环执行全部
for (var i = 1; i <= 3; i++){

    console.log('这是外层循环的第'+i+'次');

    for (var j = 1; j <= 3; j++){

        console.log('这是内层循环的第'+j+'次');

    }

}

分析要比写代码更重要;要掌握核心算法!

while 循环
  • 在条件表达式(condition expression)为真的前提下,循环执行指定的一段代码,直到表达式不为真时结束循环。
  • while 循环的语法结构:
while (condition expression) {

    // 循环体代码

}

 

// 1.要有计数器,初始化变量

// 2.要有条件表达式,完成计数器的更新,防止死循环

// 3.可以完成更复杂的条件判断

do while 循环

while 循环的一个变体。会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复执行循环体,否则退出循环。

do while 循环的语法结构:

do {

    循环体

} while (condition expression)

 

// 先执行一次循环体,再判断条件决定是否继续执行

循环流程控制小结

  • JS 循环有 for 、while、do while
  • 三个循环很多情况下都可以互相替代使用
  • 如果是用来计数,跟数字相关的,三者使用基本相同,但是我们更喜欢用for
  • while 和 do while 可以做更复杂的判断条件,比 for 循环灵活一些
  • 实际工作中,我们更常用 for 循环,它写法更简洁直观,要重点学习

continue and break

continue 用于立即【跳出本次循环】,继续下一次循环。例如我今天要吃5个包子,第3个有虫子,就扔掉第3个,继续吃第4个第5个包子。

for (var i = 1;i <= 5;i++){

    if (i == 3) {

        continue;

    }

    console.log("我正在吃第" + i + "个包子。");

}

break 用于立即【跳出整个循环】(循环结束)。例如我今天要吃5个包子,第3个有虫子,尼玛不吃了。

for (var i = 1;i <= 5;i++){

    if (i == 3) {

        break;

    }

    console.log("我正在吃第"+i+"个包子。");

}

做作业做了一小时,还是挺有成就感的,能做出来点东西,比学其他的好。


JS 数组

数组的概念

  • 数组:一组数据的集合,其中的每个数据被称作元素,在数组中可以存放 【任意类型】*的元素。
  • 数组是一种将一组数据存储在单个变量名下的优雅方式,可以说很好地解决了取名的烦恼。
  • 变量只能存储一个值,数组可以把一组相关的数据一起存放,并提供方便的访问(获取)方式。

两种方式创建数组

  1. 利用 new 创建数组:var arr = new Array();
  2. 利用【数组字面量】创建数组:var 数组名 = [];

var 数组名 = ['小白','小黑','大黄','佩奇',true,1,2];

数组的索引(访问数组)

  • 数组的索引(下标)(index):访问数组元素的序号(索引从0开始)
  • 数组可以通过索引来访问、设置、修改对应的数组元素,我们可以通过“数组名[索引]”的形式来获取数组中的元素。
  • 访问即是获取。例如: alert(arr[1]); 访问第二个元素。

遍历数组

  • 如何取出数组里的每一个元素呢?可以通过索引一项项的取出来,可是太费劲了。
  • 遍历:从头到尾访问一次 数组中的每个元素(类似晨会点名)
  • 数组长度:不要去数了,直接使用array.length获取数组元素的数量。
var arr2 = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']

 

for (var i = 0; i < arr2.length; i++) {

    console.log(arr2[i]);

 

}

 

// 1.数组的长度是元素个数,不要跟索引号混淆.

// 2.arr2.length 动态检测数组元素的个数,多好.

// 3.i 是计数器,当索引号使用,arr2[i]是数组元素的第i个数组元素.

求数组的最大值:打擂台的思想。

  1. 声明一个保存最大元素的变量 max
  2. 默认最大值可以取数组中的第一个元素。
  3. 遍历这个数组,把里面每个元素和 max 相比较。 // 循环语句
  4. 如果这个元素>max 就把这个元素存到 max 里面,否则继续下一轮比较。 // if 条件分支语句

两种新增数组元素的方式

一、通过修改 length 长度增加数组元素: length 属性是可读写的。

var arr = ['red','green','blue'];

console.log(arr.length);

arr.length = 5; // 把数组的长度修改为5,现在里面应该有5个元素了

console.log(arr);

console.log(arr[3]); // undefined

console.log(arr[4]); // undefined

二、通过修改【数组索引】的方式追加数组元素:

var arr1 = ['red','green','blue'];

arr1[3] = 'pink'; // 追加一个数组元素。

console.log(arr1);

arr1[0] = 'yellow'; // 替换原来的数组元素。

console.log(arr1);

arr1 = '有点意思'; // 警告:不要直接给数组名赋值,会直接覆盖掉数组的所有数据。

console.log(arr1);

删除元素和翻转数组

// 1.删除指定数组元素

// 将数组[2,0,6,1,77,0,52,0,25,7]中的0去掉以后,形成一个不包含0的新数组.

 

var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];

var arr1 = [];

for (var i = 0; i < arr.length; i++) {

    if (arr[i] !== 0) {

        arr1[arr1.length] = arr[i] // arr1[arr1.length]巧妙的实现 新数组从0开始赋值.

    }

}

console.log(arr1);

 

// 2. 翻转数组

// 将数组['red','green','blue','pink','purple']的内容反过来存放.

var arr2 = ['red', 'green', 'blue', 'pink', 'purple'];

var arr3 = [];

for (var j = arr2.length - 1; j >= 0; j--) {

    arr3[arr3.length] = arr2[j];

}

console.log(arr3);

冒泡排序

  • 链接至文章:关于“冒泡排序”的再思考
  • 冒泡排序:一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小)
  • 冒泡排序是一种简单的排序算法:它重复地走访过要排序的数列,一次比较两个元素。如果他们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换的,也就是说该数列已经排序完成。
  • 有 N 个数,一个数要和其他数进行比较,即比较 N-1 次。

    • 第一趟:————---,总有5个数,一个数要和其他4个数比较,即比较4次
    • 第二趟:完成1个数后,还有4个数,一个数要和其他3个数比较,即比较3次
    • 第三趟:完成2个数后,还有3个数,一个数要和其他2个数比较,即比较2次
    • 第四趟:完成3个数后,还有2个数,一个数要和其他1个数比较,即比较1次
    • 第五趟:完成4个数后,还有1个数,不用比较了。
    • 5 个数,其实只需要走 4 趟,因为最后一个数不用比较。

JS 函数

函数使用小tips:

  1. 函数名使用 【动词】。
  2. 函数的形参类似于一个变量,不用声明就可以使用的变量。

函数的概念、使用

函数:封装了一段 可被重复调用执行 的代码块,通过此代码块可以实现大量代码的重复使用。

封装:把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。

函数的使用: 1. 声明函数 2. 调用函数。可以类比 变量 的使用。

  1. 声明函数:function 函数名() { 函数体代码} 函数不调用自己不执行。
  2. 调用函数: 函数名();
// 利用函数计算1~100之间的累加和

 

function getSum() {

    var sum = 0;

    for (var i = 1; i<=100;i++){

        sum += i;

    }

    console.log(sum);

 

}

 

getSum();

getSum();

函数的参数

利用函数的参数实现函数重复不同的代码。在函数内部某些值不能固定的时候,我们可以通过参数在 调用函数时 传递不同的值进去。

形参:形式上的参数,【函数定义的时候】传递的参数 当前并不知道是什么。形参是接受实参的,形参类似于一个变量。

实参:实际的参数,【函数调用的时候】传递的参数。实参是传递给形参的。

函数的参数可以有,也可以没有,个数不限。

函数的形参与实参的个数可以不相等。

  1. 相等,输出正确的结果。
  2. 实参>形参,只取到形参的个数。
  3. 实参<形参,多的形参定义为 undefined 。
  4. 实参和形参的个数可以不匹配,但是结果不可预计,所以我们要尽量匹配上。
function 函数名(形参1,形参2,...){ // 在声明函数小括号里面的是形参

 

}

 

函数名(实参1,实参2,...); // 在函数调用小括号里面的是实参
function cook(aru){

    console.log(aru);

}

cook("酸辣土豆丝");

cook("大肘子");

 

// 注意函数的执行过程, 先寻找实参, 再传递给形参, 执行函数.

函数的返回值

  • return 语句:函数将值返回给调用者。

    • 函数只是实现某种功能,最终的结果需要返回给函数的调用者(函数名()),通过 return 实现。
    • 只要函数遇到 return 就把后面的结果返回给函数的调用者:函数名() = return 后的结果
  • return 可以终止函数:return 之后的语句不再执行。
  • return 只能返回一个值:如果用逗号隔开多个值,以最后一个为准。如果想返回多个值,可以变通一下,比如使用数组。
  • 函数如果有 return 则返回的是 return 后面的值;如果没有 return ,则返回 undefined 。
  • break continue return 的区别:

    1. break 结束当前的循环体。
    2. continue 跳出本次循环,继续执行下次循环。
    3. return 不仅可以退出循环,而且能够返回 return 语句中的值,同时还可以结束当前的函数体内代码。
function 函数名() {

    return 需要返回的结果;

}

 

函数名(); // 调用函数,在实际开发中, 经常用一个变量来接受 函数的返回结果.

arguments 的使用

  • 当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。
  • 在 JavaScript 中,arguments 是当前函数的一个【内置对象】。

    • 所有函数都内置了一个 arguments 对象, arguments 对象中存储了传递的所有实参。
    • 只有函数才有 arguments 对象,且每个函数都内置好了 arguments 。
    • arguments 的展示形式是一个伪数组,有以下特点:

      • 具有 length 属性
      • 按索引方式储存数据,因此可以通过循环遍历
      • 不具有真正数组的一些方法: push() , pop()

函数的互相调用

函数可以调用另外一个函数:因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数相互调用的情况。

function fn1() {

    console.log(11);

    fn2(); // 在 fn1 函数里调用了 fn2 函数

}

fn1();

 

function fn2() {

    console.log(22);

 

}

更多案例见 Vscode 文件。

函数的两种声明方式

  1. 命名函数:利用函数关键字自定义函数 function fn(){}
  2. 函数表达式(匿名函数):var 变量名 = function(){}; (因为预解析的问题,函数表达式函数的调用必须写在它的下面。)
var fun = function(){

    console.log('我是函数表达式');

}

fun();

 

var fun1 = function(aru){

    console.log(aru);

}

fun1('blue');

 

// 1. fun 是变量名 不是函数名

// 2. 函数表达式声明方式跟声明变量差不多,只不过变量里存的是值,而函数表达式里存的是函数

// 3. 函数表达式也可以传递参数

JS 作用域

作用域与作用域的分类

  • 作用域是什么?就是代码名字在哪个范围内起作用和效果。

    • 在一段程序代码中所用到的名字 并不是总是有效和可用的,而限定这个名字的【可用性的代码范围】就是这个名字的作用域。
    • 作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
    • 个人理解就是一个名字可重复使用(在多个不同的作用域中),破解了千古难题之起名字的难题。
  • JS 的作用域(ES6)之前:全局作用域 局部作用域。

    • 全局作用域:整个 script 标签 或者是 一个单独的 JS 文件。
    • 局部作用域:在函数内部就是局部作用域,这个代码的名字只在函数内部起作用。
var num = 10;

console.log(num);

 

function fn(){

    var num = 20;

    console.log(num);

}

fn();

变量作用域的分类

  • 变量的作用域:根据作用域的不同,变量分为全局变量和局部变量。

    1. 全局变量:在全局作用域下的变量。在全局下都可以使用,函数里也可以使用。

注意:如果在函数内部,没有声明就直接赋值的变量也属于全局变量。

  1. 局部变量:在局部作用域下的变量,或者在函数内部的变量。

注意:函数的形参也可以看做是局部变量。

  • 执行效率的区别:

    • 全局变量只有在浏览器关闭的时候才会销毁,比较占内存资源。
    • 局部变量,当其所在的代码块被执行时,才会被初始化;当程序执行完毕就会销毁,比较节约内存资源。
  • ES6 之后才有块级作用域:{ }
  • 作用域链: 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值。

    • 就近原则:从目标出发,一层层去看一下,就近取值。

JS 预解析

  • JavaScript 代码是由浏览器(browzer)中的 JavaScript 解析器来执行的,JavaScript 解析器在运行 JavaScript 代码时分为两步:预解析 和 代码执行。

    • 预解析: JS 引擎把 JS 里面所有的 var 还有 function 声明提升到当前作用域的最前面。
    • 代码执行: 按照代码书写的顺序从上到下执行。
  • 预解析分为:变量预解析(变量提升) 和 函数预解析(函数提升)

    • 变量提升:把所有的 【变量声明】 提升到当前的作用域最前面(见案例1),不提升赋值操作。
    • 函数提升:把所有的 【函数声明】 提升到当前作用域的最前面,不调用函数。
// 坑1: uncaught referenceError:

console.log(num);

var num = 10;

// 相当于执行了以下代码:

 

var num; // 变量提升

console.log(num);

num = 10;
// 坑2: uncaught typeError: fun is not a function

fun();

var fun = function() {

        console.log(22);

 

    }

// 相当于执行了以下代码:

 

var fun; // 变量提升

fun(); // 无法调用,这不是一个函数.

fun = function(){

    console.log(22);

}
fn();

function fn(){

    console.log(11);

}

// 相当于执行了以下代码:

 

function fn(){  // 函数提升

    console.log(11);

}

 

fn();
// 预解析案例

 

var num = 10;

fun();

 

function fun(){

    console.log(num);

    var num = 20;

}

// 相当于执行了以下操作

 

var num;

function fun(){

    var num;

    console.log(num);

    num = 20;

}

num = 10;

fun();

JS 对象

什么是对象?

  • 现实生活中:万物皆对象。

    • 对象是一个 【具体】 的事物,看得见摸得着的实物。例如,一本书、一辆车、一个人可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。
    • 对象判断练习:明星 周星驰;女朋友 杨幂;班主任 咱们班班主任;苹果 这个苹果;手机 我的小米手机;游戏 王者荣耀;
  • 在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。

    • 属性:事物的特征,在对象中用属性来表示(常用名词)
    • 方法:事物的行为,在对象中用方法来表示(常用动词)
  • 为什么需要对象?

    • 保存一个值时,可以使用变量;保存多个值(一组值)时,可以使用数组;如果要保存一个人的完整信息呢?
    • 例如,将“张三丰”的个人信息保存在数组中的方式为:var arr = ['张三丰','男',128,154];,疑惑:姓名、性别、后面两个是什么呢?
    • 将“张三丰”的个人信息保存在对象中:
人.姓名 = '张三丰';

人.性别 = '男';

人.年龄 = 128;

人.身高 = 154;

创建对象的三种方式

一、利用字面量来创建对象: 对象的字面量是{},里面包含了这个具体事物(对象)的属性和方法。

  1. 里面的属性或者方法采取 键值对 的形式。 键 属性名 : 值 属性值
  2. 多个属性或者方法中间使用 ,号隔开。
  3. 方法冒号后面跟的是一个匿名函数。
var obj = {

    uname: '张三丰',

    age: 18,

    sex: '男',

    sayHi: function() {

        console.log("hi~");

 

    }

}

 

console.log(obj.uname);

console.log(obj['age']);

obj.sayHi();
  • 使用对象:

    1. 调用对象的属性 对象名.属性名 或者 对象名['属性名']
    2. 调用对象的方法 对象名.方法名()
  • 变量、属性;函数、方法的区别:

    • 变量、属性的相同点在于都是用来存储数据的。不同点在于变量是单独声明并赋值,单独存在;属性在对象里面,不需要声明,使用的时候必须 对象.属性
    • 函数、方法的相同点在于都是实现某种功能,做某件事。不同点在于函数是单独声明,单独存在;方法在对象里面,调用的时候 对象.方法()

二、利用 new Object 创建对象: var obj = new Object();

  1. 利用 = 号赋值的方法 添加对象的属性和方法
  2. 每个属性和方法之间用 ; 号结束
var obj = new Object();

    obj.uname = '张三丰';

    obj.age = 18;

    obj.sex = '男';

    obj.sayHi = function() {

        console.log("hi~");

 

    }

}

 

console.log(obj.uname);

console.log(obj['age']);

obj.sayHi();

三、利用构造函数创建对象:一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象里面一些公共的属性和方法抽象出来封装到函数里面。

  1. 前两种一次只能创建一个对象。利用函数,重复这些相同的代码。
  2. 构造函数名字的首字母要大写!
  3. 调用 new 构造函数名();
  4. 构造函数不需要 return 就可以返回结果
function 构造函数名() {

    this.attribute = value;

    this.方法 = function() {}

}

new 构造函数名();
function Star(uname, age, sex, song) {

    this.name = uname;

    this.age = age;

    this.sex = sex;

    this.sing = function(song) {

        console.log(song);

 

    }

 

}

var ldh = new Star('刘德华', 18, '男');

console.log(ldh.age);

ldh.sing('冰雨');

 

var zxy = new Star('张学友', 19, '男');

console.log(zxy.name);

zxy.sing('情书');
  • 类(class):构造函数抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
  • 对象的实例化:创建对象特指某一个,通过 new 关键字创建对象的过程。
  • new 关键字:1.先在内存中创建了一个空的对象,2.this 都会指向这个对象,3.执行构造函数代码,给这个空对象添加属性和方法,4. 返回这个对象。

遍历对象属性:for...in...语句

var obj = {

    name:'李二蛋',

    age:18,

    sex:'男',

}

for (var k in obj){

    console.log(k); // 输出属性

    console.log(obj[k]); // 输出属性值

}

对象小结

  • 对象可以让代码结构更简单
  • 对象属于复杂数据类型 object
  • 对象的本质就是一组无序的相关属性和方法的集合
  • 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果.
  • 对象实例特指一个事物,比如这个苹果
  • for in 语句用于对对象的属性进行循环遍历操作.

JS 内置对象

  • JS 中的对象分为三种:自定义对象、内置对象;浏览器对象(JS独有的)。
  • 内置对象:就是指 JS 语言自带的一些对象,这些对象供开发者使用,提供了一些常用的或是最基本而必要的功能(属性和方法)。

查阅文档(MDN)

  • MDN:Mozilla 开发者网络提供了有关 开放网络技术 的信息,包括 HTML CSS 和 WWW 及 HTML5 应用的 API。
  • W3C:
  • 如何学习对象中的方法:

    1. 查阅该方法的功能
    2. 查看里面参数的意义和类型,参数使用[]代表可选。
    3. 查看返回值的意义和类型
    4. 通过 demo 进行测试

Math 对象

  • 不是一个构造函数,不需要使用 new 来调用,直接使用里面的属性和方法就可以了。
  • Math 对象中的成员:Math.PI ; Math.floor() ; Math.ceil() ; Math.round() ; Math.abs() ; Math.max() / Math.min()

    • Math.round(),遇到5的时候,特殊,往大了取。
  • Math 对象中的随机数方法:Math.random()
  • 动动手:封装一个自己的数学对象,里面有 PI,最大值和最小值。
var Math1 = {

    PI: 3.141592653,

    max: function() {

        var max = arguments[0];  // 使用arguments来接受实参

        for (var i = 1; i < arguments.length; i++) {

            if (arguments[i] > max) {

                max = arguments[i];

            }

 

        }

        return max;

    },

    min: function() {

        var min = arguments[0];

        for (var i = 1; i < arguments.length; i++) {

            if (arguments[i] < min) {

                min = arguments[i];

            }

 

        }

        return min;

    },

}

console.log(Math1.PI);

console.log(Math1.max(1, 2, 4, 5, 7, 3));

console.log(Math1.min(1, 2, 4, 5, 6, 9, 8, 38));

Date 对象

  • Date 对象是一个构造函数,必须使用 new 来调用。
  • 不加参数返回当前时间,加参数可以使用字符串格式‘2020-5-26 8:8:8’
  • 日期的格式化:使用字符串的拼接功能完成+三元表达式(小于10的话补0)
  • 为什么计算机的时间是从1970.01.01日开始? Unix
  • 时间戳:独一无二,过去就不再回来的时间印记。
  • 倒计时案例:

    1. 核心算法:输入的时间 - 现在的时间 = 剩余的时间即倒计时,但是不能拿着时分秒相减,比如05分-25分,结果是负数。
    2. 用时间戳来做,用户输入时间总的毫秒数 - 现在时间总的毫秒数 = 剩余时间的毫秒数。
    3. 把剩余时间总的毫秒数转化为天、时、分、秒(时间戳转换为时分秒)。
  • 时间戳转换时分秒:

    • d = parseInt(总秒数/60/60/24); // 计算天数
    • h = 总秒数/60/60%24; // 计算小时
    • m = 总秒数/60%60; // 计算分数
    • s = parseInt(总秒数%60); // 计算当前秒数

数组对象

  • 两种创建数组的方式:利用字面量或者利用 new Array()

    • var arr = [1,2,3]
    • var arr1 = new Array(); // 创建了一个空的数组
    • var arr2 = new Array(2); // 这个2表示数组的长度为2,里面有2个空的数组元素
    • var arr3 = new Array(2,3); // 等价于 [2,3] 表示里面有2个数组元素 2 和 3
  • 判断是否为数组的两种方式:

    • 运算符方式:arr instanceof Array true or false
    • 数组对象方法:Array.isArray(arr) true or false
  • 添加数组元素:

    • 方法|后面添加:push() 在数组的末尾 添加一个或者多个数组元素;push完毕之后,返回的结果是新数组的长度。
    • 方法|开头添加:unshift()在数组的开头 添加一个或者多个数组元素;unshift完毕之后,返回的结果是新数组的长度。
  • 删除数组元素:

    • 方法|末尾删除:pop() 删除数组的最后一个元素,它的返回值是“删除的那个元素”。
    • 方法|开头删除:shift() 删除数组开头的第一个元素,它的返回值是“删除的那个元素”。
  • 筛选数组:

    • 一种是以前的方法,newArr[newArr.length] = arr[i]
    • 新的方法:newArr.push(arr[i])
  • 数组排序:

    • arr.reverse()
    • arr.sort() 这个有点问题,完美写法:arr.sort(function(a,b){return a - b)})
  • 数组索引方法:arr.indexOf() arr.lastIndexOf() 返回索引号,若无返回-1。
  • 数组去重:核心算法,在新数组里对某个元素进行索引,如果返回值是-1,表明新数组里还没有这个元素,因此添加这个元素。
  • 数组转换为字符串:将数组转化为一个字符串。

字符串对象

  • 基本包装类型:把简单数据类型包装成一个复杂数据类型。

    • 简单数据类型是没有属性和方法的,只有对象才有。
    • string number Boolean 都可以被包装。
  • 字符串的不可变性:字符串里面的值不可变,虽然看上去可以改变内容,其实是地址变了,内存中开辟了一个内存空间,变量名指向这个空间。

    • 因此不要大量的给你的字符串进行重复赋值,也不要大量的拼接字符串。
    • 字符串所有的方法,都不会修改字符串本身(不可变性),操作完成会返回一个新的字符串。
  • 根据字符返回位置:str.indexOf('要查找的字符',[起始的位置])
  • 根据位置返回字符:str.charAt(index)

    • 返回相应索引号的字符ASCII码:str.charCodeAt(0)
    • str[index] H5新增方法
  • 字符串的操作方法:连接字符串和剪切字符串

    • concat(str1,str2,str3...) 连接两个或多个字符串,等效于+
    • substr(start,length) 从 start 位置开始, length 取得个数。sub 子的意思 substr 子串。不常用了。
    • slice(star,end) 从 start 位置开始,截取到 end 位置, end 取不到。
    • substring(start,end) 和 slice 相同, 但是不接受负值。
  • 字符串的操作方法:替换字符和字符转换为数组

    • replace(‘被替换的字符’,‘替换为的字符’)
    • split('分隔符') 将字符串转换为数组,和 join 的作用正好相反。
  • [ ] 一个作业待办,字符串对象的属性和方法练习。

JS 简单与复杂数据类型

介绍两种数据类型的 内存分配 情况,以及它们如何传递参数?

简单数据类型又叫做基本数据类型或者值类型;复杂类型又叫做引用类型,在存储时变量中储存的仅仅是地址(引用),因此得名。

  • 值类型:string number boolean undefined null 。
  • typeof 检测 null 类型 返回的是一个空的对象 object(JavaScript 的一个特别的地方)
  • 引用类型:通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date 等

堆和栈:

  • 栈:由操作系统自动分配释放 存放函数的参数值、局部变量的值等。简单数据类型直接将值存到栈里。
  • 堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型则将值所在的堆的地址(十六进制地址)存到栈里。注意:JavaScript 中没有堆栈的概念,只是通过堆栈的方式,更好理解代码的执行方式。

简单数据类型传参:

var num = 10;

num = 20;

console.log(num);

// 等价于:

var num; // 变量提升

num = 10;

num = 20; // 简单数据类型直接修改值

console.log(num);
function fn(a){

a++;

console.log(a);

}

var x = 10; // 变量提升, x 的值为10

fn(x);  //

console.log(x);

函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部变量。

复杂数据类型传参:

function Person(name){

    this.name = name;

}

 

function f1(x){ // x=p

    console.log(x.name); // 输出 刘德华

    x.name = "张学友";

    console.log(x.name); // 输出 张学友

}

 

var p = new Person("刘德华"); // p 是 Person 对象的一个实例,这是一个复杂数据类型,地址存在栈里.

console.log(p.name);  // 输出"刘德华"

f1(p); // 把 p 传递给 x, x = p,地址给了x

consol.log(p.name); // 刘德华更正为"张学友"

如果觉得我的文章对你有用,请随意赞赏