JavaScript
负责页面中的的行为,运行在浏览器端的脚本语言。
输出语句
alert(“要输出的内容”);
document.write(“要输出的内容”);
- 该内容将会被写到 body 标签中,并在页面中显示
console.log(“要输出的内容”);
基本语法
- 单行注释 // …
- 多行注释 /_ … _/
- JS 中严格区分大小写
- JS 中每一条语句以分号(;)结尾,只有单行内需要分割语句,这个分号才是必须的
- JS 中会忽略多个空格和换行
- JS 语句是按照自上向下的顺序一条一条执行的
- 在 JS 中可以使用{}来为语句进行分组,同一个{}中的语句我们称为是一组语句,这一组语句我们也称为一个代码块
标识符
- 在 JS 中所有的可以由我们自主命名的都可以称为是标识符
- 例如:变量名、函数名、属性名都属于标识符
- JS 底层保存标识符时实际上是采用的 Unicode 编码,所以理论上讲,所有的 utf-8 中含有的内容都可以作为标识符
- 命名规则:
- 标识符中可以含有字母、数字、_、$
- 标识符不能以数字开头
- 标识符不能是 ES 中的关键字或保留字
- 标识符一般都采用驼峰命名法 — aBbbCcc
JS 的编写位置
- 编写到外部 js 文件中,然后通过 script 标签引入(推荐)
- 好处:可以复用多个页面
- 坏处:不能在编写修改,但是可以使用内部 script 标签
<script type="text/javascript" src="文件路径"></script>
- 编写到 script 标签内 — 写在页面底部
<script type="text/javascript"></script>
- 写在超链接的 href 属性中,这样当点击超链接时,会执行 js 代码
<a href="javascript:alert('点击弹窗');">弹窗</a>
- 编写到标签的 onclick 属性中,当我们点击按钮时,js 代码才会执行(不推荐)
<button onclick="alert("点击弹窗")"></button>
数据 | 内存 | 变量
数据
- 存储于内存中代表特定信息的, 本质就是 0101 二进制
- 具有可读和可传递的基本特性
- 万物(一切)皆数据, 函数也是数据
内存
- 内存条通电后产生的存储空间(临时的)
- 产生和死亡: 内存条(集成电路板)==>通电==>产生一定容量的存储空间==>存储各种数据==>断电==>内存全部消失
- 内存的空间是临时的, 而硬盘的空间是持久的
- 一块内存包含 2 个数据
- 内部存储的数据(一般数据/地址数据)
- 内存地址值数据
- 内存分类
- 栈: 全局变量, 局部变量 (空间较小)
- 堆: 对象 (空间较大)
变量
- 值可以变化的量, 由变量名与变量值组成
- 一个变量对应一块小内存, 变量名用来查找到内存, 变量值就是内存中保存的内容
- 声明变量
- 使用 var、const、 let 关键字声明
- var a;
- 为变量赋值: a = xxx;
- 声明和赋值同时进行:var a = xx;
三者之间的关系
- 内存是一个容器, 用来存储程序运行需要操作的数据
- 变量是内存的标识, 我们通过变量找到对应的内存, 进而操作(读/写)内存中的数据
问题: JS 引擎如何管理内存?
- 内存生命周期
- 分配需要的内存
- 使用分配到的内存
- 不需要时将其释放/归还
- 释放内存
- 为执行函数分配的栈空间内存: 函数执行完自动释放
- 存储对象的堆空间内存: 当内存没有引用指向时, 对象成为垃圾对象, 垃圾回收器后面就会回收释放此内存
var & let & const
es6 之前创建变量只有 var,let/const 是 es6 后出来的
- var 定义的变量,没有块的概念,可以跨块访问,不能跨函数
- let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问
- const 用来定义常量,使用时必须初始化(即赋值),只能块作用域里访问,且不能修改
- var 定义的变量可以先使用,后声明,存在变量提升,let 必须先声明后使用
- var 允许在相同作用域内重复声明同一个变量,let 和 const 不允许
- 在全局上下文中,基于 var 声明的变量会和全局对象(window)有映射,而 let 不会
- 会产生暂时性死区:检测一个未被声明的变量类型时,不会报错,会返回 undefined
- let、const 会把当前所在的大括号作为一个全新的块级上下文
数据存储
可以用来保存字面量,而且变量的值是可以任意改变的
- JS 中的变量都是保存到栈内存中的,
- 基本数据类型的值直接在栈内存中存储,值与值之间是独立存在,修改一个变量不会影响其他的变量
- 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,
- 而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响
- 比较两个基本数据类型的值时,就是比较值。
- 比较两个引用数据类型时,它是比较对象的内存地址,如果两个对象是一样,但是地址不同,它也会返回 false
关于引用变量赋值问题
- 2 个引用变量指向同一个对象, 通过一个引用变量修改对象内部数据, 另一个引用变量也看得见
- 2 个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象
问题: 在 js 调用函数时传递变量参数时, 是值传递还是引用传递
- 只有值传递, 没有引用传递, 传递的都是变量的值, 只是这个值可能是基本数据, 也可能是地址(引用)数据
- 如果后一种看成是引用传递, 那就值传递和引用传递都可以有
转义字符
\"
:表示 “
\'
:表示 ‘
\n
:表示换行
\t
:制表符
\\
:表示\
js 的数据类型
- 七种基本类型,一种引用类型
- Number、Boolean、String、undefined、null、Bigint(es2020 新增,范围比 Number 的大)、Symbol(ES6 新增)
- Object对象(包括普通
Object
、Function
、Array
、Date
、RegExp
、Math
)
Number 数值
- 特殊的数字
Infinity 正无穷
-Infinity 负无穷
NaN 非法数字(Not A Number)
- 进制:
- 如果需要表示
16进制
的数字,则需要以0x开头
- 如果需要表示
8进制
的数字,则需要以0开头
- 如果要要表示
2进制
的数字,则需要以0b开头
,但是不是所有的浏览器都支持
- 示例:像”070”这种字符串,有些浏览器会当成 8 进制解析,有些会当成 10 进制解析
- 可以在parseInt()中传递一个第二个参数,来指定数字的进制
null 和 undefined
- undefined 代表没有赋值
- null 代表赋值了, 只是值为 null
- 由于 undefined 衍生自 null,所以 null == undefined 会返回 true。
- 但是 null === undefined 会返回 false。
- null 的使用
- var a = null // a 将指向一个对象, 但对象此时还没有确定
- a = null // 让 a 指向不再使用的对象成为垃圾对象(垃圾回收机制 GC)
NaN
- 与任何值都不相等,包括自身
- 可以通过 isNaN()函数来判断一个值是否是 NaN
- function isNaN(x){ return x! = x}
- 机制:会先判断参数是不是 Number 类型,不是尝试转为 Number,之后再去判断是不是 NaN
Unicode 编码
\u四位编码
:在字符串中使用的 Unicode 编码
&#编码
:在网页中使用的 Unicode 编码,这里的编码需要的是 10 进制
- 示例:
<h1 style="font-size: 200px;">☠</h1>
typeof — 类型检测方案
区分数据类型,并返回 number、 string、 boolean、undefined、object、function、symbol
- 对于
基本数据
类型,除null都
可以正确判断
- 对于
引用类型
,除function
外,都会返回object
- typeof 返回值是 string,即
双层typeof
返回的类型是string
- typeof
未定义的变量
,返回"undefined"
- typeof(
null
) —> “object
“
- typeof(
NaN
) —> “number
“
- typeof(
Infinity
) —> “number
“
instanceof — 类型检测方案
判断对象的原型链上是否存在构造函数的原型。只能判断引用类型。检查一个对象是否是一个类的实例
- 语法:A instanceof B,常用来判断 A 是否为 B 的实例,如果是,则返回 true,否则返回 false,
- 如果 B 函数的显式原型对象在 A 对象的原型链上, 返回 true, 否则返回 false
- arr instanceof Array ,可以
判断数组类型
,但不推荐
,因为如果网页存在多个 iframe,便会存在多个 Array 构造函数,此时判断会存在问题
- 所有的对象都是 Object 的后代,所以任何对象和 Object 左 instanceof 检查时都会返回 true
- Number、Boolean、String 基本类型不能判断
Object.prototype.toString.call([value]) — 类型检测方案
可以精准判断数据类型,与 Array.isArray 结合使用可以判断数组和对象,此方式兼容性最好
1 2 3 4 5 6 7 8
| if (!Array.isArray) { Array.isArray = function (o) { return ( typeof o === 'object' && Object.prototype.toString.call(o) === '[object Array]' ) } }
|
类型转换
在 js 中,只有三种类型转换
转换为 Number 类型:Number()/parseFloat()/parseInt()
- 显式/强制:直接使用 Number()/parseFloat()/parseInt()
- 隐式:比较操作(<,>,<=,>=)、按位操作(|,&,^,~)、算术操作(+,-,*,/,%)、一元+-操作
- Number 类型使用 toString(整数)可以将数字转为指定的进制,默认 10 进制
- parseFloat(): 把一个字符串转换为一个浮点数
- parseInt(): 把一个字符串转换为一个整数,将一个字符串中的有效的整数内容取出来
1 2 3 4
| ['1','2','3'].map(parseInt)相当于执行了以下三次过程: parseInt('1', 0, ['1','2','3']): radix 为 0 时,默认取 10,最后返回 1 parseInt('2', 1, ['1','2','3']): radix 取值为 2~36,返回 NaN parseInt('3', 2, ['1','2','3']): radix 取值为 2,二进制只包括 0,1,返回 NaN
|
- 对非 String使用 parseInt()或 parseFloat(),会先将其转换为 String 然后在操作
- 字符串 –> 数字
类型 |
结果 |
undefined |
NaN |
null |
+0 |
Boolean |
true:1,false:+0 |
Number |
返回对应的值 |
String |
空字符串返回 0,出现任何一个非有效数字返回 NaN,其他的直接转换为对应的值 |
Object |
先执行 ToPrimitive 方法,再执行 Number 类型转换 |
转换为 String 类型:String()/toString()
- 显式/强制:直接使用 String()/toString()
- 隐式:+ 运算符有一侧操作数为 string 类型
- null 或 undefined 调用 String()方法,返回字符串格式是它们本身
- null 或 undefined 使用 toString()会报错
转化为 Boolean 类型:Boolean()
- 显式/强制:直接使用 Boolean()
- 隐式:通过 !! 或 !
- 除 0,-0,null,NaN,undefined,或空字符串(“”)为 false 外,其余全为 true
==隐式转换规则
- 类型相同的比较
- 类型是 undefined 或 null, 返回 true
- 如:null == null // true
- 如:undefined == undefined // true
- 如果一个是+0,另一个是-0,返回 true
- 如果类型是对象,二者引用同一个对象,返回 true,否则返回 false
- null 和 undefined 比较,仅当它们之间比较返回 true
- 如:null == undefined // true
- NaN 比较,NaN 与任何之后比较都返回 false,包括自己
- 字符串与数字比较,先将字符串转换为数字在比较
- 布尔值与非布尔值比较:先将布尔值转换为数字在比较
- 对象与原始类型比较,将对象通过ToPrimitive转换为原始类型对应的类型在比较
- ! 的优先级高,如遇到[] == ![], 先进行非运算,
- 又因为任何对象转换成布尔值都得到true,先转布尔在非运算
- 即 ![] == false, 根据==隐式转换规则,对象与原始类型转换,两边先转为数字在比较,
- 即 ![] ==> false ==> 0
- [] 经过 ToPrimitive 方法 转换为’ ‘,
- 所以[] == ![] 变成 ‘ ‘ == 0
- 然后根据字符串与数字比较,先将字符串转为数字在比较,’’ 的布尔值为 0
- 即 0 == 0 ,为 true
- 其他的
- {} == !{} // !{}->false->0 {}->”[object Object]”->NaN
- {} == true
- [] == [] // false 比较引用地址
- {} == [] // 报错
- {} + {} // “[object Object][object Object]”
- {} + [] // 0 ,{}被当做一个块,并非{}转NaN,相当于执行 ({},+[]),返回值为小括号最后面的表达式的返回值
- {q:1} + [] // 0
- var a = {q:1};a + [] // “[object Object]”
toString 和 valueOf 方法有什么区别
都属于 Object 对象,是为了解决 JavaScript 值运算与显示的问题。
- js 对象的键必须是字符串
- toString(): 返回当前对象的字符串形式
- valueOf() : 返回该对象的原始值
类型 |
valueOf |
toString |
Array[1,2,3] |
数组本身[1,2,3] |
“1,2,3” |
Object |
对象本身 |
[object Object] |
Boolean 类型 |
Boolean 值 |
“true” 或”false” |
Function |
函数本身 |
function fnName(){code} |
Number |
数值 |
数值的字符串形式 |
Date |
毫米格式时间戳 |
GMT 格式时间字符串 |
- 隐式转换会自动调用 toString 和 valueOf
- 强制转化为字符串类型时,优先调用 toString
- 强制转化为数值类型时,优先调用 valueOf
- 使用运算符操作符情况下,valueOf 优先级高于 toString
- 对象类型转换为原始值回调用内置的[ToPrimitive]函数
- ToPrimitive 方法接受两个参数,一个是输入的值 value,一个是期望转换的类型 Type
- 如果未传入 PreferredType 参数,让 hint 等于’default’,后面会将 hint 修改为”number”
- 如果 value 是 基本类型,直接返回对应的类型的值
- 否则,调用 valueOf 方法,如果得到原始值,则返回
- 否则,调用 toString 方法,如果得到原始值,则返回
- 否则,报错
- OrdinaryToPrimitive(input,hint)
- 如果 hint 是 ‘string’,那么就将 methodNames 设置为 toString、valueOf
- 如果 hint 是 ‘number’,那么就将 methodNames 设置为 valueOf、toString
1 2 3 4 5
| - 设变量a={x:100},obj={},然后设obj[a] = 100 ,则此时obj[a]为多少? - 解:由于js对象的键必须为字符串,所以先将变量a转换为字符串,即a = "{x:100}" 然后因为强制转化为字符串类型时,优先调用toString,通过上方表格可知,obj[a]为[object Object] - {} + 1 :js引擎回解析成1个代码块和1个1,最终结果为1 - 1 + {} :先将{}调用ToPrimitive转为'[object Object]',然后跟1拼串,最终结果1[object Object]
|
运算符
逻辑运算符
- !!: 将变量
转
化为布尔
值
- !:取反,对非 boolean 类型的元素,则会将其
转boolean
类型再取反
- &&:只有两个值都为 true 时,才会返回 true,如果第一个值为 false,则不会看第二个值
- 对于非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且返回原值
- 如果
第一个值为true
,则必然返回第二个值
- 如果
第一个值为false
,则直接返回第一个值
- 如果两个值
都为true
,则返回后边的
- ||:两个值中只要有一个 true,就返回 true,如果第一个值为 true,则不会检查第二个值
- 对于非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且返回原值
- 如果
第一个值为true
,则直接返回第一个值
- 如果
第一个值为false
,则返回第二个值
- 如果
两个值中有false
,则返回靠前的false
赋值运算符
=
:赋值
+=
:a += 5 相当于 a = a+5
-=
:a -= 5 相当于 a = a-5
*=
:a = 5 相当于 a = a5
/=
:a /= 5 相当于 a = a/5
%=
:a %= 5 相当于 a = a%5
n++,n--
:先自增,自减,并且赋值时,把自增、自减前的值的赋值,即得到的结果是变量的原值
++n,--n
:先自增,自减,并且把变化后的值赋值给变量,即得到的结果是变量的新值
- 示例:
1 2 3 4
| const n1 = 10 const n2 = 10 var n = n1++ var m = ++n2
|
相等运算符
==
:等于,值相等返回 true,如果值的类型不同,则会自动进行类型转换,将其转换为相同的类型,然后在比较
!=
:不等于,两个值是否不相等,不相等返回 true,也会对变量进行自动的类型转换,然后在比较
===
:绝对等于,类型也相等,不会做自动的类型转换
!==
:不全等,不会做自动的类型转换,如果两个值的类型不同,直接返回 true
算数运算符
+、-、*、/
:加减乘除,任何值做-、/、*运算时都会自动转换为 Number
%
:算数运算符,取模运算(取余数)
关系运算符
>、>=、<、<=
- 对于
非数值
进行比较时,会将其转
换为数字
然后在比较
- 如果符号两侧的值
都
是字符串
时,会分别一位一位比较
字符串中字符的Unicode编码
- 注:在比较两个字符串型的数字时,一定要转型
三元运算符(条件运算符)
- 语法:
条件表达式?语句1:语句2
;
- 执行的流程:
- 条件运算符在执行时,首先对条件表达式进行求值,
- 为 true,则执行语句 1,并返回执行结果,为 false,则执行语句 2,并返回执行结果
- 如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后在运算
一元运算符
+、-
:正负号,只需要一个操作数
- 对于非 Number 类型的值,会先转换为 Number,然后在运算
+
变量转
化为Number
类型
任何值和字符串相加都会转换为字符串
,叫做拼串操作
流程控制语句
条件判断语句
- 语法一:if(条件表达式){为 true 语句…}
- 语法二:if(条件表达式){为 true 语句…}else{为 false 语句…}
- 语法三:if(条件表达式){语句…}else if(条件表达式){语句…}else{语句…}
条件分支语句 switch
1 2 3 4 5 6 7
| switch(条件表达式){ case 表达式: 语句... break; default: break; }
|
- 执行流程
- 依次将 case 后的表达式的值和 switch 后的条件表达式的值进行全等比较,如果为 true,则从当前 case 处开始执行代码。
- 为 false,则继续向下比较,知道所有结果都为 false,只执行 default 后的语句
循环语句
- for循环
- 语法:for(① 初始化表达式;② 条件表达式;④ 更新表达式){ 语句… }
- 执行流程:
- 执行初始化表达式,初始化变量(初始化表达式只会执行一次)
- 执行条件表达式,判断是否执行循环。为 true,则执行循环,为 false,终止循环
- 执行更新表达式,更新表达式执行完毕继续重复上一步
- 注:for 循环中的三个部分都可以省略,也可以写在外部,for(;;){}死循环
- 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 打印2-1000质数 for(var i=2 ; i<=1000; i++){ var flag = true; for(var j=2 ; j<=Math.sqrt(i) ; j++){ if(i%j == 0){ flag = false; break; } } if(flag){ document.write(i+' ') } } 打印九九乘法表
for(var i=1 ; i<=9 ; i++ ){ for(var j=1 ; j<=i ; j++){ document.write("<span>"+j+"*"+i+"="+i*j+"</span>"); } document.write("<br />"); }
|
- while循环
- 语法:while(条件表达式){ 语句… }
- 执行流程
- 先对条件表达式进行求值判断,
- 如果值为 true,则执行循环体,
- 循环体执行完毕以后,继续对表达式进行判断,以此类推
- 如果值为 false,则终止循环
- do…while循环
- 语法:do{ 语句… }while(条件表达式)
- 执行流程:
- 先执行循环体,
- 循环体执行完毕以后,在对 while 后的条件表达式进行判断,
- 如果结果为 true,则继续执行循环体,执行完毕继续判断以此类推 -如果结果为 false,则终止循环
- do…while循环和while循环区别:
- while 是先判断后执行,
- 而 do…while 会先执行后判断,
- do…while 可以保证循环体至少执行一次,而 while 不能
var n = 1;
- 将条件表达式写死为 true 的循环,叫做死循环,可以使用 break,来终止循环
函数 function
函数也是一个对象,函数中可以封装一些功能,在需要时可以执行这些功能
创建一个函数对象
- 方法一:使用构造函数(少用)
- 语法:const fun = new Function(语句…);
- 方法二:使用函数声明
- 语法:function 函数名([形参 1,形参 2…形参 N]){ 语句… }
- 方法三: 使用函数表达式
- 语法: const 函数名 = function([形参 1,形参 2…形参 N]){ 语句… }
调用方法:
- 函数对象([实参 1,实参 2])
- new 函数对象()
- 对象.函数对象()
- 函数对象.call/apply(obj)
形参与实参:
- 实参:
- 在调用函数时,可以在()中指定,实参将会赋值给函数中对应的形参
- 调用函数时解析器不会检查实参的类型和数量,可以传递任意数据类型的值
- 多余实参不会被赋值,如果实参的数量少于形参的数量,则没有对应实参的形参将是 undefined
- 形参:
- 定义函数时,可以在()中定义一个或多个形参,形参之间使用,隔开
- 定义形参就相当于在函数内声明了对应的变量但是并不赋值,形参会在调用时才赋值。
构造函数:
- 创建一个构造函数:与普通函数一样,但首字母要大写
- 调用方式:使用 new 关键字来调用
- 构造函数是专门用来创建对象的函数
- 一个构造函数我们也可以称为一个类
- 通过一个构造函数创建的对象,我们称该对象时这个构造函数的实例
- 通过同一个构造函数创建的对象,我们称为一类对象
- 构造函数就是一个普通的函数,只是他的调用方式不同,
- 如果直接调用,它就是一个普通函数
- 如果使用 new 来调用,则它就是一个构造函数
- 执行流程:
- 立刻创建一个新的对象
- 将新建的对象设置为函数中 this,在构造函数中可以使用 this 来引用新建的对象
- 逐行执行函数中的代码
- 将新建的对象作为返回值返回
作用域
- 定义:变量与函数的可访问范围,由当前环境与上层环境的一系列变量对象组成。
全局作用域:
- 直接编写在 script 标签中的 JS 代码,都在全局作用域
- 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象 window,
- 创建的变量都会作为 window 对象的属性保存
- 创建的函数都会作为 window 对象的方法保存
- 全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到
- 在函数作用域中也可以访问到全局作用域的变量。
- 尽量不要在全局中创建变量
函数作用域:函数执行时创建的作用域
- 函数作用域在函数执行时创建,在函数执行结束时销毁。
- 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
- 在函数作用域中可以访问到全局作用域的变量,反过来不行
- 在函数中要访问全局变量可以使用 window 对象
- 作用:隔离变量,不同作用域同名变量不会有冲突。
作用域链
- 定义:调用某个函数或属性时,先在当前作用域寻找,如果找不到的情况下去父级寻找,如果父级找不到继续向上级寻找,直到找到全局作用域为止,如果全局作用域中依然没有找到,则会报错 ReferenceError,这就是链式查找的过程
声明提前
变量的声明提前
- 使用 var 关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值)
- 但是如果声明变量时不使用 var 关键字,则变量不会被声明提前
- 在函数作用域中,也具有以上特性
- 在函数作用域中,不使用关键字声明的变量都会成为全局变量
函数的声明提前
- 在全局作用域中, 使用函数声明形式创建的函数 function 函数(){},会在所有的代码执行之前就被创建,所以可以在函数声明前来调用函数
- 在全局作用域中,使用函数表达式创建的函数 var fun = function(){},不会被声明提前,所以不能在声明前调用
- 在函数作用域中,使用函数声明创建的函数,会在所有的函数中的代码执行之前就被创建好了。
函数的方法
- call() 和 apply()
- 这两个方法都是函数对象的方法,需要通过函数对象来调用
- 通过两个方法可以直接调用函数,并且可以通过第一个实参(对象)来指定函数执行中 this
- call()方法可以将实参在对象之后
依次传递
- apply()方法需要将实参
封装
到一个数组
中统一传递
- arguments(封装实参的对象)
- arguments 和 this 类似,都是函数中的隐含的参数
- arguments 是一个类数组元素,它可以通过索引来操作数据,获取长度
- 在调用函数时,我们所传递的实参都会在 arguments 中保存
- arguments.length 可以用来获取实参的长度
- arguments 中有一个属性 callee 表示当前执行的函数对象
- function fun(a,b) { console.log(arguments.callee == fun) } // true
- 即使不定义形参,也可以通过 arguments 来使用实参
- arguments[0] 表示第一个实参
- arguments[1] 表示第二个实参
this(函数的上下文对象)
- 解析器在每次调用函数都会向函数内部传递进一个隐含的参数,这个隐含的参数就是 this
- this 指向的是一个对象,这个对象我们称为函数执行的上下文对象
- 使用 this 来引用上下文对象,根据函数的调用形式不同,this 的值也不同
- 当
以函数的形式调用
时,this是window
— xxx(),指向 window
- 当
以方法的形式调用
时,谁调用方法this就是谁
— obj.xxx(), 指向 obj
- 当
以构造函数的形式调用
时,this就是新创建的那个对象
- 通过 call/apply 指定谁调用: xxx.call(obj),指向 obj
- 在全局作用域中 this 代表 window
- 示例
1 2 3 4 5 6 7 8 9 10
| function Person(name, age, gender) { this.name = name this.age = age this.gender = gender this.sayName = function () { alert(this.name) } } var per = new Person('孙悟空', 18, '男')
|
(IIFE)立即执行函数:
- 全称: Immediately-Invoked Function Expression 立即调用函数表达式
- 别名: 匿名函数自调用
- 定义:函数定义完,立即被调用,往往只会执行一次
- 语法:(function(){ alert(“我是一个匿名函数~~~”); })();
- 作用
回调函数
- 定义:定义了该函数,没有直接执行,需要按下或者在一定时候才会执行的函数
- 常见的回调函数
- DOM 事件函数
- 定时器函数
- ajax 回调函数
- 生命周期回调函数
1 2 3 4 5 6 7 8 9
| var btn = document.getElementById('btn') btn.onclick = function () { alert(this.innerHTML) }
setInterval(function () { }, 20000)
|
对象
对象的分类:
- 内建对象 — 由 ES 标准中定义的对象,在任何的 ES 的实现中都可以使用
- 比如:Math String Number Boolean Function Object….
- 宿主对象 — 由 JS 的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
- 自定义对象 — 由开发人员自己创建的对象
in 运算符
- 定义:检查一个对象中是否含有指定的属性,有则返回 true,没有则返回 false
- 语法:”属性名” in 对象
使用 new 关键字创建一个对象
- 语法:使用 new 关键字调用的函数,是构造函数 constructor,var obj = new Object();
- 向对象中
添加
属性:对象.属性名 = 属性值
(可以是任意类型,也可以是个函数)
- 特殊属性名的添加方式:对象[“属性名”] = 属性值
读取
对象中的属性:对象.属性名
,如果读取对象中没有的属性,返回 undefined
修改
对象的属性值:对象.属性名 = 新值
删除
对象的属性:delete 对象.属性名
- 调用方法:对象.函数对象(); // 如果一个函数作为一个对象的属性值保存,那么我们称这个函数是这个对象的方法
使用对象字面量来创建一个对象
- 语法:const 对象 = {属性名:属性值,属性名:属性值….}; // 可以在创建对象时,直接指定对象中的属性,也可以为空
- 属性名可以加引号也可以不加,如果要使用一些特殊的名字,则必须加引号
- 属性名和属性值是一组一组的名值对结构,名和值之间使用:连接,多个名值对之间使用,隔开
- 示例
1 2 3 4 5 6
| const obj = { name: '孙悟空', age: 18, gender: '男', address: '花果山', }
|
使用工厂方法传建对象
- 优点:可以批量创建
- 缺点:创建的对象都是 Object 这个类型,无法区分出多种不同类型的对象
- 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function createPerson(name, age, gender) { var obj = new Object() obj.name = name obj.age = age obj.gender = gender obj.sayName = function () { alert(this.name) } return obj } var obj2 = createPerson('猪八戒', 28, '男') var obj3 = createPerson('蜘蛛精', 18, '女')
|
枚举对象中的属性使用 for … in 语句
- 语法:for(var 变量 in 对象){}
- for…in 语句 对象中有几个属性,循环体就会执行几次
- 每次执行时,会将对象中的一个属性的名字赋值给变量
- 示例
1 2 3 4
| for (var n in obj) { console.log('属性名:' + n) console.log('属性值:' + obj[n]) }
|
break | continue | return
break 关键字 — 会立即终止离他最近的那个循环语句
- 可以用来退出 switch 或循环语句,
- 不能在 if 语句中使用 break 和 continue
label — 标识当前的循环
- 语法:label:循环语句
- 使用 break 语句时,可以在 break 后跟着一个 label,这样 break 将会结束指定的循环
- 示例
1 2 3 4 5 6 7 8
| outer: for (var i = 0; i < 5; i++) { console.log('@外层循环' + i) for (var j = 0; j < 5; j++) { break outer console.log('内层循环:' + j) } }
|
continue 关键字 — 用来跳过当次循环
- 同样 continue 也是默认只会对离他最近的循环循环起作用
return — 可以结束整个函数
- 语法:return 值(任意类型的值,不写相当于 undefined)
- 可以使用 return 来设置函数的返回值,值将会作为函数的执行结果返回
- 在 return 后的语句都不会执行