主流浏览器 | 内核 |
---|---|
IE | trident |
Chrome | webkit/blink |
firefox | Gecko |
Opera | presto |
Safari | webkit |
编译性语言(c、c++、R) | 解释性语言 <>(php、js、python) | |
---|---|---|
特点 | 通篇翻译,生成特定的文件 | 逐行翻译,不生成特定文件 |
优点 | 快 | 跨平台(直接翻译成机器码) |
缺点 | 移植性不好(不跨平台) | 慢 |
注意:JAVA既不是编译性语言也不是解释性语言,可跨平台(可在linux、unix运行)
.java --> 通过javac指令编译 --> .class -->通过jvm虚拟机解释执行
(js引擎)是单线程
同步:多线程(同时做多件事:实质是电脑同时只做一件事)
异步:单线程(同时只能做一件事:实质是电脑同时做多件事,例如html里link标签的加载)
ECMA标准
把任务分成多个时间片,争抢时间片
A,1ms
–>B,1ms
–>B,1ms
–>A,1ms
–>B,1ms
–>B,1ms
–>A,1ms
–…
轮转时间片:象棋车轮战
不可更改的原始值(stack:FILO) | 引用值(heap) | |
---|---|---|
种类 | Number String Boolean undefined null | Array Object function…date RegExp |
区别 | ② = ①,值②不会因值①改变而改变 | ② = ①,值②会因值①改变而改变 |
原理 | 用栈存储①的值,②拷贝的是①的值 | 用栈存储①的地址,用堆存储①的值,②拷贝的是①的地址 |
//原始值:Number String Boolean undefined null
var a = 10;
var b = a;//赋的是a的值
a = 20;
document.write(b);
//结果->10
//引用值:Array Object function...date RegExp
var a = [1];
var b = a;//赋的是a的地址
a.push(2);//在a的地址增加一个值
document.write(b);
//结果->1,2
注意以下情况
var a = [1,2];
var b = a;//赋的是a的地址
a = [1,3];//创建一个新数组,并更改a的地址
document.write(b);
//结果->1,2,思考为什么结构不是1,3?
//因为a = [1,3];不是更改原来的数据,而是在堆里开辟了 新的空间用于存储新的数组[1,3]
var a = 1 + 1 + "a" + (1 + 2);
document.write(a);
//结果->2a3
var a = "a" + true + 1;
document.write(a);
//结果->atrue1
a++ | ++a |
---|---|
先执行语句后自加 | 先自加后执行语句 |
var a = 10;
document.write(a++);//先执行语句后自加,10
document.write(a);//11
表达式①&& 表达式② |
表达式①|| 表达式② |
---|---|
表达式①为真,则返回表达式②的值;表达式①为假,则返回表达式①的值 | 表达式①为真,则返回表达式①的值;表达式①为假,则返回表达式②的值 |
var a = 1 && 2;
document.write(a);//结果->2
//解决浏览器兼容性问题,既能在非IE浏览器又能在IE浏览器正常使用
//e在非IE浏览器中有值,window.event在IE浏览器中有值,e 等于 window.event
var event = e || window.event;
if(1 < 2){
document.write("a")
}
1 < 2 && document.write("a")
//aa
var i = 11;
//i--语句相当于if(i),即当i自减到0时,循环结束
for(; --i; ){
document.write(i+' ');
}
var i = 10;
while(i){
document.write(i+' ');
i--;
}
//结果->10 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1
- Number(mix)把内容转换成数
var demo = "123";//=>> number:123
var demo = false;//=>> number:0
var demo = null;//=>> number:0
var demo = undefined;//=>> number:NaN
var demo = "a";//=>> number:NaN
var sth = Number(demo);
console.log(typeof sth + ":" + sth);
Number(undefined)``Number("a") |
Number(null) |
---|---|
NaN | 0 |
2. parseInt(string,radix)把内容转换成整型
var demo = "123";//=>> number:123
从第一个数字位开始看,一直看到非数字为止
var demo = "123abc";//=>> number:123
var demo = "10.9"; var radix = 16;//=>> number:16
var demo = "b"; var radix = 16;//=>> number:11
var sth = parseInt(demo,radix);
radix是进制的意思,如果radix=16,则证明用16进制转换结果
console.log(typeof sth + ":" + sth);
parseInt("123abc") |
parseInt("10.9" , 16) |
parseInt("b" , 16) |
---|---|---|
123 | 16 | 11 |
3. parseFloat(string)把内容转换成浮点型
var demo = "123abc";//=>> number:123
var demo = "123.9";//=>> number:123.9
var demo = "123.9.2";//=>> number:123.9
var sth = parseFloat(demo);
console.log(typeof sth + ":" + sth);
4. String(mix)把内容转换成字符串
var demo = 123.9;//=>> string:123.9
var sth = String(demo);
console.log(typeof sth + ":" + sth);
5. Boolean(mix)把内容转换成字符串
var demo = 123.9;//=>> boolean:true
var demo = "";//=>> boolean:false
var sth = Boolean(demo);
console.log(typeof sth + ":" + sth);
6. toString(mix)把内容转换成字符串
var demo = 123.9;//=>> string:123.9
var demo = undefined;//=>> Uncaught TypeError
var demo = null;//= >> Uncaught TypeError
var demo = {
};//=>> string:[object Object]
var sth = demo.toString();
console.log(typeof sth + ":" + sth);
undefined.toString() 、 null.toString() |
Uncaught TypeError |
---|
实现将2进制转换成16进制
var demo = 10101010;
var demo2 = parseInt(demo,2);//将2进制转成10进制
console.log(typeof demo2 + ":" + demo2);//=>> number:170
var sth = demo2.toString(16);//将10进制转成16进制
console.log(typeof sth + ":" + sth);//=>> string:aa
parseInt(radix) |
toString(radix) |
---|---|
将radix进制转换成10进制 | 将10进制转换成radix进制 |
1.isNaN()-->Number()//判断这个数是否是NaN
console.log(isNaN("123"));//=>>false
console.log(isNaN("NaN"));//=>>true
console.log(isNaN("abc"));//=>>true
原理:先把变量放入Number("abc"),转换结果与NaN比对
2.++/-- +/-(一元正负)
var a = "123.4";a++;//=>>number:124.4
var a = -"123.4";//=>>number:-123.4
console.log(typeof a + ":" + a);
3.+(加号)有一个值是字符串结果都会变成字符串
var a = "123.4" + 1;//=>>number:string:123.41
console.log(typeof a + ":" + a);
4.-(减)*(乘)/(除)%(模)-->Number()
var a = "123.4" * 1;//=>>number:number:123.4
console.log(typeof a + ":" + a);
5.&& || !先转换乘boolean值
6.< > <= >=
var a = 1 > "2"; //有数字将所有值转化成数字进行比较
var a = "3" > "2"; //全是字符串转化成ascii码进行比较
7.== !=
var a = 1 == "1"; //=>>boolean:true
var a = 1 == true; //=>>boolean:true
console.log(typeof a + ":" + a);
undefined == null |
NaN == NaN |
---|---|
true | false |
var a = 1 === "1"; //=>>boolean:false
var a = 1 !== "1"; //=>>boolean:true
console.log(typeof a + ":" + a);
console.log(typeof(typeof(a)));//=>>string
var a = 123123.245454
alert(a.toFixed(3));//123123.245
//形式参数————形参
function test(x){
console.log(x);
//arguments ———— 实参列表
console.log(arguments);
//Arguments(3) [10, 3, 4]
}
//实际参数————实参
test(10,3,4);
//任意个数求和————不定参
function sum(){
var result = 0;
for(i = 0; i < arguments.length; i++){
result += arguments[i];
}
console.log(result);
}
sum(1,2,3,4,5,6,7,7);
function sum(a,b) {
a = 2;
console.log(arguments[0]);//->>2
arguments[1] = 3;
console.log(arguments[1]);//->>3
}
sum(1,2);
function sum(a,b) {
b = 2;
console.log(arguments[1]);//->>undefined
}
sum(1);
//普通方法
function fbnq(f,s,num){
if(num == 0){
return;
}
var t = f + s;
document.write(t + " ")
f = s;
s = t;
fbnq(f,s,num-1)
}
var num = parseInt(window.prompt("input"));
var f = 0;
var s = 1;
if(num){
document.write(1 + " ");
fbnq(f,s,num-1);
}
//快捷方法
function fb(n){
//结束条件
if(n == 1 || n == 2){
return 1;
}
//运算规律
return fb(n - 1) + fb(n - 2);
}
var n = window.prompt("input");
fb(n);
//快捷方法
function mul(n){
//结束条件
if(n == 1){
return 1;
}
//运算规律
return n * mul(n - 1);
}
var n = window.prompt("input");
mul(n);
a = 10;相当于window.a = 10;
,在全局上var a = 10;相当于window.a = 10;
function test(){
var a = b = 10;
document.write(window.a + "----");
document.write(window.b);
}
test();//undefined----10
结论:b是全局变量,而a是局部变量
2.3 四部曲:
- 创建AO对象(Activition Object)(执行期上下文)
- 找形参和变量声明,将变量和形参名名作为AO对象的属性名,值是undefined
- 将实参和形参统一
- 在函数体里面找函数声明,值赋予函数体
预编译例题集
eg:name\prototype
),但有些不可以(eg:[[scope]]
),这些属性仅供JavaScript引擎存取。作用域例题集
// 基本形式(标准)
(function(){
}())
// 基本形式(非标准)
(function(){
})()
function test(){
//函数声明
console.log ("a");
}
var demo = function(){
//函数表达式
console.log ("a");
}
//函数表达式+执行符号()
test();
//函数表达式+执行符号()
var demo = function(){
//函数表达式
console.log ("a");
}()
// 一旦函数表达式成为立即执行函数,该表达式就会
// 失去对原来函数的索引。即在上述这个例子中:
// 在控制台输入demo,不会返回方法,而是返回undefined
function test(){
//函数声明 + 执行符号()
console.log ("a");
}()
//Uncaught SyntaxError
//+(正)-(负)!(非)或者()括号都可以使函数声明变成函数表达式
-function test(){
//函数表达式 + 执行符号()
console.log ("a");
}()
//a
(function test(){
//函数表达式 + 执行符号()
console.log ("a");
})()
//a
var num = (function (a, b, c){
return a + b + c;//6
}(1, 2, 3));
闭包是什么:当内部函数被保存到外部时,将会生成闭包。
闭包的危害:闭包会导致原有作用域链不释放,造成内存泄露(内存占用)
闭包的作用:(例子见闭包例题集)
eg:函数累加器
)eg:eater
)eg:Deng
)闭包例题集
对象的创建方法
//2.1 系统自带的构造函数 new Object()
// 双胞胎:两个结果一模一样的独立个体
var obj = {
};
console.log(obj);// {}
var obj = new Object();
console.log(obj);// {}
//2.2 自定义
// 构造函数用大驼峰式命名规则
function Person(){
}//与函数声明不一样的地方就是名字用大驼峰式命名规则
var person = new Person(); //new Person()会返回一个对象给person1
console.log(person);//Person {}
构造函数的内部原理
function Student(name,age,sex){
// var this = {
// name:
// age:
// .....
// }
this.name = name;
this.age = age;
this.sex = sex;
this.grade = 2019;
// return this;
}
var car = new Student();
//当你new一个sutdent,会发生如下变化:
//①自动生成隐式的this结构体
//②根据你的执行语句生成属性
//③return this;最终生成
function Person(name,height){
this.name = name;
this.height = height;
// return {};//{}
return 123;//Person {name: "aaa", height: 180}
}
var person = new Person('aaa',180);
console.log(person);
//所以如果没有return语句,会执行隐式的return this;
//如果有自定义return{}语句,会执行自定义的return {},并返回{};
//如果自定义返回语句不是return {},会执行隐式的return this,因为有new;
把原始值(没有属性和方法)转换成对象值(有属性和方法)
// undefined和NaN都不能有属性;数字\字符串\布尔有原始值和对象值
var num = 123;//原始值
num.len = 1;//不报错,能执行以下语句,进行隐式的中间环节——// 包装类
//new Number(123).len = 1; delete
console.log(num.len);//undefined
//new Number(123).len = 没有值
var num = new Number(123);//Number {123}//对象值
num.len = 1;
console.log(num.len);//1
// 一旦数字的对象能参与运算,返回的是原始值数字。
console.log(typeof num);//object
console.log(typeof (num * 2));//number
//易错点!!!
var arr = [1,2,3,4,5];
console.log(arr.length);//5
arr.length = 2;//length是数组本身的属性,可以进行截断操作
console.log(arr);//[1, 2]
// 基于这个理论问:字符串也有length属性,同样操作为什么没有被截断?
var str = '12345';
console.log(str.length);//5
str.length = 2;
//new String('abcd').length = 2; delete 销毁新建出来的String('abcd'),并不会影响str
console.log(str);//12345
console.log(str.length);//12345 str自身没有属性length,但其包装类new String()有,所以调用了其包装类
//这里str.length返回的是对象字符串自带的属性length的值,不会人为的更改而变化
包装类例题集
//Person.prototype = {} --原型(是函数Person的祖先)
Person.prototype.name = 'abc';
// 构造函数必须大驼峰式命名
// 构造函数就像一个生产车间,生产的每个产品都有相同的基本属性
function Person(){
}
var person = new Person();
console.log(person);//Person {}//函数Person并没有name属性
console.log(person.name);//abc//获得了函数Person祖先name属性的值
var person1 = new Person();
console.log(person1.name);//abc//原型是其构造函数制造出的对象的公共祖先
//固定的值,无论构造几个对象都执行1次,减少代码耦合
Car.prototype = {
height : 1400,
lang : 4900,
carName : 'BMW'
}
function Car (color,owner){
this.owner = owner;
//固定的值构造几个对象就执行几次,造成代码冗余、耦合
// this.carName = 'BMW';
// this.height = 1400;
// this.lang = 4900;
this.color = color;
}
var car = new Car('red','Mr.Zhang');
var car1 = new Car('green','Mis.Liu');
Person.prototype.lastName = 'Deng';
function Person(){
}
var person =new Person();
person.lastName = 'Liu';//没有改变原型的属性,而是增加了构造函数的属性
//无法通过后代改变(增/删/改)祖先的属性,只能通过Person.prototype.lastName来修改原型的属性
3. 对象如何查看原型–> 隐式属性_proto_
4. 对象如何查看对象的构造函数–> constructor
//问题①:为什么明明function A中没有__proto__属性,
//但当在控制台打印a.__proto__的值为原型?
function A (){
//答①:当执行new A()时会隐式在function A中创建this,
//this中有系统自带属性__proto__,这是它能找到原型的根本原因
// var this = {
// __proto__:A.prototype,
// }
}
var a = new A();
A.prototype = {
name = 'abc';
};
var obj = {
name:'sunny';
}
function A (){
}
var a = new A();
a.__proto__ = obj;
绝大多数对象
的最终都会继承自Object.prototypeGrand.prototype.lastName = 'Deng';
function Grand(){
}
var grand = new Grand();
Father.prototype = grand;
function Father(){
this.name = 'xuming';
}
var father = new Father();
Son.prototype = father;
function Son(){
this.hobby = 'smoke';
}
var son = new Son();
情况一:
function Father(){
this.fortune = {
card1:'visa',
}
}
var father = new Father();
Son.prototype = father;
function Son(){
}
var son = new Son();
function Father(){
this.num = 100;
}
var father = new Father();
Son.prototype = father;
function Son(){
}
var son = new Son();
son.num = son.num + 1;所以father.num并不受影响
// 方式一:
Person.prototype.name = "a";
function Person(){
}//若是在这里改变name的值,Object.create(原型)执行的效果会就做不到一样了
var person = new Person();
console.log(person.name);//a
// 方式二:var obj = Object.create(原型);
Person.prototype.name = "a";
function Person(){
}
var person = Object.create(Person.prototype);
console.log(person.name);//a
Object.create(prototype(原型),defindProperty(特性))
四大属性之一:不可配置属性
eg.1:
console.log(Object.create());// Object prototype may only be an Object or null
eg.2:
console.log(Object.create(null));//{No properties}
//返回一个没有__proto__属性的object
eg.3:
var obj = Object.create(null);
obj.__proto__ = {
name:'sunday'};
console.log(obj.name);//undefined
//不是系统定义的__proto__ 无法正常使用
console.log(undefined.toString());//Cannot read property 'toString' of undefined
console.log(null.toString());//Cannot read property 'toString' of null
原型例题集
call/apply例题集
继承例题集
var deng = {
smoke : function(){
console.log('smoking....');
return this;//可以实现执行函数后返回自身
},
drink : function (){
console.log('drinking....');
return this;
},
perm : function(){
console.log('perming....');
return this;
}
}
deng.smoke().drink().perm().drink();
obj.prop === obj["prop"]
var deng = {
wife1 : {
name : 'lucy'},
wife2 : {
name : 'sophy'},
wife3 : {
name : 'icy'},
sayWife : function(num){
//方式一:
// switch(num){
// case 1:
// return this.wife1
// }
//方式二:可实现字符串拼接
return this['wife' + num].name;
//相当于this.wife2.name
}
}
console.log(deng.sayWife(2));//sophy
对象的枚举例题集
// 初始化一个复杂的数据:3的阶乘
var num = (function(n){
if(1 == n){
return 1;
}
return n * arguments.callee(n-1);
//arguments.callee实现调用自身,解决立即函数没有函数名而无法递归的问题
}(3))
面试例题集及克隆作业
push
:在数组最后一位开始添加pop
:移除数组最后一位shift
: 移除数组第一位unshift
:在数组第一位开始添加reverse
:逆转数组splice
:截取数组sort
:数组排序concat
:拼接数组join
:数组元素连接符数组例题集
封装type及数组去重作业
"use strict"
with
,arguments.callee
,func.caller
es3.0中this未被赋值,this指向window | es5.0中this未被赋值,this为undefined |
---|
es3.0中this是原始值时,自动转化为包装类 | es3.0中this是原始值时,不转化 |
---|
- DOM——Document Object Model文档对象模型
- DOM是一套操作HTML的方法集合
- 趣味小例子
对节点的增删改查
document
代表整个文档document.getElementById()
元素id在IE8以下浏览器,不区分id的大小写,而且也返回匹配name属性的元素document.getElementByTagName()
选择特定标签名的元素,返回类数组document.getElementByClassName()
选择特定类名的元素,IE8及其以下版本没有,可以多个class一起,返回类数组document.getElementByName()
选择特定数据名的元素querySelector()
css选择器 ,返回一个 在IE7及其以下版本没有 非实时性querySelectorAll()
css选择器,返回一组 在IE7及其以下版本没有 非实时性parentNode
->父节点(最顶端的parentNode为#document)childNodes
->子节点们firstChild
->第一个子节点lastChild
->最后一个子节点nextSibling
->后一个兄弟节点&previousSibling
->前一个兄弟节点parentElement
->返回当前父元素节点children
->只返回当前元素的元素子节点firstElementChild
->第一个元素节点(IE不兼容)lastElementChild
->最后一个元素节点(IE不兼容)node.childElementCount === node.children.length
继承关系document —> HTMLDocument.prototype —> Document.prototype
继承关系HTMLHeadElement/HTMLBodyElement/HTMLTitleElement/HTMLParagraphElement/HTMLInputElement/HTMLTableElement/…etc—> HTMLElement—>Element
document的继承树:
setInterval
var minutesNode = document.getElementsByTagName('input')[0];
var secondsNode = document.getElementsByTagName('input')[1];
var minutes = seconds = 0;
var timer = setInterval(function(){
seconds ++;
if(seconds == 60){
seconds = 0;
minutes ++;
if(minutes == 3){
clearInterval(timer);
}
}
minutesNode.value = minutes;
secondsNode.value = seconds;
},100)
window.pageXOffset
/window.pageYOffset
(ie8及其以下不兼容)document.body.scrollTop + document.documentElement.scrollTop
(ie8及其以下兼容)function getScrollOffset(){
if(window.pageXOffset){
return{
x:window.pageXOffset,
y:window.pageYOffset
}
}else{
return{
x:document.body.scrollLeft + document.documentElement.scrollLeft,
y:document.body.scrollTop + document.documentElement.scrollTop
}
}
}
window.innerWidth
/window.innerHeight
(ie8及其以下不兼容)document.documentElement.clientWidth
/document.documentElement.clientHeight
(标准模式下任何浏览器都兼容)document.body.clientHeight
/document.body.clientWidth
(怪异模式下任何浏览器都兼容)document.compatMode
的值:"CSS1Compat"——标准模式
/"BackCompat"——怪异模式
function getViewportOffset(){
if(window.innerWidth){
return{
width:window.innerWidth,
height:window.innerWidth
}
}else{
if(document.compatMode == "CSS1Compat"){
//标准模式,有
return{
width:document.documentElement.clientWidth,
heighty:document.documentElement.clientHeight
}
}else{
//怪异模式,无
return{
width:document.body.clientWidth,
height:document.body.clientHeight
}
}
}
}
dom.offsetWidth
/dom.offsetHeight
(视觉上的尺寸:包括padding,包括margin)dom.offsetLeft
/dom.offsetTop
(距离与无定位的父级元素,返回相对文档的坐标。距离与已定位的父级元素,返回相对于最近的有定位的父级的坐标)dom.offsetParent
(返回最近有定位的父级,如无返回body,body.offsetParent,返回null)window.scroll(x,y)
/window.scrollTo(x,y)
/window.scrollBy(x,y)
实现自动阅读的功能
eg:float-->cssFloat
eg:background-color-->backgroundColor
//封装查看样式的方法getStyle(elem,prop)
function getStyle(elem,prop){
if(window.getComputedStyle(elem,null)[prop]){
//不能用.prop,必须[prop]
return window.getComputedStyle(elem,null)[prop];
}else{
return elem.currentStyle[prop];
}
}
脚本化CSS例题集
div>
- obj.addEventListener(type,fn,false)
2.1 IE9以下不兼容,可以为一个事件绑定多个处理程序
注意一下两张图片的区别:
- obj.attachEvent(
on
+ type,fn)
3.1 IE独有,一个事件同样可以绑定多个处理程序
- 绑定事件一旦发生在循环里,要考虑是否产生闭包
事件处理函数的运行环境
- ele.onxxx = fuction(){}
1.1 程序this指向dom元素本身
- obj.addEventListener(type,fn,false)
2.1 程序this指向dom元素本身
- obj.attachEvent(
on
+ type,fn)
3.1 程序this指向window
var div = document.getElementsByTagName('div')[0];
div.attachEvent('onclick',function(){
handle.call(div);//让this指向元素本身
});
function handle(){
console.log(this);//div
}
- 封装兼容性addEvent(elem,type,handle)方法——给一个dom对象添加一个该事件类型的处理函数
function addEvent(elem,type,handle){
if(elem.addEventListener){
elem.addEventListener(type,handle,false);
}else if(elem.attachEvent){
elem.attachEvent('on' + type,function(){
handle.call(elem);
})
}else{
elem['on'+type] = handle;
}
}
解除事件处理程序
ele.onclick = false/''/null;
ele.removeEventListener(type , fn , false);
ele.detachEvent('on' + type , fn)
- 若绑定匿名函数,则无法解除
事件处理模型——事件冒泡、捕获
- 事件冒泡
- 结构上(非视觉)嵌套关系的元素,会存在事件冒泡功能,即同一事件,自子元素冒泡向父元素。(自底向上)
var wrapper = document.getElementsByClassName('wrapper')[0];
var content = document.getElementsByClassName('content')[0];
var box = document.getElementsByClassName('box')[0];
wrapper.addEventListener('click',function(){
console.log('wrapper');
},false);
content.addEventListener('click',function(){
console.log('content')
},false);
box.addEventListener('click',function(){
console.log('box')
},false);
- 事件捕获
- 结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,即同一事件,自父元素捕获至子元素,子元素进行事件执行(事件源元素)(自顶向下)
- IE没有捕获事件
var wrapper = document.getElementsByClassName('wrapper')[0];
var content = document.getElementsByClassName('content')[0];
var box = document.getElementsByClassName('box')[0];
//事件捕获实现:addEventListener(type,fn,ture)
wrapper.addEventListener('click',function(){
console.log( 'wrapper');
},true);
content.addEventListener('click',function(){
console.log('content')
},true);
box.addEventListener('click',function(){
console.log('box')
},true);
思考题:我们知道同一对象的同一个事件类型上绑定了两个对象处理函数,一个是事件冒泡,另一个是事件捕获,问这两个对象处理函数执行顺序如何?
先捕获后冒泡,其中注意捕获至子元素的时候是子元素执行,优先级和冒泡一样,是否先执行取决于代码位置
var wrapper = document.getElementsByClassName('wrapper')[0];
var content = document.getElementsByClassName('content')[0];
var box = document.getElementsByClassName('box')[0];
//冒泡事件
content.addEventListener('click',function(){
console.log('contentBubble')
},false);
wrapper.addEventListener('click',function(){
console.log('wrapperBubble')
},false);
box.addEventListener('click',function(){
console.log('boxBubble')
},false);
//捕获事件
wrapper.addEventListener('click',function(){
console.log( 'wrapper');
},true);
content.addEventListener('click',function(){
console.log('content')
},true);
box.addEventListener('click',function(){
console.log('box')
},true);
- focous(聚焦)、blur、change、submit、reset、select等事件不冒泡
取消冒泡和阻止
- 取消冒泡
1.1 W3C标准event.stopPropagation();但不支持ie9以下版本
1.2 IE、Google独有event.cancelBubble = true;
1.3 封装取消冒泡的函数stopBubble(event)
function stopBubble(event){
if(event.stopPropagation()){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
- 阻止默认事件
默认事件——表单提交、a标签自动跳转只顶端、右键自动弹出菜单等
2.1 return false; 以对象属性的方式注册的事件才生效
2.2 event.preventDefault();W3C标注,IE9以下不兼容
2.3 event.returnValue = false;兼容IE
封装阻止默认事件的函数cancelHandler(event)
function cancelHandler(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
//虽然还有一种return false,但封装进来只会返回false
}
取消a标签的默认事件
方法1:
<a href="javascript:void(false)"> baidu.com a>
方法2:
a.onclick = function(){
return false;
}
事件对象
- event || window.event(用于IE)
- 事件源对象srcElement:(chrome都有)
2.1 event.target 火狐只有这个
2.2 event.srcElement IE只有这个
- 兼容性写法:
var wrapper = document.getElementsByClassName('wrapper')[0];
var box = document.getElementsByClassName('box')[0];
wrapper.onclick = function(e){
var event = e || window.event;//兼容性设计
var target = event.target || event.srcElement;//兼容性设计
console.log(target);
}
事件委托
- 利用事件冒泡,和事件源对象进行处理
- 优点:
2.1 性能高 不需要循环所有的元素一个个绑定事件
2.2 灵活 当有新的子元素时不需要重新绑定事件
var ul = document.getElementsByTagName('ul')[0];
ul.onclick = function(e){
var event = e || window.event;
var target = event.target ||event.srcElement;
console.log(target.innerText);
}
事件分类
- 鼠标事件
click
mousedown
mousemove
mouseup
contextmenu用于右键取消菜单
mouseover
mouseout
mouseenter
mouseleave
1.1. 用e.button来区分鼠标的按键,0(左键)/1(滚轮)/2 (右键)
1.2. DOM3标准规定:click事件只能监听左键,只能通过mousedown
和mouseup
触发右键
实现小方块随鼠标移动
var div = document.getElementsByTagName('div')[0];
var disX,disY;
div.onmousedown = function(e){
//先按下去
disX = e.pageX - parseInt(div.style.left);
disY = e.pageY - parseInt(div.style.top);
//鼠标挪动的频次太快,系统的监听事件频次太慢
document.onmousemove = function(e){
//再跟随移动
var event = e || window.event;
div.style.left = e.pageX - disX + 'px';
div.style.top = e.pageY - disY + 'px';
}
document.onmouseup = function(){
//最后放开鼠标
document.onmousemove = null;
}
}
实现按钮点击跳转界面,长按拖动
//如何实现区分点击事件和拖拽事件
var a = document.getElementsByTagName('a')[0];
var firstTime = 0;
var lastTime = 0;
var key = false;
var disX,disY;
a.onmousedown = function(e){
firstTime = new Date().getTime();
disX = e.pageX - parseInt(a.style.left);
disY = e.pageY - parseInt(a.style.top);
document.onmousemove = function(e){
var event = e || window.event;
a.style.left = e.pageX - disX + 'px';
a.style.top = e.pageY - disY + 'px';
}
}
document.onmouseup = function(){
lastTime = new Date().getTime();
if(lastTime - firstTime < 300){
//点击事件时间小于0.3秒
key = true;
}
document.onmousemove = null;
}
document.onclick = function(){
if(key){
//是拖拽的话就不能执行click
console.log('click~');
window.location.href = 'https://www.baidu.com';
key = false;//执行了click后key返回原状态
}
}
- 键盘事件
2.1 keydown
keyup``keypress
2.2keydown > keypress > keyup
2.3keydown
&keypress
的区别
- keypress返回ASCII码,可以转换成相应字符
- keydown可以响应任意键盘按键,keypress只可以响应字符类键盘按钮并区分大小写
打印出按下的键盘:
document.onkeypress = function(e){
console.log('onkeypress');
console.log(String.fromCharCode(e.charCode));
}
- 文本操作事件
3.1 input
change
focus
blur
<input
style = 'width:100px;height:20px;border:purple solid 1px;color:#999'
value = '请输入用户名'
onfocus = "if(this.value == '请输入用户名')this.value = '';this.style.color = '#424242'"
onblur = "if(this.value == '')this.value = '请输入用户名';this.style.color = '#999'">
- 窗体操作类(window上的时间)
3.1 scroll load
json
JSON是一种传输数据的格式(以对象为样板,本质就是对象,但用途有别,对象就是本地用的,json用于传输)
JSON.parse(); string --> json
JSON.stringify(); json – >string
异步加载js
- js加载的缺点:加载工具方法没有必要阻塞文档,过多js加载影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作
- 有些工具方法需要按需加载,用到在加载,不用不加载
- javascript 异步加载的三种方案
3.1 defer 异步加载——等到dom文档全部解析完才会被执行。只有IE能用,也可以将代码写到内部。
3.2 async 异步加载——加载完就执行,async只能加载外部脚本(不能把js写在script标签里)
- 执行时也不阻塞页面
3.3 创建script,插入到DOM中,加载完毕后callBack(异步加载+按需加载+最常用)
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "todo.js"
//附加到documen内才能被执行
document.head.appendChild(script);
实现按需异步加载js
js加载时间线(创建–解析–加载)
- 创建document对象,开始解析web页面。这个阶段document。readyState = ‘loading’
- 遇到link外部css,创建线程加载,并继续解析文本
- 遇到lscript外部js,并且没有设置async、defer,浏览器加载,并阻塞,等待js加载完成并执行该脚本,并继续解析文本
- 遇到lscript外部js,并且有设置async、defer,浏览器创建线程加载,并继续解析文档。对于async属性的脚本,脚本加载完后立即执行(异步禁止使用document.write())
- 遇到img等,先正常解析dom结构,然后浏览器异步加载src,并继续
- 当文档解析完成,document.readyState = ‘interactive’
- 文档解析完成后,所有设置有defer的脚本会按照顺序执行。
- document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段
- 当所有async的脚本加载完成并执行后,img等加载完成后,document.readyState = 'complete’事件,windo对象触发load事件
正则表达式(RegExp)
课前补充:
- 转义字符"" (document.write()无法识别)
- 多行字符串
- reg.test();——boolean
- str.match();———字符数组
i
g
m
不区分大小写
全局匹配
多行匹配
正则表达式例题集