网站建设的维护工作有哪些,网站页面文案,三五互联网站建设,手机制作软件下载BFC、IFC、GFC、FFC CSS2.1中只有BFC和IFC, CSS3中才有GFC和FFC。 到底什么是BFC、IFC、GFC和FFC Whats FC#xff1f; 一定不是KFC#xff0c;FC的全称是#xff1a;Formatting Contexts#xff0c;是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域#xff0c;并… BFC、IFC、GFC、FFC CSS2.1中只有BFC和IFC, CSS3中才有GFC和FFC。 到底什么是BFC、IFC、GFC和FFC Whats FC 一定不是KFCFC的全称是Formatting Contexts是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域并且有一套渲染规则它决定了其子元素将如何定位以及和其他元素的关系和相互作用。 BFC BFC(Block Formatting Contexts)直译为块级格式化上下文。Block Formatting Contexts就是页面上的一个隔离的渲染区域容器里面的子元素不会在布局上影响到外面的元素反之也是如此。如何产生BFC float的值不为none。 overflow的值不为visible。 position的值不为relative和static。 display的值为table-cell, table-caption, inline-block中的任何一个。 那BFC一般有什么用呢比如常见的多栏布局结合块级别元素浮动里面的元素则是在一个相对隔离的环境里运行。 IFC IFC(Inline Formatting Contexts)直译为内联格式化上下文IFC的line box线框高度由其包含行内元素中最高的实际高度计算而来不受到竖直方向的padding/margin影响) IFC中的line box一般左右都贴紧整个IFC但是会因为float元素而扰乱。float元素会位于IFC与与line box之间使得line box宽度缩短。 同个ifc下的多个line box高度会不同。 IFC中时不可能有块级元素的当插入块级元素时如p中插入div会产生两个匿名块与div分隔开即产生两个IFC每个IFC对外表现为块级元素与div垂直排列。 那么IFC一般有什么用呢 水平居中当一个块要在环境中水平居中时设置其为inline-block则会在外层产生IFC通过text-align则可以使其水平居中。 垂直居中创建一个IFC用其中一个元素撑开父元素的高度然后设置其vertical-align:middle其他行内元素则可以在此父元素下垂直居中。 GFC GFC(GridLayout Formatting Contexts)直译为网格布局格式化上下文当为一个元素设置display值为grid的时候此元素将会获得一个独立的渲染区域我们可以通过在网格容器grid container上定义网格定义行grid definition rows和网格定义列grid definition columns属性各在网格项目grid item上定义网格行grid row和网格列grid columns为每一个网格项目grid item定义位置和空间。 那么GFC有什么用呢和table又有什么区别呢首先同样是一个二维的表格但GridLayout会有更加丰富的属性来控制行列控制对齐以及更为精细的渲染语义和控制。 FFC FFC(Flex Formatting Contexts)直译为自适应格式化上下文display值为flex或者inline-flex的元素将会生成自适应容器flex container可惜这个牛逼的属性只有谷歌和火狐支持不过在移动端也足够了至少safari和chrome还是OK的毕竟这俩在移动端才是王道。 Flex Box 由伸缩容器和伸缩项目组成。通过设置元素的 display 属性为 flex 或 inline-flex 可以得到一个伸缩容器。设置为 flex 的容器被渲染为一个块级元素而设置为 inline-flex 的容器则渲染为一个行内元素。 伸缩容器中的每一个子元素都是一个伸缩项目。伸缩项目可以是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说Flexbox 定义了伸缩容器内伸缩项目该如何布局。 div水平垂直居中的方法 在平时我们经常会碰到让一个div框针对某个模块上下左右都居中水平垂直居中其实针对这种情况我们有多种方法实现。 方法一: 绝对定位方法不确定当前div的宽度和高度采用 transform: translate(-50%,-50%); 当前div的父级添加相对定位position: relative; 图片展示 img 代码如下 div{background:red;position: absolute;left:50%;top:50%;transform: translate(-50%, -50%);
}方法二: 绝对定位方法确定了当前div的宽度margin值为当前div宽度一半的负值 图片展示 如方法一的图片展示 代码如下 div{width:600px;height: 600px;background:red;position: absolute;left:50%;top:50%;margin-left:-300px;margin-top:-300px;
}方法三 绝对定位方法绝对定位下top left right bottom 都设置0 图片展示 如方法一的图片展示 代码如下 div.child{width: 600px;height: 600px;background: red;position:absolute;left:0;top: 0;bottom: 0;right: 0;margin: auto;
}方法四: flex布局方法当前div的父级添加flex css样式 展示图如下 img 代码如下 .box{height:800px;-webkit-display:flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;border:1px solid #ccc;
}
div.child{width:600px;height:600px;background-color:red;
}方法五: table-cell实现水平垂直居中: table-cell middle center组合使用 展示图如下 img 代码如下 .table-cell {display: table-cell;vertical-align: middle;text-align: center;width: 240px;height: 180px;border:1px solid #666;
}方法六: 绝对定位calc() 函数动态计算实现水平垂直居中 展示图如下 img 代码如下 .calc{position: relative;border: 1px solid #ccc;width: 400px;height: 160px;
}
.calc .child{position: absolute;width: 200px;height: 50px;left:-webkit-calc((400px - 200px)/2);top:-webkit-calc((160px - 50px)/2);left:-moz-calc((400px - 200px)/2);top:-moz-calc((160px - 50px)/2);left:calc((400px - 200px)/2);top:calc((160px - 50px)/2);
} display: none; DOM 结构浏览器不会渲染 display 属性为 none 的元素不占据空间事件监听无法进行 DOM 事件监听性能动态改变此属性时会引起重排性能较差继承不会被子元素继承毕竟子类也不会被渲染transitiontransition 不支持 display。 visibility: hidden; DOM 结构元素被隐藏但是会被渲染不会消失占据空间事件监听无法进行 DOM 事件监听性 能动态改变此属性时会引起重绘性能较高继 承会被子元素继承子元素可以通过设置 visibility: visible; 来取消隐藏transitionvisibility 会立即显示隐藏时会延时 opacity: 0; DOM 结构透明度为 100%元素隐藏占据空间事件监听可以进行 DOM 事件监听性 能提升为合成层不会触发重绘性能较高继 承会被子元素继承,且子元素并不能通过 opacity: 1 来取消隐藏transitionopacity 可以延时显示和隐藏 在不改变当前代码的情况下使这张图片的宽度为300px? img src1.jpg stylewidth:480px!important/1.css方法 img src1.jpg stylewidth:480px!important; max-width: 300px
img src1.jpg stylewidth:480px!important; transform: scale(0.625, 1);
img src1.jpg stylewidth:480px!important; width:300px!important;2.js方法 document.getElementsByTagName(img)[0].setAttribute(style,width:300px!important;)7 种方法解决移动端 Retina 屏幕 1px 边框问题 造成边框变粗的原因 其实这个原因很简单因为css中的1px并不等于移动设备的1px这些由于不同的手机有不同的像素密度。在window对象中有一个devicePixelRatio属性他可以反应css中的像素与设备的像素比。 devicePixelRatio的官方的定义为设备物理像素和设备独立像素的比例也就是 devicePixelRatio 物理像素 / 独立像素。 解决边框变粗的6种办法 1、0.5px边框 在2014年的 WWDC“设计响应的Web体验” 一讲中Ted O’Connor 讲到关于“retinahairlines”retina 极细的线在retina屏上仅仅显示1物理像素的边框开发者应该如何处理呢。 他们曾介绍到 iOS 8 和 OS X Yosemite 即将支持 0.5px 的边框 [图片上传失败...(image-6431d2-1597762908407)] 0.5px边框 额的神呐so easy! 果真如此吗这样还不够WWDC幻灯片通常是“唬人”的但是相差不多。 问题是 retina 屏的浏览器可能不认识0.5px的边框将会把它解释成0px没有边框。包括 iOS 7 和之前版本OS X Mavericks 及以前版本还有 Android 设备。 解决方案 解决方案是通过 JavaScript 检测浏览器能否处理0.5px的边框如果可以给html标签元素添加个class。 if (window.devicePixelRatio devicePixelRatio 2) {
var testElem document.createElement(div);
testElem.style.border .5px solid transparent;
document.body.appendChild(testElem);
if (testElem.offsetHeight 1) {
document.querySelector(html).classList.add(hairlines);
}
document.body.removeChild(testElem);
}
// 脚本应该放在内如果在里面运行需要包装 $(document).ready(function() {})然后极细的边框样式就容易了 div {
border: 1px solid #bbb;
}
.hairlines div {
border-width: 0.5px;
}2、使用border-image实现 准备一张符合你要求的border-image [图片上传失败...(image-b220f2-1597762908407)] 底部边框 样式设置 .border-bottom-1px {
border-width: 0 0 1px 0;
-webkit-border-image: url(linenew.png) 0 0 2 0 stretch;
border-image: url(linenew.png) 0 0 2 0 stretch;
}上文是把border设置在边框的底部所以使用的图片是2px高上部的1px颜色为透明下部的1px使用视觉规定的border的颜色。如果边框底部和顶部同时需要border可以使用下面的border-image [图片上传失败...(image-d6c12a-1597762908407)] 上下边框 样式设置 .border-image-1px {
border-width: 1px 0;
-webkit-border-image: url(linenew.png) 2 0 stretch;
border-image: url(linenew.png) 2 0 stretch;
}到目前为止我们已经能在iphone上展现1px border的效果了。但是我们发现这样的方法在非视网膜屏上会出现border显示不出来的现象于是使用Media Query做了一些兼容样式设置如下 .border-image-1px {
border-bottom: 1px solid #666;
}
media only screen and (-webkit-min-device-pixel-ratio: 2) {
.border-image-1px {
border-bottom: none;
border-width: 0 0 1px 0;
-webkit-border-image: url(../img/linenew.png) 0 0 2 0 stretch;
border-image: url(../img/linenew.png) 0 0 2 0 stretch;
}
}缺点 修改颜色麻烦, 需要替换图片圆角需要特殊处理并且边缘会模糊 3、使用background-image实现 background-image 跟border-image的方法一样你要先准备一张符合你要求的图片。然后将边框模拟在背景上。 样式设置 .background-image-1px {
background: url(../img/line.png) repeat-x left bottom;
-webkit-background-size: 100% 1px;
background-size: 100% 1px;
}优点 缺点 修改颜色麻烦, 需要替换图片圆角需要特殊处理并且边缘会模糊 4、多背景渐变实现 与background-image方案类似只是将图片替换为css3渐变。设置1px的渐变背景50%有颜色50%透明。 样式设置 .background-gradient-1px {
background:
linear-gradient(180deg, black, black 50%, transparent 50%) top left / 100% 1px no-repeat,
linear-gradient(90deg, black, black 50%, transparent 50%) top right / 1px 100% no-repeat,
linear-gradient(0, black, black 50%, transparent 50%) bottom right / 100% 1px no-repeat,
linear-gradient(-90deg, black, black 50%, transparent 50%) bottom left / 1px 100% no-repeat;
}
/* 或者 */
.background-gradient-1px{
background: -webkit-gradient(linear, left top, left bottom, color-stop(.5, transparent), color-stop(.5, #c8c7cc), to(#c8c7cc)) left bottom repeat-x;
background-size: 100% 1px;
}5、使用box-shadow模拟边框 利用css 对阴影处理的方式实现0.5px的效果 样式设置 .box-shadow-1px {
box-shadow: inset 0px -1px 1px -1px #c8c7cc;
}优点 缺点 6、viewport rem 实现 同时通过设置对应viewport的rem基准值这种方式就可以像以前一样轻松愉快的写1px了。 在devicePixelRatio 2 时输出viewport 在devicePixelRatio 3 时输出viewport
html这种兼容方案相对比较完美适合新的项目老的项目修改成本过大。 对于这种方案可以看看《使用Flexible实现手淘H5页面的终端适配》 优点 缺点 7、伪类 transform 实现 对于老项目有没有什么办法能兼容1px的尴尬问题了个人认为伪类transform是比较完美的方法了。原理是把原先元素的 border 去掉然后利用 :before 或者 :after 重做 border 并 transform 的 scale 缩小一半原先的元素相对定位新做的 border 绝对定位。 单条border样式设置 .scale-1px{
position: relative;
border:none;
}
.scale-1px:after{
content: ;
position: absolute;
bottom: 0;
background: #000;
width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}四条boder样式设置: .scale-1px{
position: relative;
margin-bottom: 20px;
border:none;
}
.scale-1px:after{
content: ;
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}最好在使用前也判断一下结合 JS 代码判断是否 Retina 屏 if(window.devicePixelRatio devicePixelRatio 2){
document.querySelector(ul).className scale-1px;
}优点 所有场景都能满足支持圆角(伪类和本体类都需要加border-radius) 缺点 对于已经使用伪类的元素(例如clearfix)可能需要多层嵌套 [1, 2, 3].map(parseInt) what why ? 早在 2013年, 有人在微博上发布了以下代码段: [10,10,10,10,10].map(parseInt);
// [10, NaN, 2, 3, 4]parseInt parseInt() 函数解析一个字符串参数并返回一个指定基数的整数 (数学系统的基础)。 const intValue parseInt(string[, radix]);string 要被解析的值。如果参数不是一个字符串则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。 radix 一个介于2和36之间的整数(数学系统的基础)表示上述字符串的基数。默认为10。 返回值 返回一个整数或NaN parseInt(100); // 100
parseInt(100, 10); // 100
parseInt(100, 2); // 4 - converts 100 in base 2 to base 10注意 在radix为 undefined或者radix为 0 或者没有指定的情况下JavaScript 作如下处理 如果字符串 string 以0x或者0X开头, 则基数是16 (16进制).如果字符串 string 以0开头, 基数是8八进制或者10十进制那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10但是并不是所有的浏览器都遵循这个规定。因此永远都要明确给出radix参数的值。如果字符串 string 以其它任何值开头则基数是10 (十进制)。 更多详见parseInt | MDN map map() 方法创建一个新数组其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。 var new_array arr.map(function callback(currentValue[,index[, array]]) {// Return element for new_array}[, thisArg])可以看到callback回调函数需要三个参数, 我们通常只使用第一个参数 (其他两个参数是可选的)。 currentValue 是callback 数组中正在处理的当前元素。 index可选, 是callback 数组中正在处理的当前元素的索引。 array可选, 是callback map 方法被调用的数组。 另外还有thisArg可选, 执行 callback 函数时使用的this 值。 const arr [1, 2, 3];
arr.map((num) num 1); // [2, 3, 4]更多详见Array.prototype.map() | MDN 回到真实的事例上 回到我们真实的事例上 [1, 2, 3].map(parseInt)对于每个迭代map, parseInt()传递两个参数: 字符串和基数。 所以实际执行的的代码是 [1, 2, 3].map((item, index) {return parseInt(item, index)
})即返回的值分别为 parseInt(1, 0) // 1
parseInt(2, 1) // NaN
parseInt(3, 2) // NaN, 3 不是二进制所以 [1, 2, 3].map(parseInt)
// 1, NaN, NaN由此加里·伯恩哈德例子也就很好解释了这里不再赘述 [10,10,10,10,10].map(parseInt);
// [10, NaN, 2, 3, 4]如何在现实世界中做到这一点 如果您实际上想要循环访问字符串数组, 该怎么办 map()然后把它换成数字使用编号! [10,10,10,10,10].map(Number);
// [10, 10, 10, 10, 10]作者解答 概念以第二个参数为基数来解析第一个参数字符串通常用来做十进制的向上取整。 特点接收两个参数parseInt(string,radix) radix解析字符串的基数基数规则如下 1 区间范围介于2~36之间 2 当参数为 0parseInt() 会根据十进制来解析 3 如果忽略该参数默认的基数规则 parseInt(10,0);radix 为 0parseInt() 会根据十进制来解析所以结果为 10 parseInt(10,1);radix 为 1超出区间范围所以结果为 NaN parseInt(10,2);radix 为 2用2进制来解析1乘以2的1次方0乘以2的0次方所以结果是2 parseInt(10,3);radix 为 3用3进制来解析1乘以3的1次方0乘以3的0次方所以结果是3 parseInt(10,4);radix 为 4用4进制来解析1乘以4的1次方0乘以4的0次方所以结果是4 函数节流与函数防抖 什么是函数节流与函数防抖 举个栗子我们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时在人眼的视觉中就会形成一个连贯的动画所以在电影的播放以前是现在不知道中基本是以每秒 24 张的速度播放的为什么不 100 张或更多是因为 24 张就可以满足人类视觉需求的时候100 张就会显得很浪费资源。 再举个栗子假设电梯一次只能载一人的话10 个人要上楼的话电梯就得走 10 次是一种浪费资源的行为而实际生活正显然不是这样的当电梯里有人准备上楼的时候如果外面又有人按电梯的话电梯会再次打开直到满载位置从电梯的角度来说这时一种节约资源的行为相对于一次只能载一个人。 函数节流: 指定时间间隔内只会执行一次任务函数防抖: 任务频繁触发的情况下只有任务触发的间隔超过指定间隔的时候任务才会执行。 函数节流(throttle) 这里以判断页面是否滚动到底部为例普通的做法就是监听 window 对象的 scroll 事件然后再函数体中写入判断是否滚动到底部的逻辑 $(window).on(scroll, function () {// 判断是否滚动到底部的逻辑let pageHeight $(body).height(),scrollTop $(window).scrollTop(),winHeight $(window).height(),thresold pageHeight - scrollTop - winHeight;if (thresold -100 thresold 20) {console.log(end);}
});这样做的一个缺点就是比较消耗性能因为当在滚动的时候浏览器会无时不刻地在计算判断是否滚动到底部的逻辑而在实际的场景中是不需要这么做的在实际场景中可能是这样的在滚动过程中每隔一段时间在去计算这个判断逻辑。而函数节流所做的工作就是每隔一段时间去执行一次原本需要无时不刻地在执行的函数所以在滚动事件中引入函数的节流是一个非常好的实践 $(window).on(scroll, throttle(function () {// 判断是否滚动到底部的逻辑let pageHeight $(body).height(),scrollTop $(window).scrollTop(),winHeight $(window).height(),thresold pageHeight - scrollTop - winHeight;if (thresold -100 thresold 20) {console.log(end);}
}));加上函数节流之后当页面再滚动的时候每隔 300ms 才会去执行一次判断逻辑。 简单来说函数的节流就是通过闭包保存一个标记canRun true在函数的开头判断这个标记是否为 true如果为 true 的话就继续执行函数否则则 return 掉判断完标记后立即把这个标记设为 false然后把外部传入的函数的执行包在一个 setTimeout 中最后在 setTimeout 执行完毕后再把标记设置为 true这里很关键表示可以执行下一次的循环了。当 setTimeout 还未执行的时候canRun 这个标记始终为 false在开头的判断中被 return 掉。 function throttle(fn, interval 300) {let canRun true;return function () {if (!canRun) return;canRun false;setTimeout(() {fn.apply(this, arguments);canRun true;}, interval);};
}函数防抖(debounce) 这里以用户注册时验证用户名是否被占用为例如今很多网站为了提高用户体验不会再输入框失去焦点的时候再去判断用户名是否被占用而是在输入的时候就在判断这个用户名是否已被注册 $(input.user-name).on(input, function () {$.ajax({url: https://just.com/check,method: post,data: {username: $(this).val(),},success(data) {if (data.isRegistered) {$(.tips).text(该用户名已被注册);} else {$(.tips).text(恭喜该用户名还未被注册);}},error(error) {console.log(error);},});
});很明显这样的做法不好的是当用户输入第一个字符的时候就开始请求判断了不仅对服务器的压力增大了对用户体验也未必比原来的好。而理想的做法应该是这样的当用户输入第一个字符后的一段时间内如果还有字符输入的话那就暂时不去请求判断用户名是否被占用。在这里引入函数防抖就能很好地解决这个问题 $(input.user-name).on(input, debounce(function () {$.ajax({url: https://just.com/check,method: post,data: {username: $(this).val(),},success(data) {if (data.isRegistered) {$(.tips).text(该用户名已被注册);} else {$(.tips).text(恭喜该用户名还未被注册);}},error(error) {console.log(error);},});
}));其实函数防抖的原理也非常地简单通过闭包保存一个标记来保存 setTimeout 返回的值每当用户输入的时候把前一个 setTimeout clear 掉然后又创建一个新的 setTimeout这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话就不会执行 fn 函数了。 function debounce(fn, interval 300) {let timeout null;return function () {clearTimeout(timeout);timeout setTimeout(() {fn.apply(this, arguments);}, interval);};
}总结 其实函数节流与函数防抖的原理非常简单巧妙地使用 setTimeout 来存放待执行的函数这样可以很方便的利用 clearTimeout 在合适的时机来清除待执行的函数。 使用函数节流与函数防抖的目的在开头的栗子中应该也能看得出来就是为了节约计算机资源。 Set 和 Map 主要的应用场景在于 数据重组 和 数据储存 Set 是一种叫做集合的数据结构Map 是一种叫做字典的数据结构 1. 集合Set ES6 新增的一种新的数据结构类似于数组但成员是唯一且无序的没有重复的值。 Set 本身是一种构造函数用来生成 Set 数据结构。 new Set([iterable])举个例子 const s new Set()
[1, 2, 3, 4, 3, 2, 1].forEach(x s.add(x))for (let i of s) {console.log(i) // 1 2 3 4
}// 去重数组的重复对象
let arr [1, 2, 3, 2, 1, 1]
[... new Set(arr)] // [1, 2, 3]Set 对象允许你储存任何类型的唯一值无论是原始值或者是对象引用。 向 Set 加入值的时候不会发生类型转换所以5和5是两个不同的值。Set 内部判断两个值是否不同使用的算法叫做“Same-value-zero equality”它类似于精确相等运算符主要的区别是NaN等于自身而精确相等运算符认为NaN不等于自身。 let set new Set();
let a NaN;
let b NaN;
set.add(a);
set.add(b);
set // Set {NaN}let set1 new Set()
set1.add(5)
set1.add(5)
console.log([...set1]) // [5, 5]Set 实例属性 constructor 构造函数 size元素数量 let set new Set([1, 2, 3, 2, 1])console.log(set.length) // undefined
console.log(set.size) // 3Set 实例方法 操作方法 add(value)新增相当于 array里的pushdelete(value)存在即删除集合中valuehas(value)判断集合中是否存在 value clear()清空集合 let set new Set()
set.add(1).add(2).add(1)set.has(1) // true
set.has(3) // false
set.delete(1)
set.has(1) // falseArray.from 方法可以将 Set 结构转为数组 const items new Set([1, 2, 3, 2])
const array Array.from(items)
console.log(array) // [1, 2, 3]
// 或
const arr [...items]
console.log(arr) // [1, 2, 3]遍历方法遍历顺序为插入顺序 keys()返回一个包含集合中所有键的迭代器values()返回一个包含集合中所有值得迭代器entries()返回一个包含Set对象中所有元素得键值对迭代器 forEach(callbackFn, thisArg)用于对集合成员执行callbackFn操作如果提供了 thisArg 参数回调中的this会是这个参数没有返回值 let set new Set([1, 2, 3])
console.log(set.keys()) // SetIterator {1, 2, 3}
console.log(set.values()) // SetIterator {1, 2, 3}
console.log(set.entries()) // SetIterator {1, 2, 3}for (let item of set.keys()) {console.log(item);
} // 1 2 3
for (let item of set.entries()) {console.log(item);
} // [1, 1] [2, 2] [3, 3]set.forEach((value, key) {console.log(key : value)
}) // 1 : 1 2 : 2 3 : 3
console.log([...set]) // [1, 2, 3]Set 可默认遍历默认迭代器生成函数是 values() 方法 Set.prototype[Symbol.iterator] Set.prototype.values // true所以 Set可以使用 map、filter 方法 let set new Set([1, 2, 3])
set new Set([...set].map(item item * 2))
console.log([...set]) // [2, 4, 6]set new Set([...set].filter(item (item 4)))
console.log([...set]) //[4, 6]因此Set 很容易实现交集Intersect、并集Union、差集Difference let set1 new Set([1, 2, 3])
let set2 new Set([4, 3, 2])let intersect new Set([...set1].filter(value set2.has(value)))
let union new Set([...set1, ...set2])
let difference new Set([...set1].filter(value !set2.has(value)))console.log(intersect) // Set {2, 3}
console.log(union) // Set {1, 2, 3, 4}
console.log(difference) // Set {1}2. WeakSet WeakSet 对象允许你将弱引用对象储存在一个集合中 WeakSet 与 Set 的区别 WeakSet 只能储存对象引用不能存放值而 Set 对象都可以WeakSet 对象中储存的对象值都是被弱引用的即垃圾回收机制不考虑 WeakSet 对该对象的应用如果没有其他的变量或属性引用这个对象值则这个对象将会被垃圾回收掉不考虑该对象还存在于 WeakSet 中所以WeakSet 对象里有多少个成员元素取决于垃圾回收机制有没有运行运行前后成员个数可能不一致遍历结束之后有的成员可能取不到了被垃圾回收了WeakSet 对象是无法被遍历的ES6 规定 WeakSet 不可遍历也没有办法拿到它包含的所有元素 属性 constructor构造函数任何一个具有 Iterable 接口的对象都可以作参数 const arr [[1, 2], [3, 4]]
const weakset new WeakSet(arr)
console.log(weakset)方法 add(value)在WeakSet 对象中添加一个元素valuehas(value)判断 WeakSet 对象中是否包含valuedelete(value)删除元素 valueclear()清空所有元素注意该方法已废弃 var ws new WeakSet()
var obj {}
var foo {}ws.add(window)
ws.add(obj)ws.has(window) // true
ws.has(foo) // falsews.delete(window) // true
ws.has(window) // false3. 字典Map 集合 与 字典 的区别 共同点集合、字典 可以储存不重复的值不同点集合 是以 [value, value]的形式储存元素字典 是以 [key, value] 的形式储存 const m new Map()
const o {p: haha}
m.set(o, content)
m.get(o) // contentm.has(o) // true
m.delete(o) // true
m.has(o) // false任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数例如 const set new Set([[foo, 1],[bar, 2]
]);
const m1 new Map(set);
m1.get(foo) // 1const m2 new Map([[baz, 3]]);
const m3 new Map(m2);
m3.get(baz) // 3如果读取一个未知的键则返回undefined。 new Map().get(asfddfsasadf)
// undefined注意只有对同一个对象的引用Map 结构才将其视为同一个键。这一点要非常小心。 const map new Map();map.set([a], 555);
map.get([a]) // undefined上面代码的set和get方法表面是针对同一个键但实际上这是两个值内存地址是不一样的因此get方法无法读取该键返回undefined。 由上可知Map 的键实际上是跟内存地址绑定的只要内存地址不一样就视为两个键。这就解决了同名属性碰撞clash的问题我们扩展别人的库的时候如果使用对象作为键名就不用担心自己的属性与原作者的属性同名。 如果 Map 的键是一个简单类型的值数字、字符串、布尔值则只要两个值严格相等Map 将其视为一个键比如0和-0就是一个键布尔值true和字符串true则是两个不同的键。另外undefined和null也是两个不同的键。虽然NaN不严格相等于自身但 Map 将其视为同一个键。 let map new Map();map.set(-0, 123);
map.get(0) // 123map.set(true, 1);
map.set(true, 2);
map.get(true) // 1map.set(undefined, 3);
map.set(null, 4);
map.get(undefined) // 3map.set(NaN, 123);
map.get(NaN) // 123Map 的属性及方法 属性 constructor构造函数 size返回字典中所包含的元素个数 const map new Map([[name, An],[des, JS]
]);map.size // 2操作方法 set(key, value)向字典中添加新元素get(key)通过键查找特定的数值并返回has(key)判断字典中是否存在键keydelete(key)通过键 key 从字典中移除对应的数据clear()将这个字典中的所有元素删除 遍历方法 Keys()将字典中包含的所有键名以迭代器形式返回values()将字典中包含的所有数值以迭代器形式返回entries()返回所有成员的迭代器forEach()遍历字典的所有成员 const map new Map([[name, An],[des, JS]]);
console.log(map.entries()) // MapIterator {name An, des JS}
console.log(map.keys()) // MapIterator {name, des}Map 结构的默认遍历器接口Symbol.iterator属性就是entries方法。 map[Symbol.iterator] map.entries
// trueMap 结构转为数组结构比较快速的方法是使用扩展运算符...。 对于 forEach 看一个例子 const reporter {report: function(key, value) {console.log(Key: %s, Value: %s, key, value);}
};let map new Map([[name, An],[des, JS]
])
map.forEach(function(value, key, map) {this.report(key, value);
}, reporter);
// Key: name, Value: An
// Key: des, Value: JS在这个例子中 forEach 方法的回调函数的 this就指向 reporter 与其他数据结构的相互转换 Map 转 Array const map new Map([[1, 1], [2, 2], [3, 3]])
console.log([...map]) // [[1, 1], [2, 2], [3, 3]]Array 转 Map const map new Map([[1, 1], [2, 2], [3, 3]])
console.log(map) // Map {1 1, 2 2, 3 3}Map 转 Object 因为 Object 的键名都为字符串而Map 的键名为对象所以转换的时候会把非字符串键名转换为字符串键名。 function mapToObj(map) {let obj Object.create(null)for (let [key, value] of map) {obj[key] value}return obj
}
const map new Map().set(name, An).set(des, JS)
mapToObj(map) // {name: An, des: JS}Object 转 Map function objToMap(obj) {let map new Map()for (let key of Object.keys(obj)) {map.set(key, obj[key])}return map
}objToMap({name: An, des: JS}) // Map {name An, des JS}Map 转 JSON function mapToJson(map) {return JSON.stringify([...map])
}let map new Map().set(name, An).set(des, JS)
mapToJson(map) // [[name,An],[des,JS]]JSON 转 Map function jsonToStrMap(jsonStr) {return objToMap(JSON.parse(jsonStr));
}jsonToStrMap({name: An, des: JS}) // Map {name An, des JS}4. WeakMap WeakMap 对象是一组键值对的集合其中的键是弱引用对象而值可以是任意。 注意WeakMap 弱引用的只是键名而不是键值。键值依然是正常引用。 WeakMap 中每个键对自己所引用对象的引用都是弱引用在没有其他引用和该键引用同一对象这个对象将会被垃圾回收相应的key则变成无效的所以WeakMap 的 key 是不可枚举的。 属性 constructor构造函数 方法 has(key)判断是否有 key 关联对象get(key)返回key关联对象没有则则返回 undefinedset(key)设置一组key关联对象delete(key)移除 key 的关联对象 let myElement document.getElementById(logo);
let myWeakmap new WeakMap();myWeakmap.set(myElement, {timesClicked: 0});myElement.addEventListener(click, function() {let logoData myWeakmap.get(myElement);logoData.timesClicked;
}, false);介绍下Set_Map_WeakSet和WeakMap的区别 5. 总结 Set 成员唯一、无序且不重复[value, value]键值与键名是一致的或者说只有键值没有键名可以遍历方法有add、delete、has WeakSet 成员都是对象成员都是弱引用可以被垃圾回收机制回收可以用来保存DOM节点不容易造成内存泄漏不能遍历方法有add、delete、has Map 本质上是键值对的集合类似集合可以遍历方法很多可以跟各种数据格式转换 WeakMap 只接受对象作为键名null除外不接受其他类型的值作为键名键名是弱引用键值可以是任意的键名所指向的对象可以被垃圾回收此时键名是无效的不能遍历方法有get、set、has、delete 6. 扩展Object与Set、Map Object 与 Set // Object
const properties1 {width: 1,height: 1
}
console.log(properties1[width]? true: false) // true// Set
const properties2 new Set()
properties2.add(width)
properties2.add(height)
console.log(properties2.has(width)) // trueObject 与 Map ES6 WeakMap和WeakSet的使用场景 JS 中的对象Object本质上是键值对的集合hash 结构 const data {};
const element document.getElementsByClassName(App);data[element] metadata;
console.log(data[[object HTMLCollection]]) // metadata但当以一个DOM节点作为对象 data 的键对象会被自动转化为字符串[Object HTMLCollection]所以说Object 结构提供了 字符串-值 对应Map则提供了 值-值 的对应 本 JavaScript垃圾回收是一种内存管理技术。在这种技术中不再被引用的对象会被自动删除而与其相关的资源也会被一同回收。 Map和Set中对象的引用都是强类型化的并不会允许垃圾回收。这样一来如果Map和Set中引用了不再需要的大型对象如已经从DOM树中删除的DOM元素那么其回收代价是昂贵的。 为了解决这个问题ES6还引入了另外两种新的数据结构即称为WeakMap和WeakSet的弱集合。这些集合之所以是“弱的”是因为它们允许从内存中清除不再需要的被这些集合所引用的对象。 使用场景储存 DOM 节点而不用担心这些节点从文档移除时会引发内存泄漏。 有以下 3 个判断数组的方法请分别介绍它们之间的区别和优劣 1. Object.prototype.toString.call() 每一个继承 Object 的对象都有 toString 方法如果 toString 方法没有重写的话会返回 [Object type]其中 type 为对象的类型。但当除了 Object 类型的对象外其他类型直接使用 toString 方法时会直接返回都是内容的字符串所以我们需要使用call或者apply方法来改变toString方法的执行上下文。 const an [Hello,An];
an.toString(); // Hello,An
Object.prototype.toString.call(an); // [object Array]这种方法对于所有基本的数据类型都能进行判断即使是 null 和 undefined 。 Object.prototype.toString.call(An) // [object String]
Object.prototype.toString.call(1) // [object Number]
Object.prototype.toString.call(Symbol(1)) // [object Symbol]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(function(){}) // [object Function]
Object.prototype.toString.call({name: An}) // [object Object]Object.prototype.toString.call() 常用于判断浏览器内置对象时。 更多实现可见 谈谈 Object.prototype.toString 2. instanceof instanceof 的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。 使用 instanceof判断一个对象是否为数组instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型找到返回 true否则返回 false。 [] instanceof Array; // true但 instanceof 只能用来判断对象类型原始类型不可以。并且所有对象类型 instanceof Object 都是 true。 [] instanceof Object; // true3. Array.isArray() 功能用来判断对象是否为数组 Array.isArray() 与 Object.prototype.toString.call() Array.isArray()是ES5新增的方法当不存在 Array.isArray() 可以用 Object.prototype.toString.call() 实现。 if (!Array.isArray) {Array.isArray function(arg) {return Object.prototype.toString.call(arg) [object Array];};
}ES5/ES6 的定义对象的区别 class 声明会提升但不会初始化赋值。Foo 进入暂时性死区类似于 let、const 声明变量。
const bar new Bar(); // its ok
function Bar() {this.bar 42;
}const foo new Foo(); // ReferenceError: Foo is not defined
class Foo {constructor() {this.foo 42;}
}class 声明内部会启用严格模式。 // 引用一个未声明的变量
function Bar() {baz 42; // its ok
}
const bar new Bar();class Foo {constructor() {fol 42; // ReferenceError: fol is not defined}
}
const foo new Foo();class 的所有方法包括静态方法和实例方法都是不可枚举的。 // 引用一个未声明的变量
function Bar() {this.bar 42;
}
Bar.answer function() {return 42;
};
Bar.prototype.print function() {console.log(this.bar);
};
const barKeys Object.keys(Bar); // [answer]
const barProtoKeys Object.keys(Bar.prototype); // [print]class Foo {constructor() {this.foo 42;}static answer() {return 42;}print() {console.log(this.foo);}
}
const fooKeys Object.keys(Foo); // []
const fooProtoKeys Object.keys(Foo.prototype); // []class 的所有方法包括静态方法和实例方法都没有原型对象 prototype所以也没有[[construct]]不能使用 new 来调用。 function Bar() {this.bar 42;
}
Bar.prototype.print function() {console.log(this.bar);
};const bar new Bar();
const barPrint new bar.print(); // its okclass Foo {constructor() {this.foo 42;}print() {console.log(this.foo);}
}
const foo new Foo();
const fooPrint new foo.print(); // TypeError: foo.print is not a constructor必须使用 new 调用 class。 function Bar() {this.bar 42;
}
const bar Bar(); // its okclass Foo {constructor() {this.foo 42;}
}
const foo Foo(); // TypeError: Class constructor Foo cannot be invoked without newclass 内部无法重写类名。 function Bar() {Bar Baz; // its okthis.bar 42;
}
const bar new Bar();
// Bar: Baz
// bar: Bar {bar: 42} class Foo {constructor() {this.foo 42;Foo Fol; // TypeError: Assignment to constant variable}
}
const foo new Foo();
Foo Fol; // its ok全局作用域中用 const 和 let 声明的变量不在 window 上那到底在哪里如何去获取 在ES5中顶层对象的属性和全局变量是等价的var 命令和 function 命令声明的全局变量自然也是顶层对象。 var a 12;
function f(){};console.log(window.a); // 12
console.log(window.f); // f(){}但ES6规定var 命令和 function 命令声明的全局变量依旧是顶层对象的属性但 let命令、const命令、class命令声明的全局变量不属于顶层对象的属性。 let aa 1;
const bb 2;console.log(window.aa); // undefined
console.log(window.bb); // undefined在哪里怎么获取通过在设置断点看看浏览器是怎么处理的 通过上图也可以看到在全局作用域中用 let 和 const 声明的全局变量并没有在全局对象中只是一个块级作用域Script中 怎么获取在定义变量的块级作用域中就能获取啊既然不属于顶层对象那就不加 windowglobal呗。 let aa 1;
const bb 2;console.log(aa); // 1
console.log(bb); // 2const和let会生成块级作用域可以理解为 let a 10;
const b 20;
相当于
(function(){var a 10;var b 20;
})()ES5没有块级作用域的概念只有函数作用域可以近似理解成这样。 所以外层window必然无法访问。 为何会出现浏览器兼容问题 同一产品版本越老 bug 越多同一产品版本越新功能越多不同产品不同标准不同实现方式 处理兼容问题的思路 要不要做 产品的角度产品的受众、受众的浏览器比例、效果优先还是基本功能优先成本的角度 (有无必要做某件事) 2.做到什么程度 让哪些浏览器支持哪些效果 3..如何做 根据兼容需求选择技术框架/库(jquery)根据兼容需求选择兼容工具(html5shiv.js、respond.js、css reset、normalize.css、Modernizr)条件注释、CSS Hack、js 能力检测做一些修补渐进增强(progressive enhancement): 针对低版本浏览器进行构建页面保证最基本的功能然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验优雅降级 (graceful degradation): 一开始就构建完整的功能然后再针对低版本浏览器进行兼容。 前端性能优化 减少 HTTP 请求减少 DOM 操作避免不必要的重绘与重排优化 CSS 选择器从右向左匹配CSS/JS minify减少文件体积开启 Gzip 压缩将 CSS 放到顶部JavaScript 放到尾部压缩图片以及使用 CSS Sprite使用 CDN 加速适当进行文件缓存合理控制 cookie 大小每次请求都会包含 cookie XSS XSS是什么 XSS是一种经常出现在web应用中的计算机安全漏洞它允许恶意web用户将代码植入到提供给其它用户使用的页面中。 比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。 这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。 对于跨站脚本攻击黑客界共识是跨站脚本攻击是新型的“缓冲区溢出攻击“而JavaScript是新型的“ShellCode”。 示例
scriptalert(document.cookie)/script特点 能注入恶意的HTML/JavaScript代码到用户浏览的网页上从而达到Cookie资料窃取、会话劫持、钓鱼欺骗等攻击。 攻击代码不一定非要在 script/script 中 原因 Web浏览器本身的设计不安全。浏览器能解析和执行JS等代码但是不会判断该数据和程序代码是否恶意。输入和输出是Web应用程序最基本的交互而且网站的交互功能越来越丰富。如果在这过程中没有做好安全防护很容易会出现XSS漏洞。程序员水平参差不齐而且大都没有过正规的安全培训没有相关的安全意识。XSS攻击手段灵活多变。 危害 盗取各类用户帐号如机器登录帐号、用户网银帐号、各类管理员帐号控制企业数据包括读取、篡改、添加、删除企业敏感数据的能力盗窃企业重要的具有商业价值的资料非法转账强制发送电子邮件网站挂马控制受害者机器向其它网站发起攻击 如何防范 将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了.表单数据规定值的类型例如年龄应为只能为int、name只能为字母数字组合。。。。对数据进行Html Encode 处理过滤或移除特殊的Html标签 例如: script, iframe , for , for , quot for过滤JavaScript 事件的标签。例如 οnclick, onfocus 等等。 参考资料 https://www.cnblogs.com/phpstudy2015-6/p/6767032.html https://www.cnblogs.com/443855539-wind/p/6055816.html https://baike.baidu.com/item/XSS%E6%94%BB%E5%87%BB/954065?fraladdin CSRF CSRFCross-site request forgery跨站请求伪造也被称为“One Click Attack”或者Session Riding通常缩写为CSRF或者XSRF是一种对网站的恶意利用。尽管听起来像跨站脚本XSS但它与XSS非常不同XSS利用站点内的信任用户而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比CSRF攻击往往不大流行因此对其进行防范的资源也相当稀少和难以防范所以被认为比XSS更具危险性。 特点 依靠用户标识危害网站利用网站对用户标识的信任欺骗用户的浏览器发送HTTP请求给目标站点另外可以通过IMG标签会触发一个GET请求可以利用它来实现CSRF攻击。 防御 通过referer、token或者验证码来检测用户提交。尽量不要在页面的链接中暴露用户隐私信息。对于用户修改删除等操作最好都使用post操作 。避免全站通用的cookie严格设置cookie的域。 圣杯布局和双飞翼布局是前端工程师需要日常掌握的重要布局方式。两者的功能相同都是为了实现一个两侧宽度固定中间宽度自适应的三栏布局。 圣杯布局与双飞翼布局 圣杯布局来源于文章In Search of the Holy Grail而双飞翼布局来源于淘宝UED。虽然两者的实现方法略有差异不过都遵循了以下要点 两侧宽度固定中间宽度自适应中间部分在DOM结构上优先以便先行渲染允许三列中的任意一列成为最高列只需要使用一个额外的标签 下面我将依次介绍圣杯布局和双飞翼布局的实现方法并在最后根据个人思考对原有方法做出一些修改给出其它一些可行的方案。 圣杯布局 1. DOM结构 div idheader/div
div idcontainerdiv idcenter classcolumn/divdiv idleft classcolumn/divdiv idright classcolumn/div
/div
div idfooter/div首先定义出整个布局的DOM结构主体部分是由container包裹的center,left,right三列其中center定义在最前面。 2. CSS代码 假设左侧的固定宽度为200px右侧的固定宽度为150px则首先在container上设置 #container {padding-left: 200px; padding-right: 150px;
}为左右两列预留出相应的空间得到如下示意图 创建布局框架 随后分别为三列设置宽度与浮动同时对footer设置清除浮动 #container .column {float: left;
}#center {width: 100%;
}#left {width: 200px;
}#right {width: 150px;
}#footer {clear: both;
}得到如下效果 设置宽度和清除浮动 根据浮动的特性由于center的宽度为100%即占据了第一行的所有空间所以left和right被“挤”到了第二行。 接下来的工作是将left放置到之前预留出的位置上这里使用负外边距nagetive margin #left {width: 200px; margin-left: -100%;
}得到 将left移动到预留位置-1 随后还需要使用定位(position)方法 #left {width: 200px; margin-left: -100%;position: relative;right: 200px;
}这里使用position: relative和right: 200px将left的位置在原有位置基础上左移200px以完成left的放置 将left移动到预留位置-2 接下来放置right只需添加一条声明即可 #right {width: 150px; margin-right: -150px;
}得到最终的效果图 将right移动到预留位置 至此布局效果完成。不过还需要考虑最后一步那就是页面的最小宽度要想保证该布局效果正常显示由于两侧都具有固定的宽度所以需要给定页面一个最小的宽度但这并不只是简单的200150350px。回想之前left使用了position: relative所以就意味着在center开始的区域还存在着一个left的宽度。所以页面的最小宽度应该设置为200150200550px body {min-width: 550px;
}综上所述圣杯布局的CSS代码为 body {min-width: 550px;
}#container {padding-left: 200px; padding-right: 150px;
}#container .column {float: left;
}#center {width: 100%;
}#left {width: 200px; margin-left: -100%;position: relative;right: 200px;
}#right {width: 150px; margin-right: -150px;
}#footer {clear: both;
}关于圣杯布局的示例可参考圣杯布局 最后提醒一下很多朋友可能会忽略的小细节在#center中包含了一条声明width: 100%这是中间栏能够做到自适应的关键。可能会有朋友认为不需要设置这条声明因为觉得center在不设置宽度的情况下会默认将宽度设置为父元素(container)的100%宽度。但需要注意到center是浮动元素由于浮动具有包裹性在不显式设置宽度的情况下会自动“收缩”到内容的尺寸大小。如果去掉width: 100%则当中间栏不包含或者包含较少内容时整个布局会“崩掉”而达不到这样的效果 中间栏仅包含较少内容 双飞翼布局 1. DOM结构 bodydiv idheader/divdiv idcontainer classcolumndiv idcenter/div/divdiv idleft classcolumn/divdiv idright classcolumn/divdiv idfooter/div
body双飞翼布局的DOM结构与圣杯布局的区别是用container仅包裹住center另外将.column类从center移至container上。 2. CSS代码 按照与圣杯布局相同的思路首先设置各列的宽度与浮动并且为左右两列预留出空间以及为footer设置浮动清除 #container {width: 100%;
}.column {float: left;
}#center {margin-left: 200px;margin-right: 150px;
}#left {width: 200px;
}#right {width: 150px;
}#footer {clear: both;
}得到如下效果示意图 双飞翼布局初始设置 以上代码将container,left,right设置为float: left而在container内部center由于没有设置浮动所以其宽度默认为container的100%宽度通过对其设置margin-left和margin-right为左右两列预留出了空间。 将left放置到预留位置 #left {width: 200px; margin-left: -100%;
}得到 放置left到预留位置 将right放置到预留位置 #right {width: 150px; margin-left: -150px;
}得到最终效果 双飞翼布局最终效果 最后计算最小页面宽度由于双飞翼布局没有用到position:relative进行定位所以最小页面宽度应该为200150350px。但是当页面宽度缩小到350px附近时会挤占中间栏的宽度使得其内容被右侧栏覆盖如下所示 中间栏内容被覆盖 因此在设置最小页面宽度时应该适当增加一些宽度以供中间栏使用假设为150px则有 body {min-width: 500px;
}至此双飞翼布局大功告成其布局整体代码为 body {min-width: 500px;
}#container {width: 100%;
}.column {float: left;
}#center {margin-left: 200px;margin-right: 150px;
}#left {width: 200px; margin-left: -100%;
}#right {width: 150px; margin-left: -150px;
}#footer {clear: both;
}关于双飞翼布局的示例可参考双飞翼布局 总结与思考 通过对圣杯布局和双飞翼布局的介绍可以看出圣杯布局在DOM结构上显得更加直观和自然且在日常开发过程中更容易形成这样的DOM结构通常和/一起被嵌套在中而双飞翼布局在实现上由于不需要使用定位所以更加简洁且允许的页面最小宽度通常比圣杯布局更小。 其实通过思考不难发现两者在代码实现上都额外引入了一个标签其目的都是为了既能保证中间栏产生浮动浮动后还必须显式设置宽度又能限制自身宽度为两侧栏留出空间。 从这个角度出发如果去掉额外添加的标签能否完成相同的布局呢答案是肯定的不过这需要在兼容性上做出牺牲 DOM结构 div idheader/div
div idcenter classcolumn/div
div idleft classcolumn/div
div idright classcolumn/div
div idfooter/div去掉额外的标签后得到的DOM结构如上所示基于双飞翼布局的实现思路只需要在center上做出修改 1. 使用calc() .column {float: left;
}#center {margin-left: 200px;margin-right: 150px;width: calc(100% - 350px);
}通过calc()可以十分方便地计算出center应该占据的自适应宽度目前calc()支持到IE9。 2. 使用border-box .column {float: left;
}#center {padding-left: 200px;padding-right: 150px;box-sizing: border-box;width: 100%;
}使用border-box可以将center的整个盒模型宽度设置为父元素的100%宽度此时再利用padding-left和padding-right可以自动得到中间栏的自适应宽度。不过需要注意的是由于padding是盒子的一部分所以padding部分会具有中间栏的背景色当中间栏高于侧栏时会出现这样的情况 padding背景色影响左侧空间 目前box-sizing支持到IE8。 3. 使用flex 这里使用flex还是需要与圣杯布局相同的DOM结构不过在实现上将更加简单 !-- DOM结构 --
div idcontainerdiv idcenter/divdiv idleft/divdiv idright/div
/divCSS代码如下 #container {display: flex;
}#center {flex: 1;
}#left {flex: 0 0 200px;order: -1;
}#right {flex: 0 0 150px;
}同源策略 同源策略可防止 JavaScript 发起跨域请求。源被定义为 URI、主机名和端口号的组合。此策略可防止页面上的恶意脚本通过该页面的文档对象模型访问另一个网页上的敏感数据。 跨域 原因 浏览器的同源策略导致了跨域作用 用于隔离潜在恶意文件的重要安全机制解决 jsonp 允许 script 加载第三方资源反向代理nginx 服务内部配置 Access-Control-Allow-Origin *cors 前后端协作设置请求头部Access-Control-Allow-Origin 等头部信息iframe 嵌套通讯postmessage https://zhuanlan.zhihu.com/p/41479807 跨域资源共享 CORS 阮一峰 JSONP 这是我认为写得比较通俗易懂的一篇文章 直接转载过来 https://blog.csdn.net/hansexploration/article/details/80314948 域名收敛 PC 时代为了突破浏览器的域名并发限制。有了域名发散。 浏览器有并发限制是为了防止DDOS攻击。 域名收敛就是将静态资源放在一个域名下。减少DNS解析的开销。 域名发散是将静态资源放在多个子域名下就可以多线程下载提高并行度使客户端加载静态资源更加迅速。 域名发散是pc端为了利用浏览器的多线程并行下载能力。而域名收敛多用与移动端提高性能因为dns解析是是从后向前迭代解析如果域名过多性能会下降增加DNS的解析开销。 事件绑定的方式 嵌入dom button onclickfunc()按钮/button直接绑定 btn.onclick function(){}事件监听 btn.addEventListener(click,function(){})事件委托 事件委托利用了事件冒泡只指定一个事件处理程序就可以管理某一类型的所有事件。所有用到按钮的事件多数鼠标事件和键盘事件都适合采用事件委托技术 使用事件委托可以节省内存。 ulli苹果/lili香蕉/lili凤梨/li
/ul// good
document.querySelector(ul).onclick (event) {let target event.targetif (target.nodeName LI) {console.log(target.innerHTML)}
}// bad
document.querySelectorAll(li).forEach((e) {e.onclick function() {console.log(this.innerHTML)}
}) prototype和proto的关系是什么 所有的对象都拥有proto属性它指向对象构造函数的prototype属性 let obj {}
obj.__proto__ Object.prototype // truefunction Test(){}
test.__proto__ Test.prototype // true所有的函数都同时拥有proto和protytpe属性 函数的proto指向自己的函数实现 函数的protytpe是一个对象 所以函数的prototype也有proto属性 指向Object.prototype function func() {}
func.prototype.__proto__ Object.prototype // trueObject.prototype.proto指向null Object.prototype.__proto__ // null原型继承 所有的JS对象都有一个prototype属性指向它的原型对象。当试图访问一个对象的属性时如果没有在该对象上找到它还会搜寻该对象的原型以及该对象的原型的原型依次层层向上搜索直到找到一个名字匹配的属性或到达原型链的末尾。 继承 JS高程第3版 第6章 继承 寄生组合式继承 function SuperType(name) {this.name namethis.colors [red]
}SuperType.prototype.sayName function() {console.log(this.name)
}
// 继承实例属性
function SubType(name, age) {SuperType.call(this, name)this.age age
}function inheritPrototype(subType, superType) {let prototype Object.create(superType.prototype)prototype.constructor subTypesubType.prototype prototype
}
// 继承原型方法
inheritPrototype(SubType, SuperType)// 定义自己的原型方法
SubType.prototype.sayAge function() {console.log(this.age)
}闭包 闭包是指有权访问另一个函数作用域中的变量的函数。 function sayHi(name) {return () {console.log(Hi! ${name})}
}
const test sayHi(xiaoming)
test() // Hi! xiaoming虽然sayHi函数已经执行完毕但是其活动对象也不会被销毁因为test函数仍然引用着sayHi函数中的变量name这就是闭包。 但也因为闭包引用着另一个函数的变量导致另一个函数已经不使用了也无法销毁所以闭包使用过多会占用较多的内存这也是一个副作用内存泄漏。 有一个函数参数是一个函数返回值也是一个函数返回的函数功能和入参的函数相似但这个函数只能执行3次再次执行无效如何实现 这个题目是考察闭包的使用 function sayHi() {console.log(hi)
}function threeTimes(fn) {let times 0return () {if (times 3) {fn()}}
}const newFn threeTimes(sayHi)
newFn()
newFn()
newFn()
newFn()
newFn() // 后面两次执行都无任何反应通过闭包变量 times 来控制函数的执行 实现add函数,让add(a)(b)和add(a,b)两种调用结果相同 function add(a, b) {if (b undefined) {return function(x) {return a x}}return a b
}虽然sayHi函数已经执行完毕但是其活动对象也不会被销毁因为test函数仍然引用着sayHi函数中的变量name这就是闭包。 但也因为闭包引用着另一个函数的变量导致另一个函数已经不使用了也无法销毁所以闭包使用过多会占用较多的内存这也是一个副作用内存泄漏。 JS垃圾回收机制 https://www.cnblogs.com/sunhuahuaa/p/7655587.html https://zhuanlan.zhihu.com/p/60484579 cookie、session、localStorage、sessionStorage区别 特性cookielocalStoragesessionStorage由谁初始化客户端或服务器服务器可以使用Set-Cookie请求头。客户端客户端数据的生命周期一般由服务器生成可设置失效时间如果在浏览器生成默认是关闭浏览器之后失效永久保存可清除仅在当前会话有效关闭页面后清除存放数据大小4KB5MB5MB与服务器通信每次都会携带在HTTP头中如果使用cookie保存过多数据会带来性能问题仅在客户端保存仅在客户端保存用途一般由服务器生成用于标识用户身份用于浏览器缓存数据用于浏览器缓存数据访问权限任意窗口任意窗口当前页面窗口 创建对象有几种方法 字面量 const obj {a: 1}构造函数 function Obj(val) {this.a val
}const obj new Obj(1)Object.create const obj Object.create({a: 1})ES6 class class abc{constructor(){this.a 123}
}bind、call、apply、箭头函数、new的区别 call和apply其实是一样的区别就在于传参时参数是一个一个传或者是以一个数组的方式来传。 call和apply都是在调用时生效改变调用者的this指向。 let name Jack
const obj {name: Tom}
function sayHi() {console.log(Hi! this.name)}sayHi() // Hi! Jack
sayHi.call(obj) // Hi! Tom bind也是改变this指向不过不是在调用时生效而是返回一个新函数。 const newFunc sayHi.bind(obj)
newFunc() // Hi! Tom请简述JavaScript中的this。 JS 中的this是一个相对复杂的概念不是简单几句能解释清楚的。粗略地讲函数的调用方式决定了this的值。我阅读了网上很多关于this的文章Arnav Aggrawal 写的比较清楚。this取值符合以下规则 在调用函数时使用new关键字函数内的this是一个全新的对象。如果apply、call或bind方法用于调用、创建一个函数函数内的 this 就是作为参数传入这些方法的对象。当函数作为对象里的方法被调用时函数内的this是调用该函数的对象。比如当obj.method()被调用时函数内的 this 将绑定到obj对象。如果调用函数不符合上述规则那么this的值指向全局对象global object。浏览器环境下this的值指向window对象但是在严格模式下(use strict)this的值为undefined。如果符合上述多个规则则较高的规则1 号最高4 号最低将决定this的值。如果该函数是 ES2015 中的箭头函数将忽略上面的所有规则this被设置为它被创建时的上下文。 想获得更深入的解释请查看他在 Medium 上的文章。 https://github.com/yangshun/front-end-interview-handbook/blob/master/Translations/Chinese/questions/javascript-questions.md#%E8%AF%B7%E7%AE%80%E8%BF%B0javascript%E4%B8%AD%E7%9A%84this 如何确定this指向 如果要判断一个运行中函数的 this 绑定就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断 this 的绑定对象。 由 new 调用绑定到新创建的对象。由 call 或者 apply 或者 bind 调用绑定到指定的对象。由上下文对象调用绑定到那个上下文对象。默认在严格模式下绑定到 undefined 否则绑定到全局对象。 一定要注意有些调用可能在无意中使用默认绑定规则。如果想“更安全”地忽略 this 绑定你可以使用一个 DMZ 对象比如 ø Object.create(null) 以保护全局对象。 ES6 中的箭头函数并不会使用四条标准的绑定规则而是根据当前的词法作用域来决定this 具体来说箭头函数会继承外层函数调用的 this 绑定无论 this 绑定到什么。这其实和 ES6 之前代码中的 self this 机制一样 最后编辑于2022-02-27 20:23 © 著作权归作者所有,转载或内容合作请联系作者 喜欢的朋友记得点赞、收藏、关注哦 文章转载自: http://www.morning.wtrjq.cn.gov.cn.wtrjq.cn http://www.morning.pfmsh.cn.gov.cn.pfmsh.cn http://www.morning.ckntb.cn.gov.cn.ckntb.cn http://www.morning.wnbqy.cn.gov.cn.wnbqy.cn http://www.morning.rdnjc.cn.gov.cn.rdnjc.cn http://www.morning.mkkcr.cn.gov.cn.mkkcr.cn http://www.morning.rnrfs.cn.gov.cn.rnrfs.cn http://www.morning.syrzl.cn.gov.cn.syrzl.cn http://www.morning.xxrwp.cn.gov.cn.xxrwp.cn http://www.morning.qnwyf.cn.gov.cn.qnwyf.cn http://www.morning.sgfpn.cn.gov.cn.sgfpn.cn http://www.morning.jkcnq.cn.gov.cn.jkcnq.cn http://www.morning.ctfwl.cn.gov.cn.ctfwl.cn http://www.morning.qjfkz.cn.gov.cn.qjfkz.cn http://www.morning.tnbsh.cn.gov.cn.tnbsh.cn http://www.morning.rwwdp.cn.gov.cn.rwwdp.cn http://www.morning.wjqbr.cn.gov.cn.wjqbr.cn http://www.morning.jxrpn.cn.gov.cn.jxrpn.cn http://www.morning.dfckx.cn.gov.cn.dfckx.cn http://www.morning.kaweilu.com.gov.cn.kaweilu.com http://www.morning.csxlm.cn.gov.cn.csxlm.cn http://www.morning.pbzlh.cn.gov.cn.pbzlh.cn http://www.morning.bfrff.cn.gov.cn.bfrff.cn http://www.morning.paxkhqq.cn.gov.cn.paxkhqq.cn http://www.morning.czqqy.cn.gov.cn.czqqy.cn http://www.morning.qxgmp.cn.gov.cn.qxgmp.cn http://www.morning.sogou66.cn.gov.cn.sogou66.cn http://www.morning.cnprt.cn.gov.cn.cnprt.cn http://www.morning.mprky.cn.gov.cn.mprky.cn http://www.morning.pffqh.cn.gov.cn.pffqh.cn http://www.morning.ywzqk.cn.gov.cn.ywzqk.cn http://www.morning.ctlzf.cn.gov.cn.ctlzf.cn http://www.morning.cfynn.cn.gov.cn.cfynn.cn http://www.morning.jkpnm.cn.gov.cn.jkpnm.cn http://www.morning.xpzkr.cn.gov.cn.xpzkr.cn http://www.morning.ckrnq.cn.gov.cn.ckrnq.cn http://www.morning.pdbgm.cn.gov.cn.pdbgm.cn http://www.morning.kghss.cn.gov.cn.kghss.cn http://www.morning.ydnxm.cn.gov.cn.ydnxm.cn http://www.morning.mdtfh.cn.gov.cn.mdtfh.cn http://www.morning.shinezoneserver.com.gov.cn.shinezoneserver.com http://www.morning.sxygc.cn.gov.cn.sxygc.cn http://www.morning.jgmlb.cn.gov.cn.jgmlb.cn http://www.morning.yfzld.cn.gov.cn.yfzld.cn http://www.morning.wxccm.cn.gov.cn.wxccm.cn http://www.morning.wglhz.cn.gov.cn.wglhz.cn http://www.morning.rdmn.cn.gov.cn.rdmn.cn http://www.morning.pclgj.cn.gov.cn.pclgj.cn http://www.morning.zdsqb.cn.gov.cn.zdsqb.cn http://www.morning.sjqpm.cn.gov.cn.sjqpm.cn http://www.morning.mgkcz.cn.gov.cn.mgkcz.cn http://www.morning.jfbrt.cn.gov.cn.jfbrt.cn http://www.morning.jmllh.cn.gov.cn.jmllh.cn http://www.morning.ldspj.cn.gov.cn.ldspj.cn http://www.morning.jxdhc.cn.gov.cn.jxdhc.cn http://www.morning.3dcb8231.cn.gov.cn.3dcb8231.cn http://www.morning.qwdqq.cn.gov.cn.qwdqq.cn http://www.morning.lwtfr.cn.gov.cn.lwtfr.cn http://www.morning.gctgc.cn.gov.cn.gctgc.cn http://www.morning.mnslh.cn.gov.cn.mnslh.cn http://www.morning.bzkgn.cn.gov.cn.bzkgn.cn http://www.morning.mcjyair.com.gov.cn.mcjyair.com http://www.morning.mdrnn.cn.gov.cn.mdrnn.cn http://www.morning.cpljq.cn.gov.cn.cpljq.cn http://www.morning.xjbtb.cn.gov.cn.xjbtb.cn http://www.morning.kxxld.cn.gov.cn.kxxld.cn http://www.morning.tkrdg.cn.gov.cn.tkrdg.cn http://www.morning.hxxwq.cn.gov.cn.hxxwq.cn http://www.morning.plhyc.cn.gov.cn.plhyc.cn http://www.morning.gjqgz.cn.gov.cn.gjqgz.cn http://www.morning.pqkgb.cn.gov.cn.pqkgb.cn http://www.morning.poapal.com.gov.cn.poapal.com http://www.morning.pwmpn.cn.gov.cn.pwmpn.cn http://www.morning.gjqnn.cn.gov.cn.gjqnn.cn http://www.morning.tpkxs.cn.gov.cn.tpkxs.cn http://www.morning.wgtr.cn.gov.cn.wgtr.cn http://www.morning.xxwfq.cn.gov.cn.xxwfq.cn http://www.morning.qxmpp.cn.gov.cn.qxmpp.cn http://www.morning.xsgxp.cn.gov.cn.xsgxp.cn http://www.morning.psxxp.cn.gov.cn.psxxp.cn