JavaScript笔记

331 阅读54分钟

JavaScript代码

var str = 'hello world!'; console.log(str);

JavaScript基础名词概念

var num = 1 + 1;

语句

JavaScript语句为由上至下 单行执行; 每一行都是一条语句, 每一条语句执行完成之后会进入下一行 语句由于 ; 结尾

表达式

上述代码中 1 + 1 就是一个表达式(expression) 指一个为了得到返回值的计算式

语句可以理解为一条命令,并不一定需要的到一个具体的期望值。表达式的目的是为了得到一个值,方便后面利用 值去做什么事情,在上述例子中 表达式 1+1 得到的值 赋值 给了 变量 num;

变量

上述例子中 num 为我们 声明 的 变量, 变量可以理解为一个容器,用于存放各种各样的值。由于需要存放各 种不同的值 所以我们要为 变量命名 num 就是 上述例子中 的变量名

变量声明

var a = 10
//将10赋值给了声明的a 这个过程做了两件事
//1.我们声明变量 通过关键字var 创建了变量a
//2.我们将10赋值给了变量num

变量赋值

变量名称 = 值;

变量引用

//使用console.log方法 在控制台中 打印 num变量的值
console.log(num);
//将变量 num 带入表达式 num + 1 让表达式成为为 num变量的内容 + 1 并且赋值给 变量 count
var count = num + 1;

标识符 ( 变量名称 )

命名规则

必须遵守的命名规则 如果不遵守 就会报错

- 由字母、数字、下划线、$符号组成,不能以数字以及其他符号开头
- 不能是关键字或保留字,例如:for、while。

命名规范

  • 具有语义性的 英文单词 不要用无意义字符 如:aaa xxx;
  • 多个单词使用驼峰命名法 变
  • 量名称 为名词 可以使用形容词为前缀
*良好的命名
maxCount
petName 

变量规则

未声明变量直接使用

console.log(x); 
// ReferenceError: x is not defined

上面代码直接使用变量 x ,系统就报错,告诉你变量 x 没有声明。

省略 var 关键字

a = 30; 
console.log(a); //30

在javascript中 变量可以省略 var关键字 直接调用或者赋值,解释器会帮我们 隐式声明 变量 但是,不写 var 的做法,不利于表达意图,而且容易不知不觉地创建全局变量,所以建议总是使用 var 命令声 明变量。

重复赋值

var x = 10;
x = 20;
console.log(x); //20
解释为
var x;
x = 10;
x = 20;
console.log(x);

x 一开始声明并且赋值为 10 后面如果想要修改 x 的值 不需要重新声明 直接再次赋值 20 覆盖之前 x 的值内 容即可

重复声明

var x = 1;
var x;
console.log(x); //1
解释为
var x;
x = 1;
console.log(x);

对同一个变量进行二次声明 第二次声明是无效的操作 因为同一个 环境中 变量名是唯一的;

重复声明赋值

var x = 1;
var x = 2;
console.log(x); //2
解释为
var x;
x = 1;
x = 2;
console.log(x);

结合上一个重复声明, 当重复声明且赋值的时候, 第二行的声明无效 但 赋值操作有效 所以 变量 x 的值 由1 覆 盖为 2

批量声明

var a,b,c,d = 10;
解释为
var a;
var b;
var c;
var d;
d = 10;

在上面的代码中 我们可以通过 , 隔开多个变量, 通过一个 var 关键字进行批量声明 , 最后一个 变量 d 赋值 为10;

*变量提升

console.log(num); //undefined
var num = 10;

//实际在javascript引擎解释后 顺序为
var num;
console.log(num); //undefined
num = 10;

  1. 先声明 num 这一步称为 变量提升
  2. 调用console.log() 打印 num的值 这时因为没有给num赋值 num的值还是 初始默认值 undefined
  3. 给num 赋值 为 10

数据类型

  • 数值(number):整数和小数(比如 1 和 3.14 )
  • 字符串(string):文本(比如 'Hello World' )。
  • 布尔值(boolean):表示真伪的两个特殊值,即 true (真)和 false (假)
  • undefined :表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值
  • null :表示空值,即此处的值为空 。
  • 对象(object):各种值组成的集合。
  • symbol (symbol ) : 唯一标识符 //es6学习前不做讨论

通常,数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefined和null,一般将它们看成两个特殊值。

类型分类

传统分类通过存储位置 把数据类型分为 基础类型 和 引用类型

基础类型 存储在 栈内存 中NumberStringBooleanUndefinedNullsymbol
引用数据类型 存储在 堆内存中 栈内存存储堆内存的地址

Number 类型

  • 数值字面量:数值的固定值的表示法

    110 1024 60.5

  • 进制

十进制
var num = 9;
进行算数计算时,八进制和十六进制表示的数值最终都将被转换成十进制数值。
十六进制
var num = 0xA;
数字序列范围:0~9以及A~F
八进制
var num1 = 07; // 对应十进制的7
var num2 = 019; // 对应十进制的19
var num3 = 08; // 对应十进制的8
数字序列范围:0~7
如果字面值中的数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析

  • 浮点数
浮点数
var n = 5e-324; // 科学计数法 5乘以10的-324次方
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数
var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004
console.log(0.07 * 100);
不要判断两个浮点数是否相等

  • 数值范围
最小值:Number.MIN_VALUE,这个值为: 5e-324
最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
无穷大:Infinity
无穷小:-Infinity

  • 数值判断

产生条件 var y = 7 - "f"

NaN:not a number 表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。

NaN 与任何值都不相等,包括他本身

isNaN: is not a number

NaN进行任何数学运算 结果也是 NaN

String类型

'joker' "kyogre"

  • 字符串字面量

    ‘海牙老师 真的帅’

  • 转义符 表现出来的

QQ浏览器截图20221219151305.png

var huan = '你好\n我是某某'

  • 字符串长度 (只读)

length属性用来获取字符串的长度

var str = '海牙 Hello World';
console.log(str.length);
  • 字符串拼接

字符串拼接使用 + 连接

console.log(11 + 11);
console.log('hello' + ' world');
console.log('100' + '100');
console.log('11' + 32);
console.log('male:' + true);

  1. 两边只要有一个是字符串,那么+就是字符串拼接功能
  2. 两边如果都是数字,那么就是算术功能。
  • 字符串换行
var longString = '第一行 '
+ '第二行 '
+ '第三行 '
+ '文本内容';
var longString = '第一行 \
第二行 \
第三行 \
文本内容';
longString
​

  • 按位取值(只读)
var str = 'hello world!';
console.log(str[1]); //e
str[1] = 'x'; //无法改写

Boolean类型

布尔值代表“真”和“假”两个状态。“真”用关键字 true 表示,“假”用关键字 false 表示。布尔值只有这两个值。

Boolean字面量: truefalse,区分大小写
计算机内部存储:true1false0

Undefined和Null

null 与 undefined 都可以表示“没有”,含义非常相似。将一个变量赋值为 undefined 或 null ,老实说,语法效 果几乎没区别。

  1. undefined表示一个声明了没有赋值的变量,变量只声明的时候值默认是undefined
  2. null表示一个空,变量的值如果想为null,必须手动设置

类型判断

JavaScript 有三种方法,可以确定一个值到底是什么类型。

  • typeof 运算符 弱类型检测 只能笼统的检测
  • instanceof 运算符
  • Object.prototype.toString 方法

typeof

一种弱判断

数值、字符串、布尔值分别返回 number 、 string 、 boolean , undefined 返回 undefined null 返回 object

typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"
typeof undefined //"undefined"
typeof null // "object"

typeof 针对未声明的变量

if (typeof v === "undefined" ) {
console.log("变量 v 不存在")
}

操作符

算术运算符

  • 加法运算符x + y
  • 减法运算符x - y
  • 乘法运算符x * y
  • 除法运算符x / y
  • 指数运算符x ** y
  • 余数运算符x % y
  • 自增运算符++x 或者 x++
  • 自减运算符--x 或者 x--
  • 数值运算符+x
  • 负数值运算符-x

一元运算符

前置++ 前置-- 后置++ 后置-- 前置++:先加1,后参与运算

后置++:先参与运算,后加1

上面两个理解后,下面两个自通

前置-- :先减1,后参与运算

后置-- :先参与运算,后减1

  • 练习
var a = 1; var b = ++a + ++a; console.log(b);//5
var a = 1; var b = a++ + ++a; console.log(b);//4
var a = 1; var b = a++ + a++; console.log(b);//3
var a = 1; var b = ++a + a++; console.log(b); //4

逻辑运算符

&& 与 两个操作数同时为true,结果为true,否则都是false
左边为真 返回右边 左边为假 返回左边本身
|| 或 两个操作数有一个为true,结果为true,否则为false
左边为假 返回右边 左边为真 返回左边本身
! 非 取反

会发生逻辑中断

关系运算符(比较运算符)

< > >= <= == != === !==

==与===的区别:==只进行值得比较,===类型和值同时相等,则相等
var result = '55' == 55; // true
var result = '55' === 55; // false 值相等,类型不相等
var result = 55 === 55; // true

尽量用=== 少用==  ==会造成隐式转换

赋值运算符

= 、+=、 -=、 *=、 /=、 %=

例如:
var num = 0;
num += 5; //相当于 num = num + 5;

运算符的优先级

优先级从高到底
1. () 优先级最高
2. 一元运算符 ++ -- !
3. 算数运算符 先* / % 后 + -
4. 关系运算符 > >= < <=
5. 相等运算符 == != === !==
6. 逻辑运算符 先&& 后||
7. 赋值运算符
8. 默认从左至右 除了 赋值运算 = 三目运算 ?: 指数运算 **

练习优先级

// 练习1:
4 >= 6 || '山海' != '琨' && !(12 * 2 == 144) && true//true
// 练习2:
var num = 10;
5 == num / 2 && (2 + 2 * num).toString() === '22'//true

数据类型转换

chrome浏览器中 不同类型的值 打印颜色不同

字符串的颜色是黑色的,数值类型是蓝色的,布尔类型也是蓝色的,undefined和null是灰色的

转换成数值类型

  • Number(Obj)
Number()可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaN
空字符串或者null 转换为0
false 1
true 0

  • parseInt(string,radix) 转换为整数 radix表示几进制 必须大于2
var num1 = parseInt("12.3abc"); // 返回12,如果第一个字符是数字会解析知道遇到非数字结束
var num2 = parseInt("abc123"); // 返回NaN,如果第一个字符不是数字或者符号就返回NaN

    console.log(parseInt(13.133))//13
    console.log(parseInt('13.133'))//13
    console.log(parseInt('13.13u'))//13
    console.log(parseInt('1k3.133'))//1
    console.log(parseInt('01001'))//1001
    console.log(parseInt('k13a'))//nan

  • parseFloat(string)
parseFloat()把字符串转换成浮点数
parseFloat()和parseInt非常相似,不同之处在与
parseFloat会解析第一个. 遇到第二个.或者非数字结束
如果解析的内容里只有整数,解析成整数

  • +,-0等运算
var str = '500';
console.log(+str); // 取正
console.log(-str); // 取负
console.log(str - 0);

转换成字符串类型

  • toString()
var num = 5;
console.log(num.toString());

undefined类型 和null不能使用toString 方法 js没有提供

  • String()
String()函数存在的意义:有些值没有toString(),这个时候可以使用String()。
比如:undefinednull
console.log(String(undefined))//'undefined'
console.log(String(null))//'null'

拼接字符串方式

num + "",当 + 两边一个操作符是字符串类型,一个操作符是其它类型的时候,会先把其它类型转换成字符 串再进行字符串拼接,返回字符串

转换成布尔类型

Boolean()

!!

(空字符串) null undefined NaN 0 会转换成false 其它都会转换成true

隐式转换(未研究透彻)

递增递减运算符(前置、后置)

  1. 如果包含的是有效数字字符串或者是有效浮点数字符串,则会将字符串转换(Number())为数值,再进行加减 操作,返回值的类型是:number类型。
  2. 如果不包含有效数字字符串,则会将字符串的值转换为NaN,返回值的类型是:number类型。
  3. 如果是boolean类型,则先会把true或者false转换为1或者0,再进行加减操作,返回值的类型是:number类 型。
  4. 如果是null类型,则先会把null转换为0,在进行加减操作,返回值的类型是:number类型。
  5. 如果是undefined,则先会把undefined转换为NaN,再进行加减操作,返回值的类型是:number类型。 6.如果是对象,则先会通过对象的valueOf()方法,进行转换,如果返回的是NaN,调用toString()方法,在进行 前面的操作,返回值的类型是:number类型。(注:空数组[]会返回0,在进行加减操作,空对象则会返回 NaN)。
    var x = '4'
    console.log(++x)//5
​
    var x = '4klu'
    console.log(++x)//nan
​
    var x = false
    console.log(++x)//1
​
    var x = undefined
    console.log(++x)//nan
​
    var x = null
    console.log(++x)//1

逻辑操作符中的隐式转换规律

注:只有undefined、null、NaN、0、空字符串会被转换为false,其余都为true

逻辑操作符一般用于语句判断中。通过判断结果返回的值进行后面的语句操作。

&& || 左边进行布尔类型转换尝试

&&如果左边为真 返回右边 左边为假 返回自己本身

|| 如果左边为假 返回右边 左边为真 返回自己本身

  1. 逻辑非(!)操作符:首先会通过Boolean()函数将其操作值转换为布尔值,然后求反。
  2. 逻辑与(&&)操作符:如果第一个值经过Boolean()函数转换后为true,则返回第二个操作值,否则返回第一个 操作值。如果有一个操作值为null这返回null,如果有一个操作值为undefined,则返回undefined,如果有 一个值为NaN,则返回NaN。
  3. 逻辑或(||)操作符:如果第一个值经过Boolean()函数转换为false,则返回第二个操作值,否则返回第一个操 作值。

(注:逻辑操作符的运算为短路逻辑运算:前一个条件已经能够得出结果后续条件不再执行!)

关系操作符(比较运算符)的隐式转换规律

(关系操作符的操作值也可以是任意类型):

  1. 如果两个操作值都是数值,则直接比较大小。
  2. 如果两个操作值都是字符串,则字符串进行其Unicode编码进行比较。
  3. 如果一个操作值是数值,则另一个值转换为数值进行比较。
  4. 如果一个操作值是对象,则调用对象的valueOf()和toString()方法,然后再进行上述比较。
  5. 如果一个操作值是布尔值,则将布尔值转换为数值再进行比较。 (注:NaN和任何值都不相等,包括自己,同时它与任何类型比较都会返回false。)

相等操作符==和===的隐式转换规律:

  1. 布尔值、字符串和数值进行比较,会先将其转换为数值再进行比较。
  2. null和undefined比较是相等的,但不是全等的。
  3. NaN与任何值都不相等,都会返回false。

布尔类型的隐式转换

流程控制语句会把后面的值隐式转换成布尔类型

转换为true 非空字符串 非0数字 true 任何对象
转换成false 空字符串 0 false null undefined NaN
// 结果是什么?
var a = !!'123';//true

测试

console.log('5'+(true*2)+false)/52false
console.log('5' - 2 + '3')//33
console.log(' ' + NaN - false + !-1)
//!-1 = false 
//String +NaN -boolean + boolean
//' NaN' - false +false //减号 两侧转换成数值运算
// NaN - 0 +false  //NaN跟任何数值做运算结果都是NaN
//NaN

1 + true;
1 + 'true';
1 + undefined;
1 + null;
NaN == NaN;
undefined == null;
null !== undefined;
2 + '5' - 3;
6 > '3' == 3;
undefined == '0';
null == 0;
null >= 0;
parseInt('13.33') === ~~'13.33';
false - 1 <= '0';
'Value is ' + (val != '0') ? 'define' : 'undefine';

关于 null 在关系运算和相等运算中的坑:

null > 0 // null 尝试转型为number , 则为0 . 所以结果为 false,
null >= 0 // null 尝试转为number ,则为0 , 结果为 true.
null == 0 // null在设计上,在此处不尝试转型. 所以 结果为false. 

参考 : bclary.com/log/2004/11…

  1. 关系运算符 和 相等运算符 并不是一个类别的.
  2. 关系运算符,在设计上,总是需要运算元尝试转为一个number . 而相等运算符在设计上,则没有这方面的考虑.
  3. 最重要的一点, 不要把 拿 a > b , a == b 的结果 想当然的去和 a >= b 建立联系. 正确的符合最初设计思想的关 系是 a > b 与 a >= b是一组 . a == b 和其他相等运算符才是一组. 比如 a === b , a != b, a !== b .

交互与写入:alert、prompt 和 confirm / write

由于我们将使用浏览器作为我们的演示环境,让我们看几个与用户交互的函数:alertpromptconfirm

alert

这个我们前面已经看到过了。它会显示一条信息,并等待用户按下 “OK”。

例如:

alert("Hello");

弹出的这个带有信息的小窗口被称为 模态窗。“modal” 意味着用户不能与页面的其他部分(例如点击其他按钮等)进行交互,直到他们处理完窗口。在上面示例这种情况下 —— 直到用户点击“确定”按钮。

prompt

pormpt有文本消息的模态窗口,还有 input 框和确定/取消按钮。

result = prompt(title, [default]);

浏览器会显示一个带有文本消息的模态窗口,还有 input 框和确定/取消按钮。

  • title

    显示给用户的文本

  • default

    可选的第二个参数,指定 input 框的初始值。

语法中的方括号 [...]

上述语法中 default 周围的方括号表示该参数是可选的,不是必需的。

访问者可以在提示输入栏中输入一些内容,然后按“确定”键。然后我们在 result 中获取该文本。或者他们可以按取消键或按 Esc 键取消输入,然后我们得到 null 作为 result

prompt 将返回用户在 input 框内输入的文本,如果用户取消了输入,则返回 null

举个例子:

var age = prompt('How old are you?', 100);
​
alert("You are" + age +"ars old!"); 

IE 浏览器会提供默认值

第二个参数是可选的。但是如果我们不提供的话,Internet Explorer 会把 "undefined" 插入到 prompt。

我们可以在 Internet Explorer 中运行下面这行代码来看看效果:

var test = prompt("Test");

所以,为了 prompt 在 IE 中有好的效果,我们建议始终提供第二个参数:

var test = prompt("Test", ''); // <-- 用于 IE 浏览器

confirm

confirm取消两个按钮的模态窗口。

result = confirm(question);

confirm 函数显示一个带有 question 以及确定和取消两个按钮的模态窗口。

点击确定返回 true,点击取消返回 false

例如:

var isBoss = confirm("Are you the boss?");
​
alert( isBoss ); // 如果“确定”按钮被按下,则显示 true

document.write

在JavaScript中document.write()函数可以向文档写入HTML表达式或JavaScript代码,用法“document.write(exp1,exp2,exp3,....)”,该函数可接受任何多个参数,并将其写入文档中。

document.write('我被写入了BODY中','还有我');

控制流程

顺序结构、分支结构、循环结构

顺序结构

从上到下执行的代码就是顺序结构

程序默认就是由上到下顺序执行的

分支结构

根据不同的情况,执行对应代码

循环结构

循环结构:重复做一件事情

分支结构

if语句是最常用的,用途最广泛。一定要牢牢掌握。

三元表达式适用于变量的赋值是二选一的情况时,最适合。

switch语句是当一个值去匹配多种情况时,最适合。

f语句

### f语句
if (/* 条件表达式 */) {
  // 执行语句
}

if (/* 条件表达式 */){
  // 成立执行语句
} else {
  // 否则执行语句
}

if (/* 条件1 */){
  // 成立执行语句
} else if (/* 条件2 */){
  // 成立执行语句
} else if (/* 条件3 */){
  // 成立执行语句
} else {
  // 最后默认执行语句
}


if判断成功后 后续else if不会进行判断 

案例: 求两个数的最大数 判断一个数是偶数还是奇数 分数转换,把百分制转换成ABCDE <60 E 60-70 D 70-80 C 80-90 B 90 - 100 A

判断四季 3-5 春 6-8夏 9-11 秋 12-2 冬

作业: 判断一个年份是闰年还是平年 判断一个人的年龄是否满18岁(是否成年)

挑战:

闰年:能被4整除,但不能被100整除的年份 或者 能被400整除的年份

三元运算符

表达式1 ? 表达式2 : 表达式3
是对if……else语句的一种简化写法
满足条件 执行表达式2 不满足执行表达式3

案例: 是否年满18岁 从两个数中找最大值

i = i ? i < 0 ? Math.max(0, len + i) : i : 0;

switch语句

switch (expression) {
  case 常量1:
    语句;
    break;
  case 常量2:
    语句;
    break;
  case 常量3:
    语句;
    break;
  …
  case 常量n:
    语句;
    break;
  default:
    语句;
    break;
}

break可以省略,如果省略,代码会继续执行下一个case
switch 语句在比较值时使用的是全等操作符, 因此不会发生类型转换(例如,字符串'10' 不等于数值 10

穿透语法switch

穿透语法switch
switch(a){
      case 1 :
      case 3 :
      case 5 :
      case 7 :
      case 8 :
      case 10 :
      case 12 :
        console.log('31')
        // alert(a)
        break
      case 4 :
      case 6 :
      case 9 :
      case 11 :
        console.log('30')
        break
      case 2:
        console.log('28')
        break
}

循环结构

while和do...while一般用来解决无法确认次数的循环。for循环一般在循环次数确定的时候比较方便 循环 是一种重复运行同一代码的方法

while语句

先判断 再执行

基本语法:

// 当循环条件为true时,执行循环体,
// 当循环条件为false时,结束循环。
while (循环条件) {
  //循环体
}

condition(条件) 为 true 时,执行循环体的代码。

例如,以下将循环输出当 i < 3 时的 i 值:

var i = 0;
while (i < 3) { // 依次显示 012
  console.log(i);
  i++;
}
​
//递减操作
var i = 10;
while (i) { // 10 9 8 7 6 5 4 3 2 1
   console.log(i);
   i--;
}

do...while语句

先执行一次 再判断循环

do..while循环和while循环非常像,二者经常可以相互替代,但是do..while的特点是不管条件成不成立,都会执行一次。

基础语法:

do {
  // 循环体;
} while (循环条件);

代码示例:

// 初始化变量
var i = 1;
var sum = 0;
do {
  sum += i;//循环体
  i++;//自增
} while (i <= 100);//循环条件

案例:

100以内所有3的倍数的和
使用do-while循环:输出询问confirm “起床没?”,选择"确定" 打印'继续睡吧,我就是跟你说一下你要迟到了', 选择"取消" 继续输出询问confirm “起床没?”
   do {
      var a = confirm('起床没')
     if(a){
       console.log('继续睡吧,我就跟你说一声')
     }
   } while (a=== false);

for语句

while和do...while一般用来解决无法确认次数的循环。for循环一般在循环次数确定的时候比较方便

for循环语法:

// for循环的表达式之间用的是;号分隔的,千万不要写成,
for (初始化表达式1; 判断表达式2; 自增or自减表达式3) {
  // 循环体4
}

执行顺序:1243 ---- 243 -----243(直到循环条件变成false)

  1. 初始化表达式
  2. 判断表达式
  3. 自增表达式
  4. 循环体

案例:

打印1-100之间所有数
求1-100之间所有数的和
求1-100之间所有数的平均值
求1-100之间所有偶数的和
同时求1-100之间所有偶数和奇数的和
打印正方形
// 使用拼字符串的方法的原因
// console.log 输出重复内容的问题
// console.log 默认输出内容介绍后有换行
var start = '';
for (var i = 0; i < 10; i++) {
  for (var j = 0; j < 10; j++) {
    start += '* ';
  }
  start += '\n';
}
console.log(start);
打印直角三角形
var start = '';
for (var i = 0; i < 10; i++) {
  for (var j = i; j < 10; j++) {
    start += '* ';
  }
  start += '\n';
}
console.log(start);

打印9*9乘法表
var str = '';
for (var i = 1; i <= 9; i++) {
  for (var j = i; j <=9; j++) {
    str += i + ' * ' + j + ' = ' + i * j + '\t';
  }
  str += '\n';
}
console.log(str);

练习:

打印9 9 乘法表
求1-100之间所有数的乘积
求1-100之间所有奇数的和
计算1-100之间能3整除的数的和
计算1-100之间不能被7整除的数的和
//选做
// 讲解思路。如果不会写程序,可以先把数学公式准备好
本金10000元存入银行,年利率是千分之三,每过1年,将本金和利息相加作为新的本金。计算5年后,获得的本金是多少?
var qian = 10000
    for(var i =1 ;i<=5;i++){
      // qian+=qian*0.003
      qian*=1.003
    }
console.log(qian)

大马驮2石粮食,中马驮1石粮食,两头小马驮一石粮食,要用100匹马,驮100石粮食,该如何 调配
    //大马驮2石粮食,中马驮1石粮食,两头小马驮一石粮食,要用100匹马,驮100石粮食,该如何 调配
    //驮100石粮食,大马需要50匹  大马为2a
    //驮100石粮食,中马需要100匹
    //驮100石粮食 小马等于100-大马-小马
    for(var a = 0; a<=50 ;a++){
      for(var b = 0;b<=100;b++){
        var c = 100 - a - b
        if((a + b + c ===100) && (2*a + b + c/2 === 100)){
          document.write('大马'+a+'中马'+b+'小马'+c+'<br>')
        }
      }
    }
    
    
五个小朋友排成一队。问第一个多大了,第一个说比第二个大两岁,问第二个,第二个说比第 三个大两岁,
以此类推。问第五个小朋友几岁了,第五个小朋友说3岁了。问第一个小朋友几岁 ?
var a = 3
    for(var i = 0; i<5;i++){
      a+=2
    }
document.write(a)

continue和break

break:立即跳出整个循环,即循环结束,开始执行循环后面的内容(直接跳到大括号)退出一个大循

continue:立即跳出当前循环,继续下一次循环(跳到i++的地方)

调试

  • 过去调试JavaScript的方式

    • alert()
    • console.log()
  • 断点调试

断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。

  • 调试步骤
浏览器中按F12-->sources-->找到需要调试的文件-->在程序的某一行设置断点

  • 调试中的相关操作
Watch: 监视,通过watch可以监视变量的值的变化,非常的常用。
F10: 程序单步执行,让程序一行一行的执行,这个时候,观察watch中变量的值的变化。
F8:跳到下一个断点处,如果后面没有断点了,则程序执行结束。

tips: 监视变量,不要监视表达式,因为监视了表达式,那么这个表达式也会执行。

  1. 代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug的能力。初学者不要觉得调试代码麻烦就不去调试,知识点花点功夫肯定学的会,但是代码调试这个东西,自己不去练,永远都学不会。
  2. 今天学的代码调试非常的简单,只要求同学们记住代码调试的这几个按钮的作用即可,后面还会学到很多的代码调试技巧。

数组

数组的概念

所谓数组,就是将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。

数组的定义

数组是一个有序的列表,可以在数组中存放任意的数据,并且数组的长度可以动态的调整。

创建方式

通过实例化创建 内置构造函数

var arr = new Array()
var arr = new Array(3); //只写一个参数,创建一个长度为3的数组 , 数组中每一项都为 空置empty [empty,empty,empty]
arr = new Array(1,2,3,4); //多个参数  会生成对应参数个数与内容的数组 [1,2,3,4]

通过数组字面量创建数组

// 创建一个空数组
var arr1 = []; 
// 创建一个包含3个数值的数组,多个数组项以逗号隔开
var arr2 = [1, 3, 4]; 
// 创建一个包含2个字符串的数组
var arr3 = ['a', 'c']; 

数组的属性

var arr = [1,2,3,4];
// 可以通过数组的length属性获取数组的长度
console.log(arr.length);
// 可以设置length属性改变数组中元素的个数
arr.length = 0;

获取数组元素

// 格式:数组名[下标]	下标又称索引
// 功能:获取数组对应下标的那个值,如果下标不存在,则返回undefined。
var arr = ['red', 'green', 'blue'];
arr[0];	// red
arr[2]; // blue
arr[3]; // 这个数组的最大下标为2,因此返回undefined

遍历数组

数组遍历的基本语法:

for(var i = 0; i < arr.length; i++) {
	// 数组遍历的固定结构
}

for in 遍历(不推荐)

for(var key in arr){
    console.log(key,arr[key]);  //key 为下标 arr[key]为对应key下标的值
}

使用for-in可以遍历数组,但是会存在以下问题:

1.index索引为字符串型数字(注意,非数字),不能直接进行几何运算。

2.遍历顺序有可能不是按照实际数组的内部顺序(可能按照随机顺序)

for of 遍历

for(var key of arr){
    console.log(key); 
}
key直接代表 数组元素
相比 for-in 不会出现顺序错乱的问题 也不会遍历出所有可枚举属性

数组元素赋值

数组的赋值

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

arr[2] = 'yellow'; //给下标为2的数组元素赋值 如果该元素本身有值会进行覆盖

arr[3] = '#368'; // 给下标为3的数组元素赋值 如果该元素不存在就新增

arr //["red", "green", "yellow", "#368"]

arr[5] = '#f60'; //如果跨位进行赋值 空位显示 empty (空置)

arr // ["red", "green", "yellow", "#368", empty, "#f60"]

多维数组

数组中包含数组的话称之为多维数组。 您可以通过将两组方括号链接在一起来访问数组内的另一个数组 使用最多的是二维数组

var arr = [[1,2,3],[4,5,6],[7,8,9]];
arr[2][1] //8

数组类型判定与隐式转换(隐式转换的补充)

var arr = [1,2,3];

typeof arr //'object'

Number(arr) //NaN

String(arr) // '1,2,3'

Bollean(arr) // true

[] == [] //false
比较的地址 不是表面看到的值

arr + '海牙' //'1,2,3海牙'

arr / 2 // NaN

arr + [] // '1,2,3'

[] + [] //''

[2]  - 1 //1

[1,]  - 1 //0
//ie 678 会把[1,]解析成[1,undeifind] 转换成number NAN

[1,2]  - 1 // NaN
//当数组中只有一项时可以转换为数字 进行运算

!![] // true
//空字符串 转布尔类型 也是true

数组基础方法(面试)

isArray(obj)

用于确定传递的值是否是一个 Array。

Array.isArray([1, 2, 3]);  
// true
Array.isArray({foo: 123}); 
// false
Array.isArray("foobar");   
// false
Array.isArray(undefined);  
// false

参数

obj 需要检测的值

返回值

如果值是Array 则为true; 否则为false

join(separator)

方法将一个数组的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

const elements = ['火', '空气', '水'];
console.log(elements.join());
// "火,空气,水"
console.log(elements.join(''));
// "火空气水"
console.log(elements.join('-'));
// "火-空气-水"

参数

separator 可选 指定分隔符号 该参数默认值为","

返回值

一个所有数组元素连接的字符串。如果 arr.length0,则返回空字符串。

注意

如果一个元素为 undefinednull,它会被转换为空字符串。

push(element1,...,elementN)

方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

var animals = ['猪', '狗', '牛'];
​
var count = animals.push('大象');
console.log(count);
// 4
console.log(animals);
// ['猪', '狗', '牛','大象']
​
animals.push('鸡', '鸭', '鹅');
console.log(animals);
//['猪', '狗', '牛', '大象', '鸡', '鸭', '鹅']
​
​

参数

elementN 可选多个参数
参数会添加到数组末尾

返回值

当调用该方法时,新的 length 属性值将被返回。

unshift(element1,...,elementN)

方法将一个或多个元素添加到数组的头部,并返回该数组的新长度。

var animals = ['猪', '狗', '牛'];
​
var count = animals.unshift('大象');
console.log(count);
// 4
console.log(animals);
// ['大象', '猪', '狗', '牛']
​
animals.unshift('鸡', '鸭', '鹅');
console.log(animals);
//[ '鸡', '鸭' , '鹅','大象','猪', '狗', '牛' ]
​
​

参数

elementN 可选多个参数
参数会添加到数组头部

返回值

当调用该方法时,新的 length 属性值将被返回。

pop()

方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];
​
console.log(plants.pop());
//  "土豆"
​
console.log(plants);
// ['西红柿', '黄瓜', '芹菜', '豆角']
​
plants.pop();
​
console.log(plants);
// ['西红柿', '黄瓜', '芹菜']
​
​

参数

返回值

从数组中删除的元素(当数组为空时返回undefined)。

shift()

方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

var array = [1, 2, 3];
​
var firstElement = array.shift();
​
console.log(array);
//  Array [2, 3]
​
console.log(firstElement);
//  1
​
​

参数

返回值

从数组中删除的元素; 如果数组为空则返回undefined 。 

slice()

切割方法返回一个新的数组对象,这一对象是一个由 beginend 决定的原数组的浅拷贝(包括 begin(起始下标),不包括end(结束下标))。原始数组不会被改变。

var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];
​
console.log(plants.slice(2));
// ['芹菜', '豆角', '土豆']
​
console.log(plants.slice(2, 4));
// [ '芹菜', '豆角']
​
console.log(plants.slice(1, 5));
//  ['黄瓜', '芹菜', '豆角', '土豆']

参数

arr.slice([begin, end) //beginend都是可选参数
如果不传参 默认切割整个数组
begin 可选
    提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
    如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒
    第二个元素到最后一个元素(包含最后一个元素)。
    如果省略 begin,则 slice 从索引 0 开始。
    **如果 begin 大于原数组的长度,则会返回空数组。
​
end 可选
    提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从
    beginend 的所有元素(包含 begin,但不包含 end)。
    slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。
    如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数
    组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
    如果 end 被省略,则 slice 会一直提取到原数组末尾。
    **如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。
​

返回值

一个含有被提取元素的新数组。

concat()

合并方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

不传参数 concat 会返回调用此方法的现存数组的一个浅拷贝。

var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];
var otherPlants = ['冬瓜', '韭菜']
var newPlants = plants.concat(otherPlants);
​
console.log(newPlants); 
//['西红柿', '黄瓜', '芹菜', '豆角', '土豆', '冬瓜', '韭菜']

参数

var newArray = oldArray.concat(value1[, value2[, ...[, valueN]]]);

valueN可选
数组和/或值,将被合并到一个新的数组中。如果省略了所有 valueN 参数,则 concat 会返回调用此
方法的现存数组的一个浅拷贝。

返回值

一个合并后的新数组。

indexOf()

方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆','黄瓜'];
​
console.log(plants.indexOf('黄瓜')); 
//1console.log(plants.indexOf('黄瓜',3)); 
//5console.log(plants.indexOf('大象')); 
//-1

参数

//arr.indexOf(searchElement[, fromIndex])
arr.indexOf(searchElement, fromIndex)
searchElement
要查找的元素
​
fromIndex 可选
开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。如果参数中提供的引
值是一个负值,则将其作为数组末尾的一个抵消,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素
开始查找 ,以此类推。 注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从
前向后查询数组。如果抵消后的索引值仍小于0,则整个数组都将会被查询。其默认值为0.

返回值

首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1

lastIndexOf()

从后往前 相当于 反向的indexOf()

方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

    //lastIndexOf() 
    var of1 = [1,2,3,4,5,6,3,2]
    console.log(of1.lastIndexOf(2))//7
    console.log(of1.lastIndexOf(2,3))//1
    console.log(of1.lastIndexOf(20))//-1 没有找到

reverse()

功能:将数组中的元素颠倒顺序。
输入:无
输出:逆序的数组
举例:

var a = [1,2,3];
a.reverse.join()// =>"3,2,1"

sort

//排序

var arr=[3,24,6,18,7,21];
    arr.sort();
    console.log(arr); //=>[18,21,24,3,6,7]
​
    var arr1=[3,24,6,18,7,21];
    arr1.sort(function(a,b){
      return a-b
    });
    console.log(arr1); //=>[3,6,7,18,21,24]

参数

语法1:数组.sort()
            会将数组转换为 字符串后,一位一位的对比
            sort方法会调用数组中每一项的toString()方法,按照unicode编码进行排序,如果数组含有undefined元素,它们将会被排到尾部。
        
​
        数组元素超过2位数排序就出了问题,上面已经说过了sort排序是按照元素的unicode码来进行排序了,
        先对每一项的第一位按照unicode从小到大进行排序,如果第一位相同再将第二位按照ascii从小到大进行排序。
        因为 12367的unicode码分别是:3132333637,
        所以顺序首先是:[18,14,21,3,6,7]的第一位unicode码相同,所以再比较第二位,
        1的ascii是494的ascii码是52,所以2124的前面,最终的排序结果是:[18,21,24,3,6,7]。
​
        虽然原因找到了,但是不是我们想要的排序结果,Array.sort()方法允许我们传入一个比较函数进去
        语法2:数组.sort(function(a,b){return a - b})
            会按照数字大小升序排列
        语法2:数组.sort(function(a,b){return b - a})
            会按照数字大小降序排列

返回值

排序后的新数组。

splice()

功能:从数组中删除元素、插入元素到数组中或者同事完成这两种操作。

输入:第一个参数为指定插入或删除的起始位置,第二个参数为要删除的 个数。之后的参数表示需要插入到数组中的元素 输出:返回一个由删除元素组成的数组。 如果没有删除返回空数组 注意:新建了一个数组,并修改了原数组

var a = [1,2,3]
var b = a.splice(1,1,'123')
console.log(a)//[1,'123','3']
console.log(b)//[2]

参数

第一个参数为指定插入或删除的起始位置,
第二个参数为要删除的个数。0就是不删除
之后的参数表示需要插入到数组中的元素 

返回值

返回一个由删除元素组成的数组。 

能够遍历数组的语法

forEach()

遍历数组 没有返回值

forEach(function (item,index,origin) {})

参数依次为:数组元素、元素的索引、数组本身

item,index,origin 可以修改 是自己命名的

功能:从头至尾遍历数组,为每个元素调用指定函数

输入:输入为一个待遍历函数

函数的参数依次为:数组元素、元素的索引、数组本身

输出:只是执行了遍历函数,无特定返回

map()

映射数组:返回一个和原数组长度相同的数组

功能:调用的数组的每一个元素传递给指定的函数,并返回一个新数组

输入:和forEach一样

输出:执行完函数的新数组 注意:返回新数组,不修改原数组

举例:

var a = [1,2,3];
var b = a.map(function(item,index,origin){
    return item*2;
}); // =>[2,4,6]

filter()

数组.filter(function(a,b,c){})

参数输入: 当前元素的值 当前元素的索引值 当前元素属于的数组对象

输出:一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

不会改编原始数组

filter() 不会对空数组进行检测。

var  arr = [1,2,3,5,6,3,2,1]
var newarr = arr.filter(function(item,index,origin){
   return item >1
})
console.log(arr)//[1,2,3,5,6,3,2,1]
console.log(newarr)// [2, 3, 5, 6, 3, 2]

find()/findIndex()

判断找到的第一个值 find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。

findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。

数组.filter(function(*item*,*index*,origin){})s

输入:回调函数,所有数组成员依次执行该函数,直到找到第一个返回值为true的成员。 回调函数可以接受三个参数,依次为值,位置,原数组。

find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。
find() 方法为数组中的每个元素都调用一次函数执行:
​
    当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
    如果没有符合条件的元素返回 undefined
​
find() 对于空数组,函数是不会执行的。
find() 并没有改变数组的原始值。

findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
findIndex() 方法为数组中的每个元素都调用一次函数执行:
​
    当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
    如果没有符合条件的元素返回 -1findIndex() 对于空数组,函数是不会执行的。
findIndex() 并没有改变数组的原始值。

var arr = [2,3,4,5,6,8,9,3]
//find()
var newarr = arr.find(function(item,index,origin){
   return item >3
})
console.log(newarr)//4 返回的是数组的值
​
​
//findIndex()
var newarr1 = arr.findIndex(function(item,index,origin){
      return item >3
})
console.log(newarr1)//2 返回的是地址值

some()

some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
​
    如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
    如果没有满足条件的元素,则返回false。
    
some() 不会对空数组进行检测。
some() 不会改变原始数组。
参数:item当前元素的值
     index当前元素的索引值
     arr当前元素属于的数组对象

var arr = [6,5,4,3,6,5]
    var newarr = arr.some(function(item,index,origin){
    return item >5
})
console.log(newarr)//true

every()

every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
​
    如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
    如果所有元素都满足条件,则返回 true。
    
every() 不会对空数组进行检测。
every() 不会改变原始数组。
参数:currentValue当前元素的值
     index当前元素的索引值
     arr当前元素属于的数组对象

var arr = [6,5,4,3,6,5]
    var newarr1 = arr.every(function(item,index,origin){
    return item >3
})
console.log(newarr1)//false

reduce

reduce()方法为归并类方法,最常用的场景就是,计算数组中的每一项的总和。

语法:arr.reduce(callback,[initialValue])
          callback:函数中包含四个参数
            - previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
            - currentValue (数组中当前被处理的元素)
            - index (当前元素在数组中的索引)
            - array (调用的数组)
          initialValue (作为第一次调用 callback 的第一个参数。)
如果第二个参数initialValue 传递了 循环array.length次 初始值为 initialValue
如果第二个参数没有传递,初始值为array[0],cur从array[1]开始 循环array.length-1
1.当reduce()方法的第二个值为空时,第一次循环方法中的第一个参数(prev)为数组的第一项值,
第二个参数(cur)为数组的第二项值,      
反之,第一次循环方法中的第一个参数(prev)为reduce的第二个参数值,
第二个参数(cur)为数值的第一项值。

2.reduce()方法的第一个参数,就是每次遍历都会执行的匿名函数,
当前函数的返回值就会传给下一次执行函数的第一个值。也就是prev

 var arr =[1,2,3,4,5]
 var b = arr.reduce(function(prev,cur,index,array){
      return prev + cur
},10)
console.log(b)//25
​
​
var arr =[1,2,3,4,5]
var b = arr.reduce(function(prev,cur,index,array){
      return prev + cur
})
console.log(b)//15

练习

排序(面试大概率)

冒泡排序

冒泡排序是一种比较简单的排序算法,这种算法是让越小或者越大的元素经由交换慢慢“浮”到数列的顶端,就像水里面的泡泡向上浮动一样,所以叫“冒泡排序”。 冒泡排序算法的原理如下:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。  
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个.
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码实现

var arr = [4,6,3,2,7,9,11,1];
var length = arr.length;
var temp; 
//length-1 大循环减少一次 大循环最后一次 不会进入小循环 没什么意义
for(var i = 0; i < length-1; i++) {
    //length-1因为会j+1 如果不减一就会超出
    //因为循环一次 就会确定一个值 所以lentgth-1的基础上-i
    for(var j = 0; j< length - i - 1; j++) {
        if (arr[j] > arr[j + 1]) {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
}

选择排序

选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

代码表现

var arr = [4,6,3,2,7,9,11,1];
var length = arr.length;
var minIndex, temp; 
for (var i = 0; i < length - 1; i++) {
    //每循环完一次 就确定一个值 
    minIndex = i;
    //先从0开始 第一轮结束 第一个值确定 要从第二个开始 所以设置i
    //无需跟自己比较  先跟1比较 一直到最后 i+1
    //length -1 j=j+1 如果j=length = 数组长度 加一就超出了 
    //而且数组前边都确定了 最后一个也就不需要比较了
    for (var j = i + 1; j < length; j++) {
        //判断 如果j中有比初始值小 就把j的下标 赋值给minIndex
      if (arr[j] < arr[minIndex]) { 
          minIndex = j; 
      }
    }
    //初始值 和得到的最小值下标互换
    temp = arr[i];
    arr[i] = arr[minIndex];
    arr[minIndex] = temp;
}


插入排序

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

代码表现

var arr = [4,6,3,2,7,9,11,1];
var length = arr.length;
for (var i = 1; i < length; i++) {
    var key = arr[i], j = i - 1;
    while (arr[j] > key) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = key;
  }

作业练习

//补零 01 02 03 04 05 06 07 08 09 10 11 ...
    for(var i = 1 ; i <=20 ; i++){

      // if(i<10){
      //   i = '0'+ i 
      // }
      // console.log(i)

      //i= i<10 ? '0'+i : i
      // console.log(i)

      //字符串可以像数组一样取下标
      i= String(i)[1] && String(i) || '0'+i
      //'0'字符串 输出是true
      // i=1 => '1'[i] => undfind => false && 	String(i) => false || '0'+i => '0'+i
      console.log(i)
    }

初始 ['a','b','c','d','e'] 
第一次 ['d','e','a','b','c']
第二次 ['b','c','d','e','a']
第三次 ['e','a','b','c','d']
...
请问第五次 第十五次数组是如何?
规律:
每一次变幻相比上一次都是每位值进行了+2位移 超出范围的从0开始 0 1 2 3 4 5 => 4 5 0 1 2 3
    var arr = ['a','b','c','d','e']
    for(var i = 1;i<=15;i++){
      var arr1 = []
      for(var j = 0 ; j<arr.length ; j++){
      //关键点(j+2)%arr.length 
        arr1[(j+2)%arr.length] = arr[j]
        
      }
      arr = arr1
      console.log(arr)
    }

字符串基础方法

charAt()

方法从一个字符串中返回指定的字符。

var str ='你好,我是海牙老师';
console.log(str.charAt(3)); 
//返回了 str[3]的值

参数

index
字符串中的字符从左向右索引,第一个字符的索引值为 0,最后一个字符(假设该字符位于字符串 stringName中)
的索引值为 stringName.length - 1。 如果指定的 index 值超出了该范围,则返回一个空字符串。

返回值

指定字符串

indexOf()

跟数组的indexof有区别 注意

方法返回在字符串中可以找到一个给定字符的第一个首字对应索引,如果不存在,则返回-1。

var plants = '西红柿,黄瓜,芹菜,豆角,土豆,黄瓜'; //length 18console.log(plants.indexOf('黄瓜')); 
//4console.log(plants.indexOf('黄瓜',5)); 
//16console.log(plants.indexOf('黄')); 
//4console.log(plants.indexOf('黄瓶')); 
//-1console.log(plants.indexOf('大象')); 
//-1console.log(plants.indexOf('')); 
//0
​
​
console.log(plants.indexOf('',5)); 
//5console.log(plants.indexOf('',19)); 
//18 超出长度的参数会返回长度

参数

str.indexOf(searchValue, fromIndex)
​
searchValue
要被查找的字符串值。
如果没有提供确切地提供字符串,searchValue 会被强制设置为 "undefined", 然后在当前字符串中查找这个值。
举个例子:'undefined'.indexOf() 将会返回0,因为 undefined 在位置0处被找到,
但是 'undefine'.indexOf() 将会返回 -1 ,因为字符串 'undefined' 未被找到。
​
fromIndex 可选
数字表示开始查找的位置。可以是任意整数,默认值为 0。
如果 fromIndex 的值小于 0,或者大于 str.length ,那么查找分别从 0str.length 开始。
(译者注:  fromIndex 的值小于 0,等同于为空情况; fromIndex 的值大于 str.length ,那么结果会直接返回 -1 。)
举个例子,'hello world'.indexOf('o', -5) 返回 4 ,因为它是从位置0处开始查找,
然后 o 在位置4处被找到。
另一方面,'hello world'.indexOf('o', 11) (或 fromIndex 填入任何大于11的值)将会返回 -1 ,
因为开始查找的位置11处,已经是这个字符串的结尾了。

返回值

查找的字符串 searchValue 的第一次出现的索引,如果没有找到,则返回 -1。

split()

方法使用指定的分隔符字符串将一个String对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。

var str ='你好,我是海牙老师';
var arr = str.split(',');
​
console.log(arr); 
// ['你好','我是海牙老师']
​
var str ='你好,我是海牙老师';
var arr = str.split('');
​
console.log(arr); 
// ["你", "好", ",", "我", "是", "海", "牙", "老", "师"]
​
var str ='你好,我是海牙老师';
var arr = str.split();
​
console.log(arr); 
//["你好,我是海牙老师"]
​
​
​
var str ='你好,我,是海,牙老,师';
var arr = str.split(',',3);
​
console.log(arr); 
// ["你好", "我", "是海"]

参数

str.split([separator[, limit]])
separator
指定表示每个拆分应发生的点的字符串。separator 可以是一个字符串或正则表达式。 
如果纯文本分隔符包含多个字符,则必须找到整个字符串来表示分割点。
如果在str中省略或不出现分隔符,则返回的数组包含一个由整个字符串组成的元素。
如果分隔符为空字符串,则将str原字符串中每个字符的数组形式返回。
limit
一个整数,限定返回的分割片段数量。
当提供此参数时,split 方法会在指定分隔符的每次出现时分割该字符串,但在限制条目已放入数组时停止。
如果在达到指定限制之前达到字符串的末尾,它可能仍然包含少于限制的条目。新数组中不返回剩下的文本。

返回值

返回源字符串以分隔符出现位置分隔而成的一个 数组(Array)

slice()

方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。

var str = 'The quick brown fox jumps over the lazy dog.';
​
console.log(str.slice(31));
//  "the lazy dog."
​
console.log(str.slice(4, 19));
//  "quick brown fox"
​
console.log(str.slice(-4));
//  "dog."
​
console.log(str.slice(-9, -5));
//  "lazy"
​
​

参数

str.slice(beginIndex[, endIndex])
​
beginIndex
从该索引(以 0 为基数)处开始提取原字符串中的字符。如果值为负数,会被当做 strLength + beginIndex 看待,这里的strLength 是字符串的长度(例如, 如果 beginIndex 是 -3 则看作是:strLength - 3)
​
endIndex
可选。在该索引(以 0 为基数)处结束提取字符串。如果省略该参数,slice() 会一直提取到字符串末尾。如果该参数为负数,则被看作是 strLength + endIndex,这里的 strLength 就是字符串的长度(例如,如果 endIndex 是 -3,则是, strLength - 3)。

返回值

返回一个从原字符串中提取出来的新字符串

trim()

方法会从一个字符串的两端删除空白字符。在这个上下文中的空白字符是所有的空白字符 (space, tab, no-break space 等) 以及所有行终止符字符(如 LF,CR等)。

var greeting = '   Hello world!   ';
​
console.log(greeting);
//  "   Hello world!   ";
​
console.log(greeting.trim());
//  "Hello world!";

返回值

一个依据调用字符串两端去掉空白的新字符串。

JavaScript 函数

函数是程序的主要“构建模块”。函数使该段代码可以被调用很多次,而不需要写重复的代码。 我们已经看到了内置函数的示例,如 alert(message)prompt(message, default)confirm(question)。但我们也可以创建自己的函数。

一个函数只做一件事、函数不调用 没有任何意义

函数定义

JavaScript 函数是被设计为执行特定任务的代码块。

JavaScript 函数会在某代码调用它时被执行。

什么是函数?

把一段相对独立的具有特定功能的代码块封装起来,形成一个独立实体,就是函数,起个名字(函数名),在后续开发中可以反复调用

函数的基础作用就是封装一段代码,将来可以重复使用。我们称之为 封装

函数示例

 function padLeft(num) {
     return String(num)[1] && String(num) || '0' + num;
 }
​
 var result = padLeft(3);
 console.log(result); //'03'

分解图

image-20200722165517471.png

函数的类型

函数拥有自己的数据类型 在某些老版本浏览器中会辨识为 object 需要用 Object.prototype.toString.call()来进行判断

function fn() {}
console.log(typeof fn);
//functionconsole.log(Object.prototype.toString.call(fn));
// "[object Function]"

函数的定义

函数的定义 有 函数表达式函数声明 两种, 函数声明的时候,函数体并不会执行,只要当函数被调用的时候才会执行。

JavaScript 函数通过 function 关键词进行定义,其后是函数名和括号 ()。

函数名可包含字母、数字、下划线和美元符号(规则与变量名相同)。

函数声名 调用函数可以放到 声名前面 因为函数声名 第一时间就声名好了

函数表达式 只有运行到这一行的时候才运行 所以不能在前边调用

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

  • 函数表达式
var 变量名 = function() {
  // 函数体
}

函数名:

函数一般都用来干一件事情,需用使用动词+名词 的驼峰结构命名,例如: setValue clearInterval 等。

函数调用

函数有声明就有调用,函数内代码只有在调用时才会执行。函数可以多次调用。

函数名(); //主动调用

//从指定数组中查询目标值
function findIdx(arr, target) {
    for (var i = 0, len = arr.length; i < len; i++) {
        if (arr[i] === target) {
            return i;
        }
    }
    return -1;
}
​
console.log(findIdx([1,2,3,4,5], 3)); //2
​
console.log(findIdx([1,2,5,4,5], 3)); // -1
​
​
// 求1-100之间所有数的和
function getSum() {
  var sum = 0;
  for (var  i = 1; i <= 100; i++) {
    sum += i;
  }
  console.log(sum);
}
// 调用
getSum(); //5050

函数的参数

函数的参数分为 形参(parameter) 和 实参(argument) , 当函数需求根据不同的值做出不同反馈时, 就需要通过使用参数。 形参为声明函数时预设的形势参数,我们可以自定义命名。 实参为调用函数时对应 形参所传递的实际参数,为所需要的原始值。

为什么要有参数

function getSum() {
  var sum = 0;
  for (var i = 1; i <= 100; i++) {
    sum += i;
  }
  console.log(sum);
}
​
// 虽然上面代码可以重复调用,但是只能计算1-100之间的值
// 如果想要计算n-m之间所有数的和,应该怎么办呢?

语法:

// 函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部
// 带参数的函数声明
function 函数名(形参1, 形参2, 形参...){
  // 函数体
}
​
// 带参数的函数调用
函数名(实参1, 实参2, 实参3);

对比:

  1. 形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。
  2. 实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。
var x = 5, y = 6;
fn(x,y); 
function sum(num1, num2) {
  console.log(num1 + num2);
}
//x,y实参,有具体的值。函数执行的时候会把x,y复制一份给函数内部的a和b,函数内部的值是复制的新值,无法修改外部的x,y

注意:

如果函数调用时 没有传入实参 对应形参默认值为 undefined

JavaScript 参数通过传递:函数只知道值,而不是参数的位置。

如果函数改变了参数的值,它不会改变参数的原始值。

参数的改变在函数之外是不可见的。

函数返回值

当 JavaScript 到达 return 语句,函数将停止执行。

如果函数被某条语句调用,JavaScript 将在调用语句之后“返回”执行代码。

返回值语法:

//声明一个带返回值的函数
function 函数名(形参1, 形参2, 形参...){
  //函数体
  return 返回值;
}
​
//可以通过变量来接收这个返回值
var 变量 = 函数名(实参1, 实参2, 实参3);

函数的调用结果就是返回值,因此我们可以直接对函数调用结果进行操作。

返回值详解: 如果函数没有显示的使用 return语句 ,那么函数有默认的返回值:undefined 如果函数使用 return语句,那么跟再return后面的值,就成了函数的返回值 如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined 函数使用return语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说return后面的所有其他代码都不会再执行。

arguments

JavaScript 函数有一个名为 arguments 对象的内置对象。

arguments 对象包含函数调用时使用的参数数组。

这样,您就可以简单地使用函数来查找(例如)数字列表中的最高值:

实例

jsx = findMax(1, 123, 500, 115, 44, 88);
function findMax() {   
    var i;    
    var max = -Infinity;
    for (i = 0; i < arguments.length; i++) { 
        if (arguments[i] > max) {  
            max = arguments[i];       
        }   
    } 
    return max;
}

或创建一个函数来总和所有输入值:

实例

jsx = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() { 
    var i, sum = 0;  
    for (i = 0; i < arguments.length; i++) {  
        sum += arguments[i]; 
    }  
    return sum;
}

函数分类

javascript非常适合函数式编程,这里简单介绍下几种基础函数方式的基础应用

纯函数

纯函数(Pure Function)

  1. 如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数
  2. 该函数不会产生任何可观察的副作用
 function padLeft(num) {
     return String(num)[1] && String(num) || '0' + num;
 }

非纯函数(函数副作用)

所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。

var str = '海牙';
function changeStr(){
    str = 'kyogre';
}
console.log(str); //海牙
change();
console.log(str); //kyogre

匿名函数

匿名函数:没有名字的函数

匿名函数如何使用:

将匿名函数赋值给一个变量,这样就可以通过变量进行调用
匿名函数自调用
windon.onload = function(){
    alert('hello');
};

关于自执行函数(匿名函数自调用)的作用:防止全局变量污染。

自调用函数

匿名函数(IIFE)不能通过直接调用来执行,因此可以通过匿名函数的自调用的方式来执行

(function () {
  alert(123);
})();

柯理化函数

柯理化(currying)

函数可以用来作为返回值

函数柯里化允许和鼓励你分隔复杂功能变成更小更容易分析的部分。这些小的逻辑单元显然是更容易理解和测试的,然后你的应用就会变成干净而整洁的组合,由一些小单元组成的组合。

//纯函数
function add(x, y) {
    return x + y;
}
console.log(add(1, 2)); // 3//柯理化
function curryingOfAdd(x) {
    return function (y) {
        return x + y;
    }
}
​
console.log(curryingOfAdd(1)(2)); // 3var tranCurry = add(3);
tranCurry(2); //5
tranCurry(8); //11

递归函数

    function add(n){
        //传递进来的是1
        //当n==5的时候结束
        if(n==5){
            return 5;
        }else{
          //不满足条件的时候,就是当前数字 + 比自己大 1 的数字
            return n + add(n + 1);
      //1+add[2]+add[3]+add[4]+add[5]
      //1+2+add[3]
      //1+2+3+add[4]
      //1+2+3+4+add[5]
        }
    }
    console.log(add(1));    // 15

回调函数 偏函数 递归函数 深度柯理化函数 通道函数 闭包 高阶函数 等函数式编程技巧会在后续学习中慢慢展开

作用域

全局变量和局部变量

  • 全局变量

    在任何地方都可以访问到的变量就是全局变量,对应全局作用域

    在js中,全局作用域中有一个 提前准备好的 对象window

    创建的局部变量,会被自动添加到window对象中

  • 局部变量

    只在固定的代码片段内可访问到的变量,最常见的例如函数内部。对应局部作用域(函数作用域)

不使用var声明的变量是全局变量,不推荐使用。
变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁

块级作用域

任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。 在es5之前没有块级作用域的的概念,只有函数作用域,现阶段可以认为JavaScript没有块级作用域

在 js 中词法作用域规则:

  • 函数允许访问函数外的数据.
  • 整个代码结构中只有函数可以限定作用域.
  • 作用域规则首先使用提升规则分析
  • 如果当前作用规则中有名字了, 就不考虑外面的名
var num = 123;
function foo() {
  console.log( num );//123
}
foo();
//*******************************
if ( false ) {
    var num = 123;
}
console.log( num ); // undefiend

作用域链

作用域链的赋值规则

  1. 在给变量赋值的时候, 首先会去当前作用域查找, 如果有直接赋值, 并停止查找
  2. 如果没有, 会去自己的父级查找, 在父级找到直接修改值然后停止查找, 如果没有继续向自己的父级查找, 直到找到全局作用域
  3. 在全局作用域内, 找到直接赋值修改他的值, 如果没有找到, 那么会在全局作用域创建一个变量, 并赋值
  4. 只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
  5. 将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。
// 案例1:
function f1() {
    function f2() {
    }
}
​
var num = 456;
function f3() {
    function f4() {    
    }
}

// 案例2
function f1() {
    var num = 123;
    function f2() {
        console.log( num );
    }
    f2();
}
var num = 456;
f1();

*作用域练习(待补充)

js没有动态作用域 函数在 声名 的时候 其中的 变量 就确定上下文关系了

作用域和作用域链 看声名的时候

预解析

JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程

预解析过程:

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
  3. 先提升var,在提升function

JavaScript的执行过程

var a = 25;
function abc (){
  alert(a);//undefined
  var a = 10;
}
abc();
// 如果变量和函数同名的话,函数优先
console.log(a);
function a() {
  console.log('aaaaa');
}
var a = 1;
console.log(a);

全局解析规则

函数内部解析规则

变量提升

  • 变量提升

    定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。

  • 函数提升

    JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面

// 1、-----------------------------------
var num = 10;
fun();
function fun() {
  console.log(num);
  var num = 20;
}
//2、-----------------------------------
var a = 18;
f1();
function f1() {
  var b = 9;
  console.log(a);
  console.log(b);
  var a = '123';
}
// 3、-----------------------------------
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
  var a = b = c = 9;
  console.log(a);
  console.log(b);
  console.log(c);
}

对象 Object

JavaScript是一门基于对象的语言。

javascript中 我们称Object为 对象 对象的概念也分广义和狭义:广义上javascript中处处是对象,狭义指的是我们通过{}字面量创建的对象。

JavaScript的对象是无序属性的集合。
    其属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。
对象的行为和特征
    特征---属性
    行为---方法
 事物的特征在对象中用属性来表示。
 事物的行为在对象中用方法来表示。

字面量

字面量(literal)是用于表达源代码中一个固定值的表示法(notation).

几乎所有计算机编程语言都具有对基本值的字面量表示, 诸如: 整数, 浮点数以及字符串; 而有很多也对布尔类型和字符类型的值也支持字面量表示; 还有一些甚至对枚举类型的元素以及像数组, 记录和对象等复合类型的值也支持字面量表示法.

字面量(literal),在高级语言中 我们可以通过更直观更高效的方式直接赋予变量 具体 , 当需要使用值得时候 才会去根据值得类型和内容进行包装解析; 先存储 后解释 。

javascript中字面量包括

1. 字符串字面量(String Literal)

var str = '张晓华'; //张晓华 就是字符串字面量

2.数组字面量(array literal)

var arr = [1,2,3,4,5]; //[1,2,3,4,5] 就是数组字面量

3.对象字面量(object literal)

var obj = {
    name:'橘子',
    age: 1,
    favorite: '小鱼干'
}
​
/*
{
    name:'橘子',
    age: 1,
    favorite: '小鱼干'
}
​
就是对象字面量
​
*/

4.函数字面量(function literal)

var fn = function(){
    alert('你好');
}
​
/*
 function(){
    alert('你好');
}
就是函数字面量
​
*/

创建对象方式(自定义)

创建对象有三种基础方式: 对象字面量 原生对象实例化 自定义构造函数

var obj = {键值对}
键值对 -> key:value
如果对象内部有多个键值对,需要使用逗号间隔

  • 字面量对象
var myCat = {
    name: '橘子',
    color: 'orange',
    age: 1,
    favorite: '小鱼干',
    speak: function(){ 
        console.log('喵~~喵~喵~~~');
    }
}

  • 原生对象实例化 new Object()
var myCat = new Object();
myCat.name = '橘子';
myCat.color = 'orange';
myCat.age = 1;
myCat.favorite = '小鱼干';
myCat.speak = function(){
    console.log('喵~~喵~喵~~~');
}

  • 自定义构造函数(目前了解)
function Cat(name,age,color,favorite){
    this.name = name;
    this.age = age;
    this.color = color;
    this.favorite = favorite;
    this.speak = function(){
       console.log('喵~~喵~喵~~~');
    }
}
var myCat = new Cat('橘子',1,'orange','小鱼干');

对象妙用 return返回多个值

//一个函数 需要返回 数组的每项和以及平均值
    function fn(arr){
      var sum = 0,avg = 0
      for(var i = 0;i<arr.length;i++){
        sum+=arr[i]
      }
      avg = sum / arr.length

      return sum,avg
    }

    console.log(fn([1,2,3]))//只会输出 avg一个值
    
    return[sum,avg]//也可以 
    
    //对象
    //都可以 
    return{
    	avg :avg,
    	sum : sum
    }
     return{
    	'avg' :avg,
    	'sum' : sum
    }

属性 方法

如果一个变量属于一个对象所有,那么该变量就可以称之为该对象的一个属性,属性一般是名词,用来描述事物的特征
如果一个函数属于一个对象所有,那么该函数就可以称之为该对象的一个方法,方法是动词,描述事物的行为和功能

对象增删改查

var person = {
    name:"张三",
    age:30,
    gender:'male',
    sayName:function(){
        console.log("my name is ",this.name);
    }
};
​

访问属性

方式一:点访问
person.name//'张三'
方式二:中括号访问
person['name']//张三

修改属性

person.name = '李四'
person['name']='李四'

添加属性

对象名.新添属性名="属性值";
person.xz = '天平'
对象名['新添属性名']='属性值'
person['xz']='天平'

删除属性

delete 对象名.属性; //点方式
delete person.age
delete 对象名["属性"]; //中括号方式
delete person['age']

特殊情况

/**
 * 一般情况下,点语法与中括号语法,作用相同
 * 
 *  特殊情况夏我们需要使用中括号语法
 *    1.对象的属性名,有纯数字或者特殊符号,只能用中括号方法
 *    2.如果涉及变量相关的时候,也需要使用中括号
 */
 //特殊情况2 如果涉及变量相关的时候,也需要使用中括号
​
    var obj1 = {
      a:1,
      b:2,
      name:'123'
    }
    var myname = 'name'
    //console.log(obj.myname)
    //点语法 会将点后边的字符 当成一个 字符串去使用 
    //obj.myname - >obj.'myname'->undefined
​
    console.log(obj[myname])
    //中括号语法 会将中括号中的字符当变量去使用 
    //obj[myname] ->obj['name']->'123'
     

访问对象中函数方法

需要按照函数调用的方式去使用

//以下结果不一样
person.sayName; //无输出,并不是调用方法
person.sayName(); //my name is jack   方法的调用,方法名后面一定要加上括号才表示调用

for in遍历对象

for(自定义变量名 in 数组/对象){
    //执行代码;
}
var person = {
    name : "jack",
    age : 12,
    sayName:function(){
        console.log("my name is",this.name);
    }
};
​
//自定义变量名key使用来指定数组的索引或者对象的属性和方法
for(var key in person){
    var value = person[key];
    //var value = person.key;
    console.log(key + ' ' + value);
}
//key是一个变量 所以不能用点语法 需要用中括号方法
//key不需要加引号

补充一:通过增强for循环可以从数组中依次获取数组的索引,或者依次从对象中获取到属性名,从以上结果可以发现,方法也被遍历出来了,不过并没有被调用,只是以Function:方法名的形式显示出来了。 补充二:为什么再增强for循环里面的var value = person[key];语句中的key不用加引号,因为这个key是个变量,专门用来存储person对象中的属性名,如果加上引号,则表示key是person中的属性,这样就会返回undefined。

总结

•基本数据类型只需要用到栈区;引用数据类型需要用到栈区和堆区;

•赋值是把右边的值保存到左边的变量中;赋值的过程中传递的栈区的内容;

•函数中的形参相当于函数内部的局部变量 ;实参传给形参的过程就是赋值的过程;

•函数调用完成后,它的局部变量会随之销毁,除非遇到特殊情况(例如闭包)

数字方法

/*
      1.random**
        *语法:Math.random()
        *作用:得到一个随机数0-1,每次生成的数字都不一样,包含0 不包含1
​
      2.round
        * 语法: Math.round()
        * 作用: 将数据 四舍五入取整
      3.ceil**
        * 语法: Math.ceil()
        * 作用: 将数据 向上取整
      4. floor**
        * 语法: Matn.floor()
        * 作用: 将数据 向下取整
​
      5. abs
        * 语法: Math.abs()
        * 作用: 取数据的绝对值
      6.sqrt
          * 语法: Math.sqrt()
          * 作用: 求平方根
      7.pow
        * 语法: Math.pow(基数, 幂)
        * 作用: 求一个基数的 X 次幂
      8. max **
        * 语法: Math.max(数据1, 数据2, 数据3, ...)
         * 作用: 求参数中 的 最大值
      9. min
        * 语法: Math.min(数据1, 数据2, 数据3, ...)
        * 作用: 求参数中 的 最小值
      10. PI
        * 语法: Math.PI
        * 作用: 求圆周率
        *PI 并非方法,而是属性,无需括号
​
    */

随机函数

  //a-b的随机数
​
  //不能用round  比如0-10 010的概率 只有一半
​
  var suiji = *Math*.floor((*Math*.random() * b-a+1) + a);
​
  console.log(suiji)

练习

数组塌陷

//按顺序删除数组内的值
    var arr = [0,1,2,3,4]
    console.log('原始数组'+arr)
​
    for(var i =0; i<arr.length;i++){
      arr.pop() //[0,1,2] i =3 arr.length =3 循环停止了
    }
​
    //组织数组塌陷
    //方法一
    for(var i =arr.length-1; i >= 0;i--){
      // arr.pop() 
      // arr.shift()
      arr.splice(i,1)
    }
​
    //方法二
    for(var i =0; i < arr.length; i++){
      // arr.pop() 
      // arr.shift()
      arr.splice(i,1)
      i-- //i++ i--循环 i一直等于0 直到 arr.length = 0 
          //0<0 不成立 循环结束 
    }
    console.log(arr)
​
    //方法三
    // for(var i =0 , len = arr.length; i<len;i++){
    //   arr.pop()
    // }

js严格模式

/**
*  JS 的严格模式
* 
*  JS 是一个相对不是很严谨的语言, 在开发的时候一些代码也不是很严格
* 
*      换句话说严格模式就是对开发的时候, 你写的代码做了一些要求
* 
*  严格模式的规则
*      1. 声明变量必须要 var 关键字
*      2. 函数的形参不可以重复
* 
*  JS 中默认是没有开启严格模式, 如果想要开启严格模式, 需要手动在代码最开始的位置(script标签内第一行), 写一个字符串 'use strict'
* 
*  现在的公司的项目中, 基本都是按照严格模式开发的
 */