js初级基础总结

183 阅读1小时+

第一段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;

标识符 ( 变量名称 )

命名规则

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

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

命名规范

  • 具有语义性的 英文单词 不要用无意义字符 如: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,一般将它们看成两个特殊值。

类型分类

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

基础类型 存储在 栈内存 中NumberStringBooleanUndefinedNull和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"

  • 字符串字面量

    ‘海牙老师 真的帅’

  • 转义符 表现出来的

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);

保留小数(掌握)

语法:toFixed(保留几位小数),保留小数的时候四舍五入,并且返回的是字符串

var numx = 123.123456
console.log(numx.toFixed(5))//123.12346
console.log(numx.toFixed(2))//123.123

转换成字符串类型

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

100.toSting(2)//1100100
转换出来是字符类型

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。

总结

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

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

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

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

instanceof

在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。

instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如:

var oStringObject = new String("hello world");
console.log(oStringObject instanceof String);      // 输出 "true"

字面量和构造函数的关系

var num = 1
​
//var numObj = new Number(1)//临时对象
//numObj.toString()
console.log(num.toString()) 
    //num.toString() 运行的时候 相当于隐式发生了三步
//numObj = null 实际上可能不是这么消除对象 但我们是这样消除

构造函数

面向对象编程’的第一步,就是要生成对象。而js中面向对象编程是基于构造函数(constructor)和原型链(prototype)的。

前面说过,“对象”是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后“对象”根据这个模板生成。

js语言中使用构造函数(constructor)作为对象的模板。所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。

function Person(name,age,sex){ //Person就是构造函数
    //var person = new Obj()
    //虚拟对象=>this //隐藏代码
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.speak = function(){
        console.log('我叫' + this.name + ',今年:' + this.age + '岁,性别:' + this.sex);
    }
    //return this //隐藏代码 new
}
  a:构造函数的函数名的第一个字母通常大写。
​
  b:函数体内使用this关键字,代表所要生成的对象实例。
​
  c:生成对象的时候,必须使用new命令来调用构造函数。

new关键字(实例化构造函数)

构造函数 ,是一种特殊的函数。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

new构造函数的时候 给构造函数隐式了一个 return this

  1. 构造函数用于创建一类对象,首字母要大写。
  2. 构造函数要和new一起使用才有意义。

new在执行时会做四件事情

1 创建一个空对象,作为将要返回的对象实例。
​
2 将空对象的原型指向了构造函数的prototype属性。
​
3 将空对象赋值给构造函数内部的this关键字。
​
4 开始执行构造函数内部的代码。

this详解

JavaScript中的this指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解
现在我们需要掌握函数内部的this几个特点
    1. 函数在定义的时候this是不确定的,只有在调用的时候才可以确定
    2. 一般函数直接执行,内部this指向全局window
    3. 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
    4. 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到了这个隐式对象身上,后续通过new关键字来调用,从而实现实例化

对象的使用

遍历对象的属性

通过for..in语法可以遍历一个对象

​
var obj = {};obj.name = 'object';
obj['name'] = 'object';
​
var key = 'name';
//obj.key 相当于直接去找obj中属性名是key的值
console.log(obj[key]);
//obj[key] => obj['name']
​
for (var i = 0; i < 10; i++) {
  obj[i] = i * 2;
}
​
for(var key in obj) {
  console.log(key + "==" + obj[key]);
}
​

删除对象的属性

function fun() { 
  this.name = 'mm';
}
var obj = new fun(); 
console.log(obj.name); // mm 
delete obj.name;
console.log(obj.name); // undefined

JSON格式对象

JSON即Javascript对象表示方法 (Javascript Object Notation) ,也就是通过字面量来表示一个对象:

JSON 英文全称 JavaScript Object Notation
JSON 是一种轻量级的数据交换格式。
它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集

JSON 语法:

json 中的建名 一定要用双引号

数据使用键名/值对表示,键名是字符串,值没有限定;
例如 “language”:”Java”
每个数据之间由逗号分隔;
使用大括号保存对象,对象可以包含若干个数据;
使用方括号保存数组,数组值使用“,”分割;
​
JSON数据使用’”键名”:”值”’的形式,其中键名要求是字符串,而值 可以是以下任意类型:
1. 数值(整数,浮点数)
2. 字符串(在双引号中)
3. 逻辑值(true/false)
4. 数组(在方括号中)
5. 对象(在花括号中)

JSON 示例:

var nodeDate = {
    "NodeName" : "P",
    "NodeType" : "Node.ELEMENT_NODE",
    "NodeId" : "",
    "NodeClassName" : "des",
    "NodeStyle": "text-align:center;color:blue;font-size:22px;text-indent:2em;",
    "NodeContent":"哈哈哈哈",
    "NodeChildElement" : []
}
//数组对象 也是一种json格式
var studentList = [      { "name": "张三", "age": 18, "sex": 1 },      { "name": "李思", "age": 19, "sex": 0 },      { "name": "王武", "age": 98, "sex": 1 },      { "name": "赵柳", "age": 77, "sex": 0 }]
var chinaMap = [      {        "code": "33",        "name": "浙江省",        "children": [          {            "code": "3301",            "name": "杭州市"          },          {            "code": "3302",            "name": "宁波市"          },          {            "code": "3303",            "name": "温州市"          }        ]
      },
      {
        "code": "32",
        "name": "湖南省",
        "children": [
          {
            "code": "3201",
            "name": "长沙市"
          },
          {
            "code": "3202",
            "name": "株洲市"
          },
          {
            "code": "3203",
            "name": "湘潭市"
          }
        ]
      }
    ]             

JSON方法API:

JSON.parse() 反序列化

将JSON数据解析为Javascript对象

方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的 reviver 函数用以在返回之前对所得到的对象执行变换(操作)。

var json = '{"result":true, "count":42}';
var obj = JSON.parse(json);
​
console.log(obj.count);
//42
​
console.log(obj.result);
// true
​
参数
JSON.parse(text[, reviver])
​
text
要被解析成 JavaScript 值的字符串
reviver 可选
转换器, 如果传入该参数(函数),可以用来修改解析生成的原始值,调用时机在 parse 函数返回之前。
返回值
Object 类型, 对应给定 JSON 文本的对象/值。
异常
若传入的字符串不符合 JSON 规范,则会抛出 SyntaxError 异常

JSON.stringify() 序列化

方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。

console.log(JSON.stringify({ x: 5, y: 6 }));
//  "{"x":5,"y":6}"console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)]));
//"[3,"false",false]"console.log(JSON.stringify({ x: [10, undefined, function(){}, Symbol('')] }));
//  "{"x":[10,null,null,null]}"console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
//  ""2006-01-02T15:04:05.000Z""
​
​
let code = {
    list:[],
    config:{"labelPosition":"right","labelWidth":100}
}
JSON.stringify(code)
//返回{"list":[],"config":{"labelPosition":"right","labelWidth":100}}
 
JSON.stringify(code,null,'\t')
//返回
{
    "list": [],
    "config": {
        "labelPosition": "right",
        "labelWidth": 100
    }
}
参数
JSON.stringify(value[, replacer [, space]])
​
value
将要序列化成 一个 JSON 字符串的值。
replacer 可选
用于转换结果的函数或数组。
如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;
如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
space 可选
指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格;如果该参数没有提供(或者为 null),将没有空格。
返回值
一个表示给定值的JSON字符串。
异常
当发现循环引用时,抛出类型错误TypeError(“循环对象值”)异常。
当试图将BigInt (BigInt 为javascript中Number能表示的最大数 2^53 - 1 )值字符串化时,会抛出类型错误 TypeError(“BigInt值不能在JSON中序列化”)。

执行上下文

 /*
      eval 性能黑洞 
      没必要使用 
    */
    eval("console.log('我是eval')");
var str = function () {
  var b = 10;
  console.log(b);
}
​
eval("str();");

1. 什么是执行上下文

简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行

2. 执行上下文的类型

执行上下文总共有三种类型:

  • 全局执行上下文: 这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。它做了两件事:

      1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。
      2. 将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。(可以存在多个script 但全局变量都是相同的 都属于window)
  • 函数执行上下文: 每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤,具体过程将在本文后面讨论。

  • Eval 函数执行上下文: 运行在 eval 函数中的代码也获得了自己的执行上下文,但由于eval是魔鬼 我们一般不通过eval进行开发操作。

执行上下文的生命周期

执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段,本文重点介绍创建阶段。

1. 创建阶段

当函数被调用,但未执行任何其内部代码之前,会做以下三件事:

  • 创建变量对象:首先初始化函数的参数 arguments,提升函数声明和变量声明。下文会详细说明。

    • 创建作用域链(Scope Chain):在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。作用域链本身包含变量对象。作用域链用于解析变量。当被要求解析变量时,JavaScript 始终从代码嵌套的最内层开始,如果最内层没有找到变量,就会跳转到上一层父作用域中查找,直到找到该变量。
  • 确定 this 指向:包括多种情况,下文会详细说明

在一段 JS 脚本执行之前,要先解析代码(所以说 JS 是解释执行的脚本语言),解析的时候会先创建一个全局执行上下文环境,先把代码中即将执行的变量、函数声明都拿出来。变量先暂时赋值为 undefined,函数则先声明好可使用。这一步做完了,然后再开始正式执行程序。

另外,一个函数在执行之前,也会创建一个函数执行上下文环境,跟全局上下文差不多,不过 函数执行上下文中会多出 this arguments 和函数的参数。

2. 执行阶段

执行变量赋值、代码执行

3. 回收阶段

执行上下文出栈等待虚拟机回收执行上下文

    /*
      垃圾回收机制 垃圾QG回收
        函数没有执行的时候 
​
          有对应的函数存储空间存放函数内容体(不解析)
          函数开始执行的时候 会解析内容 根据内容 声明变量赋予空间
          函数执行完成之后 私有局部变量的地址空间会被回收
    */

变量提升和 this 指向的细节

1. 变量声明提升

大部分编程语言都是先声明变量再使用,但在 JS 中,事情有些不一样:

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

上述代码正常输出undefined而不是报错Uncaught ReferenceError: a is not defined,这是因为声明提升(hoisting),相当于如下代码:

var a; //声明 默认值是undefined “准备工作”
console.log(a);
a = 10; //赋值

2. 函数声明提升

我们都知道,创建一个函数的方法有两种,一种是通过函数声明function foo(){} 另一种是通过函数表达式var foo = function(){} ,那这两种在函数提升有什么区别呢?

console.log(f1); // function f1(){}
function f1() {} // 函数声明
console.log(f2); // undefined
var f2 = function() {}; // 函数表达式

接下来我们通过一个例子来说明这个问题:

function test() {
    foo(); // 未捕获类型错误“foo不是函数”
    bar(); // "this will run!"
    var foo = function() {
        console.log("this won't run!");
    };
    function bar() {
        ale console.logrt("this will run!");
    }
}
test();

在上面的例子中,foo()调用的时候报错了,而 bar 能够正常调用。

我们前面说过变量和函数都会上升,遇到函数表达式 var foo = function(){}时,首先会将var foo上升到函数体顶部,然而此时的 foo 的值为 undefined,所以执行foo()报错。

而对于函数bar(), 则是提升了整个函数,所以bar()才能够顺利执行。

有个细节必须注意:当遇到函数和变量同名且都会被提升的情况,函数声明优先级比较高,因此变量声明会被函数声明所覆盖,但是可以重新赋值。

alert(a); //输出:function a(){ alert('我是函数') }
function a() {
    alert("我是函数");
} //
var a = "我是变量";
alert(a); //输出:'我是变量'

function 声明的优先级比 var 声明高,也就意味着当两个同名变量同时被 function 和 var 声明时,function 声明会覆盖 var 声明

这代码等效于:

function a() {
    alert("我是函数");
}
var a; //hoisting
alert(a); //输出:function a(){ alert('我是函数') }
a = "我是变量"; //赋值
alert(a); //输出:'我是变量'

最后我们看个复杂点的例子:

function test(arg) {
    // 1. 形参 arg"hi"
    // 2. 因为函数声明比变量声明优先级高,所以此时 argfunction
    console.log(arg);
    var arg = "hello"; // 3.var arg 变量声明被忽略, arg = 'hello'被执行
    function arg() {
        console.log("hello world");
    }
    console.log(arg);
}
test("hi");
/* 输出:
function arg(){
    console.log('hello world') 
    }
hello 
*/

这是因为当函数执行的时候,首先会形成一个新的私有的作用域,然后依次按照如下的步骤执行:

  • 如果有形参,先给形参赋值
  • 进行私有作用域中的预解释,函数声明优先级比变量声明高,最后后者会被前者所覆盖,但是可以重新赋值
  • 私有作用域中的代码从上到下执行

3. 确定 this 的指向

先搞明白一个很重要的概念 —— this 的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 —— 因为 this 是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子:

// 情况1
function foo() {
  console.log(this.a) //1
}
var a = 1
foo()
​
// 情况2
function fn(){
  console.log(this);
}
var obj={fn:fn};
obj.fn(); //this->obj// 情况3
function CreateJsPerson(name,age){
//this是当前类的一个实例p1
this.name=name; //=>p1.name=name
this.age=age; //=>p1.age=age
}
var p1=new CreateJsPerson("海牙",18);
​
//情况4 
var obj = {
    name:'海牙',
    showName:function(){
        console.log(this.name); // 海牙 this => obj
        (function(){
            console.log(this.name); //undefined this=>window
        })();
    }
}
obj.showName();
window.showName();
//报错 showName不是函数 
//window.showName =>undefind()=> 不是一个函数
</script>

//后续的点击事件 第五种情况
var oBtn = document.querySelector('#btn');
oBtn.onclick = function(e){
	console.log(e)
	this.value = '不要点我';
    //回调函数中的this指向 触发事件的对象
    //this=>oBtn 
}

接下来我们逐一解释上面几种情况

  • 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window
  • 对于 obj.foo() 来说,我们只需要记住,谁调用了函数, this指向谁,所以在这个场景下 foo 函数中的 this 就是 obj 对象
  • 在构造函数模式中,类中(函数体中)出现的 this.xxx=xxx 中的 this 是当前类的一个实例
  • IIFE匿名函数自调用时 因为没有明确调用主体 this指向 window。

2019-03-19-01.png 函数多了,就有多个函数执行上下文,每次调用函数创建一个新的执行上下文,那如何管理创建的那么多执行上下文呢?

JavaScript 引擎创建了执行上下文栈来管理执行上下文。可以把执行上下文栈认为是一个存储函数调用的栈结构,遵循先进后出的原则

2019-03-19-02.gif

自我理解

执行bar(6) 调用了bar(x) bar(x)中调用foo()

bar(6)需要bar(x)运行 bar(x)需要foo()先运行 这样反而是foo先执行了

从上面的流程图,我们需要记住几个关键点:

  • JavaScript 执行在单线程上,所有的代码都是排队执行。
  • 一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。
  • 每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收。
  • 浏览器的 JS 执行引擎总是访问栈顶的执行上下文。
  • 全局上下文只有唯一的一个,它在浏览器关闭时出栈。

我们再来看个例子:

var color = "blue";
function changeColor() {
    var anotherColor = "red";
    function swapColors() {
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
    }
    swapColors();
}
changeColor();

上述代码运行按照如下步骤:

  • 当上述代码在浏览器中加载时,JavaScript 引擎会创建一个全局执行上下文并且将它推入当前的执行栈
  • 调用 changeColor 函数时,此时 changeColor 函数内部代码还未执行,js 执行引擎立即创建一个 changeColor 的执行上下文(简称 EC),然后把这执行上下文压入到执行栈(简称 ECStack)中。
  • 执行 changeColor 函数过程中,调用 swapColors 函数,同样地,swapColors 函数执行之前也创建了一个 swapColors 的执行上下文,并压入到执行栈中。
  • swapColors 函数执行完成,swapColors 函数的执行上下文出栈,并且被销毁。
  • changeColor 函数执行完成,changeColor 函数的执行上下文出栈,并且被销毁。

2019-03-19-03.png

**包装对象

基础类型undefined、null、boolean、number、string和symbol 都是非引用类型(非对象)

之前我们学习了对象 了解到 对象具有属性和方法 也学习了字面量值 我们一起来看一个案例

var str = '你好';
var arr = str.split('');
console.log(arr);
// ["你", "好"]

问题:

一个以string基础类型的字面量为值的变量str 是如何能够通过 . 操作执行方法的呢? str到底是对象 还是 字符串呢?

var str = '你好';
//var newStr = new String('你好'); 包装 实例化对象
var arr = str.split('');
//var arr = newStr.split(''); 通过包装对象调用对象方法
// newStr = null; 销毁包装对象
console.log(arr);
// ["你", "好"]

**垃圾回收机制

垃圾QG回收

函数没有执行的时候

有对应的函数存储空间存放函数内容体(不解析)

函数开始执行的时候 会解析内容 根据内容 声明变量赋予空间

函数执行完成之后 私有局部变量的地址空间会被回收

#常用内置对象方法

javascript内置对象都提供了基本方法, 学习方法需要注意 参数 返回值 是否改变原对象 三个点。

MDN 官方文档 : developer.mozilla.org/zh-CN/docs/…

Object方法

Object.is()

方法判断两个值是否为同一个值

Object.is() 方法判断两个值是否为同一个值。如果满足以下条件则两个值相等:
​
都是 undefined
都是 null
都是 truefalse
都是相同长度的字符串且相同字符按相同顺序排列
都是相同对象(意味着每个对象有同一个引用)
都是数字且
都是 +0
都是 -0
都是 NaN
或都是非零而且非 NaN 且为同一个值
与== 运算不同。  == 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将 "" == false 判断为 true), 而 Object.is不会强制转换两边的值。
​
与=== 运算也不相同。 === 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等 ,而将Number.NaNNaN视为不相等.

参数

Object.is(value1, value2);
​
​
value1
被比较的第一个值。
value2
被比较的第二个值。

返回值

一个 Boolean 类型标示两个参数是否是同一个值。 true or false

Object.freeze()暂时不用

方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

var obj = {
  prop: 42
};
​
Object.freeze(obj);obj.prop = 33;
// Throws an error in strict mode
​
console.log(obj.prop);
// 42
​

参数

Object.freeze(obj)
​
​
obj
要被冻结的对象。

返回值

被冻结的对象。

Object.assign()

方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

var target = { a: 1, b: 2 };
var source = { b: 4, c: 5 };
​
var returnedTarget = Object.assign(target, source);
​
console.log(target);
//  { a: 1, b: 4, c: 5 }
​
console.log(returnedTarget);
//  { a: 1, b: 4, c: 5 }
​
​
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
​

参数

Object.assign(target, ...sources)
​
​
​
target
目标对象。
​
sources
源对象。
​

返回值

目标对象。

Object.keys()

方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

Object.keys({a:1,b:2,c:3,d:5});
// ["a", "b", "c", "d"]var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr));
//  ['0', '1', '2']
​
​
​
Object.keys 返回一个所有元素为字符串的数组,其元素来自于从给定的object上面可直接枚举的属性。这些属性的顺序与手动遍历该对象属性时的一致。

参数

Object.keys(obj)
​
obj
要返回其枚举自身属性的对象。

返回值

一个表示给定对象的所有可枚举属性的字符串数组。

Array方法(汇总)

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

forEach()

方法对数组的每个元素执行一次给定的函数。

var items = ['item1', 'item2', 'item3'];
var copy = [];
​
// for写法
for (var i=0; i<items.length; i++) {
  copy.push(items[i]);
}
​
// forEach方法
items.forEach(function(item){
  copy.push(item);
});
​
var arr = [1,2,3,4,5,6,7,8]
arr.forEach(function(curr,index,array){
   console.log(curr,index,array)
})
​
//手写forEach(js内部不是这样 理论是差不多的)
  function forEach(arr,callbank){
      for(var i = 0; i < arr.length;i++){
        callbank(arr[i],i,arr)//这是形参
      }
    }
    forEach([1,2,3,4,5,6],function(curr,index,array){
      console.log(curr,index,array)//这是实参
    })
​
//属性 thisAr
 arr.forEach(function(curr,index,array){
      console.log(this)//指向window
})
​
var obj = {
    name:'ls'
}
arr.forEach(function(curr,index,array){
      console.log(this)//指向obj
},obj)//改变了 内部this指向

参数

arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
​
callback
为数组中每个元素执行的函数,该函数接收一至三个参数:
    currentValue
        数组中正在处理的当前元素。
    index 可选
        数组中正在处理的当前元素的索引。
    array 可选 
        forEach() 方法正在操作的数组。
thisArg 可选
可选参数。当执行回调函数 callback 时,用作 this 的值。

返回值

undefined

sort()

方法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
//  ["Dec", "Feb", "Jan", "March"]
​
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
//  [1, 100000, 21, 30, 4]
​
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);
// [1, 2, 3, 4, 5]
​
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return b - a;
});
console.log(numbers);
// [5, 4, 3, 2, 1]
​
如果没有指明 排序函数 ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 "Banana" 会被排列到 "cherry" 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 排序函数),比较的数字会先被转换为字符串,所以在Unicode顺序上 "80" 要比 "9" 要靠前。

参数

arr.sort([function compareFunction(firstEl,secondEl) {
 
}])
​
compareFunction 可选
用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
    firstEl
    第一个用于比较的元素。
    secondEl
    第二个用于比较的元素。

返回值

排序后的数组。请注意,数组已原地排序,不会产生新数组。

map()

方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。

var originArr =  [1,2,3,4,5];
var newArr = originArr.map(function(current,index,array){
    return current * 2;
});
console.log(newArr);
//[2,4,6,8,10]
​
---------------------------------------------------
var kvArray = [{key: 1, value: 10}, 
               {key: 2, value: 20}, 
               {key: 3, value: 30}];
​
var reformattedArray = kvArray.map(function(obj) { 
   var rObj = {};
   rObj[obj['key']] = obj.value;
   return rObj;
});
console.log(reformattedArray);
// [{1: 10}, {2: 20}, {3: 30}], 
​
map 方法会给原数组中的每个元素都按顺序调用一次  callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。
​
callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身。
​
map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)

参数

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
}[, thisArg])
​
​
callback
生成新数组元素的函数,使用三个参数:
    currentValue
    callback 数组中正在处理的当前元素。
    index可选
    callback 数组中正在处理的当前元素的索引。
    array可选
    map 方法调用的数组。
thisArg可选
执行 callback 函数时值被用作this。

返回值

一个由原数组每个元素执行回调函数的结果组成的新数组。

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

filter()

方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

var arr = [
  { id: 15 },
  { id: -1 },
  { id: 0 },
  { id: 3 },
  { id: 12.2 },
  { },
  { id: null },
  { id: NaN },
  { id: 'undefined' }
];
​
function isNumber(obj) {
  return obj !== undefined && typeof(obj) === 'number' && !isNaN(obj);
}
​
var arrByID = arr.filter(function(item) {
    return isNumber(item.id) && item.id !== 0;
});
​
console.log(arrByID); 
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]
​
​
filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。
​
callback 被调用时传入三个参数:
​
元素的值
元素的索引
被遍历的数组本身
如果为 filter 提供一个 thisArg 参数,则它会被作为 callback 被调用时的 this 值。否则,callback 的 this 值在非严格模式下将是全局对象,严格模式下为 undefined。callback 函数最终观察到的 this 值是根据通常函数所看到的 "this"的规则确定的。
​
filter 不会改变原数组,它返回过滤后的新数组。
​
filter 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。

参数

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
​
callback
用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。它接受以下三个参数:
    element
    数组中当前正在处理的元素。
    index可选
    正在处理的元素在数组中的索引。
    array可选
    调用了 filter 的数组本身。
thisArg可选
执行 callback 时,用于 this 的值

返回值

一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

reduce()

方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

var originArr = [3,4,5,6,7,8];
var sum = originArr.reduce(function(acc,current,idx,arr){
    return acc + current;
});
console.log(sum);
//33 数组中每项累加和
​
var str = 'jfkldsajgklasjkhlgjefaklhjaerkl';
var statistics = str.split('').reduce(function(acc,current){
    if(acc[current]){
        acc[current]++;
    }else {
        acc[current] = 1;
    }
    return acc;
},{});
console.log(statistics);
// {a: 4, d: 1, e: 2, f: 2, g: 2, h: 2, j: 5, k: 5, l: 5, r: 1, s: 2} 字符串统计后的对象结果
​
​
reduce为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:
​
    accumulator 累计器
    currentValue 当前值
    currentIndex 当前索引
array 数组
回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。

参数

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
​
callback
执行数组中每个值 (如果没有提供 initialValue则第一个值除外)的函数,包含四个参数:
    accumulator
    累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
    currentValue
    数组中正在处理的元素。
    index 可选
    数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。
    array可选
    调用reduce()的数组
​
initialValue可选
作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

返回值

函数累计处理的结果

lastIndexOf()

方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。

var array = [2, 5, 9, 2];
var index = array.lastIndexOf(2);
// index is 3
index = array.lastIndexOf(7);
// index is -1
index = array.lastIndexOf(2, 3);
// index is 3
index = array.lastIndexOf(2, 2);
// index is 0
index = array.lastIndexOf(2, -2);
// index is 0
index = array.lastIndexOf(2, -1);
// index is 3
​
lastIndexOf 使用严格相等(strict equality,即 ===)比较 searchElement 和数组中的元素。

参数

arr.lastIndexOf(searchElement[, fromIndex])
​
searchElement
被查找的元素。
fromIndex 可选
从此位置开始逆向查找。默认为数组的长度减 1(arr.length - 1),即整个数组都被查找。如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。

返回值

数组中该元素最后一次出现的索引,如未找到返回-1。

reverse()

方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。

var array1 = ['one', 'two', 'three'];
console.log( array1);
//  ["one", "two", "three"]var reversed = array1.reverse();
console.log( reversed);
// ["three", "two", "one"]
​
console.log(array1);
//  ["three", "two", "one"]
​
reverse会对原数组造成修改影响

参数

 arr.reverse()

返回值

颠倒后的数组。

splice()

方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

var months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// 在下标1的位置新增了1项
console.log(months);
// ["Jan", "Feb", "March", "April", "June"]
​
months.splice(4, 1, 'May');
// 在下标4的位置 修改了 1项
console.log(months);
//["Jan", "Feb", "March", "April", "May"]
​
splice会修改原数组

参数

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
​
start
    指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
​
deleteCount 可选
    整数,表示要移除的数组元素的个数。
    如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
    如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。
    如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
    
item1, item2, ... 可选
    要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。

返回值

由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

includes()

方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

var array1 = [1, 2, 3];
​
console.log(array1.includes(2));
// expected output: truevar pets = ['cat', 'dog', 'bat'];
​
console.log(pets.includes('cat'));
// expected output: trueconsole.log(pets.includes('at'));
// expected output: false

参数

valueToFind
需要查找的元素值。
​
Note:  使用 includes()比较字符串和字符时是区分大小写。
​
fromIndex 可选
从fromIndex 索引处开始查找 valueToFind。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜 (即使从末尾开始往前跳 fromIndex 的绝对值个索引,然后往后搜寻)。默认为 0

返回值

返回一个布尔值 Boolean ,如果在数组中找到了(如果传入了 fromIndex ,表示在 fromIndex 指定的索引范围中找到了)则返回 true

flat()

方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

var arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]
​
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
​
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
​
//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
​
​
//二维展开替代方案
var arr = [1, 2, [3, 4]];
​
var flatArr = arr.reduce(function(acc,curr){
    return acc.concat(curr);
},[]);
​
console.log(flatArr);
//[1, 2, 3, 4]

参数

var newArray = arr.flat([depth])
​
depth 可选
指定要提取嵌套数组的结构深度,默认值为 1

返回值

一个包含将数组与子数组中所有元素的新数组。

方法汇总

toString()      把数组转换成字符串,逗号分隔每一项
valueOf()         返回数组对象值本身
// 1 栈操作(先进后出)
push()
pop()       //取出数组中的最后一项,修改length属性
// 2 队列操作(先进先出)
push()
shift()     //取出数组中的第一个元素,修改length属性
unshift()   //在数组最前面插入项,返回数组的长度
// 3 排序方法
reverse()   //翻转数组
sort();     //即使是数组sort也是根据字符,从小到大排序
// 带参数的sort是如何实现的?// 4 操作方法
concat()    //把参数拼接到当前数组
slice()     //从当前数组中截取一个新的数组,不影响原来的数组,参数start从0开始,end从1开始
splice()    //删除或替换当前数组的某些项目,参数start, deleteCount, options(要替换的项目)// 5 位置方法
indexOf()、lastIndexOf()   //如果没找到返回-1// 6 迭代方法 不会修改原数组(可选)
every()、filter()、forEach()、map()、reduce()、some() find()、findlndex()
// 7 方法将数组的所有元素连接到一个字符串中。
join()

String方法

字符串常用方法

charAt()

charAt()

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

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

参数

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

返回值

指定字符串

charCodeAt

*语法:字符串.charCodeAt(索引)

*作用:查询指定下标的值 对应的 十进制码

*返回值:查询到的值对应的十进制码 没有查到返回NAN

toLowerCase

*语法:字符串.toLowerCase

*作用:将这个字符串转换为小写

*返回值:转换后的字符串

toUpperCase

*语法:字符串.toUpperCase

*作用:将字符串转换为大写
​
*返回值:转换后的字符串

分割截取字符串的方法

substr

*语法:字符串.substr(开始索引,多少个)

*作用:截取指定的字符串

*返回值:截取到的字符串

*注意:mdn 说明这个方法将来某一天可能会删除,所以建议我们使用 substri

substring

*语法:字符串substring(开始索引,结束下标)

*作用:截取指定的字符串

*返回值:截取到的字符串

*注意

1.参数包前不包后

2.结束索引可以不写,相当于写了length

3.不可以接受负值

slice

*语法:字符串slice(开始索引,结束下标)

*作用:截取指定的字符串

*返回值:截取到的字符串

*注意

1.参数包前不包后

2.结束索引可以不写,相当于写了length

3.开始索引可以不写,相当于写了0

4.结束索引支持负数

concat

*语法:字符串.concat(数据1,数据2,数据3....)

*作用:将字符串和参数传递的数据 进行拼接

*返回值:拼接后的字符串

indexOf

*语法:字符串.indexOf(数据,开始下标)

*作用:寻找数据在字符串出的位置

*返回值:找到返回下标,找不到-1

注意

第二个参数可以不传递 默认0

第二个参数小于0从0开始 大于length从length开始

lastindexOf

*语法:字符串.indexOf(数据,开始下标)

*作用:寻找数据在字符串出的位置(从后往前找)

*注意

第二个参数小于0从0开始 大于length从length开始(方向右-左)

split**

*作用:split() 方法使用指定的分隔符字符串将一个String对象分割成 子字符串数组

*返回值 数组

*不传参 或者传递的参数字符串中没有 转换的数组只有一个值

//split
     var str = 'qwr,tr,ad, cc'
     console.log(str.split(' '))
     //['qwr,tr,ad,', 'cc'] //' '没了
​
     console.log(str.split(','))
     //['qwr', 'tr', 'ad', ' cc']逗号没了 
     console.log(str.split('a'))
     //['qwr,tr,', 'd, cc']a没了
​
     console.log(str.split(''))
     //'q', 'w', 'r', ',', 't', 'r', ',', 'a', 'd', ',', ' ', 'c', 'c'
     //每一项都分割了 包括空格
​
    console.log(str.split())//['qwr,tr,ad, cc']
    console.log(str.split('z'))//['qwr,tr,ad, cc']

trim()

语法:字符串.trim()

作用:去掉字符串两侧的空格

返回值:去掉空格后的字符串

     var str = ' a b c '
     console.log(str)//'a b c'

trimStart/trimLeft

语法:字符串.trimStart/字符串.trimLeft()

作用:去掉字符串开始(左侧)空格

返回值:去掉空格后的字符串

trimEnd/trimRight

语法:字符串.trimEnd/字符串.trimRight()

作用:去掉字符串末尾(右侧)空格

返回值:去掉空格后的字符串

includes()

语法:字符串.includes(字符串片段)

作用:判断当前值符传中,是否拥有指定字符串

返回值:布尔值

     var str = 'abcdef'
     var str1 = str.includes('bcde')
     console.log(str1)//true

startswith()

语法:字符串.startswith(字符串片段)

作用:判断字符串开始 是不是指定的 字符串片段

返回值:一个布尔值

endswith()

语法:字符串.endswith(字符串片段)

作用:判断字符结尾 是不是指定的 字符串片段

返回值:一个布尔值

replace

语法:字符串.replace(被替换的,替换的)

作用:判断字符结尾 是不是指定的 字符串片段

返回值:一个布尔值

方法汇总

// 1 字符方法
charAt()        //获取指定位置处字符
charCodeAt()    //获取指定位置处字符的ASCII码
str[0]          //HTML5,IE8+支持 和charAt()等效
// 2 字符串操作方法
concat()        //拼接字符串,等效于+,+更常用
slice()         //从start位置开始,截取到end位置,end取不到
substring()     //从start位置开始,截取到end位置,end取不到
substr()        //从start位置开始,截取length个字符
// 3 位置方法
indexOf()       //返回指定内容在元字符串中的位置
lastIndexOf()   //从后往前找,只找第一个匹配的
// 4 去除空白   
trim()          //只能去除字符串前后的空白
// 5 大小写转换方法
to(Locale)UpperCase()   //转换大写
to(Locale)LowerCase()   //转换小写
// 6 其它
search()
replace() //替换
split()  //分隔成字符串
fromCharCode() //unicode转字符串
// String.fromCharCode(101, 102, 103);  

案例

  • 截取字符串"我爱中华人民共和国",中的"中华"
var s = "我爱中华人民共和国";
s = s.substr(2,2);
console.log(s);
​
---------------------
    
function padLeft(num){
    num = num || 0;
    return ('00'+num).substr(-2);
}
  • "abcoefoxyozzopp"查找字符串中所有o出现的位置
var s = 'abcoefoxyozzopp';
var array = [];
do {
  var index = s.indexOf('o', index + 1);
    //index 第一轮为undefind  undefind+1 = NAN
    //NAN不存在  默认从0开始
  if (index != -1) {
    array.push(index);
  }
} while (index > -1);
console.log(array);
  • 把字符串中所有的o替换成!
var s = 'abcoefoxyozzopp';
do {
  s = s.replace('o', '');
} while (s.indexOf('o') > -1);
console.log(s);
​
console.log(s.replace(/o/ig, ''));
​
//错误示范
    var s1 = 'abcoefoxyozzopp';
    var snew1 = s1.replace('o','我')//这样只会第一个o变
    console.log(snew1)//abc我efoxyozzopp
  • 判断一个字符串中出现次数最多的字符,统计这个次数
var s = 'abcoefoxyozzopp';
var o = {};
​
for (var i = 0; i < s.length; i++) {
  var item = s.charAt(i);
  if (o[item]) {
    o[item] ++;
  }else{
    o[item] = 1;
  }
}
​
var max = 0;
var char ;
for(var key in o) {
  if (max < o[key]) {
    max = o[key];
    char = key;
  }
}
​
console.log(max);
console.log(char);

Math数字方法

/*
      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)

方法汇总

Math.PI                     // 圆周率
Math.random()               // 生成随机数
Math.floor()/Math.ceil()     // 向下取整/向上取整
Math.round()                // 取整,四舍五入
Math.abs()                  // 绝对值
Math.max()/Math.min()        // 求最大和最小值
​
Math.sin()/Math.cos()        // 正弦/余弦
Math.power()/Math.sqrt()     // 求指数次幂/求平方根

练习

数组塌陷

//按顺序删除数组内的值
    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'
* 
*  现在的公司的项目中, 基本都是按照严格模式开发的
 */

Date对象方法

创建 Date 实例用来处理日期和时间。Date 对象基于1970年1月1日(世界标准时间)起的毫秒数。

// 获取当前时间,UTC世界时间,距1970年1月1日(世界标准时间)起的毫秒数
var now = new Date();
console.log(now.valueOf()); // 获取距1970年1月1日(世界标准时间)起的毫秒数Date构造函数的参数
1. 毫秒数 1498099000356        new Date(1498099000356)
2. 日期格式字符串  '2015-5-1'   new Date('2015-5-1')
3. 年、月、日……                new Date(2015, 4, 1)   // 月份从0开始
  • 获取日期的毫秒形式
var now = new Date();
// valueOf用于获取对象的原始值
console.log(date.valueOf()) 
​
// HTML5中提供的方法,有兼容性问题
var now = Date.now();   
​
// 不支持HTML5的浏览器,可以用下面这种方式
var now = + new Date();         // 调用 Date对象的valueOf() 
  • 日期格式化方法
toString()      // 转换成字符串
valueOf()       // 获取毫秒值
// 下面格式化日期的方法,在不同浏览器可能表现不一致,一般不用
toDateString()
toTimeString()
toLocaleDateString()
toLocaleTimeString()
  • 获取日期指定部分
getTime()     // 返回毫秒数和valueOf()结果一样,valueOf()内部调用的getTime()
getMilliseconds() 
getSeconds()  // 返回0-59
getMinutes()  // 返回0-59
getHours()    // 返回0-23
getDay()      // 返回星期几 0周日   6周6
getDate()     // 返回当前月的第几天
getMonth()    // 返回月份,***从0开始***
getFullYear() //返回4位的年份  如 2016
  • 设置日期指定部分
setTime() //设置 到1970年的总毫秒数//就是从1970年开始 走多少秒
setMilliseconds() 
setSeconds()  // 返回0-59
setMinutes()  // 返回0-59
setHours()    // 返回0-23
//注意*** 不能设置星期几
setDate()     // 返回当前月的第几天
setMonth()    // 返回月份,***从0开始***
setFullYear() //返回4位的年份  如 2016

案例

  • 写一个函数,格式化日期对象,返回yyyy-MM-dd HH:mm:ss的形式
function formatDate(d) {
  //如果date不是日期对象,返回
  if (!date instanceof Date) {
    return;
  }
  var year = d.getFullYear(),
      month = d.getMonth() + 1, 
      date = d.getDate(), 
      hour = d.getHours(), 
      minute = d.getMinutes(), 
      second = d.getSeconds();
  month = padLeft(month);
  date = padLeft(date);
  hour =padLeft(hour);
  minute = padLeft(minute);
  second = padLeft(second);
  return year + '-' + month + '-' + date + ' ' + hour + ':' + minute + ':' + second;
}
function padLeft(num){
    return String(num)[1] && String(num) || '0' + num;
}
  • 计算时间差,返回相差的天/时/分/秒
function getInterval(start, end) {
  var day, hour, minute, second, interval;
  interval = end - start;
  interval /= 1000;
  day = ~~(interval / 60 /60 / 24);
  hour = ~~(interval / 60 /60 % 24);
  minute = ~~(interval / 60 % 60);
  second = ~~(interval % 60);
  return {
    day: day,
    hour: hour,
    minute: minute,
    second: second
  }
}