全文共11420字
JavaScript基础从变量的定义与使用、数据类型及相互转换、运算符、流程控制语句、三元运算符、数组、函数、构造函数、内置对象以及对象等基础必备技能。
JavaScript基础教程的笔记,原视频链接:www.bilibili.com/video/BV1ux…
1.初始导读
学习目标
- JavaScript是什么
- JavaScript的发展历史
- 浏览器执行JavaScript的原理
- JavaScript由哪三部分组成
- JavaScript的三个输入输出语句
2.初始JavaScript
JavaScript是什么
- JavaScript是世界上最流行的语言之一,,是一种运行在客户端的脚本语言(Script是脚本的意思)
- 脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行
- 现在也可以基于Node.js技术进行服务器端编程
JavaScript的作用
- 表单动态校验(密码强度检测)(JS产生最初的目的)
- 网页特效
- 服务端开发(Node.js)
- 桌面程序(Electron)
- App(Cordova)
- 控制硬件-物联网(Ruff)
- 游戏开发(cocos2d-js)
HTML/CSS/JS 的关系
(1)HTML/CSS标记语言--描述类语言
HTML决定网页结构和内容(决定看到什么),相当于人的身体
CSS决定网页呈现给用户的模样(决定好不好看),相当于给人穿衣服、化妆
(2)JS脚本语言--编程类语言
实现业务逻辑和页面控制(决定功能),相当于人的各种动作。
3.浏览器执行JS过程
浏览器分为两部分:渲染引擎和JS引擎
- 渲染引擎:用来解析HTML与CSS,俗称内核,比如chrome浏览器的blink,老版本的webkit
- JS引擎:也称为JS解释器,用来读取网页中的JavaScript代码,对其处理后运行,比如chrome浏览器的V8
浏览器本身并不会执行JS代码,而是通过内置JavaScript引擎(解释器)来执行JS代码。JS引擎执行代码时要逐行解释每一句源码(转化为机器语言),然后由计算机去执行,所以JavaScript语言归于脚本语言,会逐行解释执行。
4. 三部分组成
ECMAScript(JavaScript语法)、DOM(页面文档对象模型)、BOM(浏览器对象模型)
ECMAScript 规定了 JS 的编程语法和基础核心知识,是所有浏览器厂商共同遵循的一套 JS 语法工业标准。
DOM文档对象模型:是 W3C 组织推荐的处理可扩展标记语言的标准化接口。通过DOM提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
BOM浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
5.JS 三种书写位置
行内式、内嵌式、外部
1、行内式 JS
<body>
<input type="button" value="唐伯虎" onclick="alert('秋香姐')"/>
</body>
- 可以将单行或少量JS代码写在HTML标签的事件属性中(以on开头的属性),如onclick
- 注意单双引号的使用:在HTML中我们推荐使用双引号,JS中我们推荐使用单引号
- 可读性差,在html中编写JS大量代码时,不方便阅读;
- 引号易错,引号多层嵌套匹配时,非常容易弄混;
- 特殊情况下使用。
2、内嵌式 JS
<head>
<!--2.内嵌式的js-->
<script>
//alert("我是帅哥");
</script>
</head>
- 可以将多行JS代码写到
<script>
标签中 - 内嵌 JS 是学习时常用的方式
3、外部 JS文件
<body>
<scrpit src="my.js"></script>
</body>
- 利于HTML页面代码结构化,把大段JS代码独立到HTML页面之外,既美观,也方便文件级别的复用
- 引用外部JS文件的 script 标签中间不可以写代码
- 适合与 JS 代码量比较大的情况
6.注释
单行注释(ctrl + /) ://
多行注释(shift+alt+a) :/* */
7.输入输出语句
为了方便信息的输入输出,JS中提供了一些输入输出语句,其常用的语句如下:
方法 | 说明 | 归属 |
---|---|---|
alert(msg) | 浏览器弹出警示框 | 浏览器 |
console.log(msg) | 浏览器控制台打印输出信息 | 浏览器 |
prompt(info) | 浏览器弹出输入框,用户可以输入 | 浏览器 |
<script>
//这是一个输入框
prompt('请输入你的名字');
//alert 退出警示框 输出的 展示给用户的
alert('计算的结果');
//console 控制台输出 给程序员测试用的
console.log('程序员能看到的');
</script>
8.变量
目标
- 能够说出变量的主要作用
- 能够写出变量的初始化
- 能够说出变量的命名规范
- 能够画出变量是如何在内存中存储的
- 能够写出交换变量案例
变量的概述
本质:变量是程序在内存中申请的一块用来存放数据的空间。
变量的使用
变量在使用时分为两步:1.声明变量,2.赋值
//声明变量,就开辟了内存空间
var age; //声明一个 名称为age的变量
age = 10; //把age这个变量赋值为10
- var 是一个JS 关键字,用来声明变量(variable变量的意思)。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管
- age 是程序员定义的变量名,我们要通过变量名来访问内存中分配的空间
变量的初始化:声明变量并赋值
var age = 18;
变量语法扩展
(1)更新变量
一个变量被重新赋值后,它原有的值就会被覆盖,变量值将已最后一次赋的值为准。
var age = 18;
age = 81;
(2)声明多个变量
var age = 18,
address = '火影村',
name = '麦克';
(3)声明变量的特殊情况
1、只声明不赋值
var age; //undefined
console.log(age); //打印undefined
2、不声明,不赋值,直接使用某个变量会报错
3、不声明直接赋值使用,可以,但不推荐
变量命名规范
- 由字母、数字、下线、美元符号($)组成。
- 严格区分大小写。
- 不能以数字开头
- 不能是关键字、保留字
- 变量名必须有意义,别用拼音
- 遵循小驼峰命名法。首字母小写,后面单词的首字母需要大写。如myFirstName
9.数据类型
目标
- 能够说出5种简单数据类型
- 能够使用typeof获取变量的类型
- 能够说出1~2种转换为数值型的方法
- 能够够说出1~2种转换为字符型的方法
- 能够说出什么是隐式转换
数据类型简介
1、为什么需要数据类型?
在计算机中,不同的数据所占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型
2、变量的数据类型
变量是用来存储值的所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。JavaScript是一种弱类型或者说动态类型。 这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。
var age = 10; //这是一个数字型
var name = '麦克'; //这是一个字符串
在代码运行时,变量的数据类型是由 JS 引擎 根据 = 右边变量值的数据类型来判断的,运行完毕之后,变量就确定了数据类型。
3、JavaScript拥有动态类型,变量的数据类型是可变的。
var x = 10;
x = 'make';
4、数据类型的分类
简单数据类型(Number,String,Boolean,Undefined,Null)
复杂数据类型(object)
简单数据类型
1、Number型
简单数据类型 | 说明 | 默认值 |
---|---|---|
Number | 数字型,包含整型值和浮点型值,如21、0.21 | 0 |
Boolean | 布尔值类型,如true、false,等价于 1 和 0 | false |
String | 字符串类型,如'张三‘,注意,在js 里,字符串都是带引号的 | '' |
Undefined | var a; 声明了变量a但是没有给值,此时a = undefined | undefined |
Null | var a = null; 声明了变量a为空值 | null |
<script>
var num1 = 010; //010 八进制 转换为十进制就是 8
//十六进制 0~9 a~f #fffff 数字的前面加 0x 表示十六进制
var num2 = 0xa; //转换为十进制就是10
console.log(Number.MAX_VALUE); //数字型的最大值
console.log(Number.MIN_VALUE); //数字型的最小值
console.log(Number.MAX_VALUE * 2); //Infinity 无穷大
console.log(-Number.MAX_VALUE * 2); //-Infinity 无穷小
console.log('make' - 100); //非数字 NaN
</script>
isNaN()
这个方法用来判断非数字,并且返回一个值,如果是数字返回false,如果不是数字,返回true
2、字符串型 String
任何类型和string类型相加(+),结果都是字符串类型
(1)字符串引号嵌套
JS 可以用单引号嵌套双引号,或者用双引号嵌套单引号(外双内单,外单内双)
(2)字符串转义符
类似HTML里面的特殊字符,字符串中也有特殊字符,我们称之为转义符。
转义符都是 \ 开头的,这些转义字符要写到引号里面,常用的转义符及其说明如下:
转义符 | 解释说明 |
---|---|
\n | 换行符,n是newline的意思 |
\ | 斜杠 \ |
' | ' 单引号 |
" | “ 双引号 |
\t | tab 缩进 |
\b | 空格,b 是blank的意思 |
(3)字符串长度
字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过字符串的length属性可以获取整个字符串的长度。
<script>
var str = "my name is andy";
alert(str.length);
</script>
(4)字符串拼接
多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串
拼接前会把与字符串相加的任何类型转换成字符串,再拼接成一个新的字符串。
+号总结口诀:数值相加,字符相连
3、Boolean类型
false:0
true:1
4、undefined
如果一个变量声明未赋值,就是undefined未定义数据类型
<script>
var variable;
console.log(variable); //undefined
console.log('你好' + variable); //你好undefined
console.log(11 + variable); //NaN
console.log(true + variable); //NaN
</script>
5、null
一个声明变量给null值,里面存的值为空(学习对象时,会继续研究null)
<script>
var vari = null;
console.log('你好' + vari); //你好null
console.log(11 + vari); //11
console.log(true + vari); //1
</script>
获取变量数据类型
typrof 可用来获取检测变量的数据类型
<script>
var num = 10;
console.log(typeof num);
var str = '124';
console.log(typeof str);
var flag = true;
console.log(typeof flag);
var unde;
console.log(typeof unde);
var timer = null;
console.log(typeof timer); //输出object
</script>
字面量
字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。
- 数字字面量:8,9,10
- 字符串字面量:’黑马程序员‘,’前端‘
- 布尔字面量:true,flase
数据类型转换
使用表单、prompt获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另一种数据类型。
我们通常会实现3种方式的转换:
- 转换为字符串类型
- 转换为数字型
- 转换为布尔型
1、转换为字符串
方式 | 说明 | 案例 |
---|---|---|
toString ( ) | 转成字符串 | var num = 1; alert(num.toString()) |
String( ) 强制转换 | 转成字符串 | var num = 1; alert(String(num)); |
加号拼接字符串 | 和字符串拼接的结果都是字符串 | var num = 1; alert(num + "我是字符串") |
<script>
// 1. 把数字型转换为字符串型 toString()
var num = 10;
var str = num.toString();
console.log(typeof str);
// 2. 利用 String()
console.log(typeof String(num));
// 3. 直接加字符串,隐式转换
console.log(typeof (num + ''));
</script>
2、转换为数字型
方式 | 说明 | 案例 |
---|---|---|
parseInt( string ) 函数 | 将string类型转成整数数组型 | parseInt('60') |
parseFloat(string) 函数 | 将string类型转成浮点数数值型 | parseFloat('60.2') |
Number() 强制转换函数 | 将string类型转换为数值型 | Number('12') |
js 隐式转换 (- * /) | 利用算术运算隐式转换为数值型 | '12' - 0 |
3、转换为布尔类型
方式 | 说明 | 案例 |
---|---|---|
Boolean() | 其他类型转换成布尔值 | Boolean('true') |
- 代表空、否定的值会被转换为 false,如 “、0、NaN、null、undefined”
- 其余值都会被转换为true
<script>
//以下都为false,其他都是true
console.log(Boolean(''));
console.log(Boolean(0));
console.log(Boolean(NaN));
console.log(Boolean(null));
console.log(Boolean(undefined));
</script>
10.解释型语言和编译型语言
概述:
计算机不能直接理解任何出机器语言以外的语言,所以必须要把程序所写的程序语言翻译成机器语言才能执行程序。程序语言翻译成机器语言的工具,被称为翻译器。
翻译器翻译的方式有两种:一个是编译,另外一个是解释。两种方法之间的区别在于翻译的时间点不同。
- 编译器是在代码执行之前进行编译,生成中间代码文件。
- 解释器是在运行时进行及时解释,并立即执行(当编译器以解释方式运行的时候,也称之为解释器)。
11.运算符
目标
- 能够使用常用运算符
- 能够说出前置递增和后置递增的区别
- 能够说出运算符的优先级
运算符
运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。
算术运算符
加、减、乘、除、取余
递增和递减运算符
如果需要反复给数字变量添加或减去1,可以使用递增(++)和递减(--) 运算符来完成。
在JavaScript中,递增(++)和递减(--)既可以放在变量前面,也可以放在变量后面,放在变量前面时,我们可以称为前置递增(递减)运算符,放在变量后面时,我们称为后置递增(递减)运算符。
所以:递增和递减运算符必须和变量配合使用。
比较运算符
概念:比较运算符(关系运算符)是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true / false)作为比较运算的结果。
- <、>、>=、<=、==、!=
- 全等,要求值和数据类型都一致:===、!==
逻辑运算符
概念:逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值。后面开发中经常用于多个条件的判断。
短路运算符:&&、||、!
赋值运算符
概念:用来把数据赋值给变量的运算符
=、+=、-=、*=、/=、%=
运算符优先级
优先级 | 运算符 | 顺序 | ||
---|---|---|---|---|
1 | 小括号 | () | ||
2 | 一元运算符 | ++、--、! | ||
3 | 算数运算符 | 先 * / % 后 + - | ||
4 | 关系运算符 | >、>= 、<、<= | ||
5 | 相等运算符 | ==、!=、===、!== | ||
6 | 逻辑运算符 | 先&& 后 | ||
7 | 赋值运算符 | = | ||
8 | 逗号运算符 | , |
12.流程控制
在一个程序执、行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。
简单理解:流程控制就是来控制我们代码按照什么结构顺序来执行。
流程控制主要有三种结构,分别是顺序结构、分支结构和循环结构,这三种结构代表三种代码执行的顺序。
switch和if else if的区别
- 一般情况下,两者可以互换
- switch ... case 语句通常处理case比较确定值的情况,而 if ... else ... 语句更加灵活,常用于范围判断(大于、等于某个范围)
- switch语句进行条件判断后总结执行到程序的条件语句,效率更高。而 if... else 语句有几种条件,就得判断多少次。
- 当分支比较少时,if... else语句的执行效率比switch语句高。
- 当分支比较多时,switch语句的执行效率比较高,而且结构更清晰。
13.三元表达式
由三元运算符组成的式子。
条件表达式 ? 表达式1 : 表达式2
如果条件表达式结果为真,则返回表达式1的值,如果条件表达式为加,则返回表达式2的值。
14.循环
目标
循环的目的
能够说出for循环的执行过程
能够使用断点调试来观察代码的执行过程
能够使用for循环完成累加求和等案例
能够使用双重for 循环完成乘法表案例
能够说出while 循环和 do while 循环的区别
能够说出 break 和 continue 的区别
循环的目的
可以重复执行某些代码
在实际问题中,有许多具有规律性的重复操作,因此在程序汇总要完成这类操作就需要重复执行某些语句。
for循环
for(初始化变量; 条件表达式; 操作表达式){
//循环体
}
while 循环
while (条件表达式){
//循环体
}
do while 循环
do{
//循环体
}while(条件表达式)
continue、break
continue关键字用于立即跳出本次循环,继续下一次循环(本次循环体中continue之后的代码就会少执行一次)
break关键字用于跳出当前循环(循环结束)。
15.断点调试
断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程汇总可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。
断点调试可以帮我们观察程序的运行过程
- 浏览器中按F12 --> sources --> 找到需要调试的文件 --> 在程序的某一行设置断点
- Watch:监视,通过watch可以监视变量的值的变化,非常的常用。
- F11 :程序单步执行,让程序一行一行的执行,这个时候,观察watch 中变量的值的变化。
代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug 的能力。初学者不要觉得调试麻烦就不去调试,知识点花点功夫肯定学得会,但是代码调试这个东西,自己不去练,永远都学不会。
16.数组
目标
能够知道为什么要有数组
能够创建数组
能够获取数组中的元素
能够对数组进行遍历
能够给数组新增一个元素
能够独立完成冒泡排序的案例
数组的概念
数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
//普通变量一次只能存储一个值
var num = 10;
//数组一次可以存储多个值
var arr = [1,2,3,4,5];
数组中可以存放任意类型的数据,例如字符串,数字,布尔值等。
var arr2 = [1, 2, 'make', true];
创建数组
JS中创建数组有两种方式:
- 利用 new 创建数组
- 利用数组字面量创建数组
(1)利用 new 创建数组
var 数组名 = new Array();
var arr = new Array(); //创建一个新的空数组
(2)利用数组字面量创建数组
var arr1 = []; //创建了一个空数组
var arr2 = [1, 2, 'make', true];
获取数组中的元素
var arr2 = [1, 2, 'make', true];
console.log(arr2[0]);
遍历数组
var arr2 = [1, 2, 'make', true];
for(var i = 0; i < arr2.length; i++){
console.log(arr2[i]);
}
数组中新增元素
- 可以通过修改length长度来实现数组扩容的目的
- length属性是可读写的
<script>
var arr = [1, 2, 3];
console.log(arr.length); // 3
arr[3] = 4; // 新增数组元素,修改索引号 追加数组元素
console.log(arr.length); // 4
arr.length = 5;
console.log(arr.length); // 5
arr.length = 1; // 将数组长度设为1
console.log(arr.length); // 1
console.log(arr[0]); // 1
console.log(arr[1]); // undefined
console.log(arr[2]); // undefined
arr = '123';
console.log(arr); //不要直接给数组名赋值,否则里面的数组元素都没有了
</script>
17.函数
目标
- 能够说出为什么需要函数
- 能够根据语法书写函数
- 能够根据需求封装函数
- 能够说出形参和实参的传递过程
- 能够使用函数的返回值
- 能够使用arguments获取函数的参数
函数的概念
函数就是封装了一段可以被重复执行调用的代码块,目的就是让大量代码重复使用。
<script>
//声明函数
function 函数名(){
//函数体
}
//调用函数
函数名();
</script>
函数的使用
<script>
//求[num1,num2]的和,并打印出来
function getSum(num1, num2){ //形参
var sum = 0;
for(var i = num1; i <= num2; i++){
sum += i;
}
console.log(sum);
}
getSum(1, 50); //实参
</script>
函数的参数
形参和实参
- 在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参。
- 在调用该函数时,同样也需要传递相应的参数,这些参数被称为实参。
参数 | 说明 |
---|---|
形参 | 形式上的参数,函数定义的时候传递的参数,当前并不知道是什么 |
实参 | 实际上的参数,函数调用的时候传递的参数,实参是传递给形参的 |
参数的作用:在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去。
函数形参和实参匹配问题
<script>
//函数形参实参个数匹配
function getSum(num1, num2){
console.log(num1 + num2);
}
// 1.如果实参的个数和形参的个数一致,则正常输出结果
getSum(1,2);
// 2. 如果实参的个数多于形参的个数,会取到形参的个数
getSum(1, 2, 3);
// 3. 如果实参的个数少于形参的个数,打印NaN
getSum(1);
// 形参可以看作是不用声明的变量, num2 是一个变量都是没有接收值,此时num2的值就是undefined
</script>
小结
- 函数可以带参数也可以不带参数。
- 声明参数的时候,函数名括号里面的是形参,形参的默认值为undefined。
- 调用函数的时候,函数名括号里面的是实参。
- 多个参数中间用逗号分隔。
- 形参的个数可以和实参不匹配,但是结果不可预计,我们尽量要匹配。
函数的返回值
通过使用 return 语句可以让函数将值返回给调用者。
return 之后的代码不执行
<script>
//求[num1,num2]的和,并打印出来
function getSum(num1, num2){
var sum = 0;
for(var i = num1; i <= num2; i++){
sum += i;
}
console.log(sum);
return 1;
}
console.log(getSum(1, 5));
</script>
函数都有返回值,如果没有return,则返回undefined;
arguments的使用
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在JavaScript 中,argument 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments对象中存储了传递的所有实参。
<script>
// arguments 的使用,只有函数才有arguments 对象,而且每个函数都内置好了这个argument
function fn(){
console.log(arguments); //里面存储了所有传递过来的实参
console.log(arguments.length);
console.log(arguments[2]);
//我们可以按照数组的方式遍历argument
for(var i = 0; i < arguments.length; i++){
console.log(argument[i]);
}
}
fn(1, 2, 3);
</script>
arguments 展示的是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有数组的 length 属性
- 按照索引的方式进行存储
- 它没有真正数组的一些方法 pop() push() 等
伪数组,并不是真正意义上的数组
函数的两种声明方式
- 利用函数关键字自定义函数(命名函数)
- 函数表达式(匿名函数)
<script>
// 函数的两种声明方式
// 1. 利用函数关键字自定义函数(命名函数)
function fn(){
console.log('命名函数');
}
fn();
// 2. 函数表达式(匿名函数)
// var 变量名 = function() {}
var fun = function(aru){
console.log('我是函数表达式');
console.log(aru);
}
fun('make');
// (1)fun是变量名,不是函数名
// (2)函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值,而函数表达式里面存的是函数
// (3)函数表达式也可以进行传递参数
</script>
18.作用域
目标
能够说出JavaScript 的两种作用域
能够区分全局变量和局部变量
能够说出如何在作用域链中查找变量的值
作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用功能提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
- 全局作用域
- 局部作用域
- 在 es6 的时候新增块级作用域
变量的作用域
1.全局作用域:整个script 标签,或者是一个单独的js 文件。 2.局部作用域(函数作用域) :在函数内部就是局部作用域,整个代码的名字只在函数内部起效果和作用。
<script>
var num = 10;
console.log('全局变量:' + num);
function fn(){
// 局部作用域
var num = 20;
console.log('局部变量:' + num);
}
fn();
</script>
作用域链
- 只要是代码,就至少有一个作用域。
- 写在函数内部的局部作用域。
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
- 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪种数据能被内部访问,就称作作用域链
<script>
// 作用域链
var num = 10;
function fn(){ //外部函数
var num = 20;
function fun(){
console.log(num); //打印20
}
fun();
}
fn();
</script>
19.预解析
目标
- 能够知道解析器运行 JS 分为哪两步
- 能够说出变量提升的步骤和运行过程
- 能够说出函数提升的步骤和运行过程
预解析
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript解析器在运行JavaScript 代码的时候分为两步:预解析和代码执行。
先来看看下面的代码
<script>
console.log(num); //undefined 坑1
var num = 10;
/*
相当于执行下面代码
var num;
console.log(num);
num = 10;
*/
fn(); //正常打印11
function fn(){
console.log(11);
}
fun(); //报错,坑2
var fun = function(){
console.log(22);
}
/*
相当于执行下面代码
var fun;
fun();
fun = function(){
console.log(22);
}
*/
</script>
- JS 引擎会把 js 里面所有的 var 还有 function 提升到当前作用域的最前面
- 代码执行,安装代码书写的顺序从上往下执行。
变量预解析和函数预解析
(1)变量预解析(变量提升)
把所有的变量声明提升到当前的作用域最前面,不提升赋值。
(2)函数预解析(函数提升)
把所有的函数声明 (不包括匿名表达式)提升到当前作用域的最前面,不调用函数。
预解析案例
案例一
<script>
var num = 10;
fun();
function fun(){
console.log(num); //输出 undefined
var num = 20;
}
/*
相当于执行了以下操作
var num;
function fun(){
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
*/
</script>
案例二
<script>
var num = 10;
function fn(){
console.log(num); //打印 undefined
var num = 20;
console.log(num); //打印 20
}
fn();
/*
相当于以下代码
var num = 10;
function fn(){
var num;
console.log(num);
num = 20;
console.log(num);
}
fn();
*/
</script>
案例三
<script>
var a = 18;
f1();
function f1(){
var b = 9;
console.log(a); //打印 undefined
console.log(b); //打印 9
var a = '123';
}
</script>
案例四
<script>
function fn(){
var a;
a = b = c = 9;
//相当于 var a=9; b=9; c=9; b和c直接赋值,没有var声明,当全局变量看
//集体声明 var a=9, b=9, c=9;
console.log(a);
console.log(b);
console.log(c);
}
fn();
console.log(b); // 9
console.log(c); // 9
console.log(a); //报错
</script>
20.对象
目标
- 能够说出为什么需要对象
- 能够使用字面量创建对象
- 能够使用西沟函数创建对象
- 能够说出 new 的执行过程
- 能够遍历对象
对象
(1)什么是对象?
现实生活中,万物皆对象,对象是一个具体的事物,看得见摸得着的实物。例如,一本书、一辆汽车、一个人可以是 “对象” ,一个数据库,一张网页,一个与远程服务器的连接也可以是 “对象“ 。
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事务都是对象,例如字符串,数值、数组、函数等。
对象是由属性和方法组成的。
- 属性:事物的特征,在对象中用属性来表示(常用名词)
- 方法:事务的行为,在对象中用方法来表示(常用动词)
(2)为什么需要对象?
保存一个值是,可以用变量,保存多个值(一组值)时,可以使用数组。
如果要保存一个人的完整信息呢?
JS 中的对象表达结构更清晰,更强大。
创建对象的三种方式
- 利用字面量创建对象
- 利用 new Object 创建对象
- 利用构造函数创建对象
(1)利用字面量创建对象
对象字面量:就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法。
注意:
属性或方法我们采取键值对的形式 键 属性名 : 值 属性值;
多个属性或方法中间用逗号隔开的;
方法冒号后面跟的是一个匿名函数。
<script>
// 1. 利用对象字面量创建对象 { }
// var obj = {}; //创建一个空的对象
var obj = {
uname : '张三',
age : 18,
sex : '男',
sayHi: function(){
console.log('hi~');
}
}
// 2. 使用对象(对象的调用)
console.log(obj.uname); //方法一
console.log(obj.age);
obj.sayHi();
console.log(obj['uname']); //方法二
</script>
对象的调用
- 对象里面的属性调用:对象.属性名,这个小点 . 就理解为 “的”。
- 对象里面属性的另一种调用方式:对象[ '属性名' ] ,注意方括号里面的属性必须加引号。
- 对象里面的方法调用:对象 . 方法名(),注意这个方法名字后面一定加括号。
(2)利用 new Object 创建对象
<script>
//利用 new Object 创建对象
var obj = new Object();
obj.uname = '张三';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function(){
console.log('hi~');
}
// (1) 我们是利用等号 = 赋值的方法,添加对象的属性和方法。
// (2) 每个属性和方法之间用分号结束。
console.log(obj.uname);
console.log(obj['sex']);
obj.sayHi();
</script>
(3)利用构造函数创建对象
我们一次创建一个对象,里面很多的属性和方法是大量相同的,我们只能复制;因此我们可以利用函数的方法,重复这些相同的代码,我们就把这个函数称为构造函数。
构造函数就是把我们对象里面一些相同的属性和方法抽象出来封装到函数里面。
<script>
/* function 构造函数名() {
this.属性 = 值;
this.方法 = function(){ }
}
new 构造方法名(); */
function Star(uname, age, sex){
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang){
console.log(sang);
}
}
var ldh = new Star('刘德华', 18, '男');
console.log(typeof ldh);
console.log(ldh['sex']);
ldh.sing('冰雨');
var zxy = new Star('张学友', 19, '男');
//构造函数的首字母大写
//构造函数不需要return,就可以返回结果
</script>
我们属性和方法前面必须添加this
变量、属性、函数、方法的区别
变量:单独声明赋值,单独存在。
属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征。
函数:单独存在的,通过 “函数名()” 的方式就可以调用
方法:对象里面的函数称为方法,方法不需要声明,使用 “对象 . 方法名()” 的方式就可以调用,方法用来描述该对象的行为和功能。
构造函数与对象的区别
构造函数,如Star(),抽象了对象的公共部分,封装到了函数里面,它泛指一大类(class) 。
创建对象,如new Star(),特指某一个,通过new 关键字创建对象的过程,我们也称为对象实例化。
new 关键字
new关键字执行过程
- new 构造函数可以在内存中创建一个空的对象
- this 就会指向刚才创建的空对象
- 执行构造函数里面的代码,给这个空对象添加属性和方法
- 返回这个对象(所以构造函数里面不需要 return)
遍历对象属性
for ... in 语句,用于对数组或者对象的属性进行循环操作。
<script>
var obj = {
name : '张三',
age : 18,
sex : '男',
fn : function(){
console.log('fn');
}
}
for(var k in obj){
console.log(obj[k]); //遍历方法,输出的是代码
}
</script>
21.内置对象
目标
- 能够说出什么是内置对象
- 能够根据文档查询指定API 的使用方法
- 能够使用Math 对象的常用方法
- 能够使用Date 对象的常用方法
- 能够使用Array 对象的常用方法
- 能够使用String 对象的常用方法
内置对象
- JavaScript 中的对象分为3种:自定义对象、内置对象、浏览器对象。
- 前面两种对象是JS 基础内容,属于 ECMAScript ;第三个浏览器对象属于我们 JS 独有的,我们 JS API 讲解。
内置对象就是JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)。
查文档
学习一个内置对象的使用,只要学会其常用成员的使用即可,我们可以通过查文档学习,可以通过 MDN/W3C 来查询。
Mozilla 开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括 HTML、CSS和万维网及 HTML 5应用的API。
如何学习对象中的方法?
- 查阅该方法的功能
- 查看里面参数的意义和类型
- 看返回值的意义和类型
- 通过 demo 进行测试
Math 对象
Math概述
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对性、取整、最大值等)可以使用Math 中的成员。
Math.PI //圆周率
Math.floor() //向下取整
Math.ceil() //向上取整
Math.round() //四舍五入,就近取整,注意 -3.5的结果是 -3
Math.abs() //绝对值
Math.max()/Math.min() //求最大和最小值
实例
<script>
// 1. 绝对值方法
console.log(Math.abs(1)); // 1
console.log(Math.abs(-1)); // 1
console.log(Math.abs('-1')); // 1
console.log(Math.abs('make')); // NaN
// 2. 三个取整方法
// (1) Math.floor() 向下取整
console.log(Math.floor(1.1)); // 1
console.log(Math.floor(1.9)); // 1
console.log(Math.floor(-1.6)); // -2
// (2) Math.ceil() 向上取整
console.log(Math.ceil(1.1)); // 2
console.log(Math.ceil(1.9)); // 2
console.log(Math.ceil(-1.1)); // -1
// (3) Math.round() 四舍五入,其他数字都是四舍五入,但是 .5 特殊,它往大了取
console.log(Math.round(1.4)); // 1
console.log(Math.round(1.5)); // 2
console.log(Math.round(-1.4)); // -1
console.log(Math.round(-1.5)); // -1
console.log(Math.round(-1.6)); // -2
console.log(Math.round(-1.9)); // -2
</script>
随机数方法 random ( )
左闭右开
<script>
// 1. Math对象随机方法 random() 返回一个随机的小数
// 2. 这个方法里面不跟畜生
// 3. 代码验证
console.log(Math.random());
// 4. 我们想要得到两个数之间的随机整数,并且包含这两个整数
// Math.floor(Math.random() * (max - min +1)) + min;
function getRandom(min, max){
min = Math.ceil(min); //向上取整
max = Math.floor(max); //向下取整
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandom(1, 10));
// 5. 随机点名
var arr = ['张三', '李四', '王五', 'make'];
console.log(arr[getRandom(0, arr.length - 1)]);
</script>
封装自己的数学对象
<script>
// 利用对象封装自己的数学对象
var myMath = {
PI : 3.1415926,
max : function() {
var max = arguments[0];
for(var i = 1; i < arguments.length; i++){
if(arguments[i] > max){
max = arguments[i];
}
}
return max;
},
min : function() {
var min = arguments[0];
for(var i = 1; i < arguments.length; i++){
if(arguments[i] < min){
min = arguments[i];
}
}
return min;
}
}
console.log(myMath.PI);
console.log(myMath.max(1, 5, 9));
console.log(myMath.min(3, 1, 8));
</script>
日期对象
Date概述
- Date 对象和 Math 对象不一样,他是一个构造函数,所以我们需要实例化后才能使用。
- Date 实例用来处理日期和时间。
实例
<script>
// Date() 日期对象 是一个钩子函数,必须使用new 来调用创建我们的日期对象
var arr = new Array(); // 创建一个数组对象
var obj = new Object(); // 创建了一个对象实例
// 1. 使用 Date
var date = new Date();
console.log(date);
// 2. 带参数
var date1 = new Date('2019-10-1 8:8:8');
console.log(date1);
var date = new Date();
console.log(date.getFullYear());
console.log(date.getMonth()); //打印比当前月份小1个月 [0, 11]
</script>
日期格式化
(1)年月日星期
方法名 | 说明 | 代码 |
---|---|---|
getFullYear( ) | 获取当年 | obj.getFullYear( ) |
getMonth( ) | 获取当月(0-11) | obj.getMonth( ) |
getDate( ) | 获取当天日期 | obj.getDate( ) |
getDay( ) | 获取星期几(周日0 到 周六6) | obj.getDay( ) |
getHours( ) | 获取当前小时 | obj.getHours( ) |
getMinutes( ) | 获取当前分钟 | obj.getMinutes( ) |
getSeconde( ) | 获取当前秒钟 | obj.getSeconds( ) |
(2)时分秒
<script>
// 格式化日期 时分秒
var date = new Date();
console.log(date.getHours());
console.log(date.getMinutes());
console.log(date.getSeconds());
//要求封装一个函数返回当前的时分秒 格式 08:08:08
function getTime() {
var time = new Date();
var h = time.getHours();
h = h < 10 ? '0' + h : h;
var m = time.getMinutes();
m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
console.log(getTime());
</script>
Date总的毫秒数(时间戳)
获取日期的总的毫秒形式
- Date 对象是基于 1970年1月1日 (世界标准时间)起的毫秒数。
- 利用总的毫秒数来计算时间更精确。
数组对象
数组对象的创建
- 字面量方式
- new Array()
<script>
var arr = [1, 2, 3];
console.log(arr[0]);
var arr1 = new Array(3); //表示数组长度为3
console.log(arr1);
var arr2 = new Array(1, 2, 3); //等价于 [1, 2, 3]
console.log(arr2);
</script>
检测是否为数组
(1)instanceof 可以用来检测是否为数组
<script>
var arr = [];
var obj = {};
console.log(arr instanceof Array); //true
console.log(obj instanceof Array); //false
</script>
(2)Array . isArray()方法
<script>
var arr = [];
var obj = {};
console.log(Array.isArray(arr)); //true
console.log(Array.isArray(obj)); //false
</script>
HTML 5 新增的方法,IE 9以上版本支持
添加、删除数组元素
方法名 | 说明 | 返回值 |
---|---|---|
push( 参数1... ) | 末尾添加一个多个元素,注意修改原数组 | 并返回新的长度 |
pop() | 删除数组最后一个元素,把数组长度减一,无参数,修改原数组 | 返回删除的元素的值 |
unshift(参数1... ) | 向数组的开头添加一个或更多元素,注意修改原数组 | 并返回新的长度 |
shift() | 删除数组的第一个元素,数组长度减 1,无参数,修改原数组 | 并返回第一个元素的值 |
<script>
var arr = [1, 2, 3];
// 添加元素
arr.push(4, 'make'); // 在数组后面添加两个元素
console.log(arr);
arr.unshift('jack', 0); // 在数组前面添加两个元素
console.log(arr);
// 删除元素
arr.pop(); // 删除最后一个元素
console.log(arr);
arr.shift();
console.log(arr); // 删除第一个元素
</script>
实例
<script>
// 有一个包含工资的数组 [1500, 1200, 2000, 2100, 1800]
// 要求把数组中工资超过2000 的删除,剩余的放到新数组里面
function screen(array){
var newArr = [];
for(var i = 0; i < array.length; i++){
if(array[i] > 2000){
newArr[newArr.length] = array[i];
}
}
return newArr;
}
var arr = [1500, 1200, 2000, 2100, 1800, 3000];
var newArr = screen(arr);
console.log(newArr);
</script>
数组排序、反转
方法名 | 说明 | 是否修改原数组 |
---|---|---|
reverse() | 颠倒数组中元素的顺序,无参数 | 该方法会改变原来的数组,返回新数组 |
sort() | 对数组的元素进行排序 | 该方法会改变原来的数组,返回新数组 |
<script>
var arr = [1, 2, 3, 4, 5];
arr.reverse();
console.log(arr);
var arr1 = [2, 5, 1, 9];
arr1.sort(); //默认是升序排序
console.log(arr1);
arr1.sort(function(a, b) {
return b - a; //降序排序
//return a - b; //升序排序
});
console.log(arr1);
</script>
数组索引方法
方法名 | 说明 | 返回值 |
---|---|---|
indexOf() | 数组中查找给定元素的第一个索引 | 如果存在返回索引号,如果不存在,则返回 -1 |
lastIndexOf() | 在数组中的最后一个的索引 | 如果存在返回索引号,如果不存在,则返回 -1 |
索引从0开始
数组转换为字符串
方法名 | 说明 | 返回值 |
---|---|---|
toString() | 把数组转换成字符串,逗号分隔每一项 | 返回一个字符串 |
join(' 分隔符 ') | 方法用于把数组中的所有元素转换为一个字符串 | 返回一个字符串 |
<script>
var arr = [1, 2, 3];
console.log(arr.toString()); // 1,2,3
var arr1 = ['make', 'jack'];
console.log(arr1.join('-')); // make-jack
</script>
字符串对象
基本包装类型
为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String、Num,ber和Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
字符串不可变
指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
根据位置返回字符
方法名 | 说明 | 使用 |
---|---|---|
charAt(index) | 返回指定位置的字符(index 字符串的索引号) | str.charAt(0) |
charCodeAt(index) | 获取指定位置处字符的 ASCII 码(index索引号) | str.charCodeAt(0) |
str[index] | 获取指定位置处字符 | H5、IE8+支持和charAt()等效 |
字符串操作方法
方法名 | 说明 |
---|---|
concat(str1, str2, str3...) | concat()方法用于连接两个或多个字符串。拼接字符串,等效于+ |
substr(start, length) | 从start 位置开始(索引号),length 取的个数,重点记住这个 |
slice(start, end) | 从start 位置开始,截取到end 位置,end 取不到(他们俩都是索引号) |
substring(start, end) | 从start 位置开始,截取到end 取不到,左闭右开,不接受负值 |
字符串替换与分割
replace('被替换的字符', '替换为的字符')
split('')
21.简单数据类型和复杂数据类型
目标
- 能够说出简单数据类型的类型分配
- 能够说出复杂数据类型的内存分配
- 能够说出简单数据类型如何传参
- 能够说出复杂数据类型如何传参
简单数据类型与复杂数据类型
简单数据类型又叫作基本数据类型或者值类型,复杂数据类型又叫作引用类型。
- 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型。
string、number、boolean、undefined、null
- 引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型。
通过new 关键字创建的对象(系统对象、自定义对象),如Object、Array、Date等。
<script>
var timer = null;
console.log(typeof timer); // object类型
// 如果有个变量我们以后打算存储为对象,暂时没想好放啥,这个时候就给 null
</script>
堆和栈
堆栈空间分配区别:
1、栈(操作系统):由操作系统自动分配释放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
注意:JavaScript 中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来信息其他语言。
简单类型的内存分配
简单数据类型存放在栈里面,栈里面直接开辟一个空间,存放的是值
复杂类型的内存分配
复杂数据类型存放到堆里面,栈里存放的是地址,十六进制表示
简单类型传参
函数的形参也可以看作是一个变量,当我们把一个值类型变量作为参数传给函数的形参是,其实是把变量在栈空间里的值复制了一份,那么在方法内部对形参做任何修改,都不会影响到外部变量。
复杂类型传参
函数的形参也可以看作是一个变量,当我们把应用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个对地址,所以操作的是同一个对象。