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 指向的理解
1,元素绑定事件,方法中的this 是当前操作的元素。
2,方法名前面是否有点,有点,点前面是谁this就是谁,没有点this是window(严格模式下是undefined)
3,构造函数执行,方法体中的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
攻击
15,以下代码要实现为5个input按钮循环绑定click 事件,绑定完成后点击1.2,3,4,5 分别弹出 0,1,2,3,4,5 个字符。
请问下面代码是否能实现?效果是什么样的?
应该怎么样修改才能是我们想要的效果,并说明理由?
<div id="btnBox">
<input type="text" value="button-1">
<input type="text" value="button-2">
<input type="text" value="button-3">
<input type="text" value="button-4">
<input type="text" value="button-5">
</div>
var btnBox = document.getElementById('btnBox'),
inputs = btnBox.getElementsByTagName('input');
for(var i = 0; i< inputs.length; i++){
inputs[i].onclick = function(){
alert(i);
}
}
不能实现,每次点击都是弹出来5,因为事件绑定是“异步编程”,当触发点击行为,内部方法执行时,外部的循环早已结束,用到的变量i 不是私有变量,利用“作用域链”的查找机制,会用到全局下的变量i,此时全局下的变量i 已经是5了。
怎么实现?
1,闭包
利用闭包机制,把需要用到的变量存储到自己的私有作用域中“闭包有保护作用”
for(var i = 0; i< inputs.length; i++){
inputs[i].onclick = (function (i){
return function(){
alert(i);
};
})(i);
每一轮循环,都执行自执行函数,形成一个私有作用域,这个作用域不销毁,里面设置私有变量 i ,让i 存储后期要用到的索引,第一个作用域: i=0; 第二个作用域:i=1....... 点击方法执行,用到变量i,会向上层的作用域查找,上级作用域中存储的i 就是我们要用到的索引。
这个基于闭包解决问题的方式,特别占用内存。
2,自定义属性
用target 属性来确定当前点击的某个元素
for(let i = 0; i< inputs.length; i++){
inputs[i].onclick = function(ev){
if(inputs[i] ==ev.target){
alert(i);
}
}
}
3,ES6
es6 的let 定义变量会形成块级作用域:
for(let i = 0; i< inputs.length; i++){
inputs[i].onclick = function(){
alert(i);
}
}
16,数组去重的方法
var ary =[1,2,3,2,4,35,25,2,3,4,5,35,38];
//基于内置类的原型,扩展方法,供它的实例调取使用,我们增加的方法设置“my”的前缀,防止内置方法重写
Array.prototype.myUnique = function myUnique(){
var obj = {};
for(var i=0;i<this.length;i++){
var item = this[i];
//判断是否存在该属性,如果存在则删除
if(obj.hasOwnProperty(item)){
// 优化方案 把最后一项和这一项交换顺序,删除最后一项,但是这一项可能会改变数组顺序
this[i]= this[this.length-1];
this.length--; //删除重复的元素
i--; //防止数组索引改变,数组塌陷
}
obj[item] = item;
}
obj =null; //提前释放内存
return this;// 可以实现链式写法
}
ary.myUnique();
console.log(ary);
17, document.parentNode 和 document.parentnode 的区别
js中严格区分大小写, document.parentNode 返回null(有该属性,只是该属性值没有) ,document.parentnode 没有该属性返回undefined.
18, 怎么规避多人开发函数重名的问题?
基于单例模式实现模块化开发,或者基于闭包机制实现模块化开发。
单例模式:把实现当前模块的功能和属性都放在一个命名空间下。
19,js中如何实现面向对象中的继承?(机率高)
1,原型链继承
就是让子类的原型等于new 出来的父类的实例
//1,给原型对象中添加成员 对象继承了原型对象
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log("我是person的方法");
}
//p 是子类 子类的原型=父类的实例
function P(){
}
P.prototype = new Person("张三",2);
var p = new P();
p.sayHello();
2,构造继承
在子类中通过apply或call调用父类的构造函数来进行继承
//1,Person是父类
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log("我是person的方法");
}
//P 是子类
function P(){
Person.apply(this);//调用父类的构造函数
}
var p= new P("张三",2);
p.sayHello();
3,混入继承(拷贝继承)
//父类
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log("我是person的方法");
}
//P 是子类
function P(){
var Parent = new Person();
for(var k in Parent){
P.ptototpe[k] =Parent[k]
}
}
var p= new P("张三",2);
p.sayHello();
4,实例继承
让子类的实例等于父类,返回子类的实例
//父类
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log("我是person的方法");
}
//P 是子类
function P(){
var instance = new Person('张三',24);
return instance;
}
var p = new P();
p.sayHello();
5,组合继承
可以避免共享父类的属性,子类父类有自己的原型,在子类的原型上修改不会影响父类。
//父类
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log("我是person的方法");
}
//P 是子类
function P(){
Person.call(this);
}
p.prototype = new Person('张三',21)
p.sayHello();
20,闭包的作用是什么,优缺点?(机率高)
就做参考一下,自己写的,还有一篇关于闭包的详细介绍文章,-----在上面,嘿嘿
闭包是js中一个重要的机制,通过函数执行形成一个不销毁私有作用域,既保护了里面的私有变量不受外边的影响,又能够把一些信息保存下来,主要是保护和保存的功能。对于保护功能在项目中,封装的一些插件可以放在闭包中,以防止和别人的冲突。对于保存功能,在做循环的事件绑定的时候,索引已经变成全局下的了,可以用闭包机制形成私有作用域把索引保存起来在后期使用的时候索引就不改变了。
21,apply 和call 的区别 :
函数.apply(this,[函数需要的参数列表,是一个数组]) [ ] 代表参数可传可不传
函数.call(this,[参数1],[参数2],[参数3])
1,第一个参数都是要把this修改的对象,apply是使用数组传参,call是使用单个参数
2,call 一般用于函数的形参确定了多少个时,apply用于函数参数不确定时
3,当call 和apply第一个参数传null/undefined ,this指向window
4, 当call 和apply第一个参数传值类型时,会将值类型转换成对应的引用类型
22,去除字符串的空格
1,js去除所有字符串的空格
var str = str.replace(/\s*/g,' ')
2,去除首尾空格
str.trim()
str.replace(/^\s+|\s+$/g,' ')
3,jQuery 的去除首尾空格
$.trim(str)
23,截取浏览器传的参数的方法:
function showWindowHref(){
var sHref = window.location.href;
var args = sHref.split('?');
var arr = args.split('&');
var obj ={};
for(var i=0;i<arr.length;i++){
var arg = arr[i].split('=');
obj[arg[0]] = arg[1];
}
return obj;
}
24,数组去重的方法
//1,简单的数组去重
function myUnique (arr){
var arr2=[];
for(var i=0;i<arr.length;i++){
if(arr2.indexOf(arr[i])!=-1){
//indexOf没有该元素则返回-1,!=-1 说明有该元素,什么操作也不做
}else{
//没有该元素则往数组里添加元素
arr2.push(arr[i])
}
}
}
//比较优化的数组去重
Array.prototype.myUnique = function myUnique(){
var obj = {};
for(var i=0;i<this.length;i++){
var item =this[i];
if(obj.hasOwnProperty(item)){
//判断如果有该元素,则把该元素放到数组的最后一个
this[i] = this[this.length-1];
//删除该元素
this.length--;
//为了防止数组索引改变
i--;
}
obj[item] = item;
}
obj =null; //提前释放内存
return this;//可以进行链式编程
}
25,css 中有哪几种定位方式,区别是什么:
css定位有四种不同类型,position值分别为: relative,absolute,fixed,static
relative(相对定位):相对定位的偏移参考元素是本身,不会使元素脱离文档流。
absolute(绝对定位):绝对定位元素以最近的父级元素作为参考坐标。如果父级元素没有设置定位,那么绝对定位元素参考html。
fixed(固定定位):固定定位位移参考坐标是窗口,会使元素脱离文档流。
static(静态定位):默认值,元素框正常形成的。
26,冒泡排序
function sort(arr){
for(var i=0;i<arr.length-1;i++){
for(var j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
27,数组的常用方法
1、push 在数组末尾添加一个或多个元素,并返回数组的长度, 可以添加任意类型的值作为数组的一个元素。
2、unshift 在最前面添加一个或多个元素,并返回数组的长度,可以添加任意类型的值作为数组的一个元素。
3、pop 删除最后一个元素,并返回删除元素的值;如果数组为空则返回undefine。该方法会改变原始数组。
4、shift 删除数组第一个元素,并返回被删除的元素;如果数组为空则返回undefine。该方法会改变原始数组。
5、slice截取数组,得到截取的数组;不改变原始数组,得到新的数组.与String的substring()方法类似。语法:slice(start,end)
6、splice剪接数组,向/从数组中添加/删除项目,然后返回被删除的项目,该方法会改变原始数组,索引从0开始。
7、concat 合并两个或多个数组,得到新数组,原始数组不改变,如果要进行concat()操作的参数是数组,那么添加的是数组中的元素,而不是数组。
8、indexOf 数组元素索引,并返回元素索引,不存在返回-1,索引从0开始
9、join 数组转字符串,与toString()方法类似
10、reverse 颠倒数组中元素的顺序,该方法会改变原来的数组,而不会创建新的数组。
28,字符串的常用方法
1,indexOf(),返回指定字符创第一次出现的位置。
2,lastIndexOf(),返回指定字符串最后一次出现的位置。
3,substring(),截取字符串字符串中两个指定索引号之间的字符(两个索引不能为负值)
4,slice(),提取字符串中两个指定索引号之间的字符(索引可以为负值,-1就是倒数第二位)
5,charAt(),返回指定索引的字符
6,concat(),连接两个或多个字符串,返回连接后的新字符串。
7,split(),把字符串分割为子字符串数组
8,toString(),返回字符串对象,比如把数字转换成字符串对象。
9,trim(),移除字符串首位空格,经常在对input和textarea的值做判断时用到。
10,toLowerCase(),把字符串转换成小写的。
11,toUpperCase(),把字符串转换成大写的
29,js垃圾回收机制
https://blog.youkuaiyun.com/yingzizizizizizzz/article/details/77333996
30,如何对代码进行优化
https://showcc.github.io/2018/03/06/optimization/
31,h5的新特性
https://blog.youkuaiyun.com/m0_37696296/article/details/81083402
32,说说你对Es6 的了解
https://www.cnblogs.com/yujihang/p/6798157.html
1,let,const, 都是用来声明定义变量。let主要用来定义变量会提供块级作用域,const通常用来定义常量,一旦声明,常量的值就不能改变。
2、.class, extends, super(类)
3,箭头操作符
4.template string(字符串模板)用反引号(`)
来标识起始,用${}
来引用变量,而且所有的空格和缩进都会被保留在输出之中
5.destructuring,自动解析数组或对象中的值。
33,js定时器
setTimeout: 设置一个定时器,在定时器到期后执行一次函数或代码段,只执行一次
var timeoutId = window.setTimeout(func[, delay, param1, param2, ...]);
清除定时器:
window.clearInterval(timeid);
setInterval: 以固定的时间间隔重复调用一个函数或者代码段,会执行n次
var intervalId = window.setInterval(func, delay[, param1, param2, ...]);
清除定时器:
window.clearTimeout(tmid);
34,盒子模型
盒子模型包含了元素内容(content)、内边距(paddiing)、外边距(margin)、边框(border)
盒子模型包括W3C 盒子模型和IE盒子模型,区别:W3C盒模型(标准的盒子模型)的width是指内容的宽度,IE盒模型的Width是指content+padding+border的总宽度。从网上找来的一张图:
35、常用的http的状态码
200:请求成功;
301:永久移动,请求的资源被永久的转移到其他的URL;
302:临时移动,请求的资源被临时移动,客户端应该使用原有的URL;
400:错误请求,服务器不理解请求的语法;
401:未授权,请求需要进行登录验证;
404:请求的资源不存在;
500:服务器内部错误;
304:未修改,请求的资源未修改,服务器不会响客户端返回任何内容,客户端通常会缓存访问过的资源;
503:由于过载或系统维护,服务器暂时无法处理客户端的请求;
分类 | 分类描述 |
---|---|
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
36,介绍一下304状态码的工作过程:
客户端在第一次访问成功后,再次向服务器请求文件时,发现自已客户端缓存的文件有Last Modified ,会在请求的中加上if Modified Since(这个缓存文件的时间),服务端只需要判断这个时间和当前请求的文件的修改时间来确定返回200 或304;
对于静态文件,服务器会自动完成最后修改时间的比较,完成缓存或者更新,返回304则表明,该资源从上次缓存到现在并没有修改过。
对于动态页面,往往没有Last Modified信息,浏览器和代理服务器不会做缓存,每次请求的时候都会完成一次200的请求。
37,关于vue的一些问题
beforCreate、Create、beforMounted、Mounted、beforUpdate、update、beforDestory、Destory
。。。。