九、对象
对象是一种数据的集合,数据格式为键值对。
9.1 初始化
9.1.1 字面量
对象字面量以"{}"作为边界,由多个键值对组成,键与值通过":"隔开,键值对之间通过","隔开
var obj = {name:"terry",age:12,gender:"male"};
9.1.2 构造函数模式
使用系统内置的对象构造函数Object()
var obj = new Object(); //等价于var obj = {}
obj是对象实例,构造函数是创建对象实例时使用的模板
使用自定义的对象构造函数,例Student()
var stu = new Student();
9.2 属性访问
(用于读写)
9.2.1点访问
对象.属性
var obj = {name:"terry",age:12,gender:"male"};
var name = obj.name;
obj.name = 'terry';
9.2.2中括号访问
对象[变量]
var name = 'age';
obj[name];
9.3 属性遍历
打印出某个对象中所有的属性
for(var key in obj){
}
依次从obj中获取属性名赋值给key,通过obj[key]访问属性值 (属性名若为变量,则必须通过中括号方式访问变量值)
9.4 对象序列化
- 什么叫序列化
将对象转换成字符串
- 为什么要做序列化
方便网络传输(http/tcp/ip协议中不允许传输对象,只允许传输字符串和字节流),解决对象在io中传递的问题。
9.4.1 常规转换
var obj = {name:'user'}
obj.toString() //'[object Object]'
9.4.2 转换为json字符串
var obj = {name:'user'}
JSON.stringify(obj) //'{"name":"user"}'
9.4.3 转换为查询字符串
var qs = require('querystring')
qs.stringify(obj)
9.5 Object()
所有构造函数的父构造函数,所有的构造函数都直接间接的继承Object。所有的实例对象都可以调用其构造函数及其父构造函数的原型中的方法:
Object.prototype.constructor() //输出创建该对象时使用的构造函数
Object.prototype.toString() //默认情况下输出[object object]
Object.prototype.valueOf()
Object.prototype.hasOwnProperty() //判断某一个属性是不是属于当前对象
Object.prototype.isPrototypeOf() //指定的对象是否在本对象的原型链中
Object.prototype.propertyIsEnumerable() //指定的属性是否可枚举
Object.prototype.toSource()
obj的构造函数是Object,所以obj可以调用Object.prototype的方法
var obj = {}
obj.toString();
arr的构造函数是Array,Array继承Object,因此,arr可以调用Array.prototype及Object.prototype中的方法
var arr = new Array(3);
arr.toString();
9.6 删除属性
delete 对象.属性
对比java对象,js对象有哪些特殊的地方
1. js对象的属性可以被删除,java对象属性是固定的
2. js对象的属性可以随意添加,java对象属性是固定的
3. js对象可以通过字面量及构造函数来获取,java对象只能通过类构建
//student有且只能有两个属性
class Student{
private String name;
private Integer age;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
Student student = new Student();
9.7 自定义属性
var obj = {
name:"terry" //name是可以迭代的,是可读可写
}
假设:
- name是不可以迭代的
- name是不可写的
- name是不可以被删除
当对象属性的值发生变化的时候,我想知道?
var obj = { _name:"alxe", age:0 }; Object.defineProperty(obj,"name",{ configurable:true, writable:true, //enumerable:true; 使用set、get时不设置enumerable、value //value:"terry", set:function(v){ this._name = v; console.log("名字被修改"); }, get:function(){ return this._name; } }) obj.name = "terry"; console.log(obj.name);
当name、age、gender属性发生变化的时候,都想检测到.
Object.defineProperties(obj,{ name:{ }, gender:{ } })
十、数组
数组是由若干个元素组成,元素可以是任意的数据类型。通过索引(从0开始)访问元素,数组的长度通过length属性获取。
10.1 初始化
10.1.1 字面量
var arr = [8,1,20,3,2,9]
10.1.2 构造函数模式
var arr = new Array(); // var arr = [];
var arr = new Array(5); // var arr = [,,,,];
arr[0] = "terry"
arr[1] = "larry" //["terry","larry"]
//es6出现
Array.of(2); //[2]
Array.of(2,3) //[2,3]
10.2 访问
console.log(arr[0]);
console.log(arr[100]); // undefined
10.3 length属性
length可读可写,可以通过改变数组的长度来删除数组元素
arr.length
10.4 数组遍历
- for
- while
- do-while
- for-in
10.5 数组api
api --> 应用程序编程接口-使用别人编写的代码
关注函数改变的是否是原数组本身
10.5.1 Array.*
- Array.isArray()
判断一个变量是否是数组(不能使用typeof,返回的是‘object’) - Array.from();(es6)
将一个可迭代的对象转换为数组 - Array.of();(es6)r
将参数中的值作为数组的元素
10.5.2 Array.prototype.*
遍历相关的方法
这些方法有个共同点,都需要传递一个回调函数作为参数,回调函数都有三个形参,分别为item,index,arr(可省略index/arr)
Array.prototype.forEach()
遍历数组对象
参数:回调函数
返回值:undefined
//模仿forEach写一个myForeach,其效果与forEach完全相同 var arr = ["terry","larry","tom"]; arr.forEach(function(item){ console.log(item); }); //myForeach() Array.prototype.myForEach = function(handler){ //handler为一个回调函数 for(var i=0;i<this.length;i++){ var item = this[i]; handler.call(this,item,i) } } arr.myForeach((item,index)=>{ console.log(item,index) })
- Array.prototype.every()
元素是否都满足同一个条件
参数:回调函数需要返回boolean
返回值:boolean
- Array.prototype.some()
是否有元素满足同一个条件
参数:回调函数需要返回boolean
返回值:boolean
- Array.prototype.filter()
返回回调函数返回true的元素的集合
参数:回调函数需要返回boolean
返回值:数组
- Array.prototype.map()
返回回调函数返回值组成的数组
参数:回调函数,一定要返回值
返回值:数组
栈、队列相关方法
- Array.prototype.push()
向数组的末尾追加指定值
参数:任意值
返回值:数组长度
- Array.prototype.pop()
删除并返回栈顶元素
参数:无
返回值:删除的栈顶元素
- Array.prototype.shift();
出队列
参数:无
返回值:删除的队列首部元素
- Array.prototype.unshift();
将指定元素插入到队列的首部
参数:任意值
返回值:插入后数组的长度
- Array.prototype.push()
排序相关
- Array.prototype.reverse();
原值发生改变;
Array.prototype.sort();
原值发生改变;
默认将数组元素转换为字符串,然后进行排序
sort允许接收一个比较器函数作为参数,比较器函数接受两个参数,
如果a > b,返回1,升序;如果a > b,返回-1,降序
arr.sort(function(a,b){ if(a>b){ return 1; }else{ return -1 } })
//提供一个函数,接受属性作为参数,要求按照name/age/grade进行排序 var arr = [{ name:"terry",age:19,grade:98 },{ name:"larry",age:12,grade:94 },{ name:"tom",age:15,grade:91 }] function sort(array,property){ array.sort((function(prop){ return function(a,b){ if(a[prop] > b[prop]){ return 1; } else { return -1; } } })(property)) } sort(arr,'age')
- Array.prototype.reverse();
闭包:函数内部嵌套函数,内部函数拥有外部函数的变量,内部函数与外部函数的这个变量就组成了闭包。
截取
slice(begin,end)(原值不改变)
[1,2,3,4].slice(1); //[2,3,4] [1,2,3,4].slice(1,3); //数组个数为3-1
splice(begin,num,x,x,...)(原值改变)(功能更强大)
begin:开始位置,num:删除的元素个数,x,x,x:插入的元素
返回删除的元素组成的数组
[1,2,3,4,5].splice(2,2) //[3,4] [1,2,3,4,5,6].splice(3,0,2,2,2) //运行后的数组结果:[1,2,3,2,2,2,4,5,6]
10.6 克隆数组
- 蛮力法
var arr0 = JSON.parse(JSON.stringify(arr))
var arr1 = arr.slice(0)
var arr2 = [...arr]
拓展运算符(es6)
- lodash(es6拓展库)
十一、函数
函数也是对象,是一个引用数据类型。
11.1 分类
不管是普通函数还是构造函数,本质是完全一样的,只不过为了区分它们,我们将构造函数的函数名大写
- 普通函数(方法)
- 构造函数(类)
11.2 函数定义
11.2.1函数声明
函数声明与var声明变量类似,都会有变量的提升。允许在函数声明前调用函数
let result = add(1,2); // 可以执行
function add( a, b){
return a + b;
}
11.2.2 函数表达式
类似于普通的赋值表达式,变量会提升,但是函数初始化不会被提升。
add(); // 报错!
var add = function(a,b){
return a + b;
}
11.3 函数调用
- 函数名(实参列表);
add(1,2) - 函数名.call(this,实参列表)
add.call(this,1,2) - 函数名.apply(this,实参数组)
add.apply(this,[1,2])
11.4 函数内部属性
只有在函数的执行过程中,内部属性才能被确定
兜底对象(全局)
浏览器:window
nodeJs:global
arguments
保存函数的所有实参,是一个类数组对象。
arguments.callee 指向当前函数,常用于递归函数。但是在严格模式'use strict'下无法使用var foo = function(a,b){ console.log(arguments) //{'0':1,'1':2,'2':3} } foo(1,2,3)
//求阶乘 function foo(num){ if(num==1){ return 1; }else{ return arguments.callee(num-1)*num //更换函数名字时,不用考虑函数内部的名字更换 } }
this
当前的执行环境对象
与函数的调用方式有关
如果使用"()"调用函数,查看"()"是否是函数名,如果是,查看函数名前有没有点".",没有点"."this指向全局对象。有"."this指向点前面的那个对象。function test(){ function bar(){ console.log(this) } bar(); } test(); //this-->global,因为调用bar()时,前面没有'.'
11.5 箭头函数(ES6)
var foo = function(a,b){
return a+b;
}
var foo = (a,b)=>{
return a+b;
//a+b;若大括号内只有一条语句,且该语句为返回值语句,那么{}也可省略
} //箭头函数
箭头函数一般用于回调函数,是回调函数的简写。
箭头函数中的this指向包含它的外部函数的this,所以箭头函数一般放在外部函数里面,若箭头函数外没有外部函数,则this为{}。
function foo(){
["terry","larry"].forEach((item)=>{
console.log(this,item);
})
}
foo(); //global
foo.call({}) //{}
foo.call({name:"terry"}) //{name:"terry"}
new Vue({
el:"#app",
data:{
students:[]
student{}
},
methods:{
// 加载学生信息
loadStudents(){
// this 指向vue对象
$.get('/findAllStudent',(students)=>{
// this指向外部函数this,也就是指向vue对象
this.students = students;
//自定义属性
})
}
}
})
11.6 函数本质
函数是一种特殊对象,默认情况下,一个函数都会有一个原型对象与之对应,函数中有个指针prototype指向原型对象,原型对象中有个constructor指向函数,你中有我,我中有你。
fun.prototype.constructor === fun //true
11.7 函数应用
- 函数可以作为参数【回调函数-匿名内部类】
函数可以作为返回值【函数定制】
var arr = [{age:12},{age:3}]; arr.sort((function(key){ return function(a,b){ if(a[key]>b[key]){ return 1; }else{ return -1; } } })('age'))
十二、正则表达式
12.1 初始化
12.1.1 字面量
var pattern = /abc/igm
//abc-->正则表达式
//igm-->模式
12.1.2 构造函数
var pattern = new RegExp("abc","igm");
12.2 修饰符
- i ignore case 忽略大小写
- g global 全局
- m multiline 多行
12.3 使用
- RegExp.prototype.test()
测试目标字符串是否匹配正则表达式
RegExp.prototype.exec();
从目标字符串中获取符合正则表达式的字符串
如果正则表达式中有修饰符‘g',在pattern中会维护lastIndex属性,即记录下一次开始的位置,当第二次执行exec()时,从lastIndex开始检索。若没有’g‘修饰符,则每一次都从开始位置进行检索。
var str = "my phone is 18812344321, my emil is licy@briup.com, my name is charles, my friend is jacky, his phone is 17751229900, my friend is tom, his phone is 15912344432." function search(str){ var pattern = /((188)|(177)|(159))\d{8}/g; var result; while(result = pattern.exec(str)){ console.log(result[0],pattern.lastIndex); } } //查询出所有符合模式的内容
12.4 正则表达式 (入门)
独立学科,用于匹配字符串。常用于检索,论文查重,爬虫,表单验证。
12.4.1 直接量
- /abc/
- /123/
- /s/ 空白符
- /S/ 非空白符
- /d/ /[0-9]/
- /D/ /[^0-9]/
- /w/ /[a-zA-Z0-9]/ 任意的ascii码字符
- /W/ /[^a-zA-Z0-9]/
12.4.2 字符类
- /[0-9]/ 匹配0~9中的任意一个字符
- /[^0-9]/ 匹配非0~9中的任意一个字符
12.4.3 数量词
- {n} 匹配n次
- {n,m} 匹配n~m次
- {n,} 匹配n+次
- ? 0或1次
- + 1或多次
- * 0或多次
12.4.4 贪婪匹配与非贪婪匹配
默认是贪婪匹配,对于数量来说,尽可能多得去匹配。如果希望非贪婪匹配,在数量词后添加?
var str = "hello world"
var pattern = /\w{1,5}?/ //优先匹配1个字符
12.4.5 选择
使用分隔符'|'分割供选择的字符,选择项匹配次序为从左至右。
url --> 协议://ip:port/path
var str = "my website url is http://127.0.0.1:80/cms/index.html , my database url is jdbc:mysql://127.0.0.1:3306/cms , this is ok"
var pattern = /(http|jdbc\:mysql|ftp)\:\/\/(((\d{1,3})\.){3}((\d{1,3})))(\:(\d{2,4}))?(\/[\w\.]*)*/ig
12.4.6 分组
每一个括号都是一个分组
/(http|jdbc:mysql|ftp)://(w{1,3}.){+}:?(d{2,4})?(/[w.])/ig
pattern.exec(str)
result[0] 整个模式匹配的结果
result[1] 第一个分组匹配的结果
result[2] 第二个分组匹配的结果
...
12.4.7 引用
1 引用第一个分组匹配的结果
var pattern = /(\d{1,3})\1/g;
pattern.exec(192.12) //null
pattern.exec(192.192.) //['192.192.','192.'...]
2 引用第二个分组匹配的结果
12.5 常见应用
检索出所有的手机号。
12.6 测试
(牛客网 - 正则表达式)
十三、其他内置函数
13.1 包装器类型
基本数据类型默认是无法调用Object原型中的方法,为了丰富基本数据类型的功能,即基本数据类型的变量也可以调用方法,js为此实现自动装箱功能【当调用基本数据类型变量的方法的时候,会自动转换为其构造函数的实例对象】
Number
var a = 3; a.toString(); //原本是无法调用该方法的,但由于js将其自动装箱,使其自动实现了‘a = new Number(a)’代码,即将其转换成为了引用类型的变量,因此其可以调用Number.prototype和Object.prototype中的方法 console.log(a); //当变量进行正常计算时,会将其自动拆箱
- Boolean
- String
13.2 String api
13.2.1 正则表达式相关方法
参数都可以为正则表达式,如果为字符串,会先转化为正则表达式
String.prototype.split()
将字符串根据指定参数进行切割,返回一个数组
"hello".split() //['hello'] "hello".split("") //['h','e','l','l','o'] "terry#larry".split(/\#/) //['terry','larry'],等价于"terry#larry".split('#')
- String.prototype.search()
不支持全局搜索
与RegExp.prototype.test类似,返回匹配模式的字符串的索引,如果没有匹配的结果则返回-1
String.prototype.match()
与RegExp.prototype.exec类似
- 如果非全局模式,返回结果与exec方法的执行结果类似,支持分组显示
- 如果是全局模式,返回结果为数组,数组元素为整体匹配的结果,即数组内包含所有匹配结果。
- String.prototype.replace(regexp,string)
返回值为替换后的结果
13.2.2 检索方法
- String.prototype.indexOf()
- String.prototype.lastIndexOf()
13.2.3 截取方法
- String.prototype.slice(begin,end)
返回截取后的结果,原值不改变
- String.prototype.substr(begin,len)
len表示截取的长度
返回截取后的结果,原值不改变
- String.prototype.substring(begin,end)
与slice相同
- String.prototype.trim()
消除字符串左右两边的空格,原值不改变
13.2.4 大小写转换
- String.prototype.toUpperCase();
- String.prototype.toLowerCase();
13.2.5 属性
- length
13.2.6 其他方法
...
13.3 Date
构造函数
Date.prototype.getTime();
返回一个时间戳 ,即当前时间到格林威治标准时间的毫秒数(可以使用时间戳转换成任意的数据格式)
var now = new Date(); //2020-08-10T05:48:49.439Z--当前时间 now.getTime(); //1597038529439--时间戳 var d = new Date(1597038529439) //2020-08-10T05:48:49.439Z
- Date.prototype.getFullYear();
年 - Date.prototype.getMonth();
月 - Date.prototype.getDate();
日 - Date.prototype.getDay();
周几 - Date.prototype.getHours();
时 - Date.prototype.getMinutes();
分 - Date.prototype.getSeconds()
秒
13.4 Math
是对象,不是函数
- Math.random()
- Math.ceil()
向上舍入
- Math.floor()
向下舍入
- Math.round()
四舍五入 - Math.max(4,2,6,9)
- Math.min()
十四、面向对象
14.1 构造函数封装
如何创建一个对象?
字面量/Object - 纯对象,只能Object.prototype中的方法,并且类型无法细分。
类型细分(特定对象可以调用特定方法):
工厂函数模式
function PersonFactory(name,age,gender){ var p =new Object(); p.name = name; p.age = age; p.gender = gender; return p; } var p = PersonFactory("terry",12,"gender");//p本质还是一个Object p.constructor // Object
问题:对象类型无法细分。
构造函数模式(构造函数使用new来调用)
function Person(name,age,gender){ this.name= name; this.age = age; this.gender = gender; this.sayName = function(){ console.log("my name is",this.name); } } //如果该函数使用new来调用,1) this指向当前实例对象2)函数执行完毕后,会将当前实例对象返回 var p1 = new Person("terry",12,"male"); // p1指向实例对象 var p2 = Person("terry",12,"male"); // p2为undefined,因为没有实例对象返回(this指向全局对象)
解决:对象类型细分的问题
问题:内存浪费。如果将函数存放到实例对象,每个实例对象拥有一个独自的函数,而这样是毫无意义。
//解决了内存问题,但不成熟 function sayName(){ console.log("my name is",this.name); } function Person(name,age,gender){ this.name= name; this.age = age; this.gender = gender; this.sayName = sayName;//引用地址传递 }
构造函数(实例属性)+原型(实例方法,共享属性)
基本属性维护在实例中,共同的方法维护构造函数的原型中。
function Person(name,age,gender){ this.name= name; this.age = age; this.gender = gender; } Person.prototype.sayName = function(){ console.log("my name is",this.name); } Person.prototype.sayAge = function(){ console.log("my age is",this.age); } var p = new Person("terry",12,"male");
问题:原型方法封装性较差
增强版
function Person(name,age,gender){ this.name= name; this.age = age; this.gender = gender; } Person.prototype = { constructor:Person, // 核心点 sayName :function(){ console.log("my name is",this.name); }, sayAge :function(){ console.log("my age is",this.age); } } var p = new Person("terry",12,"female")//实例对象p的__proto__值指向的是其构造函数中prototype值所指向的原型对象。 //{}会创建一个新对象,同时将Person构造函数的prototype值指向该新建立的对象,而新对象的__proto__指向的却是Object函数的原型对象的地址,如果调用‘p.constructor’返回的将是[Function:Object]。因此为了使其返回的是Person函数,我们需要在这个新创建的对象中指明constrcutor所对应的构造函数为Person。
14.2 对象检测
- typeof obj;
- obj.constructor ; // 查看obj的构造函数
- obj instanceof 构造函数 // obj是否是指定构造函数的实例(obj的原型链中是否包含指定构造函数的原型)
14.3 继承
继承即实例对象可以调用其构造函数原型中的方法以及其构造函数的父构造函数原型中的方法...
Dog继承Animal
dog -> Dog.prototype -> Animale.prototype
14.3.1 借用构造函数
function Aniaml(name,age){
this.name = name;
this.age = age;
}
Animal.prototype = {
constructor :Animal,
sayName:function(){
console.log('my name is ',this.name);
},
sayAge:function(){
console.log('my age is ',this.age);
}
}
function Dog(name,age,gender){
//借用构造函数
Animal.call(this,name,age);
/*
this.name = name;
this.age = age;
*/
this.gender = gender;
}
14.3.2 原型链继承
Dog实例若想调用父构造函数原型中的方法,则要使用原型链继承。
//子构造函数的原型指向父构造函数的实例
Dog.prototype = new Animal();//继承
Dog.prototype.constructor = Dog;
Dog.prototype.sayGender = function(){
}//其他操作必须在继承完成之后
var dog = new Dog('wang',12,'母')
十五、DOM【浏览器】
dom -- > 浏览器将html/css转换为js对象,然后我们通过js操作这些对象。
通常很少自己创建dom对象,因为浏览器已经转换了。但我们需要在html中添加结构时需要自己创建dom对象,再由浏览器转换成html/css。
var dom = document.getElementById('');//document是浏览器的内置对象,浏览器将html转换成对象,此document代表的则是整个html页面。dom是js对象,是HtmlDivElement的实例对象,所以它可以调用HtmlDivElement,HtmlElemnet,Element,Node,Object中的方法
继承关系:
Node
Element 元素节点(标签转换的元素对象)*
- HtmlElement
- HtmlDivElement
Document 文档节点(表示当前html文档)*
- HtmlDocument
- Text 文本节点
- Comment 注释节点
15.1 Node
节点信息相关属性
- Node.prototype.nodeType
文本-3;注释-8;元素-1;文档-9
Node.prototype.nodeName
- 文本 #text
- 注释 #comment
- 元素 标签名大写
- 文档 #document
- Node.prototype.nodeValue
- Node.prototype.nodeType
层次结构相关属性
Node.prototype.childNodes
返回一个类数组对象
var dom = document.getElementById("content"); var nodelist = dom.childNodes; //返回类数组对象 var arr1 = Array.prototype.slice.call(nodelist,0); //转换为数组方法一 var arr2 = Array.from(nodelist); //转换为数组方法二
- Node.prototype.firstChild
- Node.prototype.lastChild
- Node.prototype.nextSibling 下一个兄弟
- Node.prototype.parentNode
- Node.prototype.parentElement
- Node.prototype.ownerDocument 当前文档对象
方法
是通过父节点对象来调用
- Node.prototype.appendChild(child)
- Node.prototype.insertBefore(new,ref)
- Node.prototype.removeChild(child)
- Node.prototype.replaceChild(new,old)
- Node.prototype.cloneNode([boolean])
参数为true,表示除了克隆当前对象,还克隆子元素
15.2 Document
- 属性
Document.prototype.body
Document.prototype.forms
Document.prototype.images
Document.prototype.charset
Document.prototype.doctype 判断当前网页是html4还是html5
方法:
元素节点查询
- document.getElementById();
- document.getElementsByName();
- document.getElementsByClassName();
- document.getElementsByTagName();
- document.querySelector(selector);
返回第一个匹配的element
- document.querySelectorAll();
返回所有匹配的element,并将其放入一个类数组对象中。
节点创建
var new_h3 = document.createElement("h3"); new_h3.innerText = "end" //该属性是HtmlElement内的属性
15.3 Element(HtmlElement)
元素节点
- Element.prototype.children
- Element.prototype.firstElementChild
- Element.prototype.lastElementChild
- Element.prototype.nextElementSibling
- Element.prototype.parentElement
- innerText
设置标签内的文本节点
- innerHTML
设置标签内的html代码(可以将字符串解析为标签)
- style
获取(只能获取到内置样式)或设置样式
方法
- getAttribute(key)
- getAttributeNames()
- setAttribute(key,val)
15.4 事件机制
15.4.1 三要素
- 事件源:dom对象(一般特指元素节点)
- 事件处理函数:匿名函数
将在未来的某个时刻执行,由浏览器调用,并且浏览器会将事件对象传递给该函数的参数。
- 事件对象:记录了事件的详细信息
15.4.2 基本概念
事件类型
- click
- dbclick
- mouseover
- mouseenter
- mouseleave
- mouseout
- keyup 键盘
- keydown
- keypress
- blur 失去焦点
- focus
- scroll
- 事件默认行为
<a>标签有自动跳转的默认事件行为
事件冒泡
元素具有嵌套关系
<div class="outer"> <div class="center"> <div class="inner"></div> </div> </div>
- 每层元素都添加事件处理函数(非必须)
- 操作
(当我们点击inner的时候,实际上也点击center、outer。)
事件捕获: outer -> center -> inner
但事件处理函数的调用默认是按照事件冒泡的顺序来调用
事件冒泡: inner -> center -> outer
- target(目标元素)
操作的元素
15.4.3 事件绑定
事件源.on事件类型 = 事件处理函数(事件对象){
}
dom.onClick = function(event){
}
绑定方式:
- onXxx
- addEventListener()
- attachEvent()
15.4.4 事件对象
- event.target
事件的目标元素(操作的元素)
- event.clientX
- event.clientY
事件触发时候的坐标
- event.preventDefault()
阻止事件的默认行为
- event.stopPropagation() // event.cancelBubble = true(低版本IE)
取消事件冒泡
15.5 事件代理
将事件绑定在父元素上而不是子元素上
<body>
<button id="add">添加</button>
<table id="tbl">
<thead>
<tr>
<th>姓名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>zyj</td>
<td>
<a href="" id="del">删除</a>
<a href="" id="fix">修改</a>
</td>
</tr>
</tbody>
</table>
<script>
var $add = document.querySelector("#add");
var $tbl = document.querySelector("#tbl");
//添加
$add.onclick = function(){
var $new_tr = document.createElement("tr")
$new_tr.innerHTML=`
<td>`+Math.random()+`</td>
<td>
<a href="" id="del">删除</a>
<a href="" id="fix">修改</a>
</td>
`
$tbl.children[1].appendChild($new_tr);
}
//删除
$tbl.onclick = function(event){ //事件绑定在父表格上,通过target,即点击的目标元素来确认具体事件行为。
var target = event.target; //每点击一次删除链接,该事件就会执行一次。
if(target.nodeName == 'A'){
switch(target.getAttribute("id")){
case "del":
target.parentElement.parentElement.parentElement.
removeChild(target.parentElement.parentElement);
break;
case "fix":
alert("修改");
break;
}
}
event.preventDefault();
}
//下面的方法不可行,因为在html初次执行时就已经确定了所有的删除链接,并设置了事件行为,但表格是动态增长的,即删除链接的个数也在动态增长。
// var delliset = document.querySelectorAll("#del");
// Array.from(delliset).forEach((item)=>{
// item.onclick = function(){
// item.parentElement.parentElement.parentElement.removeChild(item.parentElement.parentElement);
// event.preventDefault();
// }
// }
</script>
</body>
15.6 jquery实现动态表格
jquery 实际上是对于dom api的封装,让用户使用dom方法变得更加简洁。
业务 | javascript | jquery |
---|---|---|
选择元素 | querySelector | 选择器$(" ") |
dom元素 | 无法进行批量操作 | 可以实现批量操作 |
事件绑定 | 兼容性较差 | 兼容性,高效,批量,方法简洁 |
dom层级关系 | 操作繁杂 | 操作简练 |
jQuery对象是一个类数组对象,类数组对象中的元素是Element元素
jquery对象 -> dom对象,即把类数组对象中的元素取出。
<script>
var $btn_add = $("#add");
var $tbl_user =$("#tbl");
//删除
$tbl_user.on('click','a',function(event){
var target = $(event.target);
switch(target.attr("id")){
case "del":
// 移除节点
target.parents("tr").remove()
break;
case "fix":
alert('修改');
break;
}
return false;
})
// 添加
$btn_add.on('click', function(){
// 虚拟dom
$( `
<tr>
<td> <input type="checkbox"> </td>
<td> `+Math.random()+` </td>
<td> 男 </td>
<td>
<a href="" class="btn_del">删除</a>
<a href="" class="btn_edit">修改</a>
</td>
</tr>
`).appendTo($('#tbl > tbody'))
});
</script>
十六、BOM【浏览器】
16.1 超时调用&间歇调用
//超时调用
var flag = setTimeout(function(){ //经过1000ms以后调用回调函数,只调用一次。1000ms不可靠
},1000)
//flag为超时调用函数的一种标识
console.log(flag); //异步,先打印flag值
clearTimeout(flag); //取消超时调用
//间歇调用
var flag = setInterval(function(){
console.log('时间到了') //当回调函数的执行内容相同时,控制台只会显示一次输出内容
},1000) //每隔1000ms调用一次回调函数
如何使用超时调用来模仿一个间歇调用
16.2 提示框
(企业级不会直接使用这些提示框)
- alert 警告框(可以阻塞代码的运行,用于调试)
- prompt 询问框
- confirm 确认框
16.3 打开页面
window.href = "" //window是浏览器的全局对象,var变量即被提升到window中
16.4 变量作用域
- 全局作用域,全局执行环境
方法作用域,方法执行环境
方法执行完毕后,函数内部声明的变量会被释放
var a = 3; function foo(){ var b = 4; for(var i=0;i<10;i++){} console.log(i); //10--变量没有局部作用域 } foo(); console.log(window.a); //3 console.log(window.b); //undefined--方法作用域
如何模拟一个局部作用域
function foo(){
if(true){
var c = 1; //期望c拥有局部作用域
}
console.log(c) //1
}
=======================
function foo(){
(function(){
if(true){
var c = 1;
}
})();
}
16.5 window的滚动监听
window.onscroll = function(){
}
16.6 history
window.history.go(1); //前进1页
window.history.back();
16.7 路由原理
window.onload = function(){ //当页面加载完毕后
var hash = window.location.hash.slice(1); //获取路由
switch(hash){
case "/space":
break;
case "/home":
break;
}
}
16.8 ajax--async javascript and xml
异步的javascript和xml (json),主要用于前后台分离开发中数据的交互,占据我们开发的50%以上。
//异步
function(){
查询文章信息 ajax
查询用户信息 ajax
查询评论信息 ajax
console.log('end');
}
//三个查询同时进行,由于网络等原因,返回结果的时间是不确定的。因此,console.log("end")最先执行
//数据传递
-----同步方式(返回)-----
function foo(){
return "";
}
var a = foo();
-----异步方式(回调)-----
function foo(handler){
未来的某个时刻才能获取到
handler("结果")
}
foo(function(a){});
实现过程:
实例化XMLHttpRequest
var xhr = new XMLHttpRequest()
设置请求行
xhr.open(method,url)
设置请求头
(请求方式method = "POST"的时候才会设置Content-Type)
xhr.setRequestHeader(key,val)
设置请求体
(请求方式method = "POST"的时候才会传递data)
xhr.send(data)
监听请求状态
xhr.onreadystatechange = function(){ if(this.readyState === 4){ //请求正常发送到服务器端,响应到达客户端并且已被解析为客户端可用的格式 if(this.status === 200){ console.log(this.response); } } }
status:
200 ok
500 后端接口异常
404 找不到
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。