输出语句
- alert("aa");
- document.write("aaa");
- console.log("aaa");
js编写位置
- 可以将js代码编写到标签的onclick属性中 <button onclick="alert("a");">点我一下
- 可以经js代码编写到href属性中,这样当点击超链接时,会执行js代码;<a href="javascript:alert("aaa");">你也点我一下 < /a>
- 可以将js代码编写到js标签中
- 可以将js代码编写到外部文件中,然后通过script标签引入。
基本语法
- js注释
字面量和变量
标识符
数据类型
- js中一共有六种数据类型
- String 字符串
- Number 数值
- Boolean 布尔值
- Null 空值
- Undefined 未定义
- Object 对象
- 其中String,Number Boolean Null Undefined属于基本数据类型 而Object属于引用数据类型
字符串
- 在Js中字符串需要使用引号引起来
- 单引号和和双引号都可以,但不能混用
- 在字符串中,我们可以使用\作为转义字符
Number
- 在js中所有的数值都是Number类型(包括整数和浮点数)
- 可以使用typeof来检查一个变量的类型 typeof a
- Number.MAX_VALUE 最大值
- infinity 正无穷大的
- NAN not a number
- Number.MIN_VALUE = 5e-324 大于0的最小正值
- 如果使用Js进行浮点运算,可能得到一个不精确的结果。所以千万不要使用JS进行对精确度比较高的运算
布尔值
- Boolean true false
Null
- null类型的值只有一个,就是null
- null这个值专门用来表示一个为空的对象
Undefined
- undefined只有一个 就是undefined
typeof
- String string
- Number number
- Boolean boolean
- Null Object
- Undefined undefined
强制类型转换
- 将一个数据类型转为其他的数据类型
- 类型 转换主要指,将其他的数据类型转换位String Number Boolean
将其他的数据类型转换为String
- 方式一:调用被转换数据类型的toString()方法,该方法不会改变原变量,但是null和undefined这两个值没有toString()方法。
- 方式二:调用String()函数
将其他的数据类型转换为number
- 调用Number()方法
- 1.字符串--->数字
1)纯数字
2)有字符串--NAN
3)" "和""--> 0 - 2 boolean--->数字
1) true-->1
2)false-->0 - 3 Null--->数字
null-->0 - 4 Undefined--->数字
undefined-->0 - parseInt()
- parseFloat()
如果对非String使用parseInt()或parseFloat()它会先将其转换位String然后再操作
将其他的数据类型转换为Boolean
- 使用Boolean()函数
- 1 数字--->boolean
除了0和NAN,其余都是ture - 2 String--->boolean
除了空串其余都是true - null--->boolean null-->false
- undefined--->boolean undefined-->false
- 对象也会转换为true
算术运算符
+
- 可以将两个值相加并将结果返回
- 当对非Numner类型的值进行运算时,会将这些值转换为Number然后再运算
- 任何值和NaN相加都是NaN
- 字符串相加会做拼串
- 任何值和字符串相加都会转换为字符串,并做拼串操作
- * / %
一元运算符
- 一元运算符,只需要一个操作符
- 对于非Number类型的值,他会先将转换为Number,然后再运算,可以对一个其他的数据类型使用+,来将其转换为number,他的原理和Number()函数一样
自增和自减
逻辑运算符
- js中为我们提供了三种逻辑运算符
- ! & | && ||
- 如果对非boolean值进行运算,则会将其转换为布尔值,然后再运算,并返回原值
赋值运算符
- = 可以将符号右侧的值赋值给左侧的变量
关系运算符
- 通过关系运算符可以比较两个值之间的大小关系,如果关系成立返回ture,如果关系不成立放回false
-
< >= <=
- 对于非数值进行比较时候,会先转换成数字,然后再进行比较
- 任何值和NaN进行比较都是false
- 如果符号两边都是字符串,不会将其转换为数值,会逐位比较
相等运算符
- ==
- ===
- undefined 延伸于null,所以null===undefined为true
- null==0为false
- NaN和任何值都不相等,包括他本身
- isNaN()
条件运算符
- 三元运算符
条件表达式?语句1:语句2;
运算符优先级
- 使用,可以分割多个语句,一般可以声明多个变量的时候使用
- 先乘除后加减
- && 优先级 高于||
代码块
- {}
- js中的代码块只有分组的作用,没有其他功能
if语句
- if(条件表达式){语句1}else{语句2}
- if(条件表达式){语句1}else if(){语句2}else{语句3}
switch
- switch(条件表达式){
case 表达式:
语句...
break;
case 表达式:
语句...
break;
default:
语句...
break;
}
while
- while(条件表达式){
语句....
} - 1创初始化一个变量
- 2在循环中设置一个条件表达式
- 3定义一个更新表达式,每次更新初始化变量 #### do...while
for
- for(初始化表达式,条件表达式,更新表达式){
}
break和continue
- break关键字可以用来退出switch或循环语句
- 不能在if语句中使用break和continue
- break关键字,会立即终止离他最近的那个循环语句
js 数据类型
- String 字符串
- Number 数量
- Boolean 布尔值
- Null 空值
- Undefined 末定义
- 以上这五种类型属于基本数据类型,以后我们看到的值,只要不是上边的5种,全都是对象,基本数据类型都是单一的值“hello” 123 true,值和值之间没有任何的联系。在JS中表示一个人,如果使用基本类型数据,我们所创建的变量都是独立的,不能成为一个整体
- Object 对象
对象的简介
- 对象属于复合的数据类型,在对象中可以保存多个不同的数据类型的属相
- 对象的分类
- 内建对象
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
- 比如,Match String Numner Boolean Function Object
- 宿主对象
- 由JS的运行环境的对象,目前来讲主要指由浏览器提供的对象
- 比如BOM DOM
- 自定义对象
- 由开发人员自己创建的对象
- 内建对象
- 创建对象 使用new关键字调用的函数是构建函数constructor 构建函数是专门来创建对象的函数,使用typeof检查一个对象时,会返回object
在对象中保存的值称为属性
向对象添加属性
语法:对象.属性名 = 属性值
var obj = new Object();
obj.name = "孙悟空";
读取对象中的属性
语法:对象.属性名
如果读取对象中没有的属性,不会报错而是返回undefined
修改对象的属性值
读法:对象.属性名 = 新值
删除对象的属性
语法:delete 对象.属性名
如果使用特殊的属性名 不能采用.的方式来操作
obj["123"] = 789
语法:对象["属性名"] = 属性值
读取也需要采用这种方式。
语法:对象["属性名"]
使用p[]这种形式去操作属性,更加的灵活,在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性
obj["nihao"] = "你好"
var n = "nihao";
obj[n]
属性值
JS对象的属性值,可以是任意的数据类型
甚至也可以是一个对象
in运算符
通过该运算符可以检查一个对象中是否含有指定的属性,如果有则返回true,没有返回false
语法:"属性名" in 对象
对象字面量
使用对象字面量,可以在创建对象时,直接指定对象中的属性
语法:{属性名:属性值,属性名:属性值...}
对象字面量的属性名可以加引号也可以不加,建议不加
如果要使用上些的特殊的名字,则必须加引号
属性名和值是一组组的名值对结构
名和值之间使用 ':' 链接,多个名值对之间使用 ',' 隔开
如果一个属性之后没有其他的属性了,就不要写 ','
函数
- 函数也是一个对象
- 函数中可以封装一些功能(代码),在需要的时候可以执行这些功能(代码)
- 函数可以保存一些代码在需要的时候调用。
创建一个函数对象
可以将要封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('hello world')");
封装到函数的代码不会立即执行
函数中的代码会在函数调用的时候执行
调用函数
语法:函数对象() fun();
当调用函数时,函数中封装的代码会按照顺序执行
使用函数声明创建一个对象
语法:
function 函数名([形参1,形参2...形参n]){
语句...
}
function fun2(){
console.log("hello world");
}
使用函数表达式创建一个对象
语法:
var 函数名 = function([形参1,形参2...形参n]){
语句...
}
函数的参数
- 可以在函数()中指定一个或多个形参(形式参数)
- 多个形参之间使用','隔开,声明形参就相当于在函数内部声明了对应的变量,但是不赋值
- 在调用函数时,可以在()中指定实参(实际参数)
- 实参将会赋值给函数中对应的形参
- 函数不会检查参数的类型和数量
函数的返回值
- 可以使用return 来设置函数的返回值
- 语法:return 值
- return后的值将会作为函数的执行结果返回
- 如果只写return 或 不写return 返回undefine
实参可以是任何值
for
- for(var 变量 in 对象){语句...}
立即执行函数
函数定义完,立即被调用,这种函数叫做立即执行函数
立即执行函数往往只会执行一次
(function(){
alsert("我是一个匿名函数~~~")
})();
(function(a,b){
alsert("我是一个匿名函数~~~")
})(123,456);
作用域
- 作用域指一个变量的作用的范围
- 全局作用域
- 直接编写在script标签中的JS代码,都在全局作用域
- 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
- 在全局作用域中,创建的变量都会作为window对象的属性保存
- 函数作用域
- 调用函数时创建函数作用域,函数执行完毕后,函数作用域销毁
- 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的。
- 在函数作用域中可以访问全局变量。在全局作用域中不能访问函数作用的变量。
- 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找,直接找到全局作用域,如果使用作用域中依然没有找到 ,则会报错
- 在函数中使用全局作用域,直接使用window
变量的声明提前
- 使用var关键字声明的变量,会在所有的代码执行之前被声明。
- 但是如果声明变量是不使用var关键字,则变量不会被声明提前
函数的声明提前
- 使用函数声明形式创建的函数
function 函数名(){}
它会在所有的代码执行之前就会创建,所以我们可以在函数声明前来调用函数。 - 使用函数表达是创建的函数,不会被声明提前。
this
- 解析器在调用函数每次都会向内部传递一个隐含的参数,这个隐含参数就是this,this指向的是一个对象,这个对象我们称之为函数执行的上下文对象,根据函数的调用方式不同,this会指向不同的对象。
- 以函数的方式调用时,this永远都是window
- 以方法的形式调用时,this就是调用方法的对象。
工厂方法创建函数
- 使用工厂方法创建的对象,使用的构造函数都是Object
- 所以创建的对象都是Object这个类型的
- 就导致我们无法区分多种不同类型的对象
构造函数
- 创建一个构造函数,专门用来创建Person对象的
- 构造函数就是一个普通的函数,创建方式和普通函数没有区别
- 构造函数和普通函数的区别就是调用方式的不同
- 普通函数是直接调用,而构造函数需要使用new关键字来调用
- 构造函数的执行流程
- 1.立刻创建一个新的对象
- 2.将新建的对象设置为函数中的this
- 3.逐行执行函数中的代码
- 4.将新建的对象作为返回值
- 使用同一个构造函数创建的对象,我们称之为一类对象,也将一个构造函数成为一个类,我们将通过一个构造函数创建的对象称之为该类的实列。
- 使用instanceof可以检查一个对象是否是一个类的实例。语法: 对象 instanceof 构造函数 如果是返回true,否则返回false
this的情况
- 当以函数的形式调用时,this是window
- 当以方法的形式调用时,谁调用方法 this就是谁
- 当以构造函数的形式调用时,this就是新创建的那个对象
创建一个Person构造函数
在Person构造函数中,为每一个对象都添加一个sayName方法,目前我们的方法在构造函数内部创建的,也就是构造函数每执行一次就会创建一个新的sayName方法,也就是所有实例都有sayName方法是唯一的,这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个一模一样的方法
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
//向对象中添加一个方法
this.sayName = function(){
alert("Hello大家好,我是: "+this.name );
};
//创建一个Person的实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",19,"女");
}
原型
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象
- 如果函数作为普通函数调用protorype没有任何作用,当函数通过构造函数形式调用时,它所创建的对象都会有一个隐含的属性,指向该函数的原型对象,我们可以通过__proto__来访问该属性
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型中寻找,如果找到则直接使用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使用每个对象都具有这些属性和方法了
- 原型对象也是对象,所以它也有原型
- 当我们使用一个对象的属性或方法时,会先在自身中寻找
- 自身中如果有,则直接使用
- 如果没有则去原型对象中寻找,如果原型对象中有,则使用
- 如果不有则去原型的原型中寻找,直到找到Object对象的原型
- Objec对象的原型没有原型,如果在Object中依然没有找到,则返回undefined
toString()
- 当我们直接在页面中打印一个对象时,实际上是输出的对象的toString()方法的返回值
- 如果我们希望输出对象时不输出[Object Object],可以为对象添加一个toString()方法
数组(Array)
- 数组也是一个对象
- 它和我们普通对象功能类似,也是用来存储一些值的
- 不同的是普通对象是使用字符串作为属性名的,而数组使用数字来作为索引操作元素
//创建对象
var arr = new Array();
//使用typeof检查一个数组时,会返回object
//console.log(typeof arr) //object
向数组中添加元素
语法:数组[索引] = 值
arr[0] = 10;
arr[1] = 33;
读取数组中的元素
语法:数组[索引]
如果读取不存在的索引,他不会报错而是返回undefined
console.log(arr[0]);
获取数组的长度
语法:数组.length
console.log(arr.length);
对于连续的数组,使用length可以获取到数组的长度(元素个数)
对于非连续的数组,使用length会获取到数组的最大的索引加一
尽量不要创建非连续的数组
使用字面量来创建数组,可以在创建时就指定数组中的元素
语法:[]
var arr = [];
使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递
元素之间使用 ',' 隔开
var arr2 = new Array(1,2,3);
//创建一个数组中只有一个元素10
arr = [10];
//创建一个长度为10的数组
arr2 = new Array(10);
console.log(arr2.length);
数组其他方法查看文档
插入,删除,遍历
forEach() 方法需要一个函数作为参数
像这种函数,由我人创建但是不由我们调用的,我们称为回调函数
数组中有几个元素函数就会执行几次,
每次执行时,浏览器会将遍历到的元素以实参的形式传递进来
我们可以定义形参,来读取这些内容
浏览器会在回调函数中传递三个参数
第一个参数,就是当前正在遍历的元素
第二个参数,就是当前正在遍历的索引
第三个参数,就是正在遍历的数组
arr.forEach(function(value,index,obj){console.log()});
forEach() 这个方法只支持IE8以上的浏览器
call()和apply()
- 这两个方法都是函数对象的方法,需要通过函数对象来调用
- 当对函数调用call()和apply()都会调用函数执行
- 在调用call()和apply()可以将一个对象指定为第一个参数
- 此时这个对象将会成为函数执行时的this
- call()方法可以将实参在对象之后依次传递
- apply()方法需要将实参封装到一个数组中统一传递
- this的情况
- 1.以函数形式调用时,this永远都是windown
- 2.以方法形式调用时,this是调用方法的对象
- 3.以构造函数形式调用时,this是新创建的个对象
- 4.使用call和apply调用时,this是指定的那个对象
fun.call();
fun.apply();
fun();
arguments
- 在调用函数进,浏览器每次都会传递进两个隐含的参数
- 函数的上下文对象this
- 封装实参的对象arguments
- arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
- 我们即使不定义形参,也可以通过arguments来使用实参
- 只不过比较麻烦
- arguments[0] 表示第一个参数
- arguments[0] 表示第二个参数
- 它里边有一个属性叫做callee
- 这个属性对应一个函数对象,就是当前正在执行的函数的对象
Date
Math
包装类
- 基本数据类型
- String
- Number
- Boolean
- Null
- Undefined
- 引用数据类型
- Object
- 在JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象
- String()
- 可以将基本数据类型字符串转换为String对象
- Number()
- 可以将基本数据类型的数据转换为Number对象
- Boolean()
- 可以将基本数据类型的布尔值转换为Boolean对象
- 但是注意:我们在实际应用中不会使用基本数据类型的对象
- 如果使用基本数据类型的对象,在做一些比较时可能带来一些不 可预期的结果
- String()
- 方法和属性能添加给对象,不能添加给基本数据类型
- 当我们对一些基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法,调用完以后,在将其转换为基本数据类型
var s = 123;
s = s.toString();
s.hello = "你好";
console.log(hello); //undefined
字符串
正则
DOM
- DOM,全称Document Object Model文档对象模型
- js中通过DOM来对文档进行操作,只要理解了DOM就可以随心所欲的操作WEB页面
- 文档表示的就是整个HTML见面文档
- 对象表示将网页中的每一个部分都转换为一个对象
- 使用模型来表示对象之间的关系,这样方便我们获取对象
节点
- 节点Node,是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点
- 比如:html标签、属性、文本、注释、整个文档都是一个节点
- 虽然都是节点,但是实际上他们的具体类型是不同的
- 比如:标签我们称为元素节点、属性称为属性节点、文本称为文本节点、文档称为文档节点
- 节点的类型不同,属性和方法也都不尽相同
- 节点:Node-构成HTML文档最基本的单元
- 常用节点分为四类
- 文档节点:整个HTML文档
- 元素节点:HTML文档中的HTML标签
- 属性节点:元素的属性
- 文本节点:HTLM标签中的文本内容
| --- | nodeName | nodeType | nodeVlue |
|---|---|---|---|
| 文档节点 | #document | 9 | null |
| 元素节点 | 标签名 | 1 | null |
| 属性节点 | 属性名 | 2 | 属性值 |
| 文本节点 | #text | 3 | 文本内容 |
- 元素节点(Element)
- HTML中的各种标签都是元素节点,这也是我们最常用的 一个节点
- 浏览器会将页面中所有的标签都会转换为一个元素节点
- 我们只可以通过document的方法来获取元素节点
- 比如
- document.getElementById()
- 根据id属性值获取一个元素节点对象
- 属性节点(Attr)
- 属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。
- 可以通过元素节点来获取指定的属性节点
- 例如:
- 元素节点.getAttributeNode("属性名")
- 注意:我们一般不使用属性节点
- 浏览器已经为我们提供文档节点对象,这个对象就是window属性
- 可以在页面中直接使用,文档节点代表的是整个页面
事件
- 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间
- JavaSript与HTML之间的交互是通过事件实现的
- 对于Web应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键,等等。
文档的加载
- 浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就 运行一行,如果将script标签写到页面的上边,在代码执行时,页面还没有加载
- onload事件会在整个页面加载完成之后才触发
JS修改元素的样式(内联样式)
- 语法:元素.style.样式名 = 样式值
- 注意:如果CSS的样式名中含有-,这种名称在JS中是不合法的,比如background-color,需要将这种样式名修改为驼峰命名法,去掉-然后将-后面的字母大写
- 我们通过style属性设置的样式都是内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往立即显示
- 但是如果在样式中写!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时会导致JS修改样式失效
- 读取样式:语法:元素.style.width
- 通过style属性设置和读取的都是内联样式,无法读取样式表中的样式
读取元素当前的样式
- 读法:元素.currentStyle.样式名
- 它可以用来读取当前元素正在显示的样式,如果当前没有设置该样式,则获取它的默认值
- currentStyle只有IE浏览器支持,其他浏览器都不支持
- 在其他浏览器中可以使用:getComputedStyle()这个方法获取元素当前的样式,这个方法是window的方法,可以直接使用。
- 需要两个参数
- 第一个:要获取样式的元素
- 第二个:可以传递一个伪元素,一般都是null
事件对象
- onmousemove
- 该事件将会在鼠标在元素中移动时被触发
- 事件对象
- 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递响应函数(IE8作为window属性保存)
- 在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标 键盘哪个键被按下,鼠标滚轮滚动的方向...
事件的冒泡
- 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件触发时,其祖先元素的相同事件也会被触发
- 在开发中大部分情况冒泡是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡 event.cancelBubble = true;
事件的委派
- 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件
- 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
事件的绑定
- 使用对象.事件 = 函数形式的绑定响应函数
- 它只能同时为一个元素的一个事件绑定一个响应函数
- 不能绑定多个,如果绑定了多个,则后边的会覆盖掉前面的
- addEventListener()
- 通过这个方法也可以为元素绑定响应函数
- 参数:
- 1.事件的字符串,不要on
- 2.回调函数,当事件触发时,该函数会被调用
- 3.是否在捕获时触发,需要一个布尔值,一般都传fasle
- 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数
- 这样当事件被触发时,响应函数会按照函数的绑定顺序执行
- 这种方法不支持IE8(attachEvent() 1.事件的字符串,要on 2.回调函数)
- 这个方法也可以同时为一个事件绑定多个处理函数
- 不同的是它是后绑定先执行,执行顺序和addEventListener()相反
完成bind函数
- 定义一个函数,用来为指定元素绑定响应函数
- addEventListener()中的this,是绑定事件的对象
- attachEvent()中的this,是window
- 需要统一两个方法this
- 参数
- obj 要绑定事件的对象
- eventStr 事件的字符串(不要on)
- callback 回调奇函数
function bind(obj,enentStr,callback){
if(obj.addEventListener){
//大部分浏览器兼容的方式
obj.addEventListener(eventStr,callback,false);
}else{
//IE8及以下
this是由调用方式决定
callback.call(obj);
obj.attachEvent("on"+eventStr,function(){
//在匿名函数中调用回调函数
callback.call(obj);
});
}
}
事件的传播
- 关于事件的传播网景和微软公司有不同的理解
- 微软公司认为事件应该是由内向外传播,也就是当前事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就是事件应该在冒泡阶段执行
- 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的层的祖先元素的事件,然后在向内传播后代元素
- w3c综合了两个公司的方案,将事件传播分成了三个阶段
- 捕获阶段
- 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
- 目标阶段
- 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
- 冒泡阶段
- 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
- 捕获阶段
- 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
- 一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
- IE8及以下的浏览器中没有捕获阶段
鼠标滚轮事件
键盘事件
BOM
- 浏览器对象模型
- BOM可以使我们通过JS来操作浏览器
- 在BOM中为我们提供了一组对象,用来完成对浏览器的操作
- BOM对象
- window
- 代表的是整个浏览器的窗口,同时window也是网页中的全局对象
- Navigator
- 代表的当前浏览器的信息,通过该对象可以用来识别不同的浏览器
- 由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别不同的浏览器
- 一般我们只会使用userAgent来判断浏览器信息,userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,不同的浏览器会有不同的userAgent
- 在IE11中已经将微软和IE相关的标识都已经去除了,所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了
- 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息,比如:ActiveXObject
- Location
- 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息或者操作浏览器跳转页面
- 如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
- 如果直接将location属性悠为一个完整的路径,或相对路径,则我们页面会自动跳转到该路径,并且会生成相应的历史记录
- assign()
- 用来跳转到其他页面,作用和直接修改location一样
- reload()
- 用来重新加载当前页面,作用和刷新按钮一样
- 如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
- replace()
- 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
- 不会生成历史记录
- History
- 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
- 由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或 向后翻页,而且该操作只在当次访问时有效
- length
- 属性,可以获取到当成访问的链接数量
- back() forward() go()
- Screen
- 代表用户屏幕的信息,通过该对象可以获取到用户显示器相关的信息
- window
- 这些BOM对象在浏览器中都是作为window对象的属性保存
- 可以通过window对象来使用,也可以直接使用
定时器
setInterval()
定时调用
可以将一个函数,每隔一段时间执行一次
参数
1.回调函数,该函数会每隔一段时间被调用一次
2.每次调用间隔的时间,单位是毫秒
返回值
返回一个Number类型的数据
这个数字用来作为定时器的唯一标识
setInterval(function(){},1000);
clearInterval()
可以用来关闭一个定时器
方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器
IIFE
- 理解
- 全称:Immediately-Invoked Function Expressioin
- 作用
- 隐藏实现
- 不会污染外部(全局)命名空间
(function(){ //匿名函数自调用
console.log('...');
})();
函数的prototype属性
- 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
- 原型对象中有一个属性constructor,它指向函数对象
- 给原型对象添加属性(一般都是方法)
- 作用:函数的所有实例对象自动拥有原型中的属性(方法)
显示原型与隐式原型
- 每个函数function都有一个prototype,即显示原型
- 每个实例对象都有一个__proto__,可称为隐式原型
- 对象的隐式原型的值为对应构造函数的显式原型的值
- 内存结构
- 总结
- 函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象
- 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
- 程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)
原型链
- 访问一个对象的属性时,先在自身属性中查找,找到返回
- 如果没有,再沿着__prototype__这条链向上查找的,找到返回
- 如果最终没有找到,返回undefined
- 别名:隐式原型链
- 作用:查找对象的属性(方法)
- 构造函数/原型/实体对象的关系(图解)
- 构造函数/原型/实体对象的关系2(图解)
- 1.函数的的显示原型指向的对象默认是空Object实例对象(但Object不满足)
- 2.所有函数都是Function的实例(包含Function)
- 3.Object的原型对象是原型链尽头
- 1.读取对象的属性时:会自动到原型链中查找
- 2.设置对象的属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
- 3.方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
instanceof
- instanceof 是如何判断的?
- 表达示:A instanceof B
- 如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
- Function是通过new自己产生的实例
变量与函数提升
- 1.变量声明提升
- 通过var定义(声明)的变量,在定义语句之前就可以访问到
- 值:undefined
- 2.函数提升
- 通过function 声明的函数,在之前就可以直接调用
- 值:函数定义(对象)
- 问题:变量提升和函数提升是如果产生的
执行上下文
-
- 代码分类(位置)
- 全局代码
- 函数代码
-
- 全局执行上下文
- 在执行全局代码前将window确定为全局执行上下文
- 对全局数据进行预处理
- var定义的全局变量==> undefined,添加为window的属性
- function声明的全局函数==>赋值(fun),添加为window的方法
- this==>赋值(window)
-
- 函数执行上下文
- 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
- 对局部数据进行预处理
- 形参变量==>赋值(实参)==>添加为执行上下文的属性
- arguments==>赋值(实参列表),添加为执行上下文的属性
- var定义的局部变量-->undefined,添加为执行上下文的属性
- function声明的函数==>赋值(fun),添加执行上下文的方法
- this==>赋值(调用函数的对象)
- 开始执行函数体代码
执行上下文栈
- 1.在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
- 2.在全局执行上下文(window)确定后,将其添加到栈中(压栈)
- 3.在函数执行上下文创建后,将其添加到栈中(压栈)
- 4.在当前函数执行完后,将栈顶的对象移除(出栈)
- 5.当所有的代码执行完后,栈中只剩下window
作用域
闭包
-
- 如何产生闭包
- 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
-
- 闭包到底是什么?
- 使用chrome调试查看
- 理解一:闭包是嵌套的内部函数(绝大部分人)
- 理解二:包含被引用变量(函数)的对象(极少数人)
- 注意:闭包存在于嵌套的内部函数中
- 产生闭包的条件
- 函数嵌套
- 内部函数引用了外部函数的数据(变量/函数)
常见的闭包
- 1.将函数作为另一个函数的返回值
- 2.将函数作为实参传递给另一个函数调用
闭包的作用
- 1.使用函数内部的变量在函数执行完后,仍存活在内存中(延长了局部变量的生命周期)
- 2.让函数外部可以操作(读写)到函数内部的数据(变量/函数)
- 问题:
- 函数执行完后,函数内部声明的局部声明的局部变量是否还存在?
- 一般是不存在,存在于闭包中的变量才可能存在
- 在函数外部能直接访问函数内部的局部变量吗?
- 不能,但是我们可以通过闭包让外部操作它
- 函数执行完后,函数内部声明的局部声明的局部变量是否还存在?
闭包的生命周期
- 产生:在嵌套内部函数定义执行完时就产生了(不是调用)
- 死亡:在嵌套的内部函数成为垃圾对象时
优缺点
- 缺点
- 函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
- 容易造成内存泄露
- 解决
- 能不用闭包就不用
- 及时释放
- 内存溢出
- 一种程序运行出现的错误
- 当程序运行需要的内存超过了剩余的内存时,就出抛出内存溢出的错误
- 内存泄露
- 占用的内存没有及时释放
- 内存泄露积累多了就容易导致内存溢出
- 常见的内存泄露
- 意外的全局变量
- 没有及时清理的计时器或回调函数
- 闭包
对象创建模式
- 方式一:Object构造函数模式
- 套路:创建空Object对象
- 适用场景:起始时不确定对象内部数据
- 问题:语句太多
- 方式二:对象字面量模式
- 套路:使用{}创建对象,同时指定属性/方法
- 适用场景:起始时对象内部数据是确定的
- 问题:如果创建多个对象,重复代码
- 方式三:工厂模式
- 套路:通过工厂函数动态创建对象并返回
- 适用场景:需要创建多个对象
- 问题:对象没有一个具体的类型,都是Object类型
- 方式四:自定义构造函数模式
- 套路:自定义构造函数,通过new创建对象
- 适用场景:需要创建多个类型确定的对象
- 问题:每个对象都有相同的数据,浪费内存
- 方式五: 构造函数+原型的组合模式
- 套路:自定义构造函数,属性在函数中初始化,方法添加到原型上
- 适用场景:需要创建多个类型确定的对象