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;
- 先声明 num 这一步称为 变量提升
- 调用console.log() 打印 num的值 这时因为没有给num赋值 num的值还是 初始默认值 undefined
- 给num 赋值 为 10
数据类型
- 数值(number):整数和小数(比如 1 和 3.14 )
- 字符串(string):文本(比如 'Hello World' )。
- 布尔值(boolean):表示真伪的两个特殊值,即 true (真)和 false (假)
- undefined :表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值
- null :表示空值,即此处的值为空 。
- 对象(object):各种值组成的集合。
- symbol (symbol ) : 唯一标识符 //es6学习前不做讨论
通常,数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefined和null,一般将它们看成两个特殊值。
类型分类
传统分类通过存储位置 把数据类型分为 基础类型 和 引用类型
基础类型 存储在 栈内存 中Number、String、Boolean、Undefined、Null和symbol
引用数据类型 存储在 堆内存中 栈内存存储堆内存的地址
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"
-
字符串字面量
‘海牙老师 真的帅’
-
转义符 表现出来的
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);
- 两边只要有一个是字符串,那么+就是字符串拼接功能
- 两边如果都是数字,那么就是算术功能。
- 字符串换行
var longString = '第一行 '
+ '第二行 '
+ '第三行 '
+ '文本内容';
var longString = '第一行 \
第二行 \
第三行 \
文本内容';
longString
- 按位取值(只读)
var str = 'hello world!';
console.log(str[1]); //e
str[1] = 'x'; //无法改写
Boolean类型
布尔值代表“真”和“假”两个状态。“真”用关键字 true 表示,“假”用关键字 false 表示。布尔值只有这两个值。
Boolean字面量: true和false,区分大小写
计算机内部存储:true为1,false为0
Undefined和Null
null 与 undefined 都可以表示“没有”,含义非常相似。将一个变量赋值为 undefined 或 null ,老实说,语法效 果几乎没区别。
- undefined表示一个声明了没有赋值的变量,变量只声明的时候值默认是undefined
- 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()。
比如:undefined和null
console.log(String(undefined))//'undefined'
console.log(String(null))//'null'
拼接字符串方式
num + "",当 + 两边一个操作符是字符串类型,一个操作符是其它类型的时候,会先把其它类型转换成字符 串再进行字符串拼接,返回字符串
转换成布尔类型
Boolean()
!!
(空字符串) null undefined NaN 0 会转换成false 其它都会转换成true
隐式转换(未研究透彻)
递增递减运算符(前置、后置)
- 如果包含的是有效数字字符串或者是有效浮点数字符串,则会将字符串转换(Number())为数值,再进行加减 操作,返回值的类型是:number类型。
- 如果不包含有效数字字符串,则会将字符串的值转换为NaN,返回值的类型是:number类型。
- 如果是boolean类型,则先会把true或者false转换为1或者0,再进行加减操作,返回值的类型是:number类 型。
- 如果是null类型,则先会把null转换为0,在进行加减操作,返回值的类型是:number类型。
- 如果是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
逻辑操作符一般用于语句判断中。通过判断结果返回的值进行后面的语句操作。
&& || 左边进行布尔类型转换尝试
&&如果左边为真 返回右边 左边为假 返回自己本身
|| 如果左边为假 返回右边 左边为真 返回自己本身
- 逻辑非(!)操作符:首先会通过Boolean()函数将其操作值转换为布尔值,然后求反。
- 逻辑与(&&)操作符:如果第一个值经过Boolean()函数转换后为true,则返回第二个操作值,否则返回第一个 操作值。如果有一个操作值为null这返回null,如果有一个操作值为undefined,则返回undefined,如果有 一个值为NaN,则返回NaN。
- 逻辑或(||)操作符:如果第一个值经过Boolean()函数转换为false,则返回第二个操作值,否则返回第一个操 作值。
(注:逻辑操作符的运算为短路逻辑运算:前一个条件已经能够得出结果后续条件不再执行!)
关系操作符(比较运算符)的隐式转换规律
(关系操作符的操作值也可以是任意类型):
- 如果两个操作值都是数值,则直接比较大小。
- 如果两个操作值都是字符串,则字符串进行其Unicode编码进行比较。
- 如果一个操作值是数值,则另一个值转换为数值进行比较。
- 如果一个操作值是对象,则调用对象的valueOf()和toString()方法,然后再进行上述比较。
- 如果一个操作值是布尔值,则将布尔值转换为数值再进行比较。 (注:NaN和任何值都不相等,包括自己,同时它与任何类型比较都会返回false。)
相等操作符==和===的隐式转换规律:
- 布尔值、字符串和数值进行比较,会先将其转换为数值再进行比较。
- null和undefined比较是相等的,但不是全等的。
- 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.
- 关系运算符 和 相等运算符 并不是一个类别的.
- 关系运算符,在设计上,总是需要运算元尝试转为一个number . 而相等运算符在设计上,则没有这方面的考虑.
- 最重要的一点, 不要把 拿 a > b , a == b 的结果 想当然的去和 a >= b 建立联系. 正确的符合最初设计思想的关 系是 a > b 与 a >= b是一组 . a == b 和其他相等运算符才是一组. 比如 a === b , a != b, a !== b .
交互与写入:alert、prompt 和 confirm / write
由于我们将使用浏览器作为我们的演示环境,让我们看几个与用户交互的函数:alert,prompt 和confirm。
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) { // 依次显示 0、1 和 2
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-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: 监视变量,不要监视表达式,因为监视了表达式,那么这个表达式也会执行。
- 代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug的能力。初学者不要觉得调试代码麻烦就不去调试,知识点花点功夫肯定学的会,但是代码调试这个东西,自己不去练,永远都学不会。
- 今天学的代码调试非常的简单,只要求同学们记住代码调试的这几个按钮的作用即可,后面还会学到很多的代码调试技巧。
数组
数组的概念
所谓数组,就是将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。
数组的定义
数组是一个有序的列表,可以在数组中存放任意的数据,并且数组的长度可以动态的调整。
创建方式
通过实例化创建 内置构造函数
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.length 为0,则返回空字符串。
注意
如果一个元素为 undefined 或 null,它会被转换为空字符串。
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()
切割方法返回一个新的数组对象,这一对象是一个由
begin和end决定的原数组的浅拷贝(包括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) //begin 和end都是可选参数
如果不传参 默认切割整个数组
begin 可选
提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒
第二个元素到最后一个元素(包含最后一个元素)。
如果省略 begin,则 slice 从索引 0 开始。
**如果 begin 大于原数组的长度,则会返回空数组。
end 可选
提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从
begin 到end 的所有元素(包含 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('黄瓜'));
//1
console.log(plants.indexOf('黄瓜',3));
//5
console.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从小到大进行排序。
因为 1、2、3、6、7的unicode码分别是:31、32、33、36、37,
所以顺序首先是:[18,14,21,3,6,7]的第一位unicode码相同,所以再比较第二位,
1的ascii是49,4的ascii码是52,所以21在24的前面,最终的排序结果是:[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() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 -1
findIndex() 对于空数组,函数是不会执行的。
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
练习
排序(面试大概率)
冒泡排序
冒泡排序是一种比较简单的排序算法,这种算法是让越小或者越大的元素经由交换慢慢“浮”到数列的顶端,就像水里面的泡泡向上浮动一样,所以叫“冒泡排序”。 冒泡排序算法的原理如下:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个.
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码实现
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 18
console.log(plants.indexOf('黄瓜'));
//4
console.log(plants.indexOf('黄瓜',5));
//16
console.log(plants.indexOf('黄'));
//4
console.log(plants.indexOf('黄瓶'));
//-1
console.log(plants.indexOf('大象'));
//-1
console.log(plants.indexOf(''));
//0
console.log(plants.indexOf('',5));
//5
console.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 ,那么查找分别从 0 和str.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'
分解图
函数的类型
函数拥有自己的数据类型 在某些老版本浏览器中会辨识为 object 需要用 Object.prototype.toString.call()来进行判断
function fn() {}
console.log(typeof fn);
//function
console.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);
对比:
- 形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。
- 实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。
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)
- 如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。
- 该函数不会产生任何可观察的副作用
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)); // 3
var 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:
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代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
- 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
- 先提升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 0和10的概率 只有一半
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'
*
* 现在的公司的项目中, 基本都是按照严格模式开发的
*/