JavaScript

JavaScript

JavaScript简介

JavaScript是一种运行在客户端的脚本语言

ECMAScript: JavaScript的核心,描述了语言的基本语法和数据类型,

DOM:一套操作网页元素的API

BOM:一套操作浏览器功能的API

JavaScript的书写方式

script标签内部 <script></script>

script标签引入 <script src ="index.js"></script>

注意:如果script标签引入外部js文件之后,标签内部书写的javascript代码就不会生效;

JavaScript注释

单行注释:快捷键 Ctrl + /

1
// 单行注释

多行注释:

  • Submit快捷键 Ctrl + Shift + /
  • VsCode / WebStorm快捷键 Ctrl + Alt + /
1
2
3
4
/*
多行
注释
*/

JavaScript输出语句

  • alert() 弹出警告框,弹出时会阻断页面加载;
  • confirm() 弹出确认框
  • prompt() 弹出输入框
  • document.write() 在HTML页面中写入内容
  • console.log() 控制台日志,F12打开控制台,在console中可以看到打印的信息,一般是程序员看的;

变量

变量的书写方式

1
2
3
4
5
var num; 声明变量
var num; num = 8; 变量赋值
var num = 8; 声明变量并赋值
age = 18; console.log(age); 不声明变量,直接赋值
var num1 = 8, num2 = 9; 多个变量赋值,逗号隔开

变量的命名

  • 规则
    1. 只能由数字、字母、下划线_和$符号组成,不能以数字开头
    2. 不能使用关键字和保留字
    3. 字母区分大小写
  • 规范
    1. 命名需要有意义
    2. 驼峰命名法,除了首单词第一个字母小写,其他单词首字母要大写;myName、userPassword

简单数据类型

  • number(数字)
    • 进制:
      • 十进制、十六进制(0x)、八进制(0)
      • 关于二进制,计算机在只认识二进制,所以所有的代码最终都会转换成二进制数据。
    • 浮点数
      • 小数
      • 科学计数法 5e+5、5e5、5e-5
    • 数值范围
      • Number.MIN_VALUE; 最小的正数 5e-324
      • Number.MAX_VALUE; 最大的正数 1.7976931348623157e+308
      • Infinity; 无穷大
      • -Infinity; 负无穷大
  • string(字符串)
    • 转义字符
      • \' \" \\ \n
  • boolean(布尔类型)
    • 只有两个值,并且书写方式固定,大写,或者添加引号都不在是布尔类型的值。
      • true 真
      • false 假
  • undefined
    • 只有一个值 undefined; 表示一个没有赋值的变量
    • 如果过声明变量不赋值,则这个变量默认为 undefined
  • null
    • 只有一个值,表示一个空的对象

操作符

  • 算术运算符
    • +、-、*、/、%
    • 在和字符串连接时,只有加号+具有字符拼接功能
    • 有连接字符串时,其他算术运算符,如果是数字直接运算,如果是非数字,则会打印NaN
  • 赋值运算符
    • =、+=、-=、*=、/=、%=
    • num += 1; 只能等效 num = num + 1; 运算顺序不能调换,其他同理
  • 一元运算符
    • i++ 先返回值,然后自增1
    • ++i 先自增1,然后返回值
    • i--
    • --i
  • 逻辑运算符
    • && 与运算符,(串联电路)只有全为true才为true;否则为false
    • || 或运算符,(并联电路),只要有一个true,就为true
    • ! 非运算符,取反
  • 比较运算符
    • >、<、>=、<=、==、!=、===、!==
    • ==、!= 只判断值,不判断类型
    • ===、!== 判断值,并且判断类型
  • 运算优先级
    • () 优先级最高
    • 一元运算符
    • 算术运算符(先 */%+-
    • 比较运算符(先 ><>=<=== != === !==
    • 逻辑运算符(先 &&||

类型转换

  • 查看变量类型
    • typeof var num = 11; console.log(typeof num);
    • google浏览器的显示的颜色不一样
  • 转换成字符串
    • toString(); num = num.toString(); undefined和null没有toString()
    • String(); num = String(num); 都可以变成字符串,包括undefined和null
    • 拼串+空字符串;num = num + ""; 都可以变成字符串,包括undefined和null,使用最方便
  • 转换成数字类型
    • Number(); 如果不是数字的话,会返回NaN
    • parseInt(); 从第一个数字开始识别(值得第一个必须是数字),直到遇见非数字时停止,不识别小数点
    • parseFloat(); 从第一个数字开始识别(值得第一个必须是数字),直到遇见非数字时停止,只识别第一个小数点
    • 运用算术运算;+0、*1、前面加正号+
    • 布尔类型 true为1、false为0
  • 转成布尔类型
    • Boolean(); 除了以下的几个为false,其余全部是true(不能为空)
    • '' "" 0 undefined null false NaN 都为false
    • !! 双重取反;var a = "abc"; console.log(!!a);

NaN

  • number类型,特殊值,是一个非数字的数字,js不会报错,继续执行之后的代码
  • NaN不等于任何值,包括NaN自身
  • isNaN判断一个数是否为数字,返回值为false的为数字,var num = 5; console.log(isNaN(5));
  • isNaN(元素A) 判断的时候会把元素专为数字之后再判断,number(元素A)
  • 运算时,任何数值+undefined都会变为NaN

字面量/直接量与变量

  • 字面量,也叫直接量,值是固定不变的,浏览器能够直接识别的量,比如11, “abc”, true, false, undefined, null等都是字面量,可以直接会使用。
  • 字面量有哪些:11, “abc”, true, false, undefined, null,[]
  • 变量:浏览器必须要经过声明之后,才认识变量,如果没有声明,直接使用变量是会报错的。

关键字break和continue

  • break; 结束整个for循环。的内容(直接跳到大括号)
  • continue; 结束本次循环,继续执行下一个循环。

数组

数组对象的作用是:使用单独的变量名来存储一系列的值。

数组:一个有序的数据集合,下标从0开始,可以存储大量的数据;

创建数组

1
2
3
4
5
6
7
8
9
10
11
//通过构造函数创建数组
var arr = new Array();//创建了一个空数组
var arr = new Array("zs","ls","ww");//创建了一个数组,里面存放了3个字符串
var arr = new Array(1,2,3,4);//创建了一个数组,里面存放了4个数字
var arr = new Array(4);//创建了一个长度为4的数组,一般不推荐这么创建

//通过数组字面量创建数组
var arr1 = []; //创建一个空数组
var arr2 = [1, 3, 4]; //创建一个包含3个数值的数组,多个数组项以逗号隔开
var arr3 = ["a", "c"]; // 创建一个包含2个字符串的数组
var arr4 = [4];//创建了一个长度为1的,值为数字4的数组,和构造函数不一样,两个有区别。
  • 数组中可以存任何类型的值。
  • 但是,一般一个数组中放置相同类型的值,不要混放;
  • 例如存放数字,中间如果存放其他类型,算术运算的时候会出现NaN

数组的下标和长度

数组的下标:数组是有序的,数组中的每一个元素都对应了一个下标,下标是从0开始的

1
2
3
var arr = ["zs", "ls", "ww"];
arr[0];//下标0对应的值是zs
arr[2];//下标2对应的值是ww

数组的长度:跟字符串一样,数组有一个length属性,指数组中存放的元素的个数。

1
2
3
var arr = ["zs", "ls", "ww"];
arr.length;//这个数组的长度是3
//空数组的长度是0

下标与长度的关系:最大的下标 = length - 1

数组的赋值与取值

  • 数组的赋值
    • 语法格式:数组名[下标] = 值;
    • 如果下标有对应的值,会把原来的值覆盖,如果下标不存在,会给数组新增一个元素。
1
2
3
4
5
6
7
//给一个数组添加新的值,特别是在不知道数组长度的时候
arr[arr.length] = 值;
arr.push(值); //推荐写法,可以看成是 arr[arr.length] = 值; 的简化

var arr = ["red", "green", "blue"];
arr[0] = "yellow";//把red替换成了yellow
arr[3] = "pink";//给数组新增加了一个pink的值

数组赋值,下标一个很大的数值,造成数组中间有很多空值(undefined)

稀疏数组: 数组的下标不连续(避免)

例如:

1
2
var arr = ["red", "green", "blue"];
arr[100] = "一个字符串";
  • 数组的取值
    • 格式:数组名[下标]
    • 功能:获取数组对应下标的那个值,如果下标不存在,则返回undefined。
1
2
3
4
var arr = ["red", "green", "blue"];
arr[0];//red
arr[2];//blue
arr[3];//这个数组的最大下标为2,因此返回undefined

数组的遍历

遍历:遍及所有,对数组的每一个元素都访问一次就叫遍历。

冒泡排序

一趟:两两比较,如果前一个比后一个大,交换位置,可以得到一个最大的值
一趟:两两比较,只需要比length-1次,得到一个最大的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//方法1 冒泡排序重复比较  初级版本
var arr = [9, 336, 56, 47, 46, 199, 86, 463, 4, 7, 26];
var tang = 0;//外循环循环了多少趟
var ci = 0;//内循环了多少次
for (j = 0; j < arr.length - 1; j++) {
tang++;
for (var i = 0; i < arr.length - 1; i++) {
ci++;
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
console.log(arr);
console.log(tang,ci);

//方法2 冒泡排序减少次数比较 中级版本
var arr = [9, 336, 56, 47, 46, 199, 86, 463, 4, 7, 26];
var tang = 0;//外循环循环了多少趟
var ci = 0;//内循环了多少次
for (j = 0; j < arr.length - 1; j++) {
tang++;
for (var i = 0; i < arr.length - 1 - j; i++) { //- j 每比较一次,最大值不需要重复比较,所以 减掉外循环的趟数。
ci++;
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
console.log(arr);
console.log(tang, ci);

//方法3 冒泡排序检测数组有没有排列好 高级版本
var arr = [9, 336, 56, 47, 46, 199, 86, 463, 4, 7, 26];
var tang = 0;//外循环循环了多少趟
var ci = 0;//内循环了多少次
for (j = 0; j < arr.length - 1; j++) {
tang++;
for (var i = 0; i < arr.length - 1 - j; i++) { //- j 每比较一次,最大值不需要重复比较,所以 减掉外循环的趟数。
ci++;
var flag = true; //在此处做个标记,如果标记被改变,就说明比较交换了
if (arr[i] > arr[i + 1]) {
flag = false;
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
if (flag) { //flag = false;可以被省略,标记本身就是布尔类型。
//此处被执行说明flag的值没有被改变成为false。后续无需再比较。
break;
}
}
console.log(arr);
console.log(tang, ci);

函数

函数基础知识

  • 为什么要有函数
    • 在写代码的时候,有一些常用的代码需要书写多次,如果直接复制粘贴的话,会造成大量的冗余代码。
    • 函数可以封装一段重复的JavaScript代码,它只需要声明一次,就可以被多次调用。
  • 重复代码、冗余代码的缺点:
    1. 代码重复,可阅读性差
    2. 不易维护,如果代码逻辑改变了,所有地方的代码都要跟着改变,效率太低。

函数的特点

  1. 函数声明的时候,函数体并不会执行,函数体只有在调用的时候才会执行,
  2. 可以调用多次

创建函数

函数的声明:

  • function 函数名() {//函数体}
  • var fn = function() {//函数体}

函数的调用:函数名();

函数的三要素

  • 函数名
  • 函数的参数
    • 概念
      1. 形参(形式参数):在函数声明时,设置的参数。作用是占位置。
      2. 实参(实际参数):在函数调用时,传入的参数。作用:函数调用时,会把实参的值赋值给形参,这样形参就有了值。
    • 语法
1
2
3
4
5
6
7
8
// 语法:
// 带参数的函数声明
function 函数名(形参1, 形参2, 形参...){
// 函数体
}

// 带参数的函数调用
函数名(实参1, 实参2, 实参3);
  • 函数的返回值:当函数执行完的时候,我们期望函数给我一些反馈(比如计算的结果),这个时候可以让函数返回一些东西。也就是返回值。函数通过return返回一个返回值
    • return 返回值; 一般写在函数内部最后。
    • return 只返回一个,如果想返回多个值,就把值放在一个数组或者对象中,让return返回一个数组或者对象。
    • return 返回值值后,后面的代码就不在执行了,和break有点像;
    • 函数可以没有返回值 return,但是会默认 返回 return undefined;
    • 函数的参数可以有多个,但是return返回的值只有一个。

函数的文档注释

关于文档注释,javascript中还有一种注释叫做文档注释,经常用在函数声明处,用来解释这个函数的作用。

1
2
3
4
5
6
/**
文档注释
*/
写法:
写在声明函数的上方
/**后回车键
1
2
3
4
5
6
7
8
/**
* 求圆的面积
* @param r {number} 圆的半径
* @returns {number} 圆的周长
*/
function getArea (r) {
return Math.PI * r * r;
}

函数内部也可以调用函数

在函数内部是可以继续调用函数的。

递归函数

递归函数:自己直接或者间接调用自己的函数,递归函数一定要留有出口,不然就是死递归了,会无限调用;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var count = 0;
function tellStory() {
count++;
console.log("从前有座山");
console.log("山里有座庙");
console.log("庙里有个老和尚");
console.log("老和尚给小和尚讲故事");
console.log("讲什么呢?");
if(count < 5){
tellStory();
}
}

tellStory();

递归函数:算是一种数学和算法的归类

  1. 求1-100所有数的和
  2. 斐波那契数列,有个人想知道,一年之内一对兔子能繁殖多少对?于是就筑了一道围墙把一对兔子关在里面。已知一对兔子每个月可以生一对小兔子,而一对兔子从出生后第3个月起每月生一对小兔子。假如一年内没有发生死亡现象,那么,一对兔子一年内(12个月)能繁殖成多少对?兔子的规律为数列,1,1,2,3,5,8,13,21 ,34 , 55, 89, 144
1
2
3
4
5
6
7
8
9
10
11
//  1   1    2    3    5   8    13   21   34   55   89   144
//求第n个月的兔子
function getTu(n) {
if(n == 1 || n == 2){
return 1;
}
return getTu(n -1) + getTu(n-2);
}

var a = getTu(100);
console.log(a);

函数也是一种类型

函数可以作为参数

函数可以做为参数,通常把作为参数传递的函数叫做回调函数。

1
2
3
4
5
6
7
8
9
10
//函数是可以作为参数来进行传递(函数也是一种数据类型)
function fn(a) {
console.log(a);
a();
}

//如果参数是一个函数,那么这个作为参数传递的函数叫做回调函数。
fn(function(){
console.log("Hehe");
});

函数可以作为返回值

在js高级中,闭包会使用到。

1
2
3
4
5
6
7
8
function fn() {
return function(){
console.log("呵呵")
};
}

//fn() 相当于调用了 fn 函数
fn()();//调用了 fn 函数里面 return 的函数

arguments

  • 任何的函数内部都有一个对象,叫做arguments;
  • arguments会存储函数调用时传递的所有的参数;
  • arguments会存储函数所有传递进来的参数,是一个伪数组,函数如果只设置了一个形参,当传递多个实参的时候,会从第一个实参开始生效。

arguments:获取函数的实参,被函数内部的arguments替代了。

arguments是一个伪数组,用来存储函数传递进来的所有实参,函数实参的可以传递多个进来,函数的实参生效是按照函数声明时的形参生效,实参从左到右生效,多的实参忽略;

1
2
3
4
5
6
7
8
9
10
11
12
13
// max函数,无论传递多少参数,求出来最大的值
function max() {
//通过arguments可以获取到所有的参数
var m = arguments[0];
for(var i = 0; i < arguments.length; i++) {
if(arguments[i] > m) {
m = arguments[i];
}
}
return m;
}

console.log(max(1, 2, 3, 44, 6));

一般使用不到

匿名函数和自执行函数

匿名函数

匿名函数,就是没有函数名的函数;

  • 因为匿名函数没有名字,所以没法调用,
  • 可以通过赋值给一个变量来调用;
1
2
3
4
5
6
7
8
9
var fn = function () {
console.log("呵呵");
}
fn();

//函数自执行,自己调用自己
(function fn() {
console.log("呵呵");
})();

自执行函数

自己调用自己并执行的函数;

1
2
3
4
5
6
7
8
(function fn(){
console.log("我可以自己执行哦");
})();

(function(){})();
(function(){}());
(function foo(){})();
(function foo(){}());

自执行匿名函数的作用:为了防止全局变量污染。

对象

JavaScript 中的所有事物都是对象:字符串、数值、数组、函数…

此外,JavaScript 允许自定义对象。

对象的概念

  • 对象:显示生活中,一个具体事务的特征和行为。
  • 对象:JavaScript中,抽象的对应属性和方法。
  • 对象:用来存储无序的键值对集合。

JavaScript 提供多个内建对象,比如 String、Date、Array 等等。

对象只是带有属性和方法的特殊数据类型。

创建对象的方法

var obj = new Object(); 创建了一个新的空对象;

var obj = {}; 也叫字面量创建对象

1
2
3
4
5
6
7
// 可以创建一个空的对象;
var obj = {};

// 也可以创建有键值对的对象
var obj = {
键:值,
};

键值对用逗号隔开;

工厂函数

批量创建多个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 定义一个函数,用于创建学生对象
// 工厂函数:
function createStudent(name, age, sex) {
var stu = {};
stu.name = name;
stu.age = age;
stu.sex = sex;
stu.sayHi = function() {
console.log("大家好,我是"+this.name);
}
return stu;
}

//学生1
var stu1 = createStudent("zs", 18, "男");
stu1.sayHi();

//学生2
var stu2 = createStudent("ls", 20, "女");
stu2.sayHi();
  • 方法:在对象中的函数,叫做方法,this在方法中使用表示的是当前的对象
  • 函数:不在对象的函数,叫函数,在函数中使用this指向window,没有太大的意义,this不要出现在函数中,或者是全局作用域

自定义构造函数

new的作用

语法:new + 构造函数();

  1. 创建一个新的对象(类型取决了new后面跟的构造函数)
  2. 让构造函数中的this指向这个新创建的对象
  3. 执行这个构造函数
  4. new会返回这个新创建的对象
构造函数
  1. 构造函数名首字母大写(规范),要和new一起使用
  2. 实例化对象,给这个对象中添加属性和行为

操作对象属性

  • 点语法
    • 赋值:对象名.属性名 = 值; 如果已经有这个属性,则会覆盖掉这个属性的值。
    • 获取:对象名.属性名
  • []语法
    • 赋值:对象名[“属性名”] = 值;
    • 获取:对象名[“属性名”]
    • 可以在[]中使用变量名,只要值是字符串类型的属性名就可以

如果字符串属性名在变量中,就要使用[]语法,遍历对象的时候会使用到;

  • 删除对象的属性
1
2
3
4
5
6
7
8
var obj = {
name:"zs",
age:18
}

//删除obj的name属性,删除整个键值对;
delete obj.name;
delete obj.["name"];

遍历对象

遍历对象的固定语法:for..in for in

1
2
3
4
5
6
for(var key in obj) {
//对象的键
console.log(key);
//对象的值
console.log(obj[key]); //obj.key表示 obj的key属性
}

in 的用法

可以判断某个元素在不在某个对象或者函数中?

for (Array[下标] in Object);判断数组中的某一个元素存不存在对象中的键

查看对象类型

JavaScript的数据类型分为两种

JS数据类型:

  • 简单数据类型:number、string、boolean、undefined、null
1
2
3
4
5
number     数字类型
string 字符串类型
boolean 布尔类型
undefined 没有赋值的变量
null 没有赋值的空对象
  • 复杂数据类型:Array、function、自定义的对象、Object
1
2
3
Array      数组类型
function 函数类型
Object 对象类型

使用typeof查看数据类型

  1. 使用typeof查看简单数据类型:返回值 number、string、boolean undefined;只有null返回的是(Object)
  2. 使用tepyof查看复杂数据类型:返回值 Object;但是函数function返回的是function类型(函数是JavaScript中的一等公民)

使用instanceof判断数据实例

1
2
3
4
5
6
7
arr.constructor.name
var arr = [];
arr是否是Array的实例。
var obj = {};
console.log(arr instanceof Array); // 返回值true
console.log(obj instanceof Array); // 返回值false
console.log(obj instanceof Object); // 返回值true

使用constructor.name来获取数组类型

1
2
3
4
var arr = [];  //new Array()
console.log(arr.constructor.name); // 返回值Array
var obj = {}; //new Object()
console.log(obj.constructor.name); // 返回值Object

值类型与引用类型

值类型

  • 简单类型数据也叫值类型数据;
  • 变量在内存中存储数据的时候,存储的就是值本身,这个内存中的地址叫属性名,值就是本身具体的赋值。
  • 变量存储数据的时候,存储的直接就是这个值本身

引用类型

  • 复杂类型数据也叫引用类型数据;
  • 在内存中随机开辟一个用于存放对象的值,然后把这个地址存到变量名下。
  • 复杂类型:变量不会存这个对象,对象随机存在内存中,会有一个地址,变量存储的仅仅是这个对象的地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var p = {
name: "zs",
age: 18
}

function fn(person) { // fn(p) 调用时,相当于把 person = p;把 p 赋值给 person,是两个对象,
person.name = 'ls'; // 这里是两个对象内存共同连接到 p 对象;所以修改的是 p 对象的 name 属性的值
person = {name: "ww", age: 20}; // 这里 person 有了自己的对象
console.log(person.name); // 所以不再使用 p的对象 name 的值
}

fn(p); // 这里调用的是 person 对象的值,代码从是函数内部从上至下执行的结果

console.log(p.name); // 这里的值已经被 函数内部 person.name = 'ls'; 修改

流程控制

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

分支结构/选择结构

if语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (条件){
//当条件值为true时,执行这里
}

if (条件) {
//当条件为true时,执行这里
} else {
//当条件为false时,执行这里
}
// 注意:两个只能执行一个

if (条件1) {
//条件1为true的时候触发
} else if (条件2) {
//条件2为true的时候触发, 条件1肯定是false
} else {
//条件1和条件2都为false
} .........
// 可以有多个分支,但是只会选择符合条件的执行

三元运算符

语法:条件? 表达式1 : 表达式2;

解析:当条件为true是,返回表达式1的值,当条件为false时,返回表达式2的值。var result = 条件 ? 表达式1 : 表达式2;

switch语句

break可以省略不写,但是会进入后续所有的case语句,所以推荐每一个case都加上break

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
switch (变量) {
case1:
语句1;
break;
case2:
语句2;
break;
case3:
语句3;
break;
.........
default:
默认语句;
break;
}

分支结构的总结

  • switch语句可以用在明确具体值的时候使用
  • 如果是判断范围的使用if语句
  • 能够使用三元运算符的时候,推荐使用三元运算符,具体选择某一个值

循环结构

while语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
while (循环条件) {
//循环体:需要执行的代码语句
}
//当循环条件为true时,执行循环体,重复循环,直到循环条件变为false
//当循环条件为false时,结束整个循环

//计算1-100之间所有数的和
var i = 1;
var sum = 0;
while(i <= 100){//判断条件
sum += i;//循环体
i++;//自增,修改循环条件(不能省略,否则会无限满足条件循环)
}
console.log(sum);

do.while语法

1
2
3
4
5
do {
//循环体:需要执行的代码语句
} while (循环条件)
//不管循环条件是什么都会先执行一次循环体,耍流氓行为;
//然后在判断循环条件是否再次执行循环

for循环

for循环是while循环演化来的,语法简洁明了,固定结构,不会忘记自增或者自减

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for (初始语句; 条件; 自增/自减) {
//循环体:需要执行的代码语句
}

for (初始语句; 判断条件; 自增/自减) 两个分号一个都不能少,可以没有属性,但是不能没有两个分号
/*
1.初始语句
2.条件
3.自增/自减
4.循环体
执行顺序:1 243 243 243 ....2(判断条件为false)结束循环
初始语句只在第一次执行
*/

//计算1-100之间所有数的和
var sum = 0;
for (var i = 1; i <= 100; i++) {
sum += i;
}

循环结构的总结

  • for循环是使用最多最广泛的语句
  • 当不明确循环次数的时候,使用while语句
  • 如果需要先执行一次的时候选择do.while语句
  • 三种循环可以互通

断点调试

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

  • 调试步骤:
    • 浏览器中按F12–>sources–>找到需要调试的文件–>在程序的某一行设置断点
  • 调试中的相关操作:
    • Watch:监视,通过watch可以监视变量的值的变化,非常的常用。
    • F10:程序单步执行,让程序一行一行的执行,这个时候,观察watch中变量的值的变化。
    • F8:跳到下一个断点处,如果后面没有断点了,则程序执行结束。
  • 苦口婆心一下
    • 代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug的能力。初学者不要觉得调试代码麻烦就不去调试,知识点花点功夫肯定学的会,但是代码调试这个东西,自己不去练,永远都学不会。
    • 今天学的代码调试非常的简单,只要求同学们记住代码调试的这几个按钮的作用即可,后面还会学到很多的代码调试技巧。

断点调试 sources ===> ESC键 可以显示/隐藏 console

函数的断点调试

  • F8:跳到下一个断点,如果后面没有断点了,那么代码直接执行完。
  • F10:代码一步步的执行,但是遇到函数的时候会直接执行跳过。
  • F11:代码的一步步执行,遇到调用函数的时候会进入函数内部。
  • shift+F11:跳出函数调用

作用域

作用域:变量起作用的区域

全局作用域

全局作用域:在script标签内部和函数外的范围就是全局作用域;在全局作用域内声明的变量就叫做全局变量,任何地方都能访问的变量。

函数作用域

函数作用域:在函数内部的范围就是函数作用域,在函数作用域内部声明的变量,只有在当前函数内部才可以访问,外部其他范围都不能访问。

块级作用域

一对花括号之间被称为代码块,在JavaScript中,没有块级作用域。

全局变量

在函数外部var声明的变量都叫全局变量,全局任意地方都可以访问。

局部变量

在函数内部var声明的变量都叫局部变量,只有当前函数内部才可以访问。

隐式全局变量

没有用var声明的变量都叫隐式全局变量,一般不推荐。不管在函数外部还是函数内部。

预解析

规范注意:不要重复声明一个同名的变量。把需要使用的变量先声明在使用。

  • 在执行代码前,预先解析 function 声明的函数和 var 声明的变量
  • 把所有 function 声明的函数提升到当前作用域前面,但是不会提升调用,如果有多个相同的 function 函数名,会面的会覆盖掉前面的
  • 把所有的 var 声明变量提升到当前得到作用域前面,不会提升赋值,如果有多个同名的 var 声明,后面的会忽略掉。
  • 如果 function 声明和 var 声明同名,function 声明优先于 var 声明。

Math

  • Math.PI
    • 圆周率π
  • Math.max();
    • 返回最大值
  • Math.min();
    • 返回最小值
  • Math.ceil();
    • 天花板函数,向上取整,只要有不为0的小数,正数+1,负数去掉小数
  • Math.floor();
    • 地板函数,向下取整,只要有不为0的小数,负数-1,正数去掉小数
  • Math.round();
    • 四舍五入,小于0.5的小数舍掉,大于0.5的小数,正数+1负数-1
  • Math.random();
    • 返回一个(0<=x>1)的随机数,取不到1
    • 随机一个(x–y)(包含x和y(y-x需要+1))的随机数:var num = parseInt( Math.random()*(y-x+1) +x );
  • Math.abs();
    • 返回一个绝对值
  • Math.pow(x,y);
    • 返回x的y次方的值
  • Math.sqrt();
    • 返回开平方的值

Date

创建日期

1
2
3
4
var date = new Date();
var date = new Date("2018-04-18 00:00:00");
var date = new Date(2018, 3(月份从0开始), 18, 0,0,0);
var date = new Date(时间戳);

日期的格式化(了解)

日期打印的时候默认打印成为字符串

1
2
3
4
5
6
date.toString();//默认的日期格式
date.toLocalString();//本地风格的日期格式(兼容性)
date.toDateString();
date.toLocalDateString();//获取日期
date.toTimeString();
date.toLocalTimeString();//获取时间

获取日期指定的部分

  • 年:date.getFullYear();
  • 月:date.getMonth()+1; (月份从0开始)
  • 日:date.getMinutes();
  • 星期:date.getDay();(0–6;0:表示星期天)
  • 时:date.getSeconds();
  • 分:date.getHours();
  • 秒:date.getDate();
1
2
3
4
5
6
7
8
9
10
// 表示获取世界标准时间,格林威治时间
date.getUTCHours();


date.getFullYear()
date.getMonth()+1
date.getMinutes()
date.getSeconds()
date.getHours()
date.getDate()

时间戳

1
2
var date = +new Date();//1970年01月01日00时00分00秒起至现在的总毫秒数;
// 1秒=1000毫秒;

Array

  • 数组名.push();
    • 在数组最后的值后面添加一个或多个元素,返回值是数组的新长度
  • 数组名.pop();
    • 删除数组中最后一个元素,只能删除一个,返回值是删除的元素
  • 数组名.unshift();
    • 在数组最前的值前添加一个或多个元素,返回值是数组的新长度
  • 数组名.shif();
    • 删除数组中最前面的元素,只能删除一个,返回值是删除的元素
  • 数组名.join();
    • 用分隔符拼接数组元素,返回值是拼接后的字符串;()中不写默认是”,”
  • 数组名.reverse();
    • 翻转一个数组元素的顺序,返回值是翻转后的新数组。
  • 数组名.sort();
    • 对数组的引用。注意,数组在原数组上进行排序,不制作副本。
    • 数组名.sort(); 对数组中的元素进行排序,默认按照字母顺序排序
    • 数组名.sort(function(a,b){return a-b;}); 从小到大排序 (a,b是实参,自动调用数组内部,无需设置,return的值大于0就会改变位置)
    • 数组名.sort(function(a,b){return b-a;}); 从大到小排序 (a,b是实参,自动调用数组内部,无需设置,return的值大于0就会改变位置)
  • 数组名.concat(数组名2);
    • 拼接数组
    • 不会对原数组操作,返回值是拼接后的新数组
  • 数组名.slice();
    • 返回值是一个新的截取到的元素数组
    • 数组名.slice(); 截取数组所有的元素
    • 数组名.slice(2); 从下标2开始截到最后
    • 数组名.slice(2,end(end是具体的值,或者数组名.length)); 从下标2开始截到end,不包含end这个元素
  • 数组名.splice();
    • 在数组任意位置添加或删除元素,返回值是删除的元素组成的数组
    • 数组名.splice(下标, 删除几个元素, 需要添加的元素); 从下标的位置开始,删除掉几个元素,并添加新的元素(可以是多个,也可以不加);
  • 数组名.indexOf();
    • 获取某个元素在数组中从前往后查找第一次出现的下标位置,如果有这个元素返回值对应的下标,如果没有这个元素则返回值-1
    • 数组名.indexOf(下标, 元素值); 从下标开始查找
    • indexOf可以用来判断数组中是否包含了这个元素
  • 数组名.lastIndexOf();
    • 获取某个元素在数组中从后往前查找第一次出现的下标位置,如果有这个元素返回值对应的下标,如果没有这个元素则返回值-1
  • 清空一个数组
    • 数组名 = []; 直接等于一个空数组,简单快捷,推荐使用
    • 数组名.splice(0); 清空一个数组,基本上没啥用
    • 数组名.length = 0; 数组长度为0,极度不推荐的用法,不要对一个数组的长度进行人为的定义,最好的是让数组的长度自动变化

基本包装类型

概念

基本包装类型:把基本类型包装成复杂类型。

  • 简单数据类型是没有方法的。为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String/Number/Boolean。
  • JavaScript 为了我们使用的方便,提供了简单类型的调用方法。
  • 浏览器允许使用简单类型的直接调用方法,会自动把简单类型转换为复杂类型,调用完之后自动销毁这个复杂类型。
1
2
var str = "abc";
var result = str.indexOf("a");

发生了三件事情

  1. 把简单类型转换成复杂类型:var s = new String(str);
  2. 调用包装类型的indexOf方法:var result = s.indexOf("a");
  3. 销毁刚刚创建的复杂类型

Number

  • number变量名.toString();将—个数字转换成字符串
  • number变量名.toFixed(x);保留x为小数

Boolean

  • boolean变量名.toString();返回值,根据原始布尔值或者Boolean对象b存放的值返回字符串”true”或”false”。

String

字符串可以看成是一个字符数组(伪数组)。因此字符串也有长度,也可以进行遍历。String对象很多方法的名字和和Array的一样。可以少记很多的单词。

  • 字符串可以像数一样遍历,可以通过下标来操作
    • String[下标]获取
  • 所有的字符串操作,原来的字符串都不会发生改变,都有返回值;
  • String.indexOf();
    • 从前往后查找字符串第一个下标,同Array
  • String.lastIndexOf();
    • 从后往前查找字符串第一个下标,同Array
  • String.trim();
    • 去掉字符串去掉字符串两边的空格,中间的不会去除
  • String.toUpperCase();
    • 所有的字符串变成大写
  • String.toLowerCase();
    • 所有的字符串变成 小写
  • String.concat(String2);
    • 两个字符串的拼接,没啥用,一般用+拼接
  • String.slice();
    • 和Array相同
    • String.slice(2,4); 从下标2开始,截取到下标4,不包含下标4
    • String.substring(2,4); 从下标2开始,截取到下标4,不包含下标4
    • String.substr(2,2); 从下标2开始,截取length个字符串
  • String.split();
    • 和Array.join();相反,把一个字符串按照分隔符切割成一个数组()中写分隔符
  • String.replace(值1,值2);
    • 只能将字符串中的第一个值1替换为值2,后面重复的值1不能被替换
    • String.replace(/值1/g,值2); 正则替换,可以替换所有的值1为值2,返回新的字符串

逻辑中断(&&和||的短路问题)

在逻辑运算中是会返回一个值;

&&:短路与,只要碰到了假值,就会短路返回这个假值。如果都是真值,会返回最后一个真值。

||:短路或,只要碰到了真值,就会短路返回这个真值。如果都是假值,会返回最后一个假值。

JavaScript初级总结

  1. 变量
    • 定义一个变量:var num; num = 11; var num = 12; 如果一个变量没有声明,会报错。
    • 命名的规则:
      • 数字、字母、下划线、$, 不能以数字开头
      • 区分大小写
      • 不能使用关键字和保留字 var break continue typeof name top
  2. 数据类型
    • 简单数据类型(值类型):number string boolean undefined null
    • 复杂数据类型(引用类型): object function
  3. 类型转换
    • 转换成字符串:String() toString() + ""
    • 转换成数值:Number() parseInt() parseFloat() +num num - 0
    • 转换成布尔类型:Boolean() !!num
  4. 操作符
    • 算术操作符:+ - * / %
    • 赋值操作符:= += -= *= /= %=
    • 一元运算符:++ --
    • 比较运算符:> < >= <= == === != !==
    • 逻辑运算符:&& || !
  5. 语句
    • 顺序结构
    • 分支结构
      • if..else switch..case 三元运算符
      • 循环结构
        • while do..while for for..in
        • break continue
  6. 数组
    • 定义属性:var arr = [] var arr = new Array()
    • 下标(索引): 从0开始, arr.length-1
    • 长度:arr.length: 表示的数组元素的个数
    • 遍历:for(var i = 0; i < arr.length; i++) {}
  7. 函数
    • 定义函数2中 function fn() {} var fn = function(){}
    • 函数调用: 函数名()
    • 函数的参数:
      • 形参:函数声明的时候,设置的参数,叫做形参,作用是占位置。
      • 实参:函数调用的时候,设置的参数,叫做实参,作用把值赋值给形参。
      • 函数一定需要参数吗? 看有没有哪些值需要调用的时候才能确定的。
    • 返回值
      • 函数如果需要返回一个结果,那么就需要使用返回值,return 返回值;
      • 函数一定需要返回值吗? 函数什么时候需要返回值。 需要访问函数内部的某个变量的时候,就需要返回值。
    • 匿名函数:没有名字的函数,没办直接使用 给变量 自调用
    • 函数是一种数据类型,可以作为参数,也可以作为返回值。
  8. 对象
    • 定义一个对象
      • var obj = new Object();
      • var obj = {}
      • createStudent();工厂函数
      • new Student():构造函数
    • 操作对象的属性
      • obj.name
      • obj["name"]
      • obj[key]
    • for(var k in obj){}
  9. 内置:
    • Math
    • Date
    • Array
    • String
    • Number
    • Boolean

typeof

  1. typeof是用来查询数据的类型,返回的是一个字符串。
  2. typeof是一个关键字,不是一个函数。 ()提升优先级
  3. typeof比较特殊的地方

typeof只能判断简单类型,如果是复杂类型:object

1
2
3
typeof null: object
typeof undefined: undefined
typeof function(){}: function

比较运算符的转换规则

相等与全等 ==/===

  1. NaN不等于任何值,包括NaN本身
  2. null不等于任何值,除了null和undefined
  3. undefined不等于任何值,除了undefined和null
  4. 如果操作符两边有数字,那么两边都转换成数字进行比较。
  5. 如果操作符两边有布尔类型,那么两边都转换成数值进行比较。
  6. 如果操作符有字符串,那么两边都转换成字符串比较。
  7. 如果两边都是对象,那么直接比地址(引用)。

对于复杂类型来说相互比较的是地址,所以复杂类型之间不能比较 ,只能比较复杂类型的值,除非地址相同;

浅拷贝与深拷贝

浅拷贝:将对象中的各个属性依次进行复制,浅拷贝只复制了一层对象的属性。如果对象属性中还有对象,那么赋值的仅仅是地址。还是会相互影响。

深拷贝:将对象中的各个属性一次进行复制,深拷贝会递归赋值所有层对象的属性。如果对象属性中还有对象,会继续拷贝,这样拷贝出来的对象完全独立。

使用遍历可以浅拷贝一个对象,深拷贝的时候,用if判断是否是object,如果是,则使用递归。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 深拷贝实例代码
function deepCopy(obj) {
//1. 新建一个对象
var newObj = {};
//2. 遍历obj把obj中所有的属性添加到newObj中
for (var k in obj) {
//如果是简单类型,直接赋值,如果是复杂类型,需要拷贝一份,在赋值
// if (typeof obj[k] === "object") {
// newObj[k] = deepCopy(obj[k]);
// } else {
// newObj[k] = obj[k];
// }
newObj[k] = typeof obj[k] === "object" ? deepCopy(obj[k]) : obj[k];
}
return newObj;
}

构造函数的缺点

使用构造函数带来的最大的好处就是创建对象更方便了,但是其本身也存在一个浪费内存的问题,使用一个对象来存储构造函数中的方法;让实例来调用对象中的函数,既可以解决内存浪费的问题,也能防止全局函数名污染;但是相对比较麻烦;

在JavaScript高级中,使用实例来存储构造函数中的方法.