1,什么是事件委托,有什么优缺点?
事件委托又称为事件代理,是利用事件冒泡的原理把其事件处理程序交给父元素来执行。
优点:
1,首先是减少了内存占用,性能更好。
2,加快了整个页面交互的等待时间。
3,动态添加的节点也可以自动绑上其事件,无需再次绑定事件。
4,document很快就可以访问,而且可以在页面生命周期的任何时点添加事件处理程序,而不用等待其他事件完成如DOMContentLoaded、load事件。
缺点:
1,如果把所有的事件都绑上事件委托,可以会出现事件误判,就是一些不该绑定事件的元素都绑上事件了。
2,事件委托基于冒泡,对不冒泡的事件不支持。
2,事件委托如何工作:
如果有个ul,里面有什么li,我们可以在父级元素ul上绑定事件来进行事件委托。
我们现在的疑问是:ul元素如何知道li元素点击了呢?
很简单,由于所有li元素都是ul元素的子节点,故他们的事件会冒泡,无论点击哪个li元素,实际上都相当于点击了ul元素。
现在产生了另一个问题:ul元素如何知道是在哪个li元素上点击的呢?
我们很容易想到,在ul的事件处理程序中检测事件对象的target属性,就可以得到真正点击的目标元素。
下面我写了一个获取点击的li 的下标和背景色的方法
<ul id="ul1">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
window.onload = function (){
var myul = document.getElementById("ul1");
var myli = myul.getElementsByTagName("li");
myul.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target ||ev.srcElement;
//只让点击li的时候执行 ,点击ul的时候不执行
while(target.tagName !== 'LI'){
//如果点击的元素为ul,直接跳出循环
if(target === myul){
target = null;
break;
//否则,将当前元素父元素赋给target
}else{
target = target.parentNode;
}
}
//只让点击的某个li的背景颜色设为红色
target.style.background = "red";
//获取点击的某个li的下标
var index;
for(var i=0;i<myli.length;i++){
if(myli[i] === target){
index=i;
}
}
if(index>=0){alert('我的下标是第'+index+'个')};
}
}
3,说到事件冒泡,什么是事件冒泡,怎么阻止事件冒泡呢?
当事件发生后,这个事件就要开始传播(从里到外或者从外向里)。因为事件源本身(可能)并没有处理事件的能力,即处理事件的函数(方法)并未绑定在该事件源上。事件必须从这个按钮传播出去,从而到达能够处理这个事件的代码中,或者按钮的父级绑定有事件函数,当该点击事件发生在按钮上,按钮本身并无处理事件函数,则传播到父级去处理。这就是事件冒泡。
阻止事件冒泡的方法:
(1) w3c的方法是e.stopPropagation()阻止向父级传播 或e.stopImmediatePropagation()包括自身和父级传播,
IE则是使用e.cancelBubble = true
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
(2)return false
javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡。
阻止默认行为的方法:
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
//阻止浏览器的默认行为
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault )
e.preventDefault();
//IE中阻止函数器默认动作的方式
else
window.event.returnValue = false;
return false;
}
4,js常用的数据类型
基本的数据类型:
String,Number ,Boolean, Undefined,Null ,symbol
引用数据类型:Function ,Object
5,基本数据类型和引用数据类型的区别
(1)内存分配位置不同
基本数据类型存储在栈中,引用类型在栈中只存放了对象的地址,在堆中存放的是对象的值。
(2)变量访问的时候不同
基本数据类型可以直接访问到,
引用的数据类型不能直接访问,得得到堆内存中的地址,然后用这个地址获取对象中的值,就是按引用访问。
(3)复制变量的时候不同
基本数据类型复制时会把值赋值给新变量,这两个变量是完全独立的,只是拥有相同的值。
引用数据类型复制时只会把内存地址复制给新变量,也就是两个指针指向同一个对象。
6,堆和栈的区别:
(1) 堆和栈的空间分配区别
栈是由操作系统自动分配释放,
堆一般是由程序员分配释放,若程序员不释放,可能会有os回收。
(2)存放值的不同
栈一般存放函数的参数值,局部变量的值。
堆中一般存放对象的值。
(3)数据结构的区别
栈的数据结构可以看做先进后出的栈。
堆可以看做是一颗树。
(4)缓存方式的区别
1、栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
2、堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定。
(5)调用速度的区别
栈中的数据调用要比堆中的快。
7,怎么获取变量的数据类型
(1)常用的typeof(×××) 或 typeof ×××
判断string,number,boolean,undefined,function 类型的变量可以用typeof来判断
(2)Object.prototype.toString.call(×××)
可以判断任何类型, 返回结果是[Object 类型]
(3)instanceof 返回值为boolean 类型
得需要和new 出来类型变量做比较,例如 var a = new String("hello ") a instanceof String ------- true
null 和undefined 类型会报错。
(4) constructor属性
JavaScript内置对象一般都具备constructor属性
var a = new String("hello ") 可以用 a.constructor.name 来获取类型。
null 和undefind 不能获取数据类型。
8,怎样判断null 数据类型 ,NaN 类型,undefined类型,数组类型
(1) 判断是否是null类型
1,===
例:var d = null; console.log(d === null); -----true
2, Object.prototype.toString.call(null)==='[object Null]
例:Object.prototype.toString.call(d)==='[object Null] ----true
(2) 判断是否是NaN类型
1,!== Object
例:var ex= NaN; console.log(ex !== Object) -----true
(3) 判断是否是undefined 类型
1,=== void 0 或 === undefined
例:var e = undefined; console.log(e === void 0) ----- true console.log(e === undefined) ----- true
2,typeof ()
例:var e = undefined; console.log("e:"+typeof(e))
//判断是否是Null
function isNull(obj){
return obj === null;
}
//判断是否是NaN
function isNaN(obj){
return obj !== obj;
}
//判断是否是undefined
function isUndefined(obj){
return obj === void 0;
}
9、null 和 undefined 的区别
相同点:
在 if
判断语句中,值都默认为 false
大体上两者都是代表无,具体看差异
不同点:
null
转为数字类型值为0,而undefined
转为数字类型为NaN(Not a Number)
- undefined是在var 声明变量但未对其初始化时(未被赋值时),这个变量就是undefined
-
null值表示空对象指针。就是访问尚未存在的对象时所返回的值。最为常见的一个用法就是作为参数传入(说明该参数不是对象)
- 设置为
null
的变量或者对象会被内存收集器回收
10、== 和 === 的区别
== 用于一般比较,先检查两个操作数的数据类型,如果相同则进行=== 比较,如果不同则会转化成同一类型后的值看‘值’是否相等
=== 用于严格比较,如果类型不同,其结果就是不等,不需要做类型转换
11、css那些样式可以被子元素继承
可继承的:font-size
,font-weight
,line-height
,color
,cursor
等
不可继承的一般是会改变盒子模型的:display
,margin
、border
、padding
、height
等
12,关于js 中this 指向的理解
13,怎么解决跨域问题,有哪些方法?
我一般用这三种,cors
,nginx反向代理
,jsonp
jsonp
: 单纯的 get 一些数据,局限性很大...就是利用script标签的src属性来实现跨域。nginx 反向代理
: 主要就是用了nginx.conf
内的proxy_pass http://xxx.xxx.xxx
,会把所有请求代理到那个域名,有利也有弊吧..cors
的话,可控性较强,需要前后端都设置,兼容性 IE10+ ,比如- Access-Control-Allow-Origin: http://foo.example // 子域乃至整个域名或所有域名是否允许访问
- Access-Control-Allow-Methods: POST, GET, OPTIONS // 允许那些行为方法
- Access-Control-Allow-Headers: X-PINGOTHER, Content-Type // 允许的头部字段
- Access-Control-Max-Age: 86400 // 有效期
Q: 对于想携带一些鉴权信息跨域如何走起?比如cookie
!
需要配置下 header Access-Control-Allow-Credentials:true
,具体用法看下面的nginx
demo
当然cros
的配置不仅仅这些,还有其他一些,具体引擎吧....
若是我们要用 nginx
或者 express
配置cors
应该怎么搞起? 来个简易版本的
- nginx
location / {
# 检查域名后缀
add_header Access-Control-Allow-Origin xx.xx.com;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type;
add_header Access-Control-Max-Age 86400;
}
复制代码
- express, 当然这货也有一些别人封装好的
cors
中间件,操作性更强...
let express = require('express');
let app = express();
//设置所有请求的头部
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "xx.xx.com");
res.header("Access-Control-Allow-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type");
res.header("Access-Control-Allow-Credentials","true")
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
next();
});
复制代码
有些还会跟你死磕,,除了这些还有其他姿势么...我说了一个HTML5的postMessage
....
..因为真心没用过,只是以前查阅的时候了解了下..只能大体点下
这货用于iframe
传递消息居多, 大体有这么两步步
window
打开一个实例,传递一个消息到一个x域名- x 域名下监听
message
事件,获取传递的消息
这货的兼容性没那么好,而且没考虑周全下容易遭受 CSRF
攻击