ajax、axios、fetch的区别
(1)AJAX Ajax 即“AsynchronousJavascriptAndXML”(异步 JavaScript 和 XML),是指一种创立交互式网页利用的网页开发技术。它是一种在无需从新加载整个网页的状况下,可能更新局部网页的技术。通过在后盾与服务器进行大量数据交换,Ajax 能够使网页实现异步更新。这意味着能够在不从新加载整个网页的状况下,对网页的某局部进行更新。传统的网页(不应用 Ajax)如果须要更新内容,必须重载整个网页页面。其毛病如下:
- 自身是针对MVC编程,不合乎前端MVVM的浪潮
- 基于原生XHR开发,XHR自身的架构不清晰
- 不合乎关注拆散(Separation of Concerns)的准则
- 配置和调用形式十分凌乱,而且基于事件的异步模型不敌对。
(2)Fetch fetch号称是AJAX的替代品,是在ES6呈现的,应用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码构造比起ajax简略多。fetch不是ajax的进一步封装,而是原生js,没有应用XMLHttpRequest对象。
fetch的长处:
- 语法简洁,更加语义化
- 基于规范 Promise 实现,反对 async/await
- 更加底层,提供的API丰盛(request, response)
- 脱离了XHR,是ES标准里新的实现形式
fetch的毛病:
- fetch只对网络申请报错,对400,500都当做胜利的申请,服务器返回 400,500 错误码时并不会 reject,只有网络谬误这些导致申请不能实现时,fetch 才会被 reject。
- fetch默认不会带cookie,须要增加配置项: fetch(url, {credentials: 'include'})
- fetch不反对abort,不反对超时管制,应用setTimeout及Promise.reject的实现的超时管制并不能阻止申请过程持续在后盾运行,造成了流量的节约
- fetch没有方法原生监测申请的进度,而XHR能够
(3)Axios Axios 是一种基于Promise封装的HTTP客户端,其特点如下:
- 浏览器端发动XMLHttpRequests申请
- node端发动http申请
- 反对Promise API
- 监听申请和返回
- 对申请和返回进行转化
- 勾销申请
- 主动转换json数据
- 客户端反对抵挡XSRF攻打
call apply bind
题目形容:手写 call apply bind 实现
实现代码如下:
Function.prototype.myCall = function (context, ...args) { if (!context || context === null) { context = window; } // 发明惟一的key值 作为咱们结构的context外部办法名 let fn = Symbol(); context[fn] = this; //this指向调用call的函数 // 执行函数并返回后果 相当于把本身作为传入的context的办法进行调用了 return context[fn](...args);};// apply原理统一 只是第二个参数是传入的数组Function.prototype.myApply = function (context, args) { if (!context || context === null) { context = window; } // 发明惟一的key值 作为咱们结构的context外部办法名 let fn = Symbol(); context[fn] = this; // 执行函数并返回后果 return context[fn](...args);};//bind实现要简单一点 因为他思考的状况比拟多 还要波及到参数合并(相似函数柯里化)Function.prototype.myBind = function (context, ...args) { if (!context || context === null) { context = window; } // 发明惟一的key值 作为咱们结构的context外部办法名 let fn = Symbol(); context[fn] = this; let _this = this; // bind状况要简单一点 const result = function (...innerArgs) { // 第一种状况 :若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符应用,则不绑定传入的 this,而是将 this 指向实例化进去的对象 // 此时因为new操作符作用 this指向result实例对象 而result又继承自传入的_this 依据原型链常识可得出以下论断 // this.__proto__ === result.prototype //this instanceof result =>true // this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true if (this instanceof _this === true) { // 此时this指向指向result的实例 这时候不须要扭转this指向 this[fn] = _this; this[fn](...[...args, ...innerArgs]); //这里应用es6的办法让bind反对参数合并 } else { // 如果只是作为一般函数调用 那就很简略了 间接扭转this指向为传入的context context[fn](...[...args, ...innerArgs]); } }; // 如果绑定的是构造函数 那么须要继承构造函数原型属性和办法 // 实现继承的形式: 应用Object.create result.prototype = Object.create(this.prototype); return result;};//用法如下// function Person(name, age) {// console.log(name); //'我是参数传进来的name'// console.log(age); //'我是参数传进来的age'// console.log(this); //构造函数this指向实例对象// }// // 构造函数原型的办法// Person.prototype.say = function() {// console.log(123);// }// let obj = {// objName: '我是obj传进来的name',// objAge: '我是obj传进来的age'// }// // 一般函数// function normalFun(name, age) {// console.log(name); //'我是参数传进来的name'// console.log(age); //'我是参数传进来的age'// console.log(this); //一般函数this指向绑定bind的第一个参数 也就是例子中的obj// console.log(this.objName); //'我是obj传进来的name'// console.log(this.objAge); //'我是obj传进来的age'// }// 先测试作为结构函数调用// let bindFun = Person.myBind(obj, '我是参数传进来的name')// let a = new bindFun('我是参数传进来的age')// a.say() //123// 再测试作为一般函数调用// let bindFun = normalFun.myBind(obj, '我是参数传进来的name')// bindFun('我是参数传进来的age')
代码输入问题
function A(){}function B(a){ this.a = a;}function C(a){ if(a){this.a = a; }}A.prototype.a = 1;B.prototype.a = 1;C.prototype.a = 1;console.log(new A().a);console.log(new B().a);console.log(new C(2).a);
输入后果:1 undefined 2
解析:
- console.log(new A().a),new A()为构造函数创立的对象,自身没有a属性,所以向它的原型去找,发现原型的a属性的属性值为1,故该输入值为1;
- console.log(new B().a),ew B()为构造函数创立的对象,该构造函数有参数a,但该对象没有传参,故该输入值为undefined;
- console.log(new C(2).a),new C()为构造函数创立的对象,该构造函数有参数a,且传的实参为2,执行函数外部,发现if为真,执行this.a = 2,故属性a的值为2。
代码输入后果
var x = 3;var y = 4;var obj = { x: 1, y: 6, getX: function() { var x = 5; return function() { return this.x; }(); }, getY: function() { var y = 7; return this.y; }}console.log(obj.getX()) // 3console.log(obj.getY()) // 6
输入后果:3 6
解析:
- 咱们晓得,匿名函数的this是指向全局对象的,所以this指向window,会打印出3;
- getY是由obj调用的,所以其this指向的是obj对象,会打印出6。
代码输入后果
async function async1 () { await async2(); console.log('async1'); return 'async1 success'}async function async2 () { return new Promise((resolve, reject) => { console.log('async2') reject('error') })}async1().then(res => console.log(res))
输入后果如下:
async2Uncaught (in promise) error
能够看到,如果async函数中抛出了谬误,就会终止谬误后果,不会持续向下执行。
如果想要让谬误不足之处前面的代码执行,能够应用catch来捕捉:
async function async1 () { await Promise.reject('error!!!').catch(e => console.log(e)) console.log('async1'); return Promise.resolve('async1 success')}async1().then(res => console.log(res))console.log('script start')
这样的输入后果就是:
script starterror!!!async1async1 success
代码输入后果
var friendName = 'World';(function() { if (typeof friendName === 'undefined') { var friendName = 'Jack'; console.log('Goodbye ' + friendName); } else { console.log('Hello ' + friendName); }})();
输入后果:Goodbye Jack
咱们晓得,在 JavaScript中, Function 和 var 都会被晋升(变量晋升),所以下面的代码就相当于:
var name = 'World!';(function () { var name; if (typeof name === 'undefined') { name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); }})();
这样,答案就高深莫测了。
参考 前端进阶面试题具体解答
代码输入后果
console.log(1);setTimeout(() => { console.log(2); Promise.resolve().then(() => { console.log(3) });});new Promise((resolve, reject) => { console.log(4) resolve(5)}).then((data) => { console.log(data);})setTimeout(() => { console.log(6);})console.log(7);
代码输入后果如下:
1475236
代码执行过程如下:
- 首先执行scrip代码,打印出1;
- 遇到第一个定时器setTimeout,将其退出到宏工作队列;
- 遇到Promise,执行外面的同步代码,打印出4,遇到resolve,将其退出到微工作队列;
- 遇到第二个定时器setTimeout,将其退出到红工作队列;
- 执行script代码,打印出7,至此第一轮执行实现;
- 指定微工作队列中的代码,打印出resolve的后果:5;
- 执行宏工作中的第一个定时器setTimeout,首先打印出2,而后遇到 Promise.resolve().then(),将其退出到微工作队列;
- 执行完这个宏工作,就开始执行微工作队列,打印出3;
- 继续执行宏工作队列中的第二个定时器,打印出6。
什么是 XSS 攻打?
(1)概念
XSS 攻打指的是跨站脚本攻打,是一种代码注入攻打。攻击者通过在网站注入歹意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。
XSS 的实质是因为网站没有对恶意代码进行过滤,与失常的代码混合在一起了,浏览器没有方法分辨哪些脚本是可信的,从而导致了恶意代码的执行。
攻击者能够通过这种攻击方式能够进行以下操作:
- 获取页面的数据,如DOM、cookie、localStorage;
- DOS攻打,发送正当申请,占用服务器资源,从而使用户无法访问服务器;
- 毁坏页面构造;
- 流量劫持(将链接指向某网站);
(2)攻打类型
XSS 能够分为存储型、反射型和 DOM 型:
- 存储型指的是歹意脚本会存储在指标服务器上,当浏览器申请数据时,脚本从服务器传回并执行。
- 反射型指的是攻击者诱导用户拜访一个带有恶意代码的 URL 后,服务器端接收数据后处理,而后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终实现 XSS 攻打。
- DOM 型指的通过批改页面的 DOM 节点造成的 XSS。
1)存储型 XSS 的攻打步骤:
- 攻击者将恶意代码提交到⽬标⽹站的数据库中。
- ⽤户关上⽬标⽹站时,⽹站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
- ⽤户浏览器接管到响应后解析执⾏,混在其中的恶意代码也被执⾏。
- 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者假冒⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
这种攻打常⻅于带有⽤户保留数据的⽹站性能,如论坛发帖、商品评论、⽤户私信等。
2)反射型 XSS 的攻打步骤:
- 攻击者结构出非凡的 URL,其中蕴含恶意代码。
- ⽤户关上带有恶意代码的 URL 时,⽹站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
- ⽤户浏览器接管到响应后解析执⾏,混在其中的恶意代码也被执⾏。
- 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者假冒⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库⾥,反射型 XSS 的恶意代码存在 URL ⾥。
反射型 XSS 破绽常⻅于通过 URL 传递参数的性能,如⽹站搜寻、跳转等。 因为须要⽤户被动关上歹意的 URL 能力⽣效,攻击者往往会联合多种⼿段诱导⽤户点击。
3)DOM 型 XSS 的攻打步骤:
- 攻击者结构出非凡的 URL,其中蕴含恶意代码。
- ⽤户关上带有恶意代码的 URL。
- ⽤户浏览器接管到响应后解析执⾏,前端 JavaScript 取出 URL 中的恶意代码并执⾏。
- 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者假冒⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻打中,取出和执⾏恶意代码由浏览器端实现,属于前端JavaScript ⾃身的安全漏洞,⽽其余两种 XSS 都属于服务端的安全漏洞。
常见的图片格式及应用场景
(1)BMP,是无损的、既反对索引色也反对间接色的点阵图。这种图片格式简直没有对数据进行压缩,所以BMP格局的图片通常是较大的文件。
(2)GIF是无损的、采纳索引色的点阵图。采纳LZW压缩算法进行编码。文件小,是GIF格局的长处,同时,GIF格局还具备反对动画以及通明的长处。然而GIF格局仅反对8bit的索引色,所以GIF格局实用于对色调要求不高同时须要文件体积较小的场景。
(3)JPEG是有损的、采纳间接色的点阵图。JPEG的图片的长处是采纳了间接色,得益于更丰盛的色调,JPEG非常适合用来存储照片,与GIF相比,JPEG不适宜用来存储企业Logo、线框类的图。因为有损压缩会导致图片含糊,而间接色的选用,又会导致图片文件较GIF更大。
(4)PNG-8是无损的、应用索引色的点阵图。PNG是一种比拟新的图片格式,PNG-8是十分好的GIF格局替代者,在可能的状况下,应该尽可能的应用PNG-8而不是GIF,因为在雷同的图片成果下,PNG-8具备更小的文件体积。除此之外,PNG-8还反对透明度的调节,而GIF并不反对。除非须要动画的反对,否则没有理由应用GIF而不是PNG-8。
(5)PNG-24是无损的、应用间接色的点阵图。PNG-24的长处在于它压缩了图片的数据,使得同样成果的图片,PNG-24格局的文件大小要比BMP小得多。当然,PNG24的图片还是要比JPEG、GIF、PNG-8大得多。
(6)SVG是无损的矢量图。SVG是矢量图意味着SVG图片由直线和曲线以及绘制它们的办法组成。当放大SVG图片时,看到的还是线和曲线,而不会呈现像素点。这意味着SVG图片在放大时,不会失真,所以它非常适合用来绘制Logo、Icon等。
(7)WebP是谷歌开发的一种新图片格式,WebP是同时反对有损和无损压缩的、应用间接色的点阵图。从名字就可以看进去它是为Web而生的,什么叫为Web而生呢?就是说雷同品质的图片,WebP具备更小的文件体积。当初网站上充斥了大量的图片,如果可能升高每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而升高拜访提早,晋升拜访体验。目前只有Chrome浏览器和Opera浏览器反对WebP格局,兼容性不太好。
- 在无损压缩的状况下,雷同品质的WebP图片,文件大小要比PNG小26%;
- 在有损压缩的状况下,具备雷同图片精度的WebP图片,文件大小要比JPEG小25%~34%;
- WebP图片格式反对图片透明度,一个无损压缩的WebP图片,如果要反对透明度只须要22%的分外文件大小。
代码输入问题
window.number = 2;var obj = { number: 3, db1: (function(){ console.log(this); this.number *= 4; return function(){ console.log(this); this.number *= 5; } })()}var db1 = obj.db1;db1();obj.db1();console.log(obj.number); // 15console.log(window.number); // 40
这道题目看清起来有点乱,然而实际上是考查this指向的:
- 执行db1()时,this指向全局作用域,所以window.number 4 = 8,而后执行匿名函数, 所以window.number 5 = 40;
- 执行obj.db1();时,this指向obj对象,执行匿名函数,所以obj.numer * 5 = 15。
iframe 有那些长处和毛病?
iframe 元素会创立蕴含另外一个文档的内联框架(即行内框架)。
长处:
- 用来加载速度较慢的内容(如广告)
- 能够使脚本能够并行下载
- 能够实现跨子域通信
毛病:
- iframe 会阻塞主页面的 onload 事件
- 无奈被一些搜索引擎索辨认
- 会产生很多页面,不容易治理
对BFC的了解,如何创立BFC
先来看两个相干的概念:
- Box: Box 是 CSS 布局的对象和根本单位,⼀个⻚⾯是由很多个 Box 组成的,这个Box就是咱们所说的盒模型。
- Formatting context:块级高低⽂格式化,它是⻚⾯中的⼀块渲染区域,并且有⼀套渲染规定,它决定了其⼦元素将如何定位,以及和其余元素的关系和互相作⽤。
块格式化上下文(Block Formatting Context,BFC)是Web页面的可视化CSS渲染的一部分,是布局过程中生成块级盒子的区域,也是浮动元素与其余元素的交互限定区域。
艰深来讲:BFC是一个独立的布局环境,能够了解为一个容器,在这个容器中依照肯定规定进行物品摆放,并且不会影响其它环境中的物品。如果一个元素合乎触发BFC的条件,则BFC中的元素布局不受内部影响。
创立BFC的条件:
- 根元素:body;
- 元素设置浮动:float 除 none 以外的值;
- 元素设置相对定位:position (absolute、fixed);
- display 值为:inline-block、table-cell、table-caption、flex等;
- overflow 值为:hidden、auto、scroll;
BFC的特点:
- 垂直方向上,自上而下排列,和文档流的排列形式统一。
- 在BFC中高低相邻的两个容器的margin会重叠
- 计算BFC的高度时,须要计算浮动元素的高度
- BFC区域不会与浮动的容器产生重叠
- BFC是独立的容器,容器外部元素不会影响内部元素
- 每个元素的左margin值和容器的左border相接触
BFC的作用:
- 解决margin的重叠问题:因为BFC是一个独立的区域,外部的元素和内部的元素互不影响,将两个元素变为两个BFC,就解决了margin重叠的问题。
- 解决高度塌陷的问题:在对子元素设置浮动后,父元素会产生高度塌陷,也就是父元素的高度变为0。解决这个问题,只须要把父元素变成一个BFC。罕用的方法是给父元素设置
overflow:hidden
。 - 创立自适应两栏布局:能够用来创立自适应两栏布局:右边的宽度固定,左边的宽度自适应。
.left{ width: 100px; height: 200px; background: red; float: left; } .right{ height: 300px; background: blue; overflow: hidden; }<div class="left"></div><div class="right"></div>
左侧设置float:left
,右侧设置overflow: hidden
。这样左边就触发了BFC,BFC的区域不会与浮动元素产生重叠,所以两侧就不会产生重叠,实现了自适应两栏布局。
并发与并行的区别?
- 并发是宏观概念,我别离有工作 A 和工作 B,在一段时间内通过工作间的切换实现了这两个工作,这种状况就能够称之为并发。
- 并行是宏观概念,假如 CPU 中存在两个外围,那么我就能够同时实现工作 A、B。同时实现多个工作的状况就能够称之为并行。
同步和异步的区别
- 同步指的是当一个过程在执行某个申请时,如果这个申请须要期待一段时间能力返回,那么这个过程会始终期待上来,直到音讯返回为止再持续向下执行。
- 异步指的是当一个过程在执行某个申请时,如果这个申请须要期待一段时间能力返回,这个时候过程会持续往下执行,不会阻塞期待音讯的返回,当音讯返回时零碎再告诉过程进行解决。
代码输入后果
function foo(something){ this.a = something}var obj1 = { foo: foo}var obj2 = {}obj1.foo(2); console.log(obj1.a); // 2obj1.foo.call(obj2, 3);console.log(obj2.a); // 3var bar = new obj1.foo(4)console.log(obj1.a); // 2console.log(bar.a); // 4
输入后果: 2 3 2 4
解析:
- 首先执行obj1.foo(2); 会在obj中增加a属性,其值为2。之后执行obj1.a,a是右obj1调用的,所以this指向obj,打印出2;
- 执行 obj1.foo.call(obj2, 3) 时,会将foo的this指向obj2,前面就和下面一样了,所以会打印出3;
- obj1.a会打印出2;
- 最初就是考查this绑定的优先级了,new 绑定是比隐式绑定优先级高,所以会输入4。
对Service Worker的了解
Service Worker 是运行在浏览器背地的独立线程,个别能够用来实现缓存性能。应用 Service Worker的话,传输协定必须为 HTTPS。因为 Service Worker 中波及到申请拦挡,所以必须应用 HTTPS 协定来保障平安。
Service Worker 实现缓存性能个别分为三个步骤:首先须要先注册 Service Worker,而后监听到 install
事件当前就能够缓存须要的文件,那么在下次用户拜访的时候就能够通过拦挡申请的形式查问是否存在缓存,存在缓存的话就能够间接读取缓存文件,否则就去申请数据。以下是这个步骤的实现:
// index.jsif (navigator.serviceWorker) { navigator.serviceWorker .register('sw.js') .then(function(registration) { console.log('service worker 注册胜利') }) .catch(function(err) { console.log('servcie worker 注册失败') })}// sw.js// 监听 `install` 事件,回调中缓存所需文件self.addEventListener('install', e => { e.waitUntil( caches.open('my-cache').then(function(cache) { return cache.addAll(['./index.html', './index.js']) }) )})// 拦挡所有申请事件// 如果缓存中曾经有申请的数据就间接用缓存,否则去申请数据self.addEventListener('fetch', e => { e.respondWith( caches.match(e.request).then(function(response) { if (response) { return response } console.log('fetch source') }) )})
关上页面,能够在开发者工具中的 Application
看到 Service Worker 曾经启动了: 在 Cache 中也能够发现所需的文件已被缓存:
文档申明(Doctype)和<!Doctype html>
有何作用? 严格模式与混淆模式如何辨别?它们有何意义?
文档申明的作用: 文档申明是为了通知浏览器,以后HTML
文档应用什么版本的HTML
来写的,这样浏览器能力依照申明的版本来正确的解析。
的作用:<!doctype html>
的作用就是让浏览器进入规范模式,应用最新的 HTML5
规范来解析渲染页面;如果不写,浏览器就会进入混淆模式,咱们须要防止此类情况产生。
严格模式与混淆模式的辨别:
- 严格模式: 又称为规范模式,指浏览器依照
W3C
规范解析代码; - 混淆模式: 又称怪异模式、兼容模式,是指浏览器用本人的形式解析代码。混淆模式通常模仿老式浏览器的行为,以避免老站点无奈工作;
辨别:网页中的DTD
,间接影响到应用的是严格模式还是浏览模式,能够说DTD
的应用与这两种形式的区别非亲非故。
- 如果文档蕴含严格的
DOCTYPE
,那么它个别以严格模式出现(严格 DTD ——严格模式); - 蕴含过渡
DTD
和URI
的DOCTYPE
,也以严格模式出现,但有过渡DTD
而没有URI
(对立资源标识符,就是申明最初的地址)会导致页面以混淆模式出现(有 URI 的过渡 DTD ——严格模式;没有 URI 的过渡 DTD ——混淆模式); DOCTYPE
不存在或模式不正确会导致文档以混淆模式出现(DTD不存在或者格局不正确——混淆模式);HTML5
没有DTD
,因而也就没有严格模式与混淆模式的区别,HTML5
有绝对宽松的 法,实现时,曾经尽可能大的实现了向后兼容(HTML5 没有严格和混淆之分)。
总之,严格模式让各个浏览器对立执行一套标准兼容模式保障了旧网站的失常运行。
代码输入后果
const async1 = async () => { console.log('async1'); setTimeout(() => { console.log('timer1') }, 2000) await new Promise(resolve => { console.log('promise1') }) console.log('async1 end') return 'async1 success'} console.log('script start');async1().then(res => console.log(res));console.log('script end');Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .catch(4) .then(res => console.log(res))setTimeout(() => { console.log('timer2')}, 1000)
输入后果如下:
script startasync1promise1script end1timer2timer1
代码的执行过程如下:
- 首先执行同步带吗,打印出script start;
- 遇到定时器timer1将其退出宏工作队列;
- 之后是执行Promise,打印出promise1,因为Promise没有返回值,所以前面的代码不会执行;
- 而后执行同步代码,打印出script end;
- 继续执行上面的Promise,.then和.catch冀望参数是一个函数,这里传入的是一个数字,因而就会产生值浸透,将resolve(1)的值传到最初一个then,间接打印出1;
- 遇到第二个定时器,将其退出到微工作队列,执行微工作队列,按程序顺次执行两个定时器,然而因为定时器工夫的起因,会在两秒后先打印出timer2,在四秒后打印出timer1。
代码输入后果
const promise = Promise.resolve().then(() => { return promise;})promise.catch(console.err)
输入后果如下:
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
这里其实是一个坑,.then
或 .catch
返回的值不能是 promise 自身,否则会造成死循环。
display:none与visibility:hidden的区别
这两个属性都是让元素暗藏,不可见。两者区别如下:
(1)在渲染树中
display:none
会让元素齐全从渲染树中隐没,渲染时不会占据任何空间;visibility:hidden
不会让元素从渲染树中隐没,渲染的元素还会占据相应的空间,只是内容不可见。
(2)是否是继承属性
display:none
是非继承属性,子孙节点会随着父节点从渲染树隐没,通过批改子孙节点的属性也无奈显示;visibility:hidden
是继承属性,子孙节点隐没是因为继承了hidden
,通过设置visibility:visible
能够让子孙节点显示;
(3)批改惯例文档流中元素的display
通常会造成文档的重排,然而批改visibility
属性只会造成本元素的重绘;
(4)如果应用读屏器,设置为display:none
的内容不会被读取,设置为visibility:hidden
的内容会被读取。