JavaScript由ECMAScript、DOM、BOM组成。是一种运行在客户端的 脚本语言。
脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行
ECMAScript 是由ECMA 国际( 原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。
DOM——文档对象模型
文档对象模型(DocumentObject Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)
BOM——浏览器对象模型
浏览器对象模型(Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
单行注释:// 快捷键Ctrl + /
多行注释:/* 快捷键shift + alt + a(不推荐使用)
方法 | 说明 | 归属 |
---|---|---|
alert(msg) | 弹出警示框 | 浏览器 |
console.log(msg) | 控制台打印输出信息 | 浏览器 |
console.dir(msg) | 打印返回的元素对象更好的查看里面的属性和方法 | 浏览器 |
prompt(info) | 弹出输入框,用户可以输入 | 浏览器 |
<script> 弹出警示框 输出 alert(******) 控制台打印输出信息 console.log(*****) console.dir(*****) 弹出输入框 输入 prompt(******)
变量是用来存储数据的空间,通过变量名来匹配。
var age; 声明一个名称为age的变量
var 是一个 JS关键字,用来声明变量( variable 变量的意思 )。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管
age 是程序员定义的变量名,我们要通过变量名来访问内存中分配的空间
age=10; 给age这个变量赋值为10
var age =10,声明一个age的变量赋值为10
更新变量:值会变化,取最后的变量。
声明多个变量:用,隔开
只声明,不赋值,结果是undefined(未定义的)
不声明,不赋值,直接使用变量。报错。
不声明,只赋值,依然可以使用,但不提倡。
不能数字开头
不能有空格,需要加 ‘ ’ 不然不成立,
字符只允许 "$ _"两个字符
首字母不建议大写,遵守驼峰命名法。
不能 是关键字、保留字。例如:var、for、while
变量名必须有意义。 MMD BBD nl → age
JS的变量数据类型是只有程序在运行过程中根据等号右边变量值来确定的。
JS是动态语言,变量的数据类型是可以变化的
var num =10; 数字型 var src ='pink老师' 字符串
数据类型分为:简单数据类型,复杂数据类型
简单数据类型 | 说明 | 默认值 |
---|---|---|
Number | 数字型,包含整型值和浮点值,如22,0.23 | 0 |
Boolean | 布尔值,如true、false,等价于1和0 | false |
String | 字符串类型 | "" |
Undefind | var a;声明了变量a,但没有给值,此时a=undefind | undefind |
Null | var a=null;声明了变量a,a为空值 | null |
JavaScript 数字类型既可以保存整数,也可以保存小数(浮点数)。
var age = 21; // 整数 var Age = 21.3747; // 小数
数字型进制
最常见的进制有二进制、八进制、十进制、十六进制。
// 1.八进制数字序列范围:0~7 var num1 = 07; // 对应十进制的7 var num2 = 019; // 不能超过8,8进制不成立 var num3 = 08; // 不能超过8,8进制不成立 // 2.十六进制数字序列范围:0~9以及A~F var num = 0xA;
在JS中八进制前面加0,十六进制前面加 0x
数字型范围
JavaScript中数值的最大和最小值
最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
最小值:Number.MIN_VALUE,这个值为:5e-32
数字型三个特殊值
Infinity ,代表无穷大,大于任何数值
-Infinity ,代表无穷小,小于任何数值
NaN ,Not a number,代表一个非数值
isNaN
用来判断一个变量是否为非数字的类型,返回 true (不是数字)或者 false(是数字)
隐式类型转换 console.log(isNaN('123')) false
布尔类型有两个值:true 和 false ,其中 true 表示真(对),而 false 表示假(错)。
布尔型和数字型相加的时候, true 的值为 1 ,false 的值为 0。
Undefind:声明后没有赋值会变成一个默认值undefind
var vari; console.log(vari) //undefined console.log('你好'+vari) // 你好undefined console.log(11 + vari) //NaN console.log(true(值是1) + vari) // NaN
Null:声明变量给null值,里面的存的值是为空
var vari=null; console.log('你好' + vari) //你好null console.log(11 + vari) //11 console.log(true + vari) //1
转义符 | 说明 |
---|---|
\n | 换行符,n 是 newline 的意思 |
\\ | 斜杠 \ |
\ ' | ' 单引号 |
\ '' | ”双引号 |
\t | tab 缩进 |
\b | 空格 ,b 是 blank 的意思 |
字符串的长度:length
通过字符串的 length 属性可以获取整个字符串的长度。
var strMsg = "我是帅气多金的程序猿!"; alert(strMsg.length); // 显示 11
字符串的拼接
多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串
拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串
//1.1 字符串 "相加" alert('hello' + ' ' + 'world'); // hello world //1.2 数值字符串 "相加" alert('100' + '100'); // 100100 //1.3 数值字符串 + 数值 alert('11' + 12); // 1112 数值相加字符相连
字符串拼接加强
console.log('pink老师' + 18); // 只要有字符就会相连 var age = 18; console.log('pink老师age岁啦'); // 这样不行哦 console.log('pink老师' + age); // pink老师18 console.log('pink老师' + age + '岁啦'); // pink老师18岁啦
经常会将字符串和变量来拼接,变量可以很方便地修改里面的值
变量是不能添加引号的,因为加引号的变量会变成字符串
如果变量两侧都有字符串拼接,口诀“引引加加 ”,删掉数字,变量写加中间
获取检测变量的数据类型
typeof 可用来获取检测变量的数据类型
var num = 18; console.log(typeof num) // 结果 number
类型 | 例 | 结果 |
---|---|---|
String | typeof"小艾" | ”string“ |
Number | typeof 18 | "number" |
Boolean | typeof true | "boolean" |
Undefined | typeof undefined | "undefined" |
Null | typeof null | "object" |
字面量
字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。
数字字面量:8, 9, 10
字符串字面量:'黑马程序员', "大前端"
布尔字面量:true,false
方式 | 说明 | 案例 |
---|---|---|
toString() | 转字符串 | var num=1; alert(num.toString()) |
String()强制转换 | 转字符串 | var num=1; alert(String(num)) |
加好拼接字符串 | 和字符串拼接的结果都是字符串 | var num=1; alert(num+"字符串") |
toString()和String()使用方式不一样。
第三种转换方式,更多第三种加号拼接字符串转换方式,这一种方式也称之为隐式转换。
方式 | 说明 | 案例 |
---|---|---|
parselnt(string)函数 | 将string类型转成整数数值型 | parseInt('78') |
parseFloat(string)函数 | 将string类型转成浮点数数值型 | parseFloat('78.12') |
Number()强制转换函数 | 将string类型转换为数值型 | Number('12') |
js隐式转换(- * /) | 利用算术运算隐式转换为数值型 | '12'-0 |
转换布尔型
方式 | 说明 | 案例 |
---|---|---|
Boolean()函数 | 其他类型转成布尔值 | Boolean('true') |
代表空、否定的值会被转换为false ,如: ''、0、NaN、null、undefined
其余值都会被转换为true
console.log(Boolean('')) // false console.log(Boolean(0)) // false console.log(Boolean(NaN)) // false console.log(Boolean(null)) // false console.log(Boolean(undefined)) // false console.log(Boolean('字符串')) // true console.log(Boolean(12)) // true
标识符:指开发人员为变量、属性、、函数、参数取的名字。标识符不能是关键字或保留字
关键字:指JS本身已经使用了的字,不能再用它们充当变量名、方法名。
包括:break\case\catch\continue\default\delete\do\else\finally\for\function\if\in\instanceof\new\return\this\switch\this\throw\try\typeof\var\void\while\with
保留字:实际上就是预留的关键字,意思现在不是关键字,但未来可能会成为关键字,同样不能使用它们当变量名或方法名。
包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等。
运算符也被称之为操作符,用于实现赋值,比较和执行算数运算等功能的符号。
+、-、*、/、%
%:取余数(取模),返回除法的余数9%2=1
表达式和返回值
表达式:由数字运算符、变量等组成的式子称为表达式。
返回值:表达式的结果
若要反复给数字添加或减去1,可以使用
前置自增++XXX,后置自增XXX++
前置自增和后置自增如果单独使用,效果一样。
前置自增:先自加后返回原值
var num = 10; alert(++num + 10); // 21
后置自增:先返回原值后自加
var num = 10; alert(10 + num++); // 20 alert(num); //11
概念:比较运算符(关系运算符)是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true/false)作为比较运算的结果。
运算符 | 说明 | 案例 |
---|---|---|
< | 小于 | 1<2 |
> | 大于 | 2>1 |
> = | 大于等于 | 2>=2 |
< = | 小于等于 | 1<=2 |
== | 判断号(会转型) | 2==2 |
!== | 不等号 | 2!==1 |
= ! | 全等,全不等(要求值和数据类型都一致) | '2'==='2' |
= :作用是赋值,把右边给左边
==:作用是判断,判断两边是否相等(此时会有隐式转换)
===:作用判断,判断两边是否完全一致(需数据类型和值都相等)
概念:逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值
运算符 | 说明 | 案例 |
---|---|---|
&& | 逻辑”与“ and | true&&false |
|| | 逻辑”或“ or | true||false |
! | 逻辑”非“ not | !true |
原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值。
逻辑与 &&
语法:表达式1 && 表达式2
如果第一个表达式的值为真,则返回表达式2
如果第一个表达式的值为假,则返回表达式1
逻辑或 ||
语法:表达式1 || 表达式2
如果第一个表达式的值为真,则返回表达式1
如果第一个表达式的值为假,则返回表达式2
如果表达值都是假,则返回最后一个表达式
console.log(123 || 456) // 123 console.log(0 || 456) // 456 console.log(123 || 456 || 789) // 123
var num = 0; console.log(123 || num++); console.log(num); // 0 (在得到123之后,程序就终止了运算,所以还是0)
概念:用来吧数据赋值给变量的运算符
运算符 | 说明 | 案例 |
---|---|---|
= | 直接赋值 | var us = '字符串' |
+=、-= | 加、减一个数后再赋值 | var age=10; age+=5; //15 |
*=。/=、%= | 乘、除、取模后在赋值 | var age =2 ;age*=5; //10 |
优先级 | 运算符 | 顺序 |
---|---|---|
1 | 小括号() | () |
2 | 一元运算符 ++ -- ! | ++、--、! |
3 | 算术运算符 +、-、*、/ | 先乘除后加减 |
4 | 关系运算符 >、<、>=、<= | >、>=、<、<= |
5 | 相等运算符、!=、=、!== | 、!=、=、!== |
6 | 逻辑运算符 &&、||、! | 先&&后|| |
7 | 赋值运算符 = 、+=、-=、%=、*=、/= | 一样 |
8 | 逗号运算符 , | , |
在一个程序执行的过程中,各条代码的执行顺序对程序的结果是由直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。
简单来说:流程控制就是来控制代码按照什么结构顺序执行
流程控制有三种结构:顺序结构、分支结构、循环结构。
语法结构:
if(条件表达式){ //执行语句1 } else { //执行语句2 }
if(条件表达式1){ //执行语句1 } else if(条件表达式2) { //执行语句2 }else if (条件表达式3){ //执行语句3 ....{ }else { 以上条件都不满足,执行最终语句。 }
概念:有三元运算符组成的式子我们称为三元表达式。
条件表达式 ?表达式 :表达式
如果条件表达式结果为真,则返回表达式1的值,如果条件表达式结果为假,则返回表达式2的值。
var num = 10; var result = num >5 ?'是的' :'不是的'(把返回值赋值给一个变量) //是的
也是多分支语句,实现多选一。
核心词:匹配
语法:
switch(表达式) { case value1: 执行语句1; break; case value2: 执行语句2; break; ... default: 执行最后语句; }
表达式的值和case里面的值相匹配的时候是全等,必须是值和数据一致才可以
break起终止作用。如果去除break,则不会退出,会继续执行下一个case
switch语句更加精确,效率高,范围小
if语句范围更大,效率略低。
分支多使用switch,分支少使用if
目的:为了实现重复执行代码。
for循环主要用于把某些代码循环若干次,通常跟计数有关系。
for(初始化变量;条件表达式;操作表达式){ //循环体 }
初始化变量:用var,声明的一个普通变量,通常用作为计数器使用。
条件表达式:用来决定每次循环是否继续执行,终止的条件。
操作表达式:每次循环最后执行的代码,用于计数器变量进行更新(递增或递减)
for (var i = 1; i <= 100; i++){ console.log('你好') } 首先执行 'var i =1',也只执行一场 然后判断i是否满足设定条件,满足执行循环体,不满足,退出循环。 若i执行完循环体,执行i++
可以帮助进行观察程序的运行过程。
for (var i = 1; i <= 10; i++){ console.log(想要重复的内容) } 若要用户控制数量 var num = prompt('请您输入次数'); for (var i = 1; i <= num; i++){ console.log(想要重复的内容) }
for (var i = 1; i <= 100; i++) { if (i==1) { console.log('想要出现的内容') }else if(i == 100){ console.log('想要出现的内容') }else { console.log('这个人今年' + i + '岁了') } }
var sum=0; for (var i =1;i <= 100; i++){ sum += i(sum=sum+i的简写) } console.log(sum)
for(外层的初始化变量;外层的条件表达式;外层的操作表达式){ for(){里层的初始化变量,里层的条件表达式,里层的操作表达式 //执行语句; } }
for循环可以重复执行某些相同代码
for循环可以重复执行些许不同的代码,因为有计数器
for循环可以重复执行某些操作,比如算术运算符加法操作。
随看需求增加,双重for循环可以做更多、更好看的效果。
双重for循环,外层循环一次,内层for循环全部执行。
for循环是循环条件和数字直接相关的循环。
循环语法结构: while (条件循环表达式) { //循环体 } 执行思路:当条件表达式结果为true,则执行循环体,否则退出循环。 代码验证。 var num = 1; while (num <= 100) { consloe.log ('字符集') num++ }
do...while语句其实是while语句的一个变体。该循环会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复,否则退出循环。
语法结构:
do { //循环体代码-条件表达式为true时重复执行循环体代码 }while(条件表达式) 代码体验: var i=1; do { consloe.log('how are you'); i++; }while?(i<=100)
执行思路:
先执行一次循环体代码
再执行条件表达式,如果是true,则继续执行循环体代码,如果是false,则退出循环,继续执行后面的代码。
所以do...while循环语句至少会执行一次循环体代码。
continue关键词用于立即跳出本次循环,继续下一次循环
break关键字用于立即跳出整个循环(循环结束)
变量、函数的命名必须要有意义
变量的名称一般用名词,函数的名称一般用动词。
操作符的左右两边各保留一个空格。
单行注释前要有个空格
概念:可以把一组相关的数据一起存放。
数组是指一组数据的集合,其中每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的方式。
//普通变量 var num = 10; //数组 var num = [1,2,3,4]
利用new创建数组
var数组名 = new Array(); var arr =new Array(); // 创建一个新的空数组
利用数组字面量创建数组
//1.使用数组字面量方式创建空的数组 var 数组名 = [] //2.使用数组字面量方式创建带初始值的数组 var 数组名 = ['红'、'绿'、'蓝']
声明数组并赋值称为数组的初始化。
数组里面的数据一定用逗号分隔。
格式:数组名[索引号]
var 数组名 = ['红'、'绿'、'蓝'] 索引号: 0 1 2 var arr['A','B','C','D'] 索引号有0,所以选中第n位时就是:n-1 console.log(arr[0]) = A console.log(arr[2]) = B
就是把数组中的每个元素从头到尾都访问一次。
<script> var arr =[2,3,4,3,43,5]; for (var i = 0; i< arr.length; i++){ console.log(arr[i]); } </script>
数组名.length
<script> var arr =[2,3,4,3,43,5]; for (var i = 0; i< arr.length; i++){ console.log(arr.length); } </script>
<script> var min = [2,6,1,7,4] var sum = [0] for(var i = 0; i < min.length; i++){ sum= parseInt(sum) + parseInt(min[i]) var ii = sum / min.length } console.log(sum,ii); </script>
<script> var are = [2,6,1,77,52,25,7] var max = are[0] for(var i=0; i < are.length; i++){ if(are[i] > max){ max = are[i] } } console.log(max); </script>
<script> var are = ['red','green','blue'] var m = [] // var sep = '!' for(var i=0; i < are.length; i++){ m += are[i] + '|' // m += are[i] + sep } console.log(m); </script>
arr.length = X
1.新增数组元素,修改length长度 var arr = [1,2,3] arr.length = 5; console.log(arr); //[1,2,3,empty * 2] console.log(arr[3],arr[4],arr[5]) //undefined
其中索引号是:3、4、5的空间没有给值,(声明变量未给值)默认值是undefined
可以通过修改数组索引的方式追加数组元素
不能直接给数组名赋值,否则会覆盖掉以前的数据。
2.新增数组元素,修改索引号 追加数组元素 var arr = [1,2,3] arr[3] = 4 console.log(arr): 1,2,3,4 arr = 4 console.log(arr):4
<script> var are = [''] for(var i = 0; i < 10; i++){ are[i] = i + 1 } console.log(are); </script>
<script> var arr = [2,0,6,1,77,0,52,25,7] var neww = [] for(var i = 0; i < arr.length; i++){ if(arr[i] >= 25){ neww[neww.length] = arr[i] } } console.log(neww); </script>
<script> var arr = [2,0,6,1,77,0,52,0,25,7] var anew = [] for(var i = 0; i < arr.length; i++){ if(arr[i] !== 0){ anew[anew.length] = arr[i] } } console.log(anew); </script>
<script> var are = [1,2,3,4,5] var bbc = [] for(var i = are.length-1; i >= 0; i--){ bbc[bbc.length] = are[i] } console.log(bbc); // 5,4,3,2,1 </script>
<script> var are = [3,24,53,35,42] for (var i=0; i <= are.length-1; i++){ for(var j=0; j<= are.length-1-i; j++){ if(are[j] < are[j+1]){ var to = are[j] are[j] = are[j+1] are[j+1] = to } } } console.log(are); </script>
函数使用分为两步:声明函数和调用函数
1.声明函数
函数名( ) { //函数体 }
function sayH (){ console.log('hi~~') }
function 声明函数的关键字 ,全部小写
函数是做某件事情,函数名一般是动词 sayHi
函数不调用,自己不执行
2.调用函数
函数名(); sayHi(); //调用函数时要加小括号
在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参,而在调用该函数时,同样也需要传递相应的参数,这些参数被称为实参。
形参:形式上的参数,函数定义的时候,传递的参数,当前并不知道是什么。
实参:实际上的参数,函数调用的时候传递的参数,实参是传递给形参的
function 函数名(形参1.形参2){ } 函数名(实参1.实参2) //调用的函数名为实参 function cook(aru){ console.log(aru) } cook('酸辣土豆粉') cook('酸辣土豆') //酸辣土豆粉 //酸辣土豆
声明在括号里面的是形参,调用小括号是实参,形参是接收实参的
函数形参实参个数匹配:
1.如果实参的个数和形参的个数一致,则正常输出结果
2.如果实参的个数多余形参的个数,会取到形参的个数,多余的实参忽略不计。
3.如果实参个数小于形参个数,多的形参定义为undefined,结果为NaN
<script> function getSum(num1,num2){ console.log(parseInt(num1) + parseInt(num2) ); } getSum(2,3) </script>
<script> function getSum(num1,num2){ var sum =0 for(var i=num1; i<= num2; i++){ sum += i } console.log(sum); } getSum(1,100) </script>
可以实现将函数值返回给调用者
return只能返回一个值,返回的结果是最后一个值。
<script> function getSum(aru){ return aru } console.log(getSum('字符串')); </script> 求两个数的和 <script> function cook(are1,are2){ return are1 + are2 } console.log(cook(2,3)) </script> <script> 求两个数的最大值 function max(nem1,nem2){ // if(nem1 > nem2){ // return nem1 // }else { // return nem2 // } return nem1 > nem2 ? nem1 :nem2 } console.log(max(2,32)); </script>
不确定有多少个参数传递时,可以用argument来获取,实际上是当前的一个内置对象。所有的函数都内置了一个arguments对象,而且是每个函数都内置好了这个arguments。arguments对象中存储了传递的所有参数。
arguments展示形式是一个伪数组,因此可以遍历。
特点:具有length(长度)属性
按索引方式存储数据
不具有数组的push,pop等方法。
function fn(){ console.log(arguments); //里面存储了所以传递过来的实参 arguments = [1,2,3,4] //console.log(arguments.length) //4 //console.log(argumens[2]) // 3 按照数组的方式遍历 for (var i = 0; i< arguments.length; i++){ consoles.lo(argumentss[i]) } // 1,2,3,4 fn(1,2,3,4) }
<script> function getMax(){ max = arguments[0] for(var i = 1; i<arguments.length; i++){ if(arguments[i] > max){ max = arguments[i] } return max } } console.log(getMax(23,34,4,4)); </script>
<script> function reverse(arr) { var newArr = []; for (var i=arr.length - 1; i >= 0; i--){ newArr[newArr.length] = arr[i] } return newArr } var sfe = reverse([323,123,123,34]) console.log(sfe); </script>
<script> function sed(des){ for(var i=0; i< des.length-1; i++ ){ for(var j=0; j< des.length-1-i; j++){ var temp = des[j] des[j] = des[j+1] des[j+1]=temp } } return des } var dsfko = sed([1,232,423,12,1]) console.log(dsfko); </script>
<script> function sdi(year){ var flage = false if(year % 4 ==0 && year % 100 != 0 || year % 400 ==0){ flage = true } return flage } console.log(sdi(800)); </script>
<script> // 用户输入年份,输出当前年份2月份的天数 function backDay() { var year = prompt('请您输入年份:'); if (isRunYear(year)) { // 调用函数需要加小括号 alert('当前年份是闰年2月份有29天'); } else { alert('当前年份是平年2月份有28天'); } } backDay(); // 判断是否为闰年的函数 function isRunYear(year) { // 如果是闰年我们返回 true 否则 返回 false var flag = false; if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { flag = true; } return flag; } </script>
利用函数关键字定义函数(命名函数)
function fu(){ } fu();
函数表达式(匿名函数)
var 变量名 = fuction () { } var fun = fuction(){ console.log('我是函数表达式') } fun(); // fun是变量名 不是函数名 // 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值,而 函数表达式里面存的是函数 //函数表达式也可以进行传递参数
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。 JavaScript(es6前)中的作用域有两种:
全局作用域
局部作用域(函数作用域)
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
块作用域由 { } 包括。
在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用,如下面的Java代码:
java有块级作用域:
if(true){ int num = 123; system.out.print(num); // 123 } system.out.print(num); // 报错
以上java代码会报错,是因为代码中 { } 即一块作用域,其中声明的变量 num,在 “{ }” 之外不能使用;
而与之类似的JavaScript代码,则不会报错:
Js中没有块级作用域(在ES6之前)
if(true){ var num = 123; console.log(123); //123 } console.log(123); //123
在JavaScript中,根据作用域的不同,变量可以分为两种:
全局变量
局部变量
2.1 全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
全局变量在代码的任何位置都可以使用
在全局作用域下 var 声明的变量 是全局变量
特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
2.2 局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
局部变量只能在该函数内部使用
在函数内部 var 声明的变量是局部变量
函数的形参实际上就是局部变量
2.3 全局变量和局部变量的区别
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
只要是代码都一个作用域中,写在函数内部的局部作用域,未写在任何函数内部即在全局作用域中;如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据在**[内部函数可以访问外部函数变量]**的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链 案例分析1:
function f1() { var num = 123; function f2() { console.log( num ); } f2(); } var num = 456; f1();
作用域链:采取就近原则的方式来查找变量最终的值。
var a = 1; function fn1() { var a = 2; var b = '22'; fn2(); function fn2() { var a = 3; fn3(); function fn3() { var a = 4; console.log(a); //a的值 ? console.log(b); //b的值 ? } } } fn1();
4.1 预解析的相关概念
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。
代码执行: 从上到下执行JS语句。
预解析会把变量和函数的声明在代码执行之前执行完成。
4.2 变量预解析
预解析也叫做变量、函数提升。 变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
console.log(num); // 结果是多少? var num = 10; // ?
结果:undefined 注意:**变量提升只提升声明,不提升赋值**
4.3 函数预解析
函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
fn(); function fn() { console.log('打印'); }
结果:控制台打印字符串 --- ”打印“ 注意:函数声明代表函数整体,所以函数提升后,函数名代表整个函数,但是函数并没有被调用!
4.4 函数表达式声明函数问题
函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:
fn(); var fn = function() { console.log('想不到吧'); }
结果:报错提示 ”fn is not a function" 解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用
什么是对象?
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。 对象是由属性和方法组成的。
属性:事物的特征,在对象中用属性来表示(常用名词)
方法:事物的行为,在对象中用方法来表示(常用动词)
为什么需要对象?
保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组。
如果要保存一个人的完整信息呢? 例如,将“张三疯”的个人的信息保存在数组中的方式为:
var arr = [‘张三疯’, ‘男', 128,154];
上述例子中用数组保存数据的缺点是:数据只能通过索引值访问,开发者需要清晰的清除所有的数据的排行才能准确地获取数据,而当数据量庞大时,不可能做到记忆所有数据的索引值。 为了让更好地存储一组数据,对象应运而生:对象中为每项数据设置了属性名称,可以访问数据更语义化,数据结构清晰,表意明显,方便开发者使用。 使用对象记录上组数据为:
var obj = { "name":"张三疯", "sex":"男", "age":128, "height":154 }
JS中的对象表达结构更清晰,更强大。
利用字面量创建对象
就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法;{ } 里面采取键值对的形式表示
键:相当于属性名
值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
代码如下:
var star = { name : 'pink', age : 18, sex : '男', sayHi : function(){ alert('大家好啊~'); } };
上述代码中 star即是创建的对象。
对象的使用
对象的属性
对象中存储具体数据的 "键值对"中的 "键"称为对象的属性,即对象中存储具体数据的项
对象的方法
对象中存储函数的 "键值对"中的 "键"称为对象的方法,即对象中存储函数的项
访问对象的属性
对象里面的属性调用 : 对象.属性名 ,这个小点 . 就理解为“ 的 ”
对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号
示例代码如下:
console.log(star.name) // 调用名字属性 console.log(star['name']) // 调用名字属性
调用对象的方法
对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号
示例代码如下:
star.sayHi(); // 调用 sayHi 方法,注意,一定不要忘记带后面的括号
变量、属性、函数、方法总结
属性是对象的一部分,而变量不是对象的一部分,变量是单独存储数据的容器
变量:单独声明赋值,单独存在
属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征
方法是对象的一部分,函数不是对象的一部分,函数是单独封装操作的容器 - 函数:单独存在的,通过“函数名()”的方式就可以调用 - 方法:对象里面的函数称为方法,方法不需要声明,使用“对象.方法名()”的方式就可以调用,方法用来描述该对象的行为和功能。
利用 new Object 创建对象
创建空对象
var andy = new Obect();
通过内置构造函数Object创建对象,此时andy变量已经保存了创建出来的空对象
给空对象添加属性和方法
通过对象操作属性和方法的方式,来为对象增加属性和方法
示例代码如下:
andy.name = 'pink'; andy.age = 18; andy.sex = '男'; andy.sayHi = function(){ alert('大家好啊~'); }
注意:
Object() :第一个字母大写
new Object() :需要 new 关键字
使用的格式:对象.属性 = 值;
利用构造函数创建对象
构造函数
构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
构造函数的封装格式:
function 构造函数名(形参1,形参2,形参3) { this.属性名1 = 参数1; this.属性名2 = 参数2; this.属性名3 = 参数3; this.方法名 = 函数体; }
构造函数的调用格式
var obj = new 构造函数名(实参1,实参2,实参3)
以上代码中,obj即接收到构造函数创建出来的对象。
注意事项
构造函数约定首字母大写。
函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
构造函数中不需要 return 返回结果。
当我们创建对象的时候,必须用 new 来调用构造函数。
其他
构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class) 创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化
new关键字的作用
在构造函数代码开始执行之前,创建一个空对象;
修改this的指向,把this指向创建出来的空对象;
执行函数的代码
在函数完成之后,返回this---即创建出来的对象
for...in 语句用于对数组或者对象的属性进行循环操作。 其语法如下:
for (变量 in 对象名字) { // 在此执行代码 }
语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。
for (var k in obj) { console.log(k); // 这里的 k 是属性名 console.log(obj[k]); // 这里的 obj[k] 是属性值 }
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象 前面两种对象是JS 基础 内容,属于 ECMAScript; 第三个浏览器对象属于 JS 独有的, JS API 讲解内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法),内置对象最大的优点就是帮助我们快速开发
JavaScript 提供了多个内置对象:Math、 Date 、Array、String等
查找文档:学习一个内置对象的使用,只要学会其常用成员的使用即可,我们可以通过查文档学习,可以通过MDN/W3C来查询。 Mozilla 开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括 HTML、CSS 和万维网及 HTML5 应用的 API。 MDN:https://developer.mozilla.org/zh-CN/
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用 Math 中的成员。
属性、方法名 | 功能 |
---|---|
Math.PI | 圆周率 |
Math.floor() | 向下取整,往最小值取 |
Math.ceil() | 向上取整, ceil天花板 |
Math.round() | 四舍五入版 就近取整 注意 -3.5 结果是 -3 |
Math.abs() | 绝对值, 有隐式转换可以吧“1”转换为1 |
Math.max()/Math.min() | 求最大和最小值 |
Math.random() | 获取范围在[0,1)内的随机值 |
注意:上面的方法使用时必须带括号
获取指定范围内的随机整数:
function getRandom(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
Date 对象和 Math 对象不一样,Date是一个构造函数,所以使用时需要实例化后才能使用其中具体方法和属性。Date 实例用来处理日期和时间
使用Date实例化日期对象
获取当前时间必须实例化:
var now = new Date(); log(date) // 当前时间
获取指定时间的日期对象
var future = new Date('2019/5/1');
注意:如果创建实例时并未传入参数,则得到的日期对象是当前时间对应的日期对象
使用Date实例的方法和属性
方法名 | 说明 | 代码 |
---|---|---|
getFullYear( ) | 获取当年 | dOb.getFullYear( ) |
getMonth( ) | 获取当月(0-11) | dOb.getMonth( ) |
getDate( ) | 获取当天日期 | dOb.getDate( ) |
getDay( ) | 获取星期几(周日0 到周六6) | dOb.getDay( ) |
getHours( ) | 获取当前小时 | dOb.getHours( ) |
getMinutes( ) | 获取当前分钟 | dOb.getMinutes( ) |
getSeconds ( ) | 获取当前秒钟 | dOb.getSeconds( ) |
通过Date实例获取总毫米数
总毫秒数的含义
基于1970年1月1日(世界标准时间)起的毫秒数
获取总毫秒数
// 实例化Date对象 var now = new Date(); // new Date() 返回自1970年1月1日(世界标准时间)起的毫秒数 // 1. 用于获取对象的原始值 console.log(date.valueOf()) console.log(date.getTime()) // 2. 简单写可以这么做 var now = + new Date(); // 3. HTML5中提供的方法,有兼容性问题 var now = Date.now();
conutDown 倒计时
d = parselnt(总秒数/60/60/24) // 计算天数 h = parselnt(总秒数/60/60%24) // 计算小时 m = parselnt(总秒数/60%60) // 计算分 s = parselnt(总秒数%60) // 计算当天秒数 1秒等于1000毫秒
字面量方式
示例代码如下:
var arr = [1,"test",true];
new Array()
示例代码如下:
var arr = new Array();
注意:上面代码中arr创建出的是一个空数组,如果需要使用构造函数Array创建非空数组,可以在创建数组时传入参数
参数传递规则如下:
如果只传入一个参数,则参数规定了数组的长度
如果传入了多个参数,则参数称为数组的元素
instanceof 运算符
instanceof 可以判断一个对象是否是某个构造函数的实例
var arr = [1, 23]; var obj = {}; console.log(arr instanceof Array); // true ,是数组 console.log(obj instanceof Array); // false
Array.isArray()
Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
var arr = [1, 23]; var obj = {}; console.log(Array.isArray(arr)); // true console.log(Array.isArray(obj)); // false
数组中有进行增加、删除元素的方法,部分方法如下表
方法名 | 说明 | 返回值 |
---|---|---|
push(参数1...) | 末尾添加一个或多个元素,注意修改原数组 | 并返回新的长度 |
pop( ) | 删除数组最后一个元素,把数组长度减1无参数、修改原数组 | 返回它删除的元素的值 |
unshift(参数1...) | 向数组的开头添加一个更多元素,注意修改原数组 | 并返回新的长度 |
shift( ) | 删除数组的第一个元素,数组长度减1无参数、修改原数组 | 并返回第一个元素的值 |
注意:push、unshift为增加元素方法;pop、shift为删除元素的方法
数组中有对数组本身排序的方法,部分方法如下表
方法名 | 说明 | 是否修改原数组 |
---|---|---|
reverse() | 颠倒数组中元素的顺序,无参数 | 该方法会改变原数组,返回新数组 |
sort() | 对数组的元素进行排序 | 该方法会改变原数组,返回新数组 |
注意:sort方法需要传入参数来设置升序、降序排序
如果传入“function(a,b){ return a-b;}”,则为升序
如果传入“function(a,b){ return b-a;}”,则为降序
数组中有获取数组指定元素索引值的方法,部分方法如下
方法名 | 说明 | 返回值 |
---|---|---|
indexOf() | 数组中查找给定元素的第一个索引 | 如果存在返回索引号,如果不存在,则返回-1 |
lastlndexOf() | 在数组的最后一个的索引 | 如果存在返回索引号,如果不存在,则返回-1 |
数组中有把数组转化为字符串的方法,部分方法如下表
方法名 | 说明 | 返回值 |
---|---|---|
toString() | 把数组转换成字符串,逗号分隔每一项 | 返回一个字符串 |
join('分隔符') | 方法用于把数组中的所有元素转换为一个字符串 | 返回一个字符串 |
注意:join方法如果不传入参数,则按照 “ , ”拼接元素
数组中还有其他操作方法,同学们可以在课下自行查阅学习
方法名 | 说明 | 返回值 |
---|---|---|
concat() | 连接两个或多个数组 不影响原数组 | 返回一个新的数组 |
slice() | 数组截取slice(begin,end) | 返回被截取项目的新数组 |
splice() | 数组删除splice(第几个开始,要删除个数) | 返回被删除项目的新数组 注意,这个会影响原数组 |
为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
// 下面代码有什么问题? var str = 'andy'; console.log(str.length);
按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但上面代码却可以执行,这是因为
js 会把基本数据类型包装为复杂数据类型,其执行过程如下 :
// 1. 生成临时变量,把简单类型包装为复杂数据类型 var temp = new String('andy'); // 2. 赋值给我们声明的字符变量 str = temp; // 3. 销毁临时变量 temp = null;
指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
当重新给字符串变量赋值的时候,变量之前保存的字符串不会被修改,依然在内存中重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变。 由于字符串的不可变,在大量拼接字符串的时候会有效率问题
字符串通过基本包装类型可以调用部分方法来操作字符串,以下是返回指定字符的位置的方法:
方法名 | 说明 |
---|---|
indexOf(‘要查找的字符’,开始的位置) | 返回指定内容在原字符串中的位置,如果找不到就返回-1,开始的位置是index索引号 |
lastlindexOf() | 从后往前找,只第一个匹配的 |
案例:查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数
先查找第一个o出现的位置
然后 只要indexOf 返回的结果不是 -1 就继续往后查找
因为indexOf 只能查找到第一个,所以后面的查找,利用第二个参数,当前索引加1,从而继续查找
字符串通过基本包装类型可以调用部分方法来操作字符串,以下是根据位置返回指定位置上的字符:
方法名 | 说明 | 使用 |
---|---|---|
charAt(index) | 返回指定位置的字符(index 字符串的索引号) | str.charAt(0) |
charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) | str.charCodeAt(0) |
str[index] | 获取指定位置处字符 | HTML5, IE8+支持和charAt()等效 |
在上述方法中,charCodeAt方法返回的是指定位置上字符对应的ASCII码,ASCII码对照表如下:
案例:判断一个字符串 'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数
核心算法:利用 charAt() 遍历这个字符串
把每个字符都存储给对象, 如果对象没有该属性,就为1,如果存在了就 +1
遍历对象,得到最大值和该字符
注意:在遍历的过程中,把字符串中的每个字符作为对象的属性存储在对象总,对应的属性值是该字符出现的次数
字符串通过基本包装类型可以调用部分方法来操作字符串,以下是部分操作方法:
方法名 | 说明 |
---|---|
concat(str1,str2,str3...) | concat()方法用于连续两个或多个字符串。拼接字符串,等效于+,+更常用 |
substr(start,length) | 从start位置开始(索引号),length取的个数 重点记住这个 |
slice(start,end) | 从start位置开始,截取到位置,end取不到(他们俩都是索引号) |
substring(start,end) | 从start位置开始,截取到位置,end取不到 基本和slice相同,但是不接受负值 |
replace() 方法用于在字符串中用一些字符替换另一些字符,其使用格式如下:
字符串.replace(被替换的字符串, 要替换为的字符串);
split()方法用于切分字符串,它可以将字符串切分为数组。在切分完毕之后,返回的是一个新数组。
其使用格式如下:
字符串.split("分割字符")
toUpperCase 转换大写
log('abc'.toUpperCase()) //ABC
tolowerCase 转换小写
log('ABC'.tolowerCase()) // abc
简单类型(基本数据类型、值类型):在存储时变量中存储的是值本身,包括string ,number,boolean,undefined,null
复杂数据类型(引用类型):在存储时变量中存储的仅仅是地址(引用),通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等;
堆栈空间分配区别:
1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
简单数据类型存放到栈里面
2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
简单数据类型的存储方式
值类型变量的数据直接存放在变量(栈空间)中
复杂数据类型的存储方式
引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中
函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
function fn(a) { a++; console.log(a); } var x = 10; fn(x); console.log(x); // 11 // 10
函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。