每天几个前端小知识

简介: 每天几个前端小知识

javascript篇



1.说一下闭包


一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者

子函数在外调用,子函数所在的父函数的作用域不会被释放。


2.说说前端中的事件流


HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。


什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级

事件流包括下面几个阶段。


事件捕获阶段处于目标阶段事件冒泡阶段


addEventListener:addEventListener是DOM2级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。IE只支持事件冒泡。


3.说一下事件委托


简介:事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。


举例:最经典的就是ul和li标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在li标签上直接添加,而是在ul父元素上添加。


好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,

也可以有事件触发机制。


4.改变函数内部this指针的指向函数bind,apply,call的区别


通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2...这种形式。通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行。


5.JS的各种位置,比clientHeight,scrollHeight,offsetHeight,以及scrollTop,offsetTop,clientTop的区别?


clientHeight:表示的是可视区域的高度,不包含border和滚动条

offsetHeight:表示可视区域的高度,包含了border和滚动条

scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。

clientTop:表示边框border的厚度,在未指定的情况下一般为

0scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。


6.JS拖拽功能的实现


首先是三个事件,分别是mousedown,mousemove,mouseup当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。clientX,clientY标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用offsetX和offsetY来表示元素的元素的初始坐标,移动的举例应该是:鼠标移动时候的坐标-鼠标按下去时候的坐标。也就是说定位信息为:鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft.还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left以及top等等值。补充:也可以通过html5的拖放(Drag和drop)来实现



7.JS中的垃圾回收机制


必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

这段话解释了为什么需要系统需要垃圾回收,JS不像C/C++,他有自己的一套垃圾回收机制(GarbageCollection)。JavaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。例如:vara="helloworld";varb="world";

vara=b;

//这时,会释放掉"helloworld",释放内存以便再引用垃圾回收的方法:标记清除、计数引用。


标记清除


这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。


引用计数法


另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数,当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为1,;相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次数就减1,当这个值的引用次数为0的时候,说明没有办法再访问这个值了,因此就把所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为0的这些值。


用引用计数法会存在内存泄露,下面来看原因:


functionproblem(){
varobjA=newObject();varobjB=newObject();
objA.someOtherObject=objB;objB.anotherObject=objA;
}


在这个例子里面,objA和objB通过各自的属性相互引用,这样的话,两个对象的引用次数都为2,在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,因为计数不为0,这样的相互引用如果大量存在就会导致内存泄露。

特别是在DOM对象中,也容易存在这种问题:var

element=document.getElementById(’‘);varmyObj=new
Object();
myObj.element=element;element.someObject=myObj;

这样就不会有垃圾回收的过程。


8.JS监听对象属性的改变


参考回答:


我们假设这里有一个user对象,

在ES5中可以通过Object.defineProperty来实现已有属性的监听

Object.defineProperty(user,'name',{set:function(key,value){
}
})


缺点:如果id不在user对象中,则不能监听id的变化(2)在ES6中可

以通过Proxy来实现

varuser=newProxy({},{
set:function(target,key,value,receiver){
}
})

这样即使有属性在user中不存在,通过user.id来定义也同样可以这样


监听这个属性的变化哦。


9.自己实现一个bind函数

原理:通过apply或者call方法


来实现。(1)初始版本


Function.prototype.bind=func
tion(obj,arg){
vararg=Array.prototype.slice.call(arguments,1);
varcontext=this;
return
function(newArg){arg=arg.concat(Arr
ay.prototype.slice.call(newArg));
returncontext.apply(obj,arg);
}
}

(2)考虑到原型链


为什么要考虑?因为在new一个bind过生成的新函数的时候,必


须的条件是要继承原函数的原型


Function.prototype.bind=function(obj,arg){
var
arg=Array.prototype.slice.call(argu
ments,1);varcontext=this;
var
bound=function(newArg){arg=arg.co
ncat(Array.prototype.slice.call(newArg)
);returncontext.apply(obj,arg);
}
varF=function(){}
//这里需要一个寄生组合继承
F.prototype=context.
prototype;
bound.prototype=ne
wF();returnbound;
}


10.JS怎么控制一次加载一张图片,加载完后再加载下一张

(1)方法1<script

type="text/javascript
">varobj=new
Image();
obj.src="http://www.
phpernote.com/uplo
adfiles/editor/20110
7240502201179.jpg";
obj.οnlοad=function()
{
alert('图片的宽度为:
'+obj.width+';图片的高度为:'+obj.height+');
document.getElemen tById("mypic").innner HTML="<img
src='"+this.src+"'
/>";
}
</script>
<div
id="mypic">onloadi ng……</div>


方法2


<script
type="text/javascript ">varobj=new
Image();
obj.src="http://www.phpernote.com/uplo adfiles/editor/20110 7240502201179.jpg";obj.onreadystatecha nge=function(){
if(this.readyState=="complete")
alert('图片的宽度为:
'+obj.width+';图片的高度为:'+obj.height);
document.getElemen
tById("mypic").innner
HTML="<img
src='"+this.src+"'
/>";
}
}
id="mypic">onloadi
ng……</div>



11.实现JS中所有对象的深度克隆(包装对象,Date对象,正则对象)

通过递归可以简单实现对象的深度克隆,但是这种方法不管是ES6

还是ES5实现,都有同样的缺陷,就是只能实现特定的object的

深度复制(比如数组和函数),不能实现包装对象Number,String,

Boolean,以及Date对象,RegExp对象的复制。


(1)前文的方法

functiondeepClone(obj){
varnewObj=objinstanceof
Array?[]:{};for(variinobj){
newObj[i]=typeof
obj[i]=='object'?
deepClone(obj[i]):obj[i];
}
returnnewObj;
}


这种方法可以实现一般对象和数组对象的克隆,比如:


vararr=[1,2,3];
varnewArr=deepClone(arr);
//
newArr->[1,2,
3]varobj={
x:1,
y:2
}
varnewObj=deepClone(obj);
//newObj={x:1,y:2}
但是不能实现例如包装对象Number,String,Boolean,以及正则对
象RegExp和Date对象的克隆,比如:
//Number包装对象
varnum=newNumber(1);typeofnum//"object"
varnewNum=deepClone(num);
//newNum->{}空对象
//String包装对象
varstr=newString("hello");typeofstr//"object"
varnewStr=deepClone(str);
//newStr->{0:'h',1:'e',2:'l',3:'l',4:'o'};
//Boolean包装对象
varbol=newBoolean(true);typeofbol//"object"
varnewBol=deepClone(bol);
//newBol->{}空对象


(2)valueof()函数


所有对象都有valueOf方法,valueOf方法对于:如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。数组、函数和正则表达式简单地继承了这个默认方法,调用这些类型的实例的valueOf()


方法只是简单返回这个对象本身。


对于原始值或者包装类:functionbaseClone(base){return

base.valueOf();
}
//Number
varnum=newNumber(1);
varnewNum=baseClone(num);
//newNum->1
//String
varstr=new
String('hello');var
newStr=baseClone
(str);
//newStr->"hello"
//Boolean
varbol=new
Boolean(true);var
newBol=baseClone(
bol);
//newBol->true


其实对于包装类,完全可以用=号来进行克隆,其实没有深度克隆一说,这里用valueOf实现,语法上比较符合规范。


对于Date类型:

因为valueOf方法,日期类定义的valueOf()方法会返回它的一个内部表示:1970年1月1日以来的毫秒数.因此我们可以在Date的原型上定义克隆的方法:Date.prototype.clone=function(){


returnnewDate(this.valueOf());
}
vardate=new
Date('2010');var
newDate=date.clon
e();
//newDate->FriJan01201008:00:00GMT+0800


对于正则对象


RegExp:

RegExp.prototype.clone=
function(){varpattern=
this.valueOf();
varflags='';
flags+=pattern.global?'g':'';
flags+=
pattern.ignoreCase?'i':'';
flags+=pattern.multiline?
'm':'';
returnnewRegExp(pattern.source,flags);
};
varreg=new
RegExp('/111/');var
newReg=reg.clone()
;
//newReg->/\/111\//


12.来讲讲JS的闭包吧


闭包是指有权访问另外一个函数作用域中的变量的函数。闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。当在一

个函数内定义另外一个函数就会产生闭包。


(2)为什么要用:


匿名自执行函数:我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。


结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。


13.能来讲讲JS的语言特性吗

运行在客户端浏览器上;

不用预编译,直接解析执行代码;是弱类型语言,较为灵活;与操作系统无关,跨平台的语言;脚本语言、解释性语言


14.JS的全排列


functionpermutate(str)
{varresult=
[];
if(str.length
>1){var
left=str[0];
varrest=str.slice(1,
str.length);var
preResult=
permutate(rest);
for(vari=0;
i<preResult.length;i++)
{for(varj=0;
j<preResult[i].length;j++){
vartmp=preResult[i],slice(0,j)+left+preResult[i].slice(j,
preResult[i].length);result.push(tmp);
}
}
}elseif(str.length
==1){return
[str];
}
returnresult;
}
目录
相关文章
|
6月前
|
移动开发 前端开发 JavaScript
大前端时代
大前端时代
98 1
|
3月前
|
前端开发 JavaScript 数据可视化
前端实用网站
前端实用网站
|
6月前
|
前端开发 程序员 数据处理
关于前端的一些
关于前端的一些
41 1
|
6月前
|
SQL 安全 前端开发
前端安全方面
前端安全方面
49 0
|
编解码 移动开发 前端开发
什么是前端?
一、什么是前端 前端是指网页开发中与用户交互直接相关的部分,包括网页的设计、布局、交互以及与后端进行数据交互的功能。前端开发主要使用HTML、CSS和JavaScript等技术来实现网页的展示和交互功能。前端开发人员通常负责将设计师提供的网页设计转化为网页代码,并与后端开发人员进行协作,实现网页的功能和数据交互。前端开发的目标是提供用户友好的界面和良好的用户体验。 二、前端的特点 前端开发具有以下几个特点: 1. 用户界面设计:前端开发主要负责网页的设计和布局,包括页面的样式、排版、色彩等,以及用户交互的设计。前端开发人员需要具备一定的美学和设计能力,以提供用户友好的界面和良好的用户体验。
284 0
|
编解码 移动开发 前端开发
什么是前端,前端是什么?
什么是前端,前端是什么?
179 0
|
XML 前端开发 JavaScript
前端三剑客
前端三剑客
158 0
|
前端开发
前端,理解this
前端,理解this
57 0
|
Web App开发 JSON 缓存
|
前端开发
什么是前端
什么是前端自制脑图
76 0
什么是前端