03-JS基础

编程语言

  • 编程:
    • 就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程。
  • 计算机程序:
    • 就是计算机所执行的一系列的指令集合,而程序全部都是用我们所掌握的语言来编写的,所以人们要控制计算机一定要通过计算机语言向计算机发出命令。

计算机语言

  • 计算机语言指用于人与 计算机之间通讯的语言,它是人与计算机之间传递信息的媒介。
  • 计算机语言的种类非常的多,总的来说可以分成机器语言,汇编语言和高级语言三大类。
  • 实际上计算机最终所执行的都是 机器语言,它是由“0”和“1”组成的二进制数,二进制是计算机语言的基础。

编程语言

定义 :可以通过类似于人类语言的“语言”来控制计算机,让计算机为我们做事情,这样的语言就叫做编程语言(Programming Language)。编程语言是用来控制计算机的一系列指令,它有固定的格式和词汇(不同编程语言的格式和词汇不一样),必须遵守。如今通用的编程语言有两种形式:汇编语言和高级语言。

  • 汇编语言 : 汇编语言和机器语言实质是相同的,都是直接对硬件操作,只不过指令采用了英文缩写的标识符,容易识别和记忆。

  • 高级语言 : 高级语言主要是相对于低级语言而言,它并不是特指某一种具体的语言,而是包括了很多编程语言,常用的有C语言、C++、Java、C#、Python、PHP、JavaScript、Go语言、Objective-C、Swift等。

翻译器

高级语言所编制的程序不能直接被计算机识别,必须经过转换才能被执行,为此,我们需要一个翻译器。翻译器可以将我们所编写的源代码转换为机器语言,这也被称为二进制化。

编程语言和标记语言区别⭐️

  • 编程语言 : 编程语言有很强的逻辑和行为能力。在编程语言里, 你会看到很多 if else 、for 、while等具有逻辑性和行为能力的指令,这是主动的。
  • 标记语言 : 标记语言(html)不用于向计算机发出指令,常用于格式化和链接。标记语言的存在是用来被读取的, 他是被动的。

总结

  1. 计算机可以帮助人类解决某些问题
  2. 程序员利用编程语言编写程序发出指令控制计算机来实现这些任务
  3. 编程语言有机器语言、汇编语言、高级语言
  4. 高级语言需要一个翻译器转换为计算机识别的机器语言
  5. 编程语言是主动的有很强的逻辑性

解释型语言和编译型语言

概述

计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言才能执行程序。程序语言翻译成机器语言的工具,被称为翻译器。

翻译器翻译的方式有两种:一个是编译 (java),另外一个是解释 (JS)。两种方式之间的区别在于翻译的时间点不同

编译器是在代码执行之前进行编译,生成中间代码文件

解释器是在运行时进行及时解释,并立即执行(当编译器以解释方式运行的时候,也称之为解释器)

执行过程

类似于请客吃饭:
编译语言:首先把所有菜做好,才能上桌吃饭
解释语言:好比吃火锅,边吃边涮,同时进行

关键字和保留字

标识符

标识(zhi)符:就是指开发人员为变量、属性、函数、参数取的名字。
标识符不能是关键字或保留字。

标识符命名规范

  • 变量、函数的命名必须要有意义
  • 变量的名称一般用名词
  • 函数的名称一般用动词

关键字

关键词、操作符之间后加空格

关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。
包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。

保留字

保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。

包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等。

注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,该单词将被看做关键字,如此将出现关键字错误。

计算机组成

数据存储

  1. 计算机内部使用二进制 0 和 1来表示数据。
  2. 所有数据,包括文件、图片等最终都是以二进制数据(0 和 1)的形式存放在硬盘中的。
  3. 所有程序,包括操作系统,本质都是各种数据,也以二进制数据的形式存放在硬盘中。平时我们所说的安装软件,其实就是把程序文件复制到硬盘中。
  4. 硬盘、内存都是保存的二进制数据。

大小关系:bit < byte < kb < GB < TB<.....

  • 位(bit): 1bit 可以保存一个 0 或者 1 (最小的存储单位)
  • 字节(Byte):1B = 8b
  • 千字节(KB):1KB = 1024B
  • 兆字节(MB):1MB = 1024KB
  • 吉字节(GB): 1GB = 1024MB
  • 太字节(TB): 1TB = 1024GB

程序运行⭐️

计算机运行软件的过程:

  1. 打开某个程序时,先从硬盘中把程序的代码加载到内存中
  2. CPU执行内存中的代码
    注意:之所以要内存的一个重要原因,是因为 cpu运行太快了,如果只从硬盘中读数据,会浪费cpu性能,所以,才使用存取速度更快的内存来保存运行时的数据。(内存是电,硬盘是机械)

初识 JavaScript

  • JavaScript 是世界上最流行的语言之一,是一种运行在客户端的脚本语言 (Script 是脚本的意思)
  • 脚本语言:不需要编译,运行过程中由 js 解释器( js 引擎)逐行来进行解释并执行
  • 现在也可以基于 Node.js 技术进行服务器端编程

JavaScript的作用

  • 表单动态校验(密码强度检测) ( JS 产生最初的目的 )
  • 网页特效
  • 服务端开发(Node.js)
  • 桌面程序(Electron)
  • App(Cordova)
  • 控制硬件-物联网(Ruff)
  • 游戏开发(cocos2d-js)

HTML/CSS/JS 的关系⭐️

浏览器执行 JS 简介⭐️

浏览器分成两部分:渲染引擎和 JS 引擎

  • 渲染引擎 : 俗称内核 , 内核就是用来解析 html 和 css , 如 chrome 浏览器的 blink , 老版本的 webkit
  • JS 引擎 : 也称为 JS 解释器 . 用来读取网页中的 Javascript 代码 , 对其处理后运行 , 如 chrome 浏览器的 V8

浏览器本身并不会执行JS代码,而是通过内置 JavaScript 引擎(解释器) 来执行 JS 代码 。JS 引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。

js 属于高级语言 , 计算机只识别机器语言 , 中间通过 js 引擎解释转换成二进制机器语言

JS 的组成⭐️

ECMAScript

ECMAScript 是由ECMA 国际( 原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。

ECMAScript:规定了JS的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套JS语法工业标准。

更多参看MDN: MDN手册

DOM——文档对象模型

文档对象模型(DocumentObject Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)

BOM——浏览器对象模型

浏览器对象模型(Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。

JavaScript 三种引入方式

JS 有3种书写位置,分别为行内内嵌外部

行内

    <!-- 1. 行内式的 js 直接写到元素内部 -->
    <input type="button" value="唐伯虎" onclick="alert('秋香姐')" />

可以将单行或少量 JS 代码写在HTML标签的事件属性中(以 on 开头的属性),如:onclick
注意单双引号的使用:在HTML中我们推荐使用双引号, JS 中我们推荐使用单引号
可读性差, 在html中编写JS大量代码时,不方便阅读;
引号易错,引号多层嵌套匹配时,非常容易弄混;
特殊情况下使用

内嵌

    <!-- 2. 内嵌式的 js -->
    <script>
      alert("沙漠骆驼");
    </script>

可以将多行JS代码写到 script 标签中
内嵌 JS 是学习时常用的方式

外部

    <!-- 3.外部 js script 双标签 -->
    <script src="./my.js"></script>

利于HTML页面代码结构化,把大段 JS代码独立到 HTML 页面之外,既美观,也方便文件级别的复用
引用外部 JS文件的 script 标签中间不可以写代码
适合于JS 代码量比较大的情况

JavaScript 注释

  • 单行注释
// (1).单行注释 ctrl + /
  • 多行注释
/* (2).多行注释; ctrl + shift + /
   (2).多行注释; */

JavaScript输入输出语句

方法 说明 归属
prompt (info) 浏览器弹出输入框,用户可以输入 浏览器
alert (msg) 浏览器弹出警示 浏览器
console . log(msg) 浏览器弹出控制台 , 用户可以查看 浏览器
  • 注意:alert() 主要用来显示消息给用户,console.log() 用来给程序员自己看运行时的消息。

变量

变量的概述

白话:变量就是一个装东西的盒子。

通俗:变量是用于存放数据的容器。 我们通过 变量名 获取数据,甚至数据可以修改。

变量在内存中的存储

本质:变量是程序在内存中申请的一块用来存放数据的空间。类似我们酒店的房间,一个房间就可以看做是一个变量。

变量的使用

变量的使用分为变量的声明变量的赋值

声明(declare)就是定义define、创建create的意思

声明变量★

var 声明的变量,不是函数作用域就是全局作用域。没有块级作用域

//  声明变量  
var age; //  声明一个 名称为age 的变量

var 是一个 js关键字,用来声明变量( variable 变量的意思 )。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管

age 是程序员定义的变量名,我们要通过变量名来访问内存中分配的空间

赋值

age = 10; // 给 age  这个变量赋值为 10

=== 号== 赋值 表示把等号右边的值 赋给 左边

== 判断 等号两边的值是否相等 . 默认转换数据类型 , 把字符串型的数据转换成数字型

=========== 全等 , 判断等号两边的值和数据类型完全一致

变量的初始化★

//情况1:声明时赋值
var age  = 18;  
//情况2:先声明后赋值
var age;
age=18;

变量的三个步骤

  1. 开辟内存空间 var xx;
  2. 给内存空间起名 var xx;
  3. 向空间中存数据 var xx=12;

变量案例 - 变量的使用

  1. 弹出一个对话框 , 提示用户输入姓名
  2. 弹出一个对话框 , 输出用户刚才输入的姓名
    <script>
      // 1. 用户输入姓名 存储到 name 变量中
      var name = prompt("输入姓名");
      // 2. 输出这个用户名
      alert(name);
    </script>

变量语法扩展

  • 更新变量

更新变量,一个变量被重新复赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。

var age = 18;
age = 81;   // 最后的结果就是81因为18 被覆盖掉了
  • 声明多个变量

同时声明多个变量时,只需要写一个 var, 多个变量名之间使用英文逗号隔开。

var age = 10,  name = 'zs', sex = 2;
  • 声明变量特殊情况
情况 说明 结果
var age ; console.log (age); 只声明 不赋值 undefined
console.log(age) 不声明 不赋值 直接使用 报错,要先定义变量再使用
age = 10; console.log (age); 不声明 只赋值 (全局变量) 10。不建议这么写,定义变量标准书写格式应该加var
      var a = b = c = 100;
      var a=100; // a 局部变量
          b=100;
          c=100; // b c 没有用 var 声明是全局变量

变量命名规范

1.由字母(A-Za-z)、数字(0-9)、下划线(_)、美元符号( $ )组成,如:usrAge, num01, _name

2.严格区分大小写。var app; 和 var App; 是两个变量

3.不能 以数字开头。 18age 是错误的

3.不能 是关键字、保留字。例如:var、for、while

5.变量名必须有意义。 MMD BBD nl → age

6.遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。myFirstName。比如haoYongliang这是小驼峰。HaoyongLiang这是大驼峰,在学习js高级之前都遵循小驼峰命名

推荐翻译网站: 有道 爱词霸

总结 : 由字母、数字、下划线、$组成,不能以数字开头

案列-交换两个变量的值

      // 1. 我们需要y一个临时变量帮我们
      //   2. 把 apple1 给我们临时变量
      //   3. 把apple2 里面的苹果给 apple1
      // 4. 把临时变量里的苹果 appl2
      var temp; //声明了一个临时变量
      var apple1 = "青苹果";
      var apple2 = "红苹果";
      temp = apple1; //把右边给左边
      apple1 = apple2;
      apple2 = temp;
      console.log(apple1);
      console.log(apple2);

小结

  • 为什么需要变量 ?

    • 因为我们一些数据需要保存 , 所以需要变量
  • 变量是什么 ?

    • 变量就是一个容器 , 用来存放数据的 , 方便我们以后使用里面的数据
  • 变量的本质是什么 ?

    • 变量是在内存里开辟一块内存空间 , 用来存放数据的
  • 变量怎么使用 ?

    • 先声明变量 , 然后赋值 .
    • 声明变量本质是去内存中申请开辟空间
  • 什么是变量的初始化 ?

    • 声明变量并赋值
  • 变量的命名规范 ?

    • 驼峰命名法
  • 交换 2 个变量值的思路 ?

    •     //   公式
          var temp = a;
          a = b;
          b = temp;
      

数据类型

数据类型的简介

  • 为什么需要数据类型

在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。

因为不同的数据占用不同的存储空间来划分的 , 根据占用的空间不同分为不同的数据类型

var age = 10;        // 这是一个数字型
var areYouOk = '是的';   // 这是一个字符串	
  • 变量的数据类型

JavaScript 是一种弱类型或者说动态语言。JS 的变量数据类型只有程序在运行过程中 , 根据等号右边的值来确定的

JS 是动态语言 , 变量的数据类型是可以变化的

var x = 6;           // x 为数字
var x = "Bill";      // x 为字符串

数据类型的分类★

JS 把数据类型分为两类:

1.简单数据类型 (Number,String,Boolean,Undefined,Null)

2.复杂数据类型 (object)

简单数据类型★

简单数据类型(基本数据类型)

Number,String,Boolean,Undefined,Null

JavaScript 中的简单数据类型及其说明如下:

数字型 Number★

数字运算异常 , 结果就是 NaN , 比如字符串 “abc” * 3 结果就是 NaN

JavaScript 数字类型既可以保存整数,也可以保存小数(浮点数)。

var age = 21;       // 整数
var Age = 21.3747;  // 小数

最常见的进制有二进制、八进制、十进制、十六进制。

 // 1.八进制数字序列范围:0~7
var num1 = 07;   // 对应十进制的7
var num2 = 019;  // 对应十进制的19
var num3 = 08;   // 对应十进制的8
 // 2.十六进制数字序列范围:0~9以及A~F
var num = 0xA 对应十进制的10;

八进制

      console.log(018 - 017);
      //          18- 15
      // 018 超出了 看成十进制
      // 017 没有超出 , 还是 8进制

数字型范围(了解)

JavaScript中数值的最大和最小值

  • 最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
  • 最小值:Number.MIN_VALUE,这个值为:5e-32

数字型三个特殊值(NaN需要知道什么意思)

  • Infinity ,代表无穷大,大于任何数值

  • -Infinity ,代表无穷小,小于任何数值

  • NaN ,Not a number,代表一个非数值

  • 面试题:如何判断是否是NaN

​ 方法一、isNaN(12)

​ 方法二、NaN 不等于 NaN

isNaN(了解)

nan==nan // false

用来判断一个变量是否为非数字的类型,是非数字返回 true 否则 false

      console.log(isNaN(21)); // 不是非数字返回 false
      console.log(isNaN("黑马")); // 是非数字返回 true

字符串型 String★

字符串型可以是引号中的任意文本,其语法为 双引号 “” 和 单引号’’

因为 HTML 标签里面的属性使用的是双引号,JS 这里我们更推荐使用单引号。

1.字符串引号嵌套★

JS 可以用单引号嵌套双引号 ,或者用双引号嵌套单引号 (外双内单,外单内双)

var strMsg = '我是"高帅富"程序猿';   // 可以用''包含""
var strMsg2 = "我是'高帅富'程序猿";  // 也可以用"" 包含''
//  常见错误
var badQuotes = 'What on earth?"; // 报错,不能 单双引号搭配

2.字符串转义符

类似HTML里面的特殊字符,字符串中也有特殊字符,我们称之为转义符。

转义符都是 \ 开头的,常用的转义符及其说明如下:

转义符 解释说明
\n 换行符,n 是 newline 的意思
\r 回车,光标到首行
\ \ 斜杠 \
‘ 单引号
" ”双引号
\t tab 缩进
\b 空格 ,b 是 blank 的意思

3.字符串长度【重要】

字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过字符串的 length 属性可以获取整个字符串的长度。

var strMsg = "我是帅气多金的程序猿!";
alert(strMsg.length); // 显示 11

4.字符串拼接【非常重要】

多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串

拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串

+号在遇到字符串之前是加法运算 , 遇到字符串后就变成拼接字符串

//1.1 字符串 "相加"
alert('hello' + ' ' + 'world'); // hello world
//1.2 数值字符串 "相加"
alert('100' + '100'); // 100100
//1.3 数值字符串 + 数值
alert('11' + 12);     // 1112

*+ 号总结口诀:数值相加 ,字符相连*

5.字符串拼接加强【非常重要】

console.log('pink老师' + 18);        // 只要有字符就会相连 
var age = 18;
console.log('pink老师age岁啦');      // 这样不行哦
console.log('pink老师' + age);         // pink老师18
console.log('pink老师' + age + '岁啦'); // pink老师18岁啦

经常会将字符串和变量来拼接,变量可以很方便地修改里面的值

变量是不能添加引号的,因为加引号的变量会变成字符串

如果变量两侧都有字符串拼接,口诀 **“ 引引加加 ” **,删掉数字,变量写加中间

ES6 模版字符串

// 模版字符串   
console.log(`今天是${year}${month}${tate}星期二`); 直接空格换行

案例 显示年龄

      var age = prompt("请输入您的年龄");
      var str = "您今年已经" + age + "岁了";
      alert(str);

布尔型Boolean★

布尔类型有两个值:true 和 false ,其中 true 表示真(对),而 false 表示假(错)。布尔型和数字型相加的时候, true 的值为 1 ,false 的值为 0。

console.log(true + 1);  // 2
console.log(false + 1); // 1

Undefined★

一个声明后没有被赋值的变量会有一个默认值undefined ( 如果进行相连或者相加时,注意结果)

undefined 和数字相加是 NaN

undefined 和布尔型相加是 NaN

undefined 和字符串拼接是字符串

var variable;
console.log(variable);           // undefined
console.log('你好' + variable);  // 你好undefined
console.log(11 + variable);     // NaN
console.log(true + variable);   //  NaN

Null★

一个声明变量给 null 值,里面存的值为(学习对象时,我们继续研究null)

  • null 和 数字相加是数字

  • null 和 布尔型相加是布布尔型对应的值

  • null 和字符串相加是字符串

var vari = null;
console.log('你好' + vari);  // 你好null
console.log(11 + vari);     // 11
console.log(true + vari);   //  1

获取变量数据类型

typeof 可用来获取检测变量的数据类型

var num = 18;
console.log(typeof num) // 结果 number

不同类型的返回值

通过控制台的颜色查看数据是什么类型

字面量

字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。

数字字面量:8, 9, 10

字符串字面量:’黑马程序员’, “大前端”

布尔字面量:true,false

数据类型转换★

  • 转换为字符串类型
  • 转换为数字型
  • 转换为布尔型
转换为字符串★

toString() 和 String() 使用方式不一样。

三种转换方式,更多第三种加号拼接字符串转换方式, 这一种方式也称之为隐式转换。

      // 1 . 把数字转换为字符串型 变量.tostring
      var num = 10;
      var str = num.toString();
      console.log(str);
      console.log(typeof str);
      //  2 . 利用String (变量)
      console.log(String(num));
      //   3 . 利用 + 拼接字符串方法实现转换 隐式转换
      console.log(num + "");
转换为数字型★

注意 parseInt 和 parseFloat 单词的大小写,这2个是重点

隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型

      //   1. parseInt(变量) 可以吧字符型的转为数字型 得到的是整数
      console.log(parseInt(age));
      console.log(parseInt("3.14")); // 3 整数
      console.log(parseInt("3.94")); // 3 整数
      console.log(parseInt("120px")); // 会去掉这个 px 单位 先读取 120 到了px识别不了 就把px 删掉
      console.log(parseInt("rem120px")); // 会去掉这个 px 单位 先读取 120 到了px识别不了 就把px 删掉
      //   2 . parseFloat(变量) 可以把字符型转换为数字型 得到的是小数点 浮点型
      console.log(parseFloat("3.14")); // 3.14
      console.log(parseFloat("120px")); //120
      console.log(parseFloat("rem120px")); //NaN
      //   3. 利用 Number (变量)
      var str = "123";
      console.log(Number(str));
      console.log(Number("12"));
      //   4 . 利用了算数 - * / 隐式转换
      console.log("12" - 0);
      console.log("12" * 1);
      console.log("12" / 1);

计算年龄案例

      var year = prompt("请输入你的出生年龄");
      var age = 2021 - year; // year 取过来的是字符型 , 但这里用了减号 , 有隐式转换
      alert("您今年" + age + "岁了");

简单加法案列

      var num1 = prompt("请你输入第一个数");
      var num2 = prompt("请你输入第二个数");
      var result = parseFloat(num1) + parseFloat(num2);
      alert("您输入的和为" + result);
转换为布尔型

代表空、否定的值会被转换为 false ,如 ‘ ’ 、0、null、NaN、undefined

其余值都会被转换为 true

      console.log(Boolean("")); // false
      console.log(Boolean(0)); // false
      console.log(Boolean(NaN)); // false
      console.log(Boolean(null)); // false
      console.log(Boolean(undefined)); // false

课后作业

      var myname = prompt("请输入你的姓名");
      var age = prompt("请输入你的年龄");
      var sex = prompt("请输入你的性别");
      alert("你的姓名是:" + myname + "\n你的年龄是:" + age + "\n你的性别是:" + sex);

运算符

运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。

JavaScript中常用的运算符有:

1.算数运算符(+,-,*,/)

2.递增和递减运算符(++,–-)

3.比较运算符(==,!=,>,< )

4.逻辑运算符(&&,||,!)

5.赋值运算符(=,+=)

+号一边是字符串,那么就是字符串运算符,而不是说一定会进行ToString转换而还是进行默认ToNumber转换,只有使用字符串模板才是进行ToString转换

 +号一边是字符串,那么就是字符串运算符,而不是说一定会进行ToString转换而还是进行默认ToNumber转换,只有使用字符串模板才是进ToString转换

算数运算符

概念:算术运算使用的符号,用于执行两个变量或值的算术运算。(+ - * /)

取余 % 9%2=1

浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数

  • 注意 : 不能直接拿浮点数来进行相比

  • 注意 : 运算符的两边需要加一个空格

      // 1. 取余 %
      console.log(4 % 2); // 0
      console.log(5 % 2); // 1
      console.log(2 % 5); // 2
      // 2. 浮点数
      console.log(0.1 + 0.2); //0.30000004
      console.log(0.07 * 100); // 7.000001
      // 3. 不能直接拿浮点数来进行相比
      var num = 0.1 + 0.2;
      console.log(num == 0.3); // false
  • 怎么判断一个数能够被整除
    • 用 % 取余运算符来判断 , 它的余数是 0 就说明这个数能被整除 ,

表达式和返回值

表达式:是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合

简单理解:是由数字、运算符、变量等组成的式子

表达式最终都会有一个结果,返回给开发者,称为返回值

在程序里面把右边表达式计算完毕把值返回给左边

      // 1 + 1 = 2
      // 在程序里面 2 = 1 + 1 把右边表达式计算完毕把值返回给左边
      var num = 1 + 1;

递增和递减运算符★

递增和递减运算符

如果需要反复给数字变量添加或减去1,可以使用递增(++)和递减( – )运算符来完成。

在 JavaScript 中,递增(++)和递减( – )既可以放在变量前面,也可以放在变量后面。放在变量前面时,我们可以称为前置递增(递减)运算符,放在变量后面时,我们可以称为后置递增(递减)运算符。

前置和后置型运算符之所以有上面的区别,是因为运算符的优先级。在各运算符按照优先级的不同由高到低排列顺序中:

注意:递增和递减运算符必须和变量配合使用。

前置递增运算符【前加加】

++age; || 类似于 age = age +1

++num 前置递增,就是自加1,类似于 num = num + 1,但是 ++num 写起来更简单。

使用口诀:先自加,后返回

var  num = 10;
alert(++num + 10);   // 21

后置递增运算符【后加加】

num++ 后置递增,就是自加1,类似于 num = num + 1 ,但是 num++ 写起来更简单。

使用口诀:先返回原值,后自加

      var age = 10;
      console.log(age++ + 10); //20
      console.log(age); // 11

前置递增和后置递增小结

  • 单独使用时 , 运算结果相同
  • 与其他代码联和使用时 , 执行结果会不同
  • 后置 : 先原值运算 , 后自加 ( 先人后己 )
  • 前置 : 先自加 , 后运算 ( 先己后人 )
  • 开发时,大多使用后置递增/减,并且代码独占一行,例如:num++;或num–。

递增运算题

      var a = 10;
      ++a; // 11 a = 11
      var b = ++a + 2; // a=12 ++ a = 12
      console.log(b); // 14

      var c = 10;
      c++; // c = 11
      var d = c++ + 2; // c ++ =11  c = 12
      console.log(d); // 13

      var e = 10;
      var f = e++ + ++e; // 1. e ++0 =10 e = 11  2. e = 12 ++ e = 12
      console.log(f); // 22 

      // 前置递减
      var num1 = 2;
      var num2 = 20;
      var num3 = --num1 + num2; // num1=1 --num1=1  1+20=21
      var num4 = num1 + num2; // 1+20=21
      console.log(num1 + "-" + num2 + "-" + num3 + "-" + num4); // 1 20 21 21
      // 后置递减
      var num1 = 2;
      var num2 = 20;
      var num3 = num1-- + num2; // num1=1 num1--=2  2+20=22
      var num4 = num1 + num2; // 1+21=21
      console.log(num1 + "-" + num2 + "-" + num3 + "-" + num4); // 1 20 22 21

      var a = 10;
      console.log(a++ + 10); // a++=10 a=11 10+10=20
      console.log(a); // 11
      a = 10;
      console.log(++a + 10); // ++a=11 a=11 11+10=21
      console.log(a); // 11

比较运算符★

比较运算符(关系运算符)是两个数 据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true / false)作为比较运算的结果。

等号小结 跳转

=== 号== 赋值 表示把等号右边的值 赋给 左边

== 判断 等号两边的值是否相等 . 默认转换数据类型 , 把字符串型的数据转换成数字型

=========== 全等 , 判断等号两边的值和数据类型完全一致

      console.log(3 == 3); // ture
      console.log(3 == "3"); // ture
      console.log(3 != 1); // ture
      console.log(3 != "3"); //false
      console.log(3 === "3"); // false
      console.log(3 !== "3"); // ture
      console.log(3 !== 3); // false

逻辑运算符★

逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值。后面开发中经常用于多个条件的判断

  • 逻辑与 && and
    • 两侧结果都为 true , 结果才是 true , 只要有一侧结果为 false 结果就为 false
      // 1. 逻辑与 &&
      console.log(2 > 1 && 1 < 2); // ture
      console.log(2 > 1 && 1 > 2); // false
  • 逻辑或 || or
    • 两侧结果都为 false 结果才是 false , 只要有一侧结果为 true 结果就为 true
      // 2. 逻辑或 ||
      console.log(2 > 1 || 1 > 2); // ture
      console.log(2 < 1 || 1 > 2); // false
  • 逻辑非 ! not
    • 也叫取反符 , 用来取一个布尔值相反的值 , 如 true 的相反值是 false
      // 3. 逻辑非 !
      console.log(!true); // false

逻辑中断 逻辑与

  • 原理 : 短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
  • 语法: 表达式1 && 表达式2
- 如果第一个表达式的值为真,则返回表达式2
- 如果第一个表达式的值为假,则返回表达式1

      console.log(123 && 456); // 456
      console.log(0 && 456); // 0
      console.log("" && 456); // 
      console.log(NaN && 456); // NaN
      console.log(null && 456); // null

逻辑中断 逻辑或

  • 语法 : 表达式1 || 表达式2
- 如果第一个表达式的值为真,则返回表达式1
- 如果第一个表达式的值为假,则返回表达式2

      console.log(123 || 456); // 123
      console.log(0 || 456); // 456
      console.log(123 || 456 || 789); // 123

逻辑中断很重要 , 它会影响我们程序运行结果

      var num = 0;
      console.log(123 || num++); 123 // 程序运行到 123 就结束了
      console.log(num); //0

赋值运算符

用来把数据赋值给变量的运算符。

var age = 10;
age += 5;  // 相当于 age = age + 5;
age -= 5;  // 相当于 age = age - 5;
age *= 10; // 相当于 age = age * 10;

运算符优先级

  • 一元运算符里面的逻辑非优先级很高
  • 逻辑与比逻辑或优先级高

练习 1

练习 2

流程控制

在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。

简单理解:流程控制就是来控制代码按照一定结构顺序来执行

流程控制主要有三种结构,分别是顺序结构分支结构循环结构,代表三种代码执行的顺序。

顺序流程控制

顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。

分支流程控制★

分支结构 : 由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果

JS 语言提供了两种分支结构语句:if 语句switch 语句

if 语句★

执行思路 : 如果 if 里面的条件表达式结果为 true 则执行大括号里的
如果 if 条件表达式结果为假 则不执行大括号里面的语句 则执行 if 后面的代码

      if (3 < 5) {
        alert("小于5");
      }

案例 - 进入网吧

案例分析

      var age = prompt("请输入你的年龄");
      if (age >= 18) {
        alert("你可以进入网吧");
      }

if else语句(双分支语句)★

执行思路 : 如果表达式结果为真 , 那么执行语句 1 , 否则执行语句 2

      var age = prompt("请输入你的年龄");
      if (age >= 18) {
        alert("你可以进入网吧");
      } else {
        alert("未成年不可以进入网吧");
      }
  • 双分支语句 ( 二选一 )

  • 分支语句 ( 多选一 )

案列 - 判断闰年

案例分析

      // 算法 : 能被 4 整除且不能被 100整除的为闰年 , 或者能被 400 整除的就是闰年
      var year = prompt("请您输入年份");
      if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
        alert("您输入的是闰年");
      } else {
        alert("您输入的平年");
      }

案例 - 判断是否中奖

要求 : 接受用户输入的姓名 , 来判断是否中奖 , 如果输入的是刘德华 ,则提示中奖 5 元 , 否则提示没有中奖

      var myname = prompt("请输入你的名字");
      if (myname == "刘德华") {
        alert("恭喜你中奖5元");
      } else {
        alert("很遗憾你和5元奖励只差一点点");
      }

if else if 语句(多分支语句)★

执行思路 : ① 如果条件表达式 1 , 满足就执行语句 1 , 执行完毕后退出整个循 if 分支语句

​ ② 如果条件表达式 1 不满足 , 则判断条件表达式 2 满足的话执行语句 2 ,以此类推

​ ③ 如果上面的所有条件表达式都不成立 , 则执行 else 里面的语句

注意点 :

  1. 多分支语句还是多选 1 , 最后只能执行一个语句
  2. else if 里面的条件理论上是可以任意多个的
  3. else if 中间有个空格

语法结构

// 适合于检查多重条件。
if (条件表达式1) {
    语句1} else if (条件表达式2)  {
    语句2} else if (条件表达式3)  {
   语句3....
} else {
    // 上述条件都不成立执行此处代码
}

案例 - 成绩查询

案例分析 :

① 弹出 prompt 输入框 , 让用户输入分数 score ,把这个值取过来保存到整个变量里面

​ ② 使用多分支语句 if else if 语句来判断不同值

​ ③ 按照从大到小的判断思路

      //    弹出 prompt 输入框 , 让用户输入分数 score ,把这个值取过来保存到整个变量里面
      //    使用多分支语句 if else if 语句来判断不同值
      //    按照从大到小的判断思路
      var score = prompt("请输入分数");
      if (score >= 90) {
        alert("A");
      } else if (score >= 80) {
        alert("B");
      } else if (score >= 70) {
        alert("C");
      } else if (score >= 60) {
        alert("D");
      } else {
        alert("E");
      }

三元表达式★

由三元运算符组成的式子我们称三元表达式

执行思路 :

如果表达式的值为 true ,则返回表达式1的值,如果表达式的值为 false,则返回表达式2的值

简单理解: 就类似于 if else (双分支) 的简写

语法结构 :

条件表达式 ? 表达式1: 表达式2
      var num = 8;
      var result = num > 5 ? "正确" : "错误";
      console.log(result);

案例 - 倒计时

案例分析 :

  1. 用户输入 0 ~ 59 之间的一个数字
  2. 如果用户小于 10 , 则在这个数字前面补 0 , 否则不做操作
  3. 用一个变量接收这个放返回值 ( result ) , 输出
      var time = prompt("请输入一个0-59的数字");
      var result = time < 10 ? "0" + time : time;
            time = time < 10 ? "0" + time : time;
      console.log(time);
//方法2
padStart() 用于头部补全;
padEnd() 用于尾部补全。
let strS = String(s).padStart(2, '0')
var h = time.getHours().toString().padStart(2, "0");

switch分支流程控制

switch : 转换 . 开关

case : 小例子 . 选项

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

执行思路 :

利用我们的表达式的值和 case 后面的选项值相匹配 , 如果匹配上 , 就执行该 case 里面的语句

如果都没有匹配上 , 那么执行 default 里面的语句

语法结构 :

break : 退出整个 switch

switch( 表达式 ){ 
    case value1:
        // 表达式 等于 value1 时要执行的代码
        break;
    case value2:
        // 表达式 等于 value2 时要执行的代码
        break;
    default:
        // 表达式 不等于任何一个 value 时要执行的代码
}
      switch (3) {
        case 1:
          console.log("这是1");
          break;
        case 2:
          console.log("这是2");
          break;
        case 3:
          console.log("这是3");
          break;
        default:
          console.log("没有匹配结果");
      }

switch 注意事项

  • switch :开关 转换 , case :小例子 选项
  • 关键字 switch 后面括号内可以是表达式或值, 通常是一个变量
  • 关键字 case , 后跟一个选项的表达式,后面跟一个冒号
  • switch 表达式的值会与结构中的 case 的值做比较
  • 如果存在匹配全等(===) ,则与该 case 关联的代码块会被执行,并在遇到 break 时停止,整个 switch 语句代码执行结束
  • 如果所有的 case 的值都和表达式的值不匹配,则执行 default 里的代码
  • break 如果当前的 case 里面没有 break 则不会退出 switch , 是继续执行下一个 case 里的语句 , 或者遇到 default 时停止

案例 - 查询水果

案例分析 :

注意 : 所有的水果必须加引号

      var fruit = prompt("请输入你要查询的水果");
      switch (fruit) {
        case "苹果":
          alert("苹果3元/斤");
          break;
        case "草莓":
          alert("草莓13元/斤");
          break;
        case "柚子":
          alert("柚子5元/斤");
          break;
        case "枇杷":
          alert("枇杷8元/斤");
          break;
        default:
          alert("没有此水果");
      }

switch 和 if else if 区别

  • 一般情况下,它们两个语句可以相互替换
  • switch 语句经常用于 case 值比较确定的情况下 , if else 常用于范围判断 (大于等于某个范围)
  • switch 语句进行条件判断时直接跳到要执行的条件语句 , if else 有几种条件就得判断几次
  • 当分支比较少时,if… else语句的执行效率比 switch语句高。
  • 当分支比较多时,switch语句的执行效率比较高,而且结构更清晰。

作业

作业 1

      var time = prompt("请输入时间");
      if (time == 12) {
        alert("中午好");
      } else if (time == 18) {
        alert("傍晚好");
      } else if (time == 23) {
        alert("深夜好");
      } else {
        alert("请继续输入");
      }

作业 2

      // 三元表达式
      var num1 = prompt("请输入第一个数值");
      var num2 = prompt("请输入第二个数值");
      var num3 = num1 > num2 ? num1 : num2;
      alert("最大值是:" + num3);
      // if else if
      if (num1 > num2) {
        alert("最大值是:" + num1);
      } else if (num1 < num2) {
        alert("最大值是:" + num2);
      } else {
        alert("请输入有效数值");
      }

作业 3

      var num = prompt("请输入一个数");
      if (num % 2 == 0) {
        alert("这是一个偶数");
      } else if (num % 2 != 0) {
        alert("这是一个奇数");
      } else {
        alert("请输入有效数字");
      }

作业 4

      var num = prompt("请输入一个数字");
      //   需要把用户输入的字符串转化为 数字型
      num = parseInt(num);
      console.log(typeof num);
      console.log(num);
      switch (num) {
        case 1:
          alert("今天星期一");
          break;
        case 2:
          alert("今天星期二");
          break;
        case 3:
          alert("今天星期三");
          break;
        case 4:
          alert("今天星期四");
          break;
        case 5:
          alert("今天星期五");
          break;
        case 6:
          alert("今天星期六");
          break;
        case 7:
          alert("今天星期日");
          break;
        default:
          alert("请重新输入一个1~7的数字");
      }

作业 5

      var money = prompt("请输入班长口袋里钱的数目");
      if (money >= 2000) {
        alert("请大家吃西餐");
      } else if (money >= 1500) {
        alert("请大家吃快餐");
      } else if (money >= 1000) {
        alert("请大家喝饮料");
      } else if (money >= 500) {
        alert("请大家吃棒棒糖");
      } else {
        alert("请输入数字");
      }

循环流程控制

for 循环

for 循环有三种

  1. for 循环
  2. while 循环
  3. do while 循环

语法结构

for(初始化变量; 条件表达式; 操作表达式 ){
    //循环体
}
名称 作用
初始化变量 就是用 var 声明的一个普通变量 , 这个变量帮我们来记录次数。
条件表达式 用于确定每一次循环是否能被执行。如果结果是 true 就继续循环,否则退出循环。
操作表达式 用于计数器变量更新的 , 是每次循环最后执行的代码

执行过程★

1.执行初始化变量 ( var i = 1) ,初始化操作在整个 for 循环只会执行一次。

2.执行条件表达式( i <=100),如果为true,则执行循环体语句,否则退出循环,循环结束。

3.执行操作表达式( i++),此时第一轮结束。

4.第二轮开始,直接去执行条件表达式( i <=100)(不再初始化变量),如果为 true ,则去执行循环体语句,否则退出循环。

5.继续执行操作表达式( i++),第二轮结束。

6.后续跟第二轮一致,直至条件表达式为假,结束整个 for 循环。

for 循环重复相同的代码

比如输出10句“媳妇我错了”

//  基本写法
for(var i = 1; i <= 10; i++){
    console.log('媳妇我错了~');
}
// 用户输入次数
var num = prompt('请输入次数:')for ( var i = 1 ; i <= num; i++) {
    console.log('媳妇我错了~');
}

for 循环重复不相同的代码

例如,求输出1到100岁:

for 里面添加了 if else if 多分支语句

// for 里面是可以添加其他语句的 
for (var i = 1; i <= 100; i++) {
 if (i == 1) {
    console.log('这个人今年1岁了, 它出生了');
 } else if (i == 100) {
    console.log('这个人今年100岁了,它死了');
  } else {
       conso	le.log('这个人今年' + i + '岁了');
  }
}

统计思想

可以统计个数(count)、和(sum)、积(amass)、平均值(avg)
但凡涉及到统计思想,我们可以使用固定步骤完成:
1.先在循环外面定义一个变量用来存储数据,
2.编写循环
3.在循环内部满足条件,进行统计即可(统计个数用++,求和用+=,求积用*=)

将1~100之间的偶数打印到控制台★

//1.编写循环,从1开始到100结束
for (var i = 1; i <= 100; i++) {
    //2.判断i的值是不是偶数,如果是偶数就输出到控制台
    if (i % 2 == 0) {
        console.log(i);
    }
}

统计 1 ~ 100 整数的和
案例分析 :

  1. 需要循环 100 次 , 我们需要一个计数器 i
  2. 我们需要一个存储结果的变量 sum , 但是 sum 的初始值是 0
  3. 核心算法 : 1 + 2 + 3 + 4 … , sum = sum + i ;

公式

问题 :

  1. for 循环里面 sum 每循环一次会把值传到 var 里面的 sum 吗
  2. log 打印出来的 sum 是 for 循环里面做了一次循环后的 sum 的值还是 var 里面 sum 的值
//1.在循环外定义变量sum,存累加的和
var sum = 0;

//2.定义循环
for (var i = 1; i <= 100; i++) {
    //3.因为是求和,所以要对sum进行累加操作
    sum += i;
}

console.log(sum);

案例 - 1. 求 1-100 之间所有数的平均值

问题 : 不在循环外面定义 avg 也可以输出平均值 ?, avg 没有参与循环体里面的运算

      // 1. 求 1-100 之间所有数的平局值
      // 在循环外定义 sum 和 avg
      var sum = 0;
      var avg = 0;
      for (var i = 1; i <= 100; i++) {
        sum += i;
      }
      avg = sum / (i - 1);
      console.log("1-100 之间所有整数的和是:" + sum); //5050
      console.log("1-100 之间所有数的平局值是:" + avg); //50.50

案例 - 2 .求1-100 之间所有偶数,奇数的和

      var even = 0;
      var odd = 0;
      for (var i = 1; i <= 100; i++) {
      // 判断是否满足条件
        if (i % 2 == 0) {
    //因为是求和,所以要对even进行累加操作        
          even += i;
        } else {
          odd += i;
        }
      }
      console.log("1~100之间所有的偶数和是:" + even); //2550
      console.log("1~100之间所有的奇数和是:" + odd); //2500

案例 - 3 .求1-100之间能被3整除的数字的和

      var result = 0;
      for (var i = 1; i <= 100; i++) {
        if (i % 3 == 0) {
          result += i;
        }
      }
      console.log("1-100之间有能被3整除的数字的和是:" + result); //1683

案例- 4 .求1~100之间偶数的个数

//1.在循环外定义变量count,记录个数
var count = 0;
//2.定义循环
for (var i = 1; i <= 100; i++) {
    //3.判断i是否满足条件
    if (i % 2 == 0) {
        //4.因为求个数,所以用++
        count++;
    }
}

console.log(count); // 50

问题 :循环体里面用 count += 1; 也能输出正确值

案例 - 求学生成绩

      var num = prompt("请输入班级人数");
      var sum = 0; //求和的变量
      var avg = 0; // 求平均值的变量
      for (var i = 1; i <= num; i++) {
        //定义一个变量保存输入的成绩
        var score = prompt("请输入第" + i + "个同学的成绩");
        sum += parseFloat(score);
      }
      // 求平均
      avg = sum / num;
      alert("班级的总成绩为:" + sum);
      alert("班级的平均成绩为:" + avg);

问题 : 循环体外面不定义 avg 也可以求出平均值 , 那定义这个 avg 有什么意义

案例 - 一行打印五颗星

      // 采用追加字符串的方式
      var num = prompt("请输入要打印的个数");
      var str = "";
      for (var i = 1; i <= num; i++) {
        str += "★";
      }
      alert(str);

双重 for 循环

概述

循环嵌套是指在一个循环语句中再定义一个循环语句的语法结构,外循环执行一次,内循环执行全部。

语法

for (外循环的初始; 外循环的条件; 外循环的操作表达式) {
    for (内循环的初始; 内循环的条件; 内循环的操作表达式) { 
       需执行的代码;
   }
}

内层循环可以看做外层循环的循环体语句

内层循环执行的顺序也要遵循 for 循环的执行顺序

外层循环执行一次,内层循环要执行全部次数

案列 - 五行五列星星

核心逻辑

  1. 内层循环负责一行打印五个星星
  2. 外层循环负责打印五行
      // 打印五行五列
      var str = "";
      for (var i = 1; i <= 5; i++) {
        // 外层循环负责打印五行
        for (var j = 1; j <= 5; j++) {
          // 里层循环负责一行打印五颗星星
          str = str + "★";
        }
        str = str + "\n"; // 转义字符换行
      }
      console.log(str);

n 行 n 列星星

      var rows = prompt("请你输入行数");
      var cols = prompt("请你输入列数");
      var str = ""; // 空的字符串
      for (var i = 1; i <= rows; i++) { // 外层行
        for (var j = 1; j <= cols; j++) { // 内层列
          str = str + "★";
        }
        str = str + "\n";
      }
      alert(str);

案例 - 打印倒三角

j = i , 行号给了列 , 每列不超过 10 个

第一行 1-10 打印10列

第二行 2-10 打印 9 列

第三行 3-10 打印 8 列

第四行 4-10 打印 7 列

第五行 5-10 打印 6 列

第六行 6-10 打印 5 列

核心算法 : 里层循环 : j = i ; j <=10 ; j++

      // 打印倒三角案例
    // **核心算法 : 里层循环 : j = i ; j <=10 ; j++**
      var str = "";
      for (var i = 1; i <= 10; i++) {  // 外层循环负责行
        for (var j = i; j <= 10; j++) {// 里层打印的列不一样 j=i
          str = str + "★";
        }
        str = str + "\n"; // 转义字符换行
      }
      console.log(str);

案例 - 打印正三角

列数从 1 开始打印 ( j = 1) , 要小于等于行号 ( j <= i )

      // 打印正三角案例
      var str = "";
      for (var i = 1; i <= 10; i++) {  // 外层循环负责行
        for (var j = 1; j <= i; j++) {// 里层打印的列不一样 j=i
          str = str + "★";
        }
        str = str + "\n"; // 转义字符换行
      }
      console.log(str);

案例 - 九九乘法表

案例分析

//知识点1 外循环控制行数  内循环控制列数
//知识点2 如何打印正三角形,外循环i<=9,内循环j<=i
//知识点3 字符串拼接

var str = "";
for (var i = 1; i <= 9; i++) {
    for (var j = 1; j <= i; j++) {
        // 列乘行 = j * i 后面拼接空格
        str += j + "*" + i + "=" + i * j + "\t";
        // str += `${j}×${i}=${j * i}\t`;
    }
    str += "\n";
}
console.log(str);

倒乘法表

      var str = "";
      for (var i = 1; i <= 9; i++) {
        for (var j = i; j <= 9; j++) {
          str += i + "*" + j + "=" + j * i + "\t";
        }
        str += "\n";
      }
      console.log(str);

for 循环小结

  • for 循环可以重复执行某些相同代码
  • for 循环可以重复执行些许不同的代码,因为我们有计数器
  • for 循环可以重复执行某些操作,比如算术运算符加法操作
  • 随着需求增加,双重for循环可以做更多、更好看的效果
  • 双重 for 循环,外层循环一次,内层 for 循环全部执行
  • for 循环是循环条件和数字直接相关的循环

while 循环

语法结构

while (条件表达式) {
    // 循环体代码 
    // 操作表达式
}for 循环相似
for (var i = 1; i <= 100; i++)

执行思路:

1 先执行条件表达式,如果结果为 true,则执行循环体代码;如果为 false,则退出循环,执行后面代码

2 执行循环体代码

3 循环体代码执行完毕后,程序会继续判断执行条件表达式,如条件仍为true,则会继续执行循环体,直到循环条件为 false 时,整个循环过程才会结束

初始化变量; 条件表达式; 操作表达式

注意 : 使用 while 循环时一定要注意,它必须要有退出条件,否则会成为死循环

案例 - 打印人的一生

      // 打印人的一生
      var i = 1; //初始化变量
      while (i <= 100) { // 条件表达式
        console.log("你今年" + i + "岁了");
        i++; // 操作表达式 退出循环体条件
      }

案例 - 1-100 整数的和

      // 1-100 所有整数的和
      var sum = 0; // 存储和的变量
      var j = 1; // 初始化变量
      while (j <= 100) { // 条件表达式
        sum += j; 
        j++; // 操作表达式 退出循环体条件
      }
      console.log(sum); // 5050

案例 - 你爱我吗 ?

案例分析

      // 弹出一个对话框 提示你爱我吗
      var message = prompt("你爱我吗?");
      while (message !== "我爱你") {
        message = prompt("你爱我吗?");
      }
      alert("我也爱你呀宝~!")

输入用户和密码

      var user = prompt("输入用户名");
      var password = prompt("输入密码");
      while (user != "admin" || password != "123456") {
        user = prompt("输入用户名");
        password = prompt("输入密码");
      }
      alert(" 输入正确");

do-while循环

语法结构

do {
    // 循环体代码 - 条件表达式为 true 时重复执行循环体代码
} while(条件表达式);

执行思路

1 先执行一次循环体代码

2 再执行条件表达式,如果结果为 true,则继续执行循环体代码,如果为 false,则退出循环,继续执行后面代码

注意 : 先再执行循环体,再判断,do…while循环语句至少会执行一次循环体代码

案例 - 打印人的一生

      // 打印人的一生
      var i = 1;
      do {
        // 先执行循环体
        console.log("这个人" + i + "岁了");
        i++;
      } while (i <= 100); // 在判断

案例 - 1-100 整数的和

      // 计算 1-100 整数的和
      var sum = 0; // 存储和的变量
      var j = 1; // 初始化变量
      do {
        sum += j;
        j++; // 操作表达式 退出循环体条件
      } while (j <= 100); // 条件表达式
      console.log(sum);  // 5050

案例 - 你爱我吗 ?

      // 弹出一个对话框 提示你爱我吗
      do {
        var message = prompt("你爱我吗?"); // 执行循环体
            alert("我也爱你啊~宝");
      } while (message !== "我爱你"); // 条件表达式

循环小结

  • js 中循环有 for while do while
  • 三个循环很多情况下都可以相互替代使用
  • 如果是采用计次数的 , 跟数字相关的 , 三者使用基本相同 , 但是更喜欢用 for
  • while 和 do while 可以做更复杂的判断条件 , 比for 循环灵活一些
  • while 和 do while 执行顺序不一样 , while 先判断后执行 , do while 先执行一次在判断
  • while 和 do while 执行次数不一样 , do while 至少会执行一次循环体 , 而 while 可能一次也不执行
  • 实际工作中 , 更常用 for 循环 , 它语法更简洁直观 , 重点学习这个

continue

continue 关键字用于立即跳出本次循环继续下一次循环(本次循环体中 continue 之后的代码就会少执行一次)。

例如,吃5个包子,第3个有虫子,就扔掉第3个,继续吃第4个第5个包子,其代码实现如下:

// continue 关键字 退出本次循环 继续执行剩余次数
for (var i = 1; i <= 5; i++) {
    if (i == 3) {
        console.log('这个包子有虫子,扔掉');
        continue; // 跳出本次循环,跳出的是第3次循环 
    }
    console.log('我正在吃第' + i + '个包子呢');
}

案例 - 求1-100之间 除了能被7 整除数的和

      // 求1-100之间 除了能被7 整除数的和
      var sum = 0;
      for (var i = 1; i <= 100; i++) {
        if (i % 7 == 0) {
          continue;
        }
        sum += i;
      }
      console.log(sum); //4315
      var count = 1; // 21
      var num = 21;
      while (count != 35) {
        num += 21;
        count++;
      }
      console.log(num);

break

break 关键字用于立即跳出整个循环(循环结束)。

例如,吃5个包子,吃到第3个发现里面有半个虫子,其余的不吃了,其代码实现如下:

for (var i = 1; i <= 5; i++) {
    if (i == 3) {
        break; // 直接退出整个for 循环,跳到整个for下面的语句
    }
    console.log('我正在吃第' + i + '个包子呢');
}

区别 :

continue 关键字用于立即跳出本次循环继续下一次循环

break 关键字用于立即跳出整个循环(循环结束)

作业

相当于 if 里面的count每加1 , 上面的 num 就会执行21次 (num+21)

      var count = 1; // 21
      var num = 21;
      while (count != 35) {
        num++;
        if (num % 3 === 0 && num % 7 === 0) {
          count++;
        }
      }
      console.log(num);
      //  第35个能被7和3整除的数是多少
      // 定义一个计数器 / 记录能被7和3 同时整除的个数
      var count = 0;
      // 条件表达式 i+1 , 灵活不写死
      // 停止条件 count==35 , break. /不加break就陷入死循环
      for (var i = 1; i <= i + 1; i++) {
        if (i % 7 == 0 && i % 3 == 0) {
          count++;
          if (count == 35) {
            console.log("第35个是" + i + "");
            break;
          }
          console.log("第" + count + "个数是" + i);
        }
      }  // 375

数组

概念

数组 : 存储同一类数据的容器 container

数组 可以把一组数据的集合存放在单个变量下

数组,顾名思义,是相同类型的数组成的一个组,也就是说是把相同类型的一系列数据统一编制到某一个组别中。这样就可以通过数组名+索引号简单快捷的操作大量数据。
数组是指一组数据的集合,其中的每个数据被称作元素(element),在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。

JS 中创建数组方式有两种 :

  • 利用 new 创建数组
  • 利用数组字面量创建数组

利用 new 创建数组

语法

var 数组名 = new Array()var arr = new Array();   // 创建一个新的空数组

注意 Array () ,A 要大写

利用数组字面量创建数组

//1. 使用数组字面量方式创建空的数组
var  数组名 = [];
//2. 使用数组字面量方式创建带初始值的数组
var  数组名 = ['小白','小黑','大黄','瑞奇'];

数组里面的数据要用逗号分隔

数组的字面量是方括号 [ ]

声明数组并赋值称为数组的初始化

这种字面量方式也是我们以后最多使用的方式

数组中可以存放任意类型的数据,例如字符串,数字,布尔值等。

var arrStus = ['小白',12,true,28.9];

获取数组中的元素★

数组名 + 索引

索引 (下标) :用来访问数组元素的序号(数组下标从 0 开始)。

// 定义数组
var date = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"];
// 获取数组中第 7 个元素
console.log(date[6]); // 星期日

注意:如果访问时数组没有和索引值对应的元素,则得到的值是undefined

遍历数组★

数组遍历

把数组中的每个元素从头到尾都访问一次(类似学生的点名),可以通过 for 循环索引遍历数组中的每一项

for 里面的 i 是计数器 , 当索引使用

var arr = ['red','green', 'blue'];
for(var i = 0; i < arr.length; i++){
    console.log(arrStus[i]);
}

数组的长度

数组的长度:默认情况下表示数组中元素的个数

使用**“数组名.length”**可以访问数组元素的数量(数组长度)。

var arrStus = [1,2,3];
alert(arrStus.length);  // 3

注意

索引号是从 0 开始的 , 数组的长度是元素的个数

此处数组的长度是数组元素的个数 ,不要和数组的索引号混淆。

当我们数组里面的元素个数发生了变化,这个 length 属性跟着一起变化 ( 动态检测数组元素的个数)

数组的length属性可以被修改:

如果设置的length属性值大于数组的元素个数,则会在数组末尾出现空白元素

如果设置的length属性值小于数组的元素个数,则会把超过该值的数组元素删除

数组案例

案例 - 统计思想-求和/平均值

案列分析

  1. 声明一个求和变量 sum 和求平均值变量 avg
  2. 遍历这个数组 , 把里面每个数组元素加到 sum 里面
  3. 用求和变量 sum 除以数组的长度就可以得到数组的平均值
      // 求数组 [2,6,1,7,4] 里面所有元素的和以及平均值
      // 技术点1 遍历数组
      // 把数组元素的值累加到数组里面
      var sum = 0; // 声明一个求和的空变量
      var arr = [2, 6, 1, 7, 4];
      var avg = 0; // 声明一个求平均值的空变量
      for (var i = 0; i < arr.length; i++) { // 遍历数组
        sum += arr[i]; // 我们加的是数组元素 不是计数器
      }
      avg = sum / arr.length
      console.log("和是"+sum,"平均值是"+avg); // 20 4
      // 想要输出多个变量 , 用逗号分割即可
案列 - 求数组最大值

案列分析

  1. 声明一个保存最大元素的的变量 max
  2. 默认最大值可以取数组中的第一个元素
  3. 遍历这个数组 , 把里面每个数组元素和 max 做比较
  4. 如果这个数组元素大于 max 就把这个数组元素放到 max 里面 , 否则继续下一轮比较
  5. 最后输出 max
      // 求数组[2,6,1,77,52,25,7]中的最大值
      // 技术点1 遍历数组
      // 技术点2 用if来判断大于索引为0 的值
      // 技术点3 赋值,把大于max的值赋值给 max
      var arr = [2, 6, 1, 77, 52, 25, 7];
      var max = arr[0]; // 声明最大变量 并赋值数组第一个数字
      for (var i = 1; i < arr.length; i++) { // 遍历数组
        if (arr[i] > max) { // 判断条件 , 依次做比较
          max = arr[i]; // 大于的就把值赋值给 max
        }
      }
      console.log("该数组中的最大值是:"+max); // 77
案例 - 将数组中的数据按照指定的字符拼接成字符串
      // 数组转换为分割字符串
      var arr = ["red", "green", "blue", "pink"];
      var str = "";
      var sep = "卐"; // 定义一个字存放符变量
      for (var i = 0; i < arr.length; i++) {
        str += arr[i] + sep;
      }
      console.log(str);

新增数组有两种方式:

  1. 修改数组 length 长度 arr.length = 5
  2. 修改数组索引号 , 追加数组元素 arr[4]="gray"

修改数组 length 长度

  • length 属性是可读写的

  • 声明变量未给值就是 undefined

      var arr = ["red", "green", "blue"];
      arr.length = 5; // 把数组长度修改成了5
      console.log(arr);
      console.log(arr[3]); // undefined
      console.log(arr[4]); // undefined

修改数组索引号

  • 可以通过修改素组索引的方式追加数组元素 , 是常用的一种方式

  • 不能直接给数组名赋值 , 否则会覆盖掉以前的数据

      var arr = ["red", "green", "blue"];
      arr[3]="pink"
      arr[4]="gray"
      arr[0]="yellow" // 修改组中的元素
      console.log(arr);

向数组中增加元素★

arr[arr.length]="black"

      // 数组[ 数组.length ] = 新数据;
      var arr = ["red", "green", "blue"];
      // 向数组中添加两个元素
      arr[3] = "加1 "  // 如果索引不在表示添加
      arr[2] = "加1 "  // 如果索引在表示修改
      arr[arr.length]="yellow"
      arr[arr.length]="black"
      console.log(arr);

修改数组中的元素★

数组[ 索引 ] =;

数组案例

案例 - 数组存放 1-10 用 for 循环

案例分析

核心原理 : 使用 for 循环来追加数组

  1. 声明一个空数组 arr
  2. 循环中的计数器 i 可以作为数组元素存入
  3. 由于数组索引是从 0 开始的 , 因此计数器从 0 开始更合适 , 存入得到数据要加 1
      // 技术点1 先数组中添加数据  arr[i] = i
      var arr = [];
      for (var i = 0; i < 10; i++) {
        arr[i] = i + 1; // i=0 arr[0] i=1 arr[1] 
        // i为索引 i为值
      }
       console.log(arr);
案例 -筛选出大于 10 的放入新数组 (筛选数组)

案例分析

  1. 声明一个新的数组用于存放新数据 newArr
  2. 遍历原来的旧数组 , 找出大于等于 10 的元素
  3. 依次追加给新数组 newArr

arr.length 赋值一个变量 小优化

  • 不用每次重新渲染 , 减少数据库压力
      var arr = [2, 0, 13, 4, 5, 9, 24, 54, 11];
      var newArr = [];
      var len=arr.length // 变量
      for (var i = 0; i < len; i++) { // len 常亮 不用每次重新渲染 数组长度
        if (arr[i] > 10) {
          newArr[newArr.length] = arr[i];
          // newArr.push(arr[i]); // push 添加到新数组的最后面
        }
      }
      console.log(newArr);
      // 技术点1 遍历数组
      // 技术点2 用 if 筛选出大于10的元素
      // 技术点3 如何向数组中添加数据newArr[newArr.length]=值
     var arr = [2, 0, 13, 4, 5, 9, 24, 54, 11];
      var newArr = [];
      for (var i = 0; i < arr.length; i++) {
        if (arr[i] >= 10) {
            // 新数组应该从 0 开始 , 依次递增
            // 也可以新定义一个变量值为 0 , 0给newArr做索引 , 每执行完一次 +1
          newArr[newArr.length] = arr[i];
          // newArr.push(arr[i]);  //push
        }
      }
      console.log(newArr);
案例 - 数组去重
  • indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
  • 找到就返回对应字符串出现的索引 , 找不到就返回-1
      var arr = [1, 2, 1, 1, 2, 5, 21432, 112, 1, 2, 1];
      var newArr = [];
      // indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
      // 如果要检索的字符串值没有出现,则该方法返回 -1。
      for (var i = 0; i < arr.length; i++) {
        // =-1 说明在新数组里找到不到这个数 , 所以就添加到新数组后面
        if (newArr.indexOf(arr[i]) === -1) {
          newArr.push(arr[i]);
        }
      }
      console.log(newArr);
      // 删除指定数组元素 把 0 删掉
      var arr = [1, 5, 0, 10, 0, 15, 20, 0];
      var newArr = [];
      for (var i = 0; i < arr.length; i++) {
        if (arr[i] != 0) {
          newArr[newArr.length] = arr[i];
        }
      }
      console.log(newArr);
案例 - 翻转数组

案例分析

  1. 声明一个新数组
  2. 遍历旧数组从后往前遍历 , i=arr.length-1 , 给新数组索引号第 0 个元素 newArr[newArr.length]
  3. 采用递减方式 i - -
      // 数组翻转
//知识点1 数组的遍历 倒着遍历
//知识点2 获取数组中的最大索引arr.length-1
//知识点3 向数组中添加数据 arr[arr.length] = 值

      var arr = [1, 2, 3, 4, 5];
      var newArr = [];
      // 旧数组从 后往前 遍历 , 索引号=数组.length-1
      for (var i = arr.length-1; i >= 0; i--) {
        // 新数组刚开始.length=0
        newArr[newArr.length] = arr[i];
      }
      console.log(newArr); // 54321
      // arr.reverse()  //原数组里直接翻转
将数组中的两个元素互换位置
//知识点  temp=a; a=b;b=temp;
var arr = ["胡斌", "张佳", "田田", "倩文"];

//需求:将0位置的数据和3位置的数据互换位置
var temp = arr[0];
arr[0] = arr[3];
arr[3] = temp;
案例 - 冒泡排序

冒泡排序 : 是一种算法 , 把一系列的数据按照一定的顺序进行排列显示

原理 : 依次比较两个元素 , 如果他们的顺序错误就把他们交换过来 ( 相邻两个元素两两比较,大的往后放 )

有交换的趟数 , 又有每趟交换的次数

外循环的次数是它本身 length 的长度少一次 , 数组是从 0 开始循环的 , 所以还得减1: arr . length -1

知识点

  1. 外层 for 循环 (趟数) arr.length-1
  2. 内层 for 循环 (次数) arr.length-i-1
  3. 交换两个变量

arr.length - i - 1 (- i:是减去外循环的索引号 ; -1 是因为索引从0开始的 )

问题 : 内循环的执行次数是

      var arr = [5, 4, 3, 2, 1];
      // 外循环控制循环趟数 , 趟数比较的次数会比数组的长度小一, 两两相比 , 最后一个数不用做比较了 所以就 arr.length-1; 内循环做优化 -i
      for (var i = 0; i < arr.length - 1; i++) {
        // 内循环控制循环次数 , 每走完一趟内循环两两相比的次数就会减少一次
        for (var j = 0; j < arr.length - i - 1; j++) {
          // 当前元素和它后一个 做比较 , 如果大于它就把他两交换位置 , 继续做比较
          if (arr[j] > arr[j + 1]) {
            var temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
            // 交换位置 解构
            // [newArr[j], newArr[j + 1]] = [newArr[j + 1], newArr[j]];
          }
        }
      }
      console.log(arr);
var arr = [3, 2, 4, 5, 6, 434, 12, 46];

//外循环控制轮数公式arr.length-1
for (var i = 0; i < arr.length - 1; i++) {
    //内循环控制每一轮的比较次数,公式 arr.length-1-i
    for (var j = 0; j < arr.length - i - 1; j++) {
        //做比较,互换数组中的2个元素公式 temp=a;a=b;b=temp;
        if (arr[j] < arr[j + 1]) { // 大到小
            var temp = arr[j];
            arr[j] = arr[j + 1]; // 大的赋值到arr[j]
            arr[j + 1] = temp;
        }
    }
}

console.log(arr);

查询目标元素在数组中第一次出现的索引

函数

概念

函数:就是封装了一段可被重复调用执行的代码块

作用 : 可以实现大量代码的重复使用

函数的使用

声明变量需要加 var , 声明函数需要加 function 关键字

  • 函数的使用分为两步 :
  1. 声明函数
  2. 调用函数

声明函数

// 声明函数
function 函数名() {
    //函数体代码
}

function 是声明函数的关键字,必须小写

由于函数一般是为了实现某个功能才定义的, 所以通常我们将函数名命名为动词,比如 getSum

调用函数

// 调用函数
函数名();  // 通过调用函数名来执行函数体代码

调用的时候千万不要忘记添加小括号

口诀:函数不调用,自己不执行

注意:声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码。

封装函数

函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口 ( 打包 )

简单理解:封装类似于将电脑配件整合组装到机箱中 ( 类似快递打包)

案例 - 封装计算1-100累加和

   计算1-100之间值的函数
// 声明函数
function getSum(){
  var sumNum = 0;// 准备一个变量,保存数字和
  for (var i = 1; i <= 100; i++) {
    sumNum += i;// 把每个数值 都累加 到变量中
  }
  alert(sumNum);
}
// 调用函数
getSum();

函数的参数

函数可以重复相同的代码

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

  • 声明函数的小括号里面是形参 , 形参是接收实参的 ( 通过形参定义变量 )
  • 调用函数的小括号里面是实参 , 实参是传给形参的 ( 通过实参给变量赋值 )
参数 说明
形参 式上的参数 函数定义的时候传递的参数 形参是接收实参
实参 际上的参数 函数调用的时候传递的参数 实参是传递给形参

案例 - 利用函数求任意两个数的和

      // 1. 利用函数求任意两个数的和
      // 声明函数 形参
      function getSum(num1, num2) {
        console.log(num1 + num2);
      }
      // 调用函数 实参
      getSum(1, 100); // 101  5050
      getSum(1, 10); // 11  55

案例 - 利用函数求任意两个数之间的和

技术点 :

  1. 使用了函数形参里面传实参
  2. 函数体里面使用了 for 循环进行累加
      // 2. 利用函数求任意两个数之间的和
      // 声明函数 形参
      function getSum(start, end) {
        var sum = 0;
        for (var i = start; i <= end; i++) {
          sum += i;
        }
        console.log(sum);
      }
      // 调用函数 实参
      getSum(1, 100); // 5050
      getSum(1, 10); // 55

问题 代码: 有两个函数名相同 执行过程是怎样? 不执行 第一个函数 num1 +num2 ?(覆盖?)

      // 1. 利用函数求任意两个数的和
      // 声明函数 形参
      function getSum(num1, num2) {
        console.log(num1 + num2);
      }
      // 调用函数 实参
      getSum(1, 100); // 101  5050
      getSum(1, 10); // 11  55

      // 2. 利用函数求任意两个数之间的和
      // 声明函数 形参
      function getSum(start, end) {
        var sum = 0;
        for (var i = start; i <= end; i++) {
          sum += i;
        }
        console.log(sum);
      }
      // 调用函数 实参
      getSum(1, 100); // 5050
      getSum(1, 10); // 55

案例 - 求两个数之间最大值

function getMax(a, b) {
    var max = a > b ? a : b;
    console.log(max);
}
//调用函数
getMax(1,2);

函数形参和实参数量不匹配时

参数个数 说明
实参个数等于形参个数 输出正确结果
实参个数多于形参个数 只取到形参的个数
实参个数小于形参个数 多的形参定义为 undefined , 结果为 NaN

因为 : 形参可以看做不用声明的变量 , 没有被传入参数的形参2 是一个变量但是没有接收值(只声明不赋值) , 结果就是 undefined

注意:在JavaScript中,形参的默认值是undefined

小结

函数可以带参数也可以不带参数

声明函数的时候,函数名括号里面的是形参,形参的默认值为 undefined

调用函数的时候,函数名括号里面的是实参

多个参数中间用逗号分隔

形参的个数可以和实参个数不匹配,但是结果不可预计,我们尽量要匹配

函数的返回值

函数内部不应该有输出语句 , 应该把函数输出的结果返回给函数的调用者

函数名

函数只是实现某种功能 , 最终的结果需要返回给函数的调用者 , 通过 return 实现的

  • 只要函数遇到 return 就把后面的结果返回给函数的调用者 .

  • 在使用 return 语句时,函数会停止执行,并返回指定的值

  • 函数都是有返回值的 , 如果有 return 则返回 return 后面的值

  • 如果函数没有 return ,返回的值是 undefined

// 声明函数
function 函数名(){
    ...
    return  需要返回的值;
}
// 调用函数
函数名();    // 此时调用函数就可以得到函数体内return 后面的值

案例 - 利用函数求两个数的最大值

      function getMax(num1, num2) { // 声明函数
        // 用 if 语句来判断
        if (num1 > num2) {
          return num1; // 函数返回值
        } else {
          return num2;
        }
        // 用三元表达式来判断
        return num1 > num2 ? num1 : num2;
      }
      console.log(getMax(215, 242)); // 调用函数
      console.log(getMax(415, 242));

案例 - 利用函数求数组中的最大值

技术点 :

  1. 声明函数调用函数
  2. 用 for 循环遍历数组
  3. 循环体中的表达式用 if 语句
  4. 输出返回结果
  5. 简写函数的返回结果
      function getArrMax(arr) {
        var max = arr[0];
        for (var i = 1; i <= arr.length; i++) {
          if (arr[i] > max) {
            max = arr[i];
          }
        }
        return max; // 返回结果
      }
      // 实际开发中 , 我们常用一个变量来接收 函数的返回结果更简单    
// 简写方式 1    
      var re = getArrMax([ 65, 12, 85, 100]);
      var re = getArrMax([100, 102, 52, 299]);
      console.log(re);

//简写方式2
// var array = [231, 12, 47, 232];
// var max = getMax(array);
// console.log(max);

案例 - 编写函数 , 查找指定元素在数组中第一次出现的索引

      // 编写函数 , 查询指定元素在数组中第一次出现的索引并返回 ,查不到返回-1
      // 查询target 在array 数组中第一次出现的索引
      function indexOf(array, target) {
        for (var i = 0; i < array.length; i++) {
          if (array[i] == target) {
            return i;
          }
        }
        return -1; // 查不到返回-1 要写到循环外面 , 如果查第一个查不到就停止循环退出了 不会进行第二次循环
      }
      var re1 = indexOf([12, 14, 15, 22, 33], 14);
      console.log(re1);

函数返回值注意的事项

  1. return 终止函数的作用 , return 后面的代码不会被执行
  2. return 只能返回一个值 , 返回的结果是最后一个值 ,没有return 返回的是 undefines , 页面跳转不需要写返回值也可以 .
  3. 想要输出多个值利用数组 , 对象等 , 返回的是一个数组 然后用遍历循环里面的每个值

break ,continue ,return 的区别

break :结束当前的循环体(如 for、while)

continue :跳出本次循环,继续执行下次循环(如 for、while)

return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码

为什么有return : 函数外部不可以访问函数内部变量

总结 : break 和 continue 只针对于循环 , return 不仅仅针对循环还对函数返回值还退出循环

作业

03-JS基础_第1张图片

03-JS基础_第2张图片

判断是不是一个质数

      // 写一个函数 , 判断传入的数值是否是质数, 如果是质数返回true,不是返回false
      // 质数 (从2开始只能被1和自身整除的数)
      function isPrime(num) {
        for (var i = 2; i < num; i++) {
          // 遍历2到 num 看有没有被其他数整除的
          if (num % i === 0) {
            return false;
            // 有的话返回 false
          }
        }
        return true;
        // 都遍历完还没有就返回 true
      }
      var res1 = isPrime(13);
      var res2 = isPrime(12);
      console.log(res1); // true
      console.log(res2); // false
      console.log("-----------------------");

03-JS基础_第3张图片

  • return 里面 不在执行后面的
  • return 外面 返回函数调用者

arguments的使用

当不确定有多少个参数传递的时候,可以用 arguments 来获取。JavaScript 中,arguments实际上它是当前函数的一个内置对象。只有函数才有**arguments 而且每个函数都内置了一个 arguments 对象,**arguments 对象中存储了传递的所有实参。arguments展示形式是一个伪数组,因此可以进行遍历。

  • 什么是arguments?

arguments实际上它是当前函数的一个内置对象。只有函数才有arguments

  • 作用 ?

存放了所有用户传递过来的实参

  • 什么时候使用?

当用户不确定有多少个参数传递的时候,可以用 arguments 来获取

  • 伪数组
    • 具有 length 属性
    • 按照索引的方式进行存储
    • 没有正真数组的一些方法 pop ( ) , push ()

案例 - 封装函数

案例 - 对传入的参数进行求和
function getSum() {
    //通过arguments这个内置对象【数组】获取方法的实际参数
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }    
    return sum;
}

console.log(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9));
案例 - 用arguments 内置对象求最大值

知识点 :

  1. 用 arguments 对象获取传入的参数
  2. 用 for 循环遍历数组
  3. 用 if 作为判断条件来判断
  4. return 出返回值
      // 利用函数求任意个数的最大值 (arguments)
      function getArrMax() {
        var max = arguments[0];
        for (i = 0; i < arguments.length; i++) {
          if (arguments[i] > max) {
            max = arguments[i];
          }
        }
        return max;
      }
      console.log(getArrMax(1, 34, 89));
      console.log(getArrMax(122, 233, 3));

// 封装一个数组最大值

03-JS基础_第4张图片

      // 封装一个数组最大值
      function fn() {
        var max = arguments[0][0];
        for (var i = 1; i < arguments[0].length; i++) {
          if (arguments[0][i] > max) {
            max = arguments[0][i];
          }
        }
        return max;
      }
      var res3 = fn([44, 11, 66, 22]); // 66
      console.log(res3);
案例 - 封装函数-翻转数组

知识点 :

  1. 封装函数
  2. 遍历旧数组 , 从后往前遍历 i=arr.length-1 , i–
  3. 赋值 , 把旧数组的值赋值给新数组
  4. 输出返回结果
      function revese(arr) {
        if (arr instanceof Array) { // 检测是否为数组
          var newArr = []; // 定义空数组 用来存放新数组
          for (var i = arr.length - 1; i >= 0; i--) {
            newArr[newArr.length] = arr[i]; // 把就数组的值赋值给新数组
          }
          return newArr;
        } else {
          return "这个参数要求必须是数组格式[1,2,3]";
        }
         // return arr.reverse();
      }
      var arr1 = revese([1, 2, 3, 4, 5]);
      var arr2 = revese(["张三", "李四", "王五", "赵六"]);
      console.log(arr1);
      console.log(arr2);
      function reverse(arr) {
        var newArr = [];
        for (var i = arr.length - 1; i >= 0; i--) {
          newArr[newArr.length] = arr[i];
        }
        return newArr;
        // return arr.reverse();
      }
      var res4 = reverse([1, 2, 3, 4, 5]);
      console.log(res4);
案例 - 封装函数 - 冒泡排序

知识点 :

  1. 外层 for 循环 (趟数) arr.length-1
  2. 内层 for 循环 (次数) arr.length-i-1
  3. 交换两个变量
  4. 封装函数
  5. 用 双重 for 循环遍历数组
  6. 输出返回结果
      function sort(arr) {
        for (var i = 0; i < arr.length - 1; i++) {
          for (var j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] < arr[j + 1]) {
              var temp = arr[j];
              arr[j] = arr[j + 1];
              arr[j + 1] = temp;
            }
          }
        }
        return arr;
      }
      var arr1 = sort([1, 2, 8, 7, 3, 4, 5, 6]);
      var arr2 = sort([11, 13, 14, 9, 17, 2]);
      console.log(arr1);
      console.log(arr2);
案例 - 封装函数 - 判断闰年
      function isRunYear(year) {
        // 如果是闰年我们返回 true 否则 false
        var flag = false;
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
          flag = true;
        }
        return flag;
      }
      var re1 = isRunYear(2000);
      var re2 = isRunYear(2001);
      console.log(re1);
      console.log(re2);
      function isRunYear(year) {
        if ((year % 2 == 0 && year % 100 != 0) || year % 400 == 0) {
          return true;
        }
        return false;
      }
      var res1 = isRunYear(2000);
      var res2 = isRunYear(1999);
      console.log(res1);
      console.log(res2);

函数是可以相互调用的

      function fn1() {
        console.log(111); // 111
        fn2();            // 222
                          // 八
        console.log("六");// 六
      }
      function fn2() {
        console.log(222);
        console.log("八");
      }
      fn1(); // 调用 fn1 

**案例 - 判断2月份有多少天 **

知识点:

  1. 运用一个函数内部调用另一个函数
  2. 用输入框接收用户输入的年份
  3. if 判断一下是平年还是闰年 , 输出对应的天数
    • 判断时调用 isRunYear() 函数
    • isRunYear() 函数里需要传入形参 ( 用户输入的 year )
      // 用户输入年份 ,输出当前年份2月份的天数
      function backDay() {
        var year = prompt("请您输入年份:");
        // 调用封装好的判断闰年平年函数 isrunyear
        //调用函数需要加小括号
        // 括号内的变量名 year 可以不一样
        if (isRunYear(year)) { // 判断是不是闰年
          alert("当前年份是闰年2月份有29天");
        } else {
          alert("当前年份是平年2月份有28天");
        }
      }
      backDay();
      console.log("----------------------------------");
      function isRunYear(year) {
        // 如果是闰年我们返回 true 否则 false
        var flag = false;
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
          flag = true;
        }
        return flag;
      }

函数的两种声明方式

  • 自定义函数方式(命名函数)

因为有名字,所以也被称为命名函数

利用函数关键字 function 自定义函数方式

调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面

// 声明定义方式
function fn() {...}
// 调用  
fn();
  • 函数表达式方式(匿名函数)

因为函数没有名字,所以也被称为匿名函数

利用函数表达式方式的写法如下:

函数调用的代码必须写到函数体后面

// 这是函数表达式写法,匿名函数后面跟分号结束
var fun = function(aru){
    console.log("我是函数表达式");
    console.log(aru);
}// 调用的方式,函数调用必须写到函数体下面
fun("pink老师");
// 我是函数表达式
// 我是pink老师

注意 :

  • fun 是变量名 , 不是函数名
  • 函数表达事声明方式和变量差不多 , 只不过变量里面存的是值 , 函数表达式里面存的是函数
  • 函数表达式也可以进行传递参数

作用域☆

概述

作用域 : 用于限定变量 ( 代码名字) 的合法使用范围。JavaScript(es6前)中的作用域有两种:全局作用域和局部作用域,局部作用域也称为函数作用域

目的 : 提高程序的可靠性 , 减少命名冲突

全局作用域

全局作用域,这个作用域的名字叫做window,在script标签中定义的变量或者没有使用var声明的变量 在该作用域 ( 整个script 标签或者一个单独的 js 文件)

局部作用域

在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)

局部作用域也称为函数作用域。

作用域的名字我们可以理解成函数的名字(起名字的目的是为了方便理解后面的预解析知识点)

变量的作用域

在JavaScript中,根据作用域的不同,变量可以分为两种:全局变量和局部变量

全局变量

在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。

  • 全局变量在代码的任何位置都可以使用
  • 在全局作用域下 var 声明的变量 是全局变量
  • 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)

局部变量

在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)

  • 局部变量只能在该函数内部使用
  • 在函数内部 var 声明的变量是局部变量
  • 函数的形参实际上就是局部变量
      var num = 10; // 全局变量
      console.log(num); // 10

      function fn() {
        console.log(num); // 在局部变量里面打印全局变量 num
        var num1 = 11; // 局部变量
        console.log(num1); // 11
        num2 = 20; // 函数内部没有用var声明的变量是全局变量
      }
      fn(); // 调用函数
      console.log(num2); // 20

全局变量和局部变量的区别

  • 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
  • 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间

JS有没有块级作用域(了解)

块作用域由 { } 包括。if {} for {}

在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用,如下面的Java代码:

java有块级作用域:

if(true){
  int num = 123;
  system.out.print(num);  // 123
}
system.out.print(num);    // 报错

以上java代码会报错,是因为代码中 { } 即一块作用域,其中声明的变量 num,在 “{ }” 之外不能使用;

而与之类似的JavaScript代码,则不会报错:

Js 中没有块级作用域(在ES6之前

if(true){
    var num = 123;
    console.log(123); //123
}
console.log(123);   //123,ES6以前这代码正确,ES6以后就不正确了
  • let const 可以形成块级作用域

作用域链☆

概念

函数和函数之间相互嵌套 (作用域和作用域之间相互嵌套) 形参的嵌套关系 , 我们把这个关系称为作用域链

内部函数访问外部函数的变量 , 采取的是链式查找的方式来决定取哪个值 ( 就近原则 )

全局作用域称为一级作用域链

全局范围内种定义的函数称为二级作用域链

全局范围内定义的函数中的函数称为三级作用域链

  • 函数内部可以访问函数外部的变量 , 但是函数外部不可以访问函数内部的变量
      var num = 10;
      var num1 = 30;
      function fn() {
        var num = 20;
        function fun() {
          console.log(num); // 20
          console.log(num1); // 30
        }  
        fun(); // 调用函数
      }
      fn(); // 调用函数
var a = 1;
function fn1() {
    var a = 2;
    var b = '22';
    fn2();
    function fn2() {
        var a = 3;
        fn3();
        function fn3() {
            var a = 4;
            console.log(a); //a的值 ? 4
            console.log(b); //b的值 ? 22
        }
    }
}
fn1();

变量的查找顺序★

采取就近原则的方式来查找变量最终的值。先从当前作用域中找变量,找不到就从上一级作用域中找变量,依次类推…

03-JS基础_第5张图片

预解析

概念

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

  • 预解析:把使用var和function声明的内容丢在内存中 ( 提升声明到当前作用域最前边)
  • 代码执行: 从上到下执行JS语句。

为什么要域解析 : js执行引擎要运行js,必须先分析js的结构里面有哪些变量,哪些方法。分析完毕后才去运行js代码。分析的过程就是域解析 . 就好比说我们要解题,需要先审题,才能做题。

预解析步骤★

预解析分为两步★

  1. 先加载JS到内存,分析有哪些函数是使用 function 创建的,然后为这些函数创建对应的作用域。再分析这些函数中有哪些变量,并且把使用var 声明的函数放到作用域中
  2. 将代码中用 var 声明的变量加载到所处的作用域,并且给默认值undefined

最后在从上向下执行js代码

预解析分类

域解析分为 变量域解析 ( 变量提升 ) 和函数域解析 ( 函数提升 ) 还有 函数表达式声明函数问题(其实也是变量预解析)

  • 变量域解析 ( 变量提升 ) : 就是把所有的变量声明提升到当前的作用域最前面 , 变量的赋值不会提升
      console.log(num); // undefined
      var num = 10;
      // 相当执行了以下操作
      // var num; // 将var 变量声明提升到最前边 , 值不提升 undefined
      // console.log(num);
      // num = 10

结果:undefined
注意:变量提升只提升声明,不提升赋值

  • 函数域解析
      fn();
      function fn() {
        console.log(10);
      }		
      // 相当执行了以下操作
      // JS 解析会把函数声明的提升到当前作用域的最前边
      //   function fn() {
      //     console.log(10);
      //   }
      //   fn();
  • 3.函数表达式声明函数问题(其实也是变量预解析)

函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:

函数表达式调用必须写在函数表达式的下面

      fun();
      var fun = function () {
        console.log(22);
      };
      // 相当执行了以下操作
      //   var fun;  // 变量提升到最前边
      //   fun();  // 调用 fun 这个函数 ,上面没有这个函数所以会报错
      //   fun = function () {
      //     console.log(22);
      //   };

结果:报错提示 ”fn is not a function”
解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用

域解析案列

案例一

将全局变量和 fun 函数中的局部变量的声明提升到当前作用域的最上

函数域解析将函数声明提升到当前作用域最前边

按照作用域链去查找

      var num = 10;
      fun();
      function fun() {
        console.log(num);
        var num = 20;
      }
      // 相当于执行了以下操作
      var num; // 变量域解析 var 升到提当前作用域最前边
      function fun() { // 函数域解析将函数声明提升到当前作用域最前边
        var num; // 变量域解析 var 升到提当前作用域最前边
        console.log(num); // undefined
        num = 20;
      }
      num = 10;
      fun();

案例二

      var num = 10;
      function fn() {
        console.log(num);
        var num = 20;
        console.log(num);
      }
      fn();
      // 相当于执行了以下操作
      var num; // 变量域解析 var 升到提当前作用域最前边
      function fn() {
        var num; // 变量域解析 var 升到提当前作用域最前边
        console.log(num); // undefined
        num = 20;
        console.log(num); // 20
      }
      num = 10;
      fn();

案例三

      var a = 18;
      f1();
      function f1() {
        var b = 9;
        console.log(a);
        console.log(b);
        var a = "123";
      }
      //  相当于执行了以下操作
      var a; // 变量域解析
      function f1() { // 函数域解析
        var b;
        var a;
        b = 9;
        console.log(a); // undefined
        console.log(b); // 9
        a = "123";
      }
      a = 18;
      f1();

案例四★

var a = b = c = 9 ; 相当于 var a =9; b=9; c=9; b和c 直接赋值 没有 var 当全局变量来看 ; a是局部变量 , b 和 c 是全局变量

      f1();
      console.log(c);
      console.log(b);
      console.log(a);
      function f1() {
        var a = b = c = 9;
        // 相当于 var a =9; b=9; c=9; b和c 直接赋值 没有 var 当全局变量来看
        // 集体声明用逗号分隔 var a = 9, b=9, c=9;
        console.log(c);
        console.log(b);
        console.log(a);
      }
      // 相当于执行了以下操作
      function f1() { //函数作用域提升
        var a;
        a = b = c = 9; // b 和 c 是全局变量
        console.log(a); // 9
        console.log(b); // 9
        console.log(c); // 9
      }
      f1();
      console.log(c); // b 和 c 是全局变量
      console.log(b);
      console.log(a); // a 是局部变量 报错

总结 : 先把代码按照域解析排列好 , 再按照作用域链查找结果就可以了

函数提升和变量提升

  • 函数提升优先级高于变量提升优先级
function a(){
 console.log(20);
}
var a = 5;

对象

什么是对象

在 JavaScript 中,对象是一组无序的相关属性方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的。

属性:事物的特征,在对象中用属性来表示(常用名词)

方法:事物的行为,在对象中用方法来表示(常用动词)

为什么需要对象?

保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组

如果要保存一个人的完整信息呢?对象

例如,将“张三疯”的个人的信息保存在数组中的方式为:

var arr = [‘张三疯’, ‘男', 128,154];

使用对象记录上组数据为:

var obj = {
    "name":"张三疯",
    "sex":"男",
    "age":128,
    "height":154
}

对象可以让结构表达的更清晰 , 更强大 , 别人一看就知这个数组是做什么用的

创建对象的三种方式☆

  1. 利用字面量创建对象 ★
  2. 利用 new Object 创建对象
  3. 利用构造函数创建对象★

一. 利用字面量创建对象 ★

就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法

注意 :

  • 里面的属性或方法我们采取键值对的形式 键:属性名 值 : 属性值 值可以是任何类型
  • 多个属性或方法中间用逗号隔开
  • 方法冒号后面跟的是一个匿名函数

创建对象

var star = {
    name : 'pink',
    age : 18,
    sex : '男',
    sayHi : function(){
        alert('大家好啊~');
    }
};

上述代码中 star即是创建的对象。

调用对象的属性

  • 对象名 . 属性名 . 就是的
  • 对象名 [ " 属性名 " ] [’’]里面一定要加引号
console.log(star.name)     // 调用名字属性
console.log(star['name'])  // 调用名字属性

调用对象的方法

  • 对象名 . 方法名 ( ) 一定要加括号 , 方法里是函数 , 调用函数需要加括号
star.sayHi();          // 调用 sayHi 方法,注意,一定不要忘记带后面的括号

二. 利用 new Object 创建对象

是利用等号 = 赋值的方法添加对象的属性和方法

每个属性和方法之间用分号结束

创建空对象

通过内置构造函数Object创建对象,此时andy变量已经保存了创建出来的空对象

var andy = new Object();

给空对象添加属性和方法

通过对象操作属性和方法的方式,来为对象增加属性和方法

对象读和写方式一样

andy.name = 'pink';//在给name属性赋值时该属性不存在,在js中会给对象添加一个name属性
andy.age = 18;
andy.sex = '男';
andy.sayHi = function(){
    alert('大家好啊~');
}
console.log(andy.name); // 调用对象属性
console.log(andy["age"]); // 调用对象方法
andy.sayHi();

注意:

Object() :第一个字母大写

new Object() :需要 new 关键字

使用的格式:对象.属性 = 值;

案例 - 火影鸣人

      var obj = new Object(); // 创建空对象
      obj.name = "鸣人"; // 添加 name 属性
      obj.sex = "男";
      obj.age = 19;
      obj.skill = function () { // 添加方法
        console.log(this.name + "的技能是影分身术"); // this 指向构造函数创建的这个对象
      };
      obj.name = "slf"; // 赋值操作
      console.log(obj.name); // 调用属性
      console.log(obj["age"]);
      obj.skill(); // 调用方法

三. 利用构造函数创建对象★

为什么要使用构造函数 ?

因为前两种创建对象的方式一次只能创建一个对象 , 里面有很多的属性和方法是相同的 我们只能复制

因为我们可以用函数的方法重复这些相同的代码 , 我们就把这个函数称为构造函数

为什么叫构造函数 ? 因为里面封装的不是普通代码而是对象

构造函数就是把我们对象里面一些相同的属性和方法抽象出来封装到函数里面

构造函数

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

构造函数语法

    function 构造函数名(形参1,形参2,形参3) {
     this.属性名1 = 参数1;
     this.属性名2 = 参数2;
     this.属性名3 = 参数3;
     this.方法名 = function(形参4){
         
     };
}

构造函数的调用格式 - 对象

var obj = new 构造函数名(实参1,实参2,实参3) // 调用函数返回的是一个对象 new 一个对象
obj.方法名(实参4);

以上代码中,obj即接收到构造函数创建出来的对象。

案例 - 英雄对象

      function Hero(name, type, blood) {
        this.name = name;
        this.type = type;
        this.blood = blood;
        this.attack = function (Play) {
          console.log(Play);
        };
      }
      var lp = new Hero("廉颇", "力量型", "500血量");
      lp.attack("近战");
      for (var key in lp) {
        console.log(key + lp[key]);
      }
      var hy = new Hero("后裔", "射手型", "100血量");
      hy.attack("远程");
      for (var key in hy) {
        console.log(key + hy[key]);
      }

注意事项

  1. 构造函数约定首字母大写
  2. 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
  3. 构造函数中不需要 return 返回结果
  4. 当我们创建对象的时候,必须用 new 来调用构造函数
  5. 只要 new 构造函数名() 调用函数就创建一个对象 obj {}

构造函数和对象的关系

构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化

new关键字的作用

  1. 在内存中创建一个新的空对象;
  2. 修改this的指向,让this指向刚才创建出来的空对象;
  3. 执行构造函数的代码 , 给这个新对象添加属性和方法
  4. 在构造函数执行完成之后,返回这个新对象 ( 所以构造函数里面不需要return )

变量 . 属性 . 函数 . 方法总结

  • 变量 : 单独声明赋值 , 单独存在
  • 属性 : 对象里面的变量称为属性 , 不需要声明 , 用来描述该对象的特征
  • 函数 : 单独存在的 , 通过 " 函数名() " 的方式就可以调用
  • 方法 : 对象里面的函数称为方法 , 方法不需要声明 , 通过 " 对象 . 方法名() " 的方式就可以调用 , 方法用来描述该对象的行为和能力
      var num = 10;
      var obj = {
        name: "可可",
        fn: function () {
          console.log("旺旺");
        },
      };
      function fn() {
          
      }
      fn();
      console.log(obj.name);
      obj.fn();

遍历对象/数组for…in★

for … in 语句用于对于数组或者对象的属性进行循环操作

语法

for (变量 in 对象名字) {
    k 变量输出得到的是属性名
    obj[k] 对象名[变量] // 得到的是属性值
}

遍历对象

      var str = {
        name: "张三丰",
        age: 99,
        sex: "男",
        like: "太极",
        likes: function () {
          console.log("扔飞标");
        },
      };
      for (var key in str) {
        // key 属性  str // 属性值
        // console.log(key +":"+ str[key]);
        // console.log(`${key}:${str[key]}`);
        if (typeof str[key] === "function") { // 判断单前是方法还是属性
          //   console.log("这是一个方法");
          str[key](); // 打印方法 //
        } else {
          console.log(`${key}:${str[key]}`); // 打印属性
        }
      }

注意:k是对象的属性名,是一个变量,访问的时候不需要加引号!!

遍历对象

function Person(name,age){
    this.name = name;
    this.age = age;
}

var tiantian = new Person("田田",21);


//使用for.in遍历对象,拿到的key表示的是对象的属性的名字,如果想获取属性值需要写代码:对象名[key]
for(var key in tiantian){
    console.log("属性名是:"+key+",属性值是:"+tiantian[key]+"。")
}

控制台效果

属性名是:name,属性值是:田田。
属性名是:age,属性值是:21

遍历数组

//使用for..in遍历数组,拿到的key表示的是数组的索引
var arr = ["老苗","胡斌","张佳","田田"];
for(var index in arr ){//var 用于声明变量,变量名不一定非得是key,index
    console.log("索引是:"+index+",索引对应的元素是:"+arr[index]+"。")
}

控制台效果

索引是:0,索引对应的元素是:老苗。
索引是:1,索引对应的元素是:胡斌。
索引是:2,索引对应的元素是:张佳。
索引是:3,索引对应的元素是:田田。

内置对象

  • JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象
    前面两种对象是JS 基础 内容,属于 ECMAScript; 第三个浏览器对象属于 JS 独有的, JS API 讲解
  • 内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
  • 内置对象最大的优点就是帮助我们快速开发
  • JavaScript 提供了多个内置对象:Math、 Date 、Array、String等

查文档

查找文档:学习一个内置对象的使用,只要学会其常用成员的使用即可,我们可以通过查文档学习,可以通过MDN/W3C来查询。
​Mozilla 开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括 HTML、CSS 和万维网及 HTML5 应用的 API。
MDN:https://developer.mozilla.org/zh-CN/

如何学习对象中的方法

  1. 查阅该方法的功能
  2. 查看里面参数的意义和类型’’
  3. 查看返回值的意义和类型
  4. 通过 demo 进行测试

Math对象

Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用 Math 中的成员。

属性、方法名 功能
Math.PI 圆周率
Math.floor() 向下取整
Math.ceil() 向上取整
Math.round() 四舍五入版 就近取整 注意 -3.5 结果是 -3
Math.abs() 绝对值 有隐式转换 , 把字符串转化为数字
Math.max()/Math.min() 求最大和最小值
Math.random() 获取范围在[0,1)内的随机值 , 包左不包右

案例 - 封装自己的数学对象

      // 封装自己的数学对象
      var myMath = {
        PI: 3.141592653, // 属性 pi
        max: function () { // 方法最大值
          var max = arguments[0];
          for (var i = 0; i < arguments.length; i++) {
            if (arguments[i] > max) {
              max = arguments[i];
            }
          }
          return max;
        },
        min: function () { //方法最小值
          var min = arguments[0];
          for (var i = 0; i < arguments.length; i++) {
            if (arguments[i] < min) {
              min = arguments[i];
            }
          }
          return min;
        },
      };
      console.log(myMath.PI);
      console.log(myMath.max(1, 2, 55, 98, 32, 56, 66));
      console.log(myMath.min(1, 2, 55, 98, 32, 56, 66));

三个取整方法

      // (1) Math.floor() 地板 向下取整 往小了取
      console.log(Math.floor(1.1)); // 1
      console.log(Math.floor(1.9)); // 1
      // (2) Math.ceil() 天花板 向上取整 往大了取
      console.log(Math.ceil(1.1)); // 2
      console.log(Math.ceil(1.9)); // 2
      // (3) Math.round() 四舍五入 .5比较特殊 往大了取
      console.log(Math.round(1.1)); // 1
      console.log(Math.round(1.5)); // 2
      console.log(Math.round(1.9)); // 2
      console.log(Math.round(-1.1)); // -1
      console.log(Math.round(-1.5)); // 这个结果是 -1

获取指定范围内的随机整数

function getRandom(min, max) { // 公式
  return Math.floor(Math.random() * (max - min + 1)) + min; 
}
console.log(getRandom(1, 5));

案例 - 随机点名

// 随机点名
      function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      var arr = ["张三", "李四", "王五", "赵六", "孙七", "周八", "吴九", "郑十"];
      console.log(arr[getRandom(0,arr.length-1)]); // 随机 数组[索引] 索引是随机的

案例 - 猜数字游戏

      function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      // 记录下来这个随机数
      var random = getRandom(1, 10); // 调用函数 返回一个随机数值赋值给变量
      while (true) {  // 死循环 true
        var num = prompt("你来猜,输入1~10之间的整数");
        if (num > random) {
          alert("你猜大了");
        } else if (num < random) {
          alert("你猜小了");
        } else {
          alert("你猜对了");
          break; // 退出整个循环
        }
      }

image-20211121184350823

日期对象

Date 对象和 Math 对象不一样,Date是一个构造函数,所以使用时需要实例化后才能使用其中具体方法和属性。Date 实例用来处理日期和时间

new Date()

 new Date() // Sat Feb 19 2022 10:02:54 GMT+0800 (中国标准时间) 系统格式的时间
 +new Date() // 现在距离过去总毫秒数 // 当前时间总毫秒数
 +new Date("'2022-5-1 18:00:00'") // 未来时间距离过去总毫秒数 // 用户输入总毫秒数

使用Date实例化日期对象

获取当前时间必须实例化:

var now = new Date();

获取指定时间的日期对象

var future = new Date('2019/5/1');

注意:如果创建实例时并未传入参数,则得到的日期对象是当前时间对应的日期对象

使用Date实例的方法和属性

案例 - 格式化日期

注意

  1. 月份要 +1 因为月份是从 0 开始的
  2. 星期要从数组里面获取 0123456 日 一二三四五六
  3. 时分秒的个位数不足十要补 0
      function getCurrentDate() {
        var date = new Date();
        // 年月日周
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var day = date.getDate();
        var week = date.getDay();
        var arrWeek = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
        // 时分秒
        var h = h < 10 ? `0${h}` : h;
        var m = date.getMinutes();
        var m = m < 10 ? `0${m}` : m;
        var s = date.getSeconds();
        var s = s < 10 ? `0${s}` : s;
        return `今天是: ${year}${month}${day}${arrWeek[week]} ${h}:${m}:${s}`;
      }
      console.log(getCurrentDate());

案例 - 封装函数时分秒

      function getTimer() {
        var time = new Date();
        var h = time.getHours();
        h = h < 10 ? "0" + h : h; // 不足10 补0
        var m = time.getMinutes();
        m = m < 10 ? "0" + m : m;
        var s = time.getSeconds();
        s = s < 10 ? "0" + s : s;
        return h + ":" + m + ":" + s;
      }
      console.log(getTimer()); // 调用函数

通过Date实例获取总毫米数

总毫秒数的含义

基于1970年1月1日(世界标准时间)起的毫秒数

获取总毫秒数

// 实例化Date对象
var now = new Date();
// 1. 用于获取对象的原始值
console.log(date.valueOf())	
console.log(date.getTime())	
// 2. 简单写可以这么做
var now = + new Date();	
console.log(now);  返回距离现在的秒数
// 3. HTML5中提供的方法,有兼容性问题
var now = Date.now();
console.log(now);

案例 - 封装函数倒计时★

案例分析

      function countDown(time) {
        // time 用户输入的截止时间
        var nowTime = +new Date(); // 返回的是当前总的毫秒数
        var inputTime = +new Date(time); // 返回的是用户输入时间总的毫秒数
        var times = (inputTime - nowTime) / 1000; // times 剩余时间的毫秒数
        var d = parseInt(times / 60 / 60 / 24); // 天
        d = d < 10 ? "0" + d : d;
        var h = parseInt(times / 60 / 60 % 24); // 时
        h = h < 10 ? "0" + h : h;
        var m = parseInt(times / 60 % 60); // 分
        m = m < 10 ? "0" + m : m;
        var s = parseInt(times % 60); // 秒
        s = s < 10 ? "0" + s : s;
        return d + "天" + h + "时" + m + "分" + s + "秒";
      }
      console.log(countDown("2021-11-22 00:00:00"));

数组对象

创建数组的两种方式

1.字面量方式

var arr = [1,"test",true];

2.new Array()

var arr = new Array();
var arr=new Array(4) // array.length=4
var arr=new Array(1,2,3) // array[1,2,3]

注意:上面代码中arr创建出的是一个空数组,如果需要使用构造函数Array创建非空数组,可以在创建数组时传入参数

参数传递规则如下:

如果只传入一个参数,则参数规定了数组的长度

如果传入了多个参数,则参数称为数组的元素

检测是否为数组

instanceof Array 运算符

作用 : 检测变量是否是某个构造函数的实例

var arr = [1, 23];
var obj = {};
console.log(arr instanceof Array); // true
console.log(obj instanceof Array); // false

Array.isArray()

Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法 , ie 9 以上版本支持

var arr = [1, 23];
var obj = {};
console.log(Array.isArray(arr));   // true
console.log(Array.isArray(obj));   // false

添加删除数组元素的方法

注意:push、unshift为增加元素方法;pop、shift为删除元素的方法

添加需要加参数 , 删除不需要

      // (1) push
      var arr = [1, 2, 3];
      arr.push(4, 5); // [1 2 3 4 5 ] 数组末尾添加
      // console.log(arr.push(4, 5)); // 返回 5 数组的长度
      console.log(arr); // 12345
      // (2) unshift
      var arr1 = [1, 2, 3];
      arr1.unshift(0, 0); // [0 0 1 2 3 ] 数组前面添加
      // console.log(arr1.unshift(0, 0)); // 返回 5 数组的长度
      console.log(arr1); // 00123

      // (3) pop
      arr.pop(); // 删除数组最后一个元素
      // console.log(arr.pop()); // 返回删除的元素 5
      console.log(arr); // 1234
      // (4) shift
      arr1.shift(); // 删除数组第一个元素 0
      // console.log(arr1.shift()); //返回删除的元素 0
      console.log(arr1); // 0123

案例 - 筛选数组

      // 小于 2000 的放到新数组
      var arr = [1500, 1200, 2000, 2100, 1800];
      var newArry = [];
      for (var i = 0; i < arr.length; i++) {
        if (arr[i] < 2000) {
          newArry.push(arr[i]); // 新数组的末尾添加元素
        }
      }
      console.log(newArry);

案例 - 将数组中大于等于10 的元素放到新数组中

//将数组中大于等于10 的元素放到新数组中
var oldArr = [2, 1, 4, 5, 121, 2, 443, 545, 23, 78, 11, 45];
var newArr = [];

for (var index in oldArr) {//完全等价于  for(var index=0; index
    //根据索引取出旧数组中的数据,存到element变量中,第一次for循环element=2,第二次for循环element=1
    var element = oldArr[index];

    if (element >= 10) {
        newArr.push(element); // 新数组的末尾添加元素
    }
}

//查看新数组中的数据
console.log(newArr);

数组排序

数组中有对数组本身排序的方法,部分方法如下表

方法名 说明 是否修改原数组
reverse() 颠倒数组中元素的顺序 , 无参数 该方法会改变原来的数组 返回新数组
sort() 对数组的元素进行排序 该方法会改变原来的数组 返回新数组

数组翻转

      // (1) 数组翻转
      var arr = [1, 2, 3, 4, 5];
      arr.reverse();
      console.log(arr); // 5, 4, 3, 2, 1

冒泡排序

      // (1) 冒泡排序
      var arr1 = [1, 5, 3, 9, 7, 13];
      //   arr1.sort(); // 逐位进行比较 1, 13, ,3, 5, 7, 9]
      //将函数作为参数传递,这个函数称为回调函数
      arr1.sort(function (a, b) {
        return a - b; // 升序公式 1到2  
        // return b - a; // 降序 2到1
      });
      console.log(arr1); // 1, 3, 5, 7, 9, 13

注意:sort方法需要传入参数来设置升序、降序排序

  • 如果传入“function(a,b){ return a-b;}”,则为升序
  • 如果传入“function(a,b){ return b-a;}”,则为降序

将函数作为参数传递,这个函数称为回调函数

获取数组指定元素索引的方法

方法名 说明 返回值
indexOf() 数组中查找给定元素的第一个索引 如果存在返回索引号 如果不存在 则放回-1
lastdexOf() 在数组中的最后一个索引 如果存在返回索引号 如果不存在 则放回-1
      var arr = ["red", "green", "blue", "pink", "blue"];
      console.log(arr.indexOf("blue")); // 2 从前往后查找
      console.log(arr.lastIndexOf("blue")); // 4 从后往前查找

案例 - 数组去重

案例分析

  • 目标 : 把旧数组里面不重复的元素选取出来放到新数组中 , 重复的元素只保留一个 放到新数组中
  • 核心算法 : 遍历旧数组 , 拿走就数组元素去新数组里找 , 如果新数组里面没有这个元素 , 就把这个元素添加到新数组 , 否则不添加
  • 怎么知道该元素没有存在 ? 利用 新数组 indexOf(数组元素) , 返回 -1 时说明新数组里没有该元素

核心方法 :

newArr. indexOf() 查找数组指定元素的索引

newArr . push () 数组末尾添加元素

      // 数组去重
      function unique(arr) {
        // 定义一个空数组 存放去重后的数据
        var newArr = [];
        for (var i = 0; i < arr.length; i++) {
          // 遍历旧数组 , 在新数组中找指定的元素的索引 , 找不到返回-1,说明新数组中没有此元素 ,添加进去.
          if (newArr.indexOf(arr[i]) === -1) {
            newArr.push(arr[i]);
          }
        }
        return newArr;
      }
      var re1 = unique([11, 11, 22, 22, 33, 33]);
      console.log(re1); // 11,22,33

案例 - 查询数组中是否有指定元素

var arr = ["胡斌", "闫鑫", "王亚宁", "李晋", "王源", "麟哥哥"];

//判断数组中是否包含张佳
// var arry1= arr.indexOf("张佳") != -1?"此人存在":"查无此人"
if (arr.indexOf("张佳") != -1) {
    console.log("此人存在");
} else {
    console.log("查无此人");
}

数组转换为字符串

数组中有把数组转化为字符串的方法,部分方法如下表

方法名 说明 返回值
toString() 数组转字符串 , 逗号分隔每一项 返回一个字符串
join(‘字符串’) 把数组中的所有元素转换为一个字符串 返回一个字符串
      // 数组转字符串
      // 1. toString()
      var arr = [1, 2, 3];
      console.log(arr.toString()); // 1,2,3
      // 2.join(分隔符)
      var arr1 = [1, 2, 3, 4];
      console.log(arr1.join()); // 1,2,3,4
      console.log(arr1.join("-")); // 1-2-3-4
      console.log(arr1.join("&")); // 1&2&3&4

03-JS基础_第6张图片

splice 删除 插入 替换

  • 返回值 是删除数组的元素
      // splice 删除 插入 替换
      var arr1 = [1, 2, 3, 4];
      arr1.splice(1); // 1 从索引为1的开始删
      arr1.splice(1, 2); // 1,4 从索引为1 开始删 , 往后删两个
      arr1.splice(1, 2, 99); // [1,99,4]  删除了字符串的位置添加 99
      arr1.splice(1, 0, 99); // [1, 99, 2, 3, 4] 删除0个,在索引为1 的地方插入99

concat 方法用于合并两个或多个数组。

  • 返回一个新数组。
      var arr1 = [1, 2, 3];
      var arr2 = [11, 22, 33];
      var arr3 = [111, 222, 333];
      var arr = arr1.concat(arr2,arr3);
      console.log(arr);
      // [1, 2, 3, 11, 22, 33, 111, 222, 333]

字符串对象

基本包装类型

为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。

基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。

// 下面代码有什么问题?
var str = 'andy';
console.log(str.length);

按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但上面代码却可以执行,这是因为

js 会把基本数据类型包装为复杂数据类型,其执行过程如下 :

字符串去重复// 1. 生成临时变量,把简单类型包装为复杂数据类型
var temp = new String('andy');
// 2. 赋值给我们声明的字符变量
str = temp;
// 3. 销毁临时变量
temp = null;

字符串的不可变

指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。

当重新给字符串变量赋值的时候,变量之前保存的字符串不会被修改,依然在内存中重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变。
由于字符串的不可变,在大量拼接字符串的时候会有效率问题

根据字符返回位置

方法名 说明 返回值
indexOf(‘要查找的字符’ , 开始的位置) 数组中查找给定元素的第一个索引 如果存在返回索引号 如果不存在 则放回-1
lastdexOf() 在数组中的最后一个索引 如果存在返回索引号 如果不存在 则放回-1
var str = "改革春风吹满地,春天来了";
console.log(str.indexOf("春", 3)); // 8 从索引号是3的位置往后查找

案例 - 查找指定字符出现的位置及次数

案例分析

  • 核心算法 : 先查找第一个 o 出现的位置
  • 然后用 while 循环 只要 indexOf 返回的结果不是 -1 , 就继续往后查找
  • 因为 indexOf 只能查找到第一个 , 所以后面的查找 , 利用第二个参数 , 当前索引 加1 , 继续查找
 // 查找指定字符 o 出现的位置及次数 abcoefoxyozzopp
      var str = "abcoefoxyozzopp"; // 3 6 9 12
      var index = str.indexOf("o"); // 第一个 o 出现的位置
      var num = 0; // 计数器 记录 o 出现了几次
      while (index !== -1) { // 只要索引不等于-1 就一直查找
        console.log(index);
        num++; // 打印一次索引记录一次
        // 当前索引+1 查找后面 o 出现的位置
        index = str.indexOf("o", index + 1); 
        //从当前索引后一位开始查找字符"o" ,并返回位置索引,赋值判断
      }
      console.log("o出现的次数是:" + num);
      var arr = ["red", "blue", "red", "green", "pink", "red"]; // 0 2 5
      var index = arr.indexOf("red");
      var num = 0;
      while (index !== -1) {
        console.log(index);
        num++;
        index = arr.indexOf("red", index + 1);
      }
      console.log(num); // 3次

根据位置返回字符

字符串通过基本包装类型可以调用部分方法来操作字符串,以下是根据位置返回指定位置上的字符:

      var str = "abcd";
      console.log(str.charAt(0)); // a
      console.log(str.charCodeAt(0)); // 97
      console.log(str[0]); // a

在上述方法中,charCodeAt方法返回的是指定位置上字符对应的ASCII码,ASCII码对照表如下:

hasOwnProperty()

 obj.hasOwnProperty(chars) // true false

方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

案例 - 判断一个字符串 ‘abcoefoxyozzopp’ 中出现次数最多的字符,并统计其次数

  1. 核心算法:利用 charAt() 遍历这个字符串 //

  2. 把每个字符都存储给对象, 如果对象没有该属性,就为1,如果存在了就 +1

  3. 遍历对象,得到最大值和该字符

    注意:在遍历的过程中,把字符串中的每个字符作为对象的属性存储在对象中,对应的属性值是该字符出现的次数

      // 判断一个字符串 ‘abcoefoxyozzopp’ 中出现次数最多的字符,并统计其次数
      var str = "abcoefoxyozzopp";
      var o = {};
      for (var i = 0; i < str.length; i++) { // 遍历字符串
        var chars = str.charAt(i); // 把字符串的每一个字符取出来 赋值给chars
        // if (o.hasOwnProperty(chars))
        if (o[chars]) { // 对象名.属性
          // 判断一下对象里面有没有该属性 o[chars] 得到的是属性
          o[chars]++; // 如果有,该属性的值就加1 相当于计数器
        } else {
          o[chars] = 1; // 没有就把该属性存进去 ,并赋值1
        }
      }
      console.log(o);
      // 2.遍历对象
      var max = 0;
      var cha = ""; // 定义一个变量保存最大值对应的属性名
      for (var k in o) {
        // k 得是属性名
        // o 是对象名 , o[k]得到的是属性值
        if (o[k] > max) {
          max = o[k];
          cha = k; // 最大值对应的属性名
        }
      }
console.log(`出现最多的字符是${cha},出现次数是:${max},`);

03-JS基础_第7张图片

字符串操作方法

字符串通过基本包装类型可以调用部分方法来操作字符串,以下是部分操作方法:

replace ( ) 方法

replace() 方法用于在字符串中用一些字符替换另一些字符,其使用格式如下:

字符串.replace(被替换的字符串, 要替换为的字符串)var str2 = "andy";
  console.log(str.replace("a", "b")); // bndy

split()方法 ⭐️

split()方法用于切分字符串,它可以将字符串切分为数组。在切分完毕之后,返回的是一个新数组。

字符串.split("分割字符")
      var str4 = "red,pink,blue";
      console.log(str4.split(",")); // ['red', 'pink', 'blue']
      var str5 = "red&pink&blue";
      console.log(str5.split("&")); // ['red', 'pink', 'blue']

concat () 方法

concat 用于连接两个或多个字符串,数组 等效于 + + 更常用

      // 1. concat("字符串1",字符串2)
      var str = "andy";
      console.log(str.concat("red", "green")); // andyredgreen

substr () 方法 ⭐️

substr 用于截取字符

      // 2. substr("截取的起始位置","截取几个字符")
      var str1 = "改革春风吹满地";
      console.log(str1.substr(2, 2)); // 春风 - 索引和截取字符的数量

字符串大小写转换

      // 字符串大小写转换
      // str.toUpperCase() str.toLowerCase()  转大写
      const str8 = "AbcdeFg";
      console.log(str8.toUpperCase()); // ABCDEFG
      // str.toLowerCase() 转小写
      console.log(str8.toLowerCase()); // abcdefg

简单数据类型和复杂数据类型

简单数据类型

简单类型基本数据类型值类型):在存储时变量中存储的是值本身,包括string ,number,boolean,undefined,null

        // 简单数据类型 null 返回的是一个空对象 object
        var timer=null
        console.log(typeof timer); // object
        // 用途 - 如果有个变量以后打算存对象 , 暂时没想好放啥这个时候就给 null
        

复杂数据类型

复杂数据类型(引用类型):在存储时变量中存储的仅仅是地址(引用),通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等;

堆栈

JavaScript 中没有堆栈的概念

堆栈空间分配区别

1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;

简单数据类型存放到栈里面

2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。

复杂数据类型存放到堆里面

堆栈内存分配⭐️

  • 简单数据类型 是存放在里面 , 栈里面直接开辟一个内存空间存放的是
  • 复杂数据类型 首先在里面存放一个十六进制的地址 , 然后这个地址指向堆里面的数据

简单数据类型的存储方式

值类型变量的数据直接存放在变量(栈空间)中

复杂数据类型的存储方式

引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中

简单类型传参

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

function fn(a) {
    a++;
    console.log(a); 
}
var x = 10;
fn(x);
console.log(x)

复杂数据类型传参

函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。

function Person(name) {
    this.name = name;
}
function f1(x) { // x = p
    console.log(x.name); // 2. 这个输出什么 ?    
    x.name = "张学友";
    console.log(x.name); // 3. 这个输出什么 ?    
}
var p = new Person("刘德华");
console.log(p.name);    // 1. 这个输出什么 ?   
f1(p);
console.log(p.name);    // 4. 这个输出什么 ?

x的值成了 张学友 , p 的地址和 x 的地址一样 , p 也指向 张学友

03-JS基础_第8张图片

你可能感兴趣的:(javascript)