在工作中经常会用到一些有用的知识点,可能当时用的时候还记得,但是过一段时间就忘了,所以在这里做一个记录,方便以后再来复习。写得不对的地方还请各位大神指点一下。
- 1、判断传过来的变量是否是一个数组
- 2、typeof和instanceof的区别
- 3、Window.onload和DOMContentLoaded的区别
- 4、javascript延迟加载的方式
- 5、盒模型
- 6、js获取元素的宽高
- 7、float引起的问题和解决方案
- 8、display:none和visibility:hidden的区别
- 9、cookie 和session
- 10、IE 与其他浏览器的区别?
- 11、ajax
- 12、从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
- 13、get和post的区别?
- 14、attribute和property的区别是什么
- 15、浅拷贝和深拷贝的区别
- 16、变量声明提升
1、判断传过来的变量是否是一个数组
很多时候我们都会用下面这个方法来判断传递过来的对象是否是一个数组。 var isArray = value instanceof Array;
复制代码
这个方法在一般情况下(value不是从其他frame传过来的)是成立的。 但是为了防止一般情况的发生,我们可以用该方法来验证。
function isArray(value) {
return Object.prototype.toString.call(value) == "[object Array]";
}
复制代码
2、typeof和instanceof的区别
2.1 typeof
是一种操作符而不是一个函数,用来检测给定变量的数据类型。一般是用来判断"number"、"string"、"boolean"、 和 "undefined"这4种基本数据类型的。object类型用typeof来判断结果存在争议,所以一般是使用instanceof来进行判断。引用类型用typeof来进行判断时返回的都是object,以至于我们还是不知道用于判断的变量到到底是什么数据类型。 console.log(typeof(null));//object
console.log(typeof([1,2]));//object
复制代码
但实际上null是Null类型,而[1,2]是Array类型。
typeof 最常见的用法
1、判断某个变量是否未定义
2、判断某个变量是否初始化
if(typeof(b)=="undefined"){}
复制代码
不能直接用if(b)去判断,这样代码会直接报错,后面的代码也会运行不了。因为typeof判断数据类型的不足(只能用于判断基本数据类型),引用数据类型需要使用instanceof的方式来进行判断
2.2 instanceof
object instanceof constructor 此运算符可以判断一个变量是否是某个对象(类)的实例。换句话说用来检测 constructor.prototype 是否存在于参数 object 的原型链上。 下面通过代码阐述instanceof的内部机制,假设现在有 x instanceof y 一条语句,则其内部实际做了如下判断:while(x.__proto__!==null) {
if(x.__proto__===y.prototype) {
return true;
}
x.__proto__ = x.__proto__.proto__;
}
if(x.__proto__==null) {return false;}
//函数代码实现
function instanceOf(instance,constructor){
let proto=Object.getPrototypeOf(instance);
while(proto){
if(proto===constructor.prototype){
return true;
}
proto=Object.getPrototypeOf(proto);
}
return false;
}
复制代码
参考链接:juejin.im/post/5c19c1…
x会一直沿着隐式原型链__proto__向上查找直到x.proto.proto......===y.prototype为止,如果找到则返回true,也就是x为y的一个实例。否则返回false,x不是y的实例。
3、Window.onload和DOMContentLoaded的区别
Window.onload: 当页面完全加载后(包括所有图像、javascript文件、css文件等外部资源)触发的事件。
DOMContentLoaded: 在形成完整的dom树之后就会触发,不理会图像、javascript文件、css文件或其他资源是否已经下载完毕。跟$(function(){})的作用是一样的。
4、javascript延迟加载的方式
1、defer:并行加载js文件,表示脚本可以延迟到整个页面完全被解析和显示之后再执行,标记为defer的脚本按照页面上script标签的顺序执行,但只适用于外部脚本文件。。(立即下载,延迟执行)
2、async:并行加载js文件,下载完成立即执行,不保证按照页面上script标签的顺序执行。只适合外部脚本文件。并且一定会在页面的load事件前执行,但可能会在DOMContentLoaded事件触发之前或之后执行。
3、动态创建script元素。此文件当元素添加到页面之后立刻开始下载,可以使用load事件来监听script是否加载(下载)完毕,IE使用onreadystatechange函数),下载许多时可以使用promise
function loadScript(url, callback){
var script = document.createElement ("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName_r("head")[0].appendChild(script);
}
复制代码
4、使用XHR对象将脚本注入到页面中。
var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
var script = document.createElement ("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null)
复制代码
5、盒模型
共分为2种类型:W3C标准盒模型(默认) 和 IE标准盒模型(怪异盒模型)。CSS盒子模式包括如下属性:外边距(margin)、边框(border)、内边距(padding)、内容(content)
css3中有一个新属性对应着盒模型。box-sizing: content-box|border-box|inherit;
css3属性box-sizing的content-box属性对应着W3C标准盒模型;
css3属性box-sizing的border-box属性对应着IE标准盒模型;
1、:W3C标准盒模型-border-box: (默认)
元素的宽 = width + padding-left + padding-right + border-left + border-right
元素的高 = height + padding-top + padding-bottom + border-top + border-bottom
复制代码
2、IE标准盒模型-border-box
元素的宽 = width(包含padding-left + padding-right + border-left + border-right)
元素的高 = height(包含padding-top + padding-bottom + border-top + border-bottom)
复制代码
6、js获取元素的宽高
转载自:www.cnblogs.com/chengzp/p/c…
通过JS获取盒模型对应的宽和高,有以下几种方法。为了方便书写,以下用dom来表示获取的HTML的节点。
- dom.style.width/height
这种方式只能取到dom元素内联样式所设置的宽高,也就是说如果该节点的样式是在style标签中或外联的CSS文件中设置的话,通过这种方法是获取不到dom的宽高的。
- dom.currentStyle.width/height
这种方式获取的是在页面渲染完成后的结果,就是说不管是哪种方式设置的样式,都能获取到。但这种方式只有IE浏览器支持。
- window.getComputedStyle(dom).width/height
这种方式的原理和2是一样的,这个可以兼容更多的浏览器,通用性好一些。
- dom.getBoundingClientRect().width/height
这种方式是根据元素在视窗中的绝对位置来获取宽高的
5.dom.offsetWidth/offsetHeight
这个就没什么好说的了,最常用的,也是兼容最好的。
7、float引起的问题和解决方案
float:定义元素在哪个方向浮动。浮动元素会生成一个块级框,而不论它本身是何种元素。浮动的元素可以向左或向右移动,直到他的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在文档的普通流中,所以文档普通流的块级元素表现得就像浮动元素不存在一样。但是块级元素中的文本内容会漂浮到移动元素的正下面。
引起的问题:
1、父元素的高度无法被撑开,影响与父元素同级的元素。
2、与浮动元素同级的非浮动元素(行内元素)会跟随其后。
3、若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构。
解决方案:
1、额外标签法。(使元素两边都没有浮动元素)可以解决问题2、3。(缺点:不过这个办法会增加额外的标签使HTML结构看起来不够简洁。)
#test1{
float: left;
width: 100px;
height: 100px;
background: red;
}
我是span元素
复制代码
效果如下所示:(span)行内标签将另起一行
2、使用after伪类,该方法只适用于非IE浏览器,可以解决问题1。该方法中必须为需要清除浮动元素的伪对象中设置height:0,否则该元素会比实际高出若干像素;
#test1{
float: left;
width: 100px;
height: 100px;
background: red;
}
#parent:after {
content: ".";
height: 0;
visibility: hidden;
display: block;
clear: both;
}
#test2{
width: 100px;
height: 100px;
background: blue;
}
我是span标签
我是块级元素
复制代码
不给父元素添加after伪类时的效果如下所示:行内元素(span)紧挨着浮动元素、块级元素位于浮动元素之下。
效果如下所示:父元素同级的元素(span div#test2)将都另起一行。
3、浮动外部元素。
4、给包含浮动元素的父标签添加css属性 overflow:auto/hidden; zoom:1; zoom:1用于兼容IE6。
#test1{
float: left;
width: 100px;
height: 100px;
background: red;
}
#parent {
overflow: hidden;
zoom: 1;
}
#test2{
width: 100px;
height: 100px;
background: blue;
}
我是span标签
我是块级元素
复制代码
效果如下所示:父元素同级的元素(span div#test2)将都另起一行。
8、display:none和visibility:hidden的区别
display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。
visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。
#test1{
width: 100px;
height: 100px;
background: red;
display: none;
}
#test2{
width: 100px;
height: 100px;
background: red;
visibility: hidden;
}
我是span元素1
我是span元素2
复制代码
效果如下所示:
9、cookie 和session 的区别
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗。考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用cookie。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:将登陆信息等重要信息存放为session ,其他信息如果需要保留,可以放在cookie中。
10、IE 与其他浏览器区别
特性 | IE | 其他浏览器 |
---|---|---|
获取样式 | dom.currentStyle.width/height | window.getComputStyle(dom).width/width |
滤镜方面 | filter:alpha(opacity= num) | -moz-opacity:num、opacity:num等 |
添加事件 | attachEvent | addEventListener |
鼠标位置 | event.clientX | event.pageX |
事件目标 | event.srcElement | event.target |
CSS圆角 | ie7以下不支持圆角 | 支持 |
11、ajax
11.1、创建ajax的步骤
1、创建
XMLHttpRequest
对象,也就是创建一个异步调用对象。 2、创建一个新的HTTP
请求,并指定该HTTP
请求的方法、URL
及是否异步。
3、设置响应HTTP
请求状态变化的函数。通过检测readState属性的值,判断当前请求或相应过程的当前活动阶段,readState有以下几个值:
0:未初始化。尚未调用open()方法。
1:启动。已经调用open()方法,但尚未调用send()方法。
2:发送。已经调用send()方法,但尚未收到响应。
3:接收。已经接收到部分响应数据。
4:完成。已经接收到全部响应数据。
复制代码
4、发送
HTTP
请求。
5、获取异步调用返回的数据。响应数据会自动填充xhr对象的属性。主要有以下属性。
responseText:作为响应主体被返回的文本。
responseXML:如果响应的内容类型是"text/xml"或者"application/xml",这个属性将保存着响应数据的XML DOM文档。
status:响应的HTTP状态码。
statusText:HTTP状态的说明。
复制代码
6、使用JavaScript和DOM实现局部刷新。
function loadXMLDoc()
{
var xhr;
if (window.XMLHttpRequest)
{
//IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xhr=new XMLHttpRequest();
}else{
// IE6, IE5 浏览器执行代码
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.open("GET","file.txt",true);//确保浏览器兼容性。
xhr.onreadystatechange=function(){
if (xhr.readyState==4 && xhr.status==200)
{
if(xhr.status>=200&&xhr.status<300||xhr.status==304){
document.getElementById("myDiv").innerHTML=xhr.responseText;
}
}
}
xhr.send();
}
复制代码
11.2、HTTP头部信息
xhr.setRequestHeader() 用于设置请求头部信息。接收两个参数,头部字段的名称和头部字段的值。该方法必须放在open()和send()方法之间。 xhr.getResponseHeader() 传入相应的头部字段名称,获取相应的头部信息。 xhr.getAllResponseHeader() 获取所有头部信息。
11.3、ajax的优缺点
优点
- 不需要插件支持。(原生代码)
- 优秀的用户体验。(局部刷新)
- 提高web程序的性能。(异步加载,无序等待)
- 减轻服务器和宽带的负担。(,对于大量数据可以分很多批次请求进行)
缺点
- 破坏了浏览器"前进"、"后退"按钮的正常功能。
- 安全问题:AJAX暴露了与服务器交互的细节。
- 对搜索引擎的支持比较弱。
- 破坏了程序的异常机制。
- 浏览器对xhr对象的支持不足(兼容性)。
12、从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
主要经历了以下四步:(1)当发送一个URL请求时,不管这个URL是Web页面的URL还是Web页面上每个资源的URL,浏览器都会开启一个线程来处理这个请求,同时在远程DNS服务器上启动一个DNS查询。这能使浏览器获得请求对应的IP地址。
(2) 浏览器与远程Web
服务器通过TCP
三次握手协商来建立一个TCP/IP
连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
(3)一旦TCP/IP
连接建立,浏览器会通过该连接向远程服务器发送HTTP
的GET
请求。远程服务器找到资源并使用HTTP响应返回该资源,值为200的HTTP响应状态表示一个正确的响应。
(4)此时,Web
服务器提供资源服务,客户端开始下载资源。请求返回后,便进入了我们关注的前端模块,简单来说,浏览器会解析HTML
生成DOM Tree
,其次会根据CSS生成CSS Rule Tree,而javascript
又可以根据DOM API
操作DOM
。
13、get和post的区别?
不同点 | get | post |
---|---|---|
目的 | 信息获取 | 修改服务器上的资源 |
字节限制 | 2kb左右 | 理论上没有限制 |
传值方式 | 通过地址栏来传值 | 通过提交表单来传值 |
安全性 | 缓存导致安全性差 | 安全性好 |
服务器获取方式 | Request.QueryString来取得变量的值 |
然而,在以下情况中,请使用 POST 请求:
1、无法使用缓存文件(更新服务器上的文件或数据库);
2、向服务器发送大量数据(POST 没有数据量限制);
3、发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠。
14、attribute和property的区别是什么?
attribute: 是dom元素在文档中作为html标签拥有的属性,如id,class,src,title,alt等,也可以自定义属性,通过dom.setAttribute('class', 'a')来设置属性,通过dom.egtAttribute('class', 'a')来获取属性;
property: 就是dom元素在js中作为对象拥有的属性。 赋值dom.className = 'a';取值dom.className;
区别:
相同: 对于html的标准属性来说,attribute和property是同步的,是会自动更新的。
不同: 但是对于自定义的属性来说,他们是不同步的。
请看下面例子。
测试数据
window.onload=function(){
var dom=document.getElementById("test");
var addBtn=document.getElementById("add");
var delBtn=document.getElementById("delete")
addBtn.onclick=function(){
dom.setAttribute("class","name");
};
delBtn.onclick=function(){
dom.className="";
}
}
复制代码
操作标准属性(没添加属性之前————>添加属性之后————>删除属性之后)修改成功
操作自定义属性(没添加属性之前————>添加属性之后————>删除属性之后) 没修改成功
15、浅拷贝和深拷贝的区别
在说拷贝之前需要说一下赋值的问题。
基本类型赋值: 赋值之后两个变量互不干扰。
引用类型赋值: 复制的是指针,两个对象指同一个内存地址,所有互相影响。
15.1 浅拷贝
有以下两个特点:
1、重新在堆中开辟内存,拷贝前后对象的基本数据类型互不影响。
2、只拷贝一层,不能对对象中的子对象进行拷贝,子对象还会互相影响(复制)。
var person={
name:"李明",
age:40,
arr:[1,2,3,4]
}
function shallowCopy(objData){
var obj={};
for(var prop in objData){//按字母大小升序排序循环
if(objData.hasOwnProperty(prop)){
obj[prop]=objData[prop]
}
}
return obj;
}
var sCopyData=shallowCopy(person);
sCopyData["name"]="张三";
sCopyData["arr"][0]=23;
console.log(sCopyData);
console.log(person);
复制代码
输出结果如下:
分析:可以看出修改拷贝后对象的name属性,没有改变原来对象的name属性。改变拷贝后对象的arr属性后,拷贝前对象的arr属性也改变了。这是因为name属性对应的值是你基本数据类型,所以互不影响。而arr对应的属性是数组是引用类型,拷贝前后对象的arr属性指向的还是同一个内存地址。所以互相影响。
15.2 深拷贝
有以下两个特点:
- 在堆中开辟空间,拷贝前后的两个对象互不影响。
- 不止拷贝一层,对对象中的子对象进行递归拷贝。
window.onload=function(){
var person={
name:"李明",
age:40,
arr:[1,2,3,4]
}
function deepCopy(objData,obj){
obj = obj||{};
for(var prop in objData){
if(typeof objData[prop] === 'object'){
//要考虑深复制问题了
if(Object.prototype.toString.call(objData[prop]) == "[object Array]"){
//这是数组
obj[prop] =[];
}else{
//这是对象
obj[prop] = {};
}
deepCopy(objData[prop],obj[prop]);
}else{
obj[prop] = objData[prop];
}
}
return obj;
}
var sCopyData=deepCopy(person);
sCopyData["name"]="张三";
sCopyData["arr"][0]=23;
console.log(sCopyData);
console.log(person);
}
复制代码
输出结果如下所示:
从输出结果可以看出,name属性和arr属性都改变了,但是拷贝前后对象互不影响。
16、变量声明提升
变量提升是将变量声明提升到它所在作用域的最开始的部分。
//代码1
var t = 1;
function a(){
console.log(t);
var t=2;
}
a();//undefined;
复制代码
这是因为函数里的变量t声明提升到函数最开始的部分了。上面的代码1相当于代码2:
//代码2
var t = 1;
function a(){
var t;
console.log(t);
t=2;
}
a();//undefined;
复制代码
在函数内部,如果没有用var进行申明,则创建的变量是全局变量,而不是局部变量了。所以,建议变量声明加上var关键字。
//代码3
var t = 1;
function a(){
console.log(t)//undefined
t=4;
console.log(t);//4
var t=2;
console.log(t);//2
}
a();
复制代码
function声明会比var声明优先级更高一点。
//代码4
console.log(foo);
var foo=10;
console.log(foo);
function foo(){
console.log(10);
}
console.log(foo);
复制代码
相当于下面的代码:
function foo(){
console.log(10);
}
var foo;
console.log(foo);
foo=10;
console.log(foo);
console.log(foo);
复制代码
运行结果如下:
代码5
function foo(){
console.log(a);//2
}
function bar(){
var a=3;
foo();
}
var a=2;
bar();
复制代码
上面的代码的运行过程是bar()-->foo(),此时的a由于在调用bar()之前已经初始化了,所以相当于给在foo()函数的所在作用域中的this对象添加了a属性,并赋值为2,所以调用foo()函数的a时,实际上调用的foo()所在作用域的this的a属性。