2017.10.1

1. 实现不同窗体间互相通信

(1) window.postMessage()支持跨文档消息传输(Cross Document Messaging),并且可跨域传输信息。
兼容性:IE>=8 支持

消息监听:onmessage,可接受任意发送过来的消息,应对消息来源(e.origin)进行安全验证

window.addEventListener('message', fn, false);

消息发送:postMessage,获取到要传送消息的窗体对象,向其发送消息。

targetWindow.postMessage(message, targetOrigin); 

(2) 监听 localStoragestorage事件,当localStorage的键值改变时,就会触发此事件。

window.addEventListener("storage", fn, false);
window.attachEvent("onstorage", fn);

2. CORS

CORS(跨域资源共享)需要浏览器和服务器同时支持,除IE<10以外,其他浏览器都已支持,而且服务器实现了CORS接口,就可以跨源通信了。通过在服务器端设置 HTTP header 字段,服务器可以声明哪些网站有权限访问哪些资源。

浏览器将CORS请求分两类,简单请求非简单请求

(1) 简单请求:(不会触发CORS预检请求)
条件:1. 请求方法是HEAD GETPOST; 2. HTTP header是对CORS安全的首部字段。
浏览器和服务器之间使用 CORS 首部字段来处理跨域权限。浏览器在请求头信息中增加一个Origin字段,用来说明本次请求来自哪个源,服务器根据这个字段值来决定是否同意这次请求。
如果Origin指定的源不在许可范围,服务器会返回一个正常的 HTTP 回应,这个回应的头信息不包含Access-Control-Allow-Origin字段,浏览器会抛出一个错误,这个错误会被 XMLHttpRequestonerror 回调函数捕获。这个错误不能通过状态码识别,因为服务器返回的是一个正常的回应,状态码可能为200。
如果Origin指定的源在许可范围内,服务器返回的响应会包含几个头信息字段:Access-Control-Allow-Origin (Access-Control-Allow-CredentialsAccess-Control-Expose-HeadersContent-Type 可选)

(2)非简单请求:(会进行预检请求)
条件:对服务器有特殊要求的请求,请求方法是PUTDELETE,或者Content-Type字段类型是application/json
非简单请求会在正式通信前,增加一次HTTP预检请求。
浏览器会先询问服务器,当前域名是否在服务器许可名单中,以及可以使用哪些HTTP请求方法和头信息字段,当得到服务器肯定回应,会返回Access-Control-Allow-Origin字段,表示可以请求数据。如果服务器返回否定回应,会触发一个错误,被XMLHttpRequestonerror 回调函数捕获。

3. flex-box

弹性盒子(flexible box)是CSS3的一种新的布局模式,尤其是在屏幕宽度自适应时,弹性布局使得父元素中子元素的排列、对齐、空间分配变得更便捷灵活。对于可伸缩的父元素,子元素随其扩大或缩小,并能够合适地填满父元素空间。弹性布局包括多个CSS3属性,有设置在父元素上的,有设置在子元素上的。

父元素上的属性:
display:flex; 让父元素变成Flex容器。
flex-direction:子元素在Flex容器中放置的方向 (row|row-reverse|column|column-reverse)
flex-wrap:默认子元素都显示在一行(nowrap),改变此属性(wrap/wrap-reverse),可以让子元素多行显示。
justify-content:在主轴上对齐子元素,在父元素有多余的空间时才会进行空间分配 (flex-start|flex-end|center|space-between|space-around)
align-items:在侧轴上对齐子元素(flex-start|flex-end|center|baseline|stretch)
align-content:当多行的Flex容器的侧轴还有多余空间时,可用来调节多行子元素在容器内的对齐方式(flex-start|flex-end|center|space-between|space-around|stretch)

子元素上的属性:
order:默认子元素是按文档中的顺序显示排列的,在Flex容器中可通过order属性改变子元素的显示顺序
flex-grow:可以定义子元素的扩大比例。所有的子元素值相同时,占据相同的空间。
flex-shrink:可以定义子元素的缩小比例。
flex-basis:子元素的分配Flex容器剩余空间之前的默认尺寸。0表示不考虑子元素周围额外空间,auto表示额外空间根据flex-grow值做分配。
flexflex-growflex-shrinkflex-basis三个属性的缩写。默认值:0 1 auto
align-self:单个子元素侧轴的对齐方式。

4. 前端优化

(1) 加载页面和静态资源方面:
静态资源的合并压缩;使用缓存;使用CDN;后端渲染,数据直接输出到html模版

(2)页面渲染和页面操作方面:
减少DOM操作;懒加载;css放在html文档的前面加载,js在后面加载;事件节流;尽早执行操作(DOMContentLoaded: DOM渲染完即可操作,此时图片视频可能还没加载完;window.onload:页面全部资源加载完才会执行,包括图片视频)

5. BFC

块级格式化上下文(block formatting context),创建了新BFC的盒子是独立布局的,是一个隔离的独立容器盒子,里面子元素的样式不会影响到外面的元素,盒子里的子元素的布局和定位和外部元素互不影响。

作用:
(1) 避免margin重叠。块级标签之间竖直方向的margin会重叠。可以用overflow:hidden;来解决。
(2) 清除浮动。子元素浮动,父元素的高度会塌陷,父元素高度不会被子元素撑开的问题。

触发BFC的条件:
(1) 浮动元素:float的值不为none
(2) position的值为absolutefixed
(3) overflow为除了visible以外的值(autoscrollhidden)。
(4) display的值为inline-blocktable-celltable-caption

6. web安全-攻击及防范

(1) XSS 跨站脚本攻击(Cross Site Scripting)
攻击者向web页面插入恶意html标签或者js代码。比如一个看似安全的链接,用户点击后,攻击者窃取用户的cookie;或者攻击者在网页中加一个恶意表单,用户提交表单的时候,把消息传送到攻击者的服务器,而不是原本的站点。
防范:对用户输入做字符过滤或者转义;避免在cookie中泄露用户隐私;最好使用POST提交表单。

(2) CSRF 跨站请求伪造(Cross-site request forgery)
要完成一次CSRF攻击,关键点:登录受信任的网站A,并在本地生成cookie;在不登出A的情况下,访问危险网站B。
防范:通过验证码或者token检测用户;避免全站通用cookie,设置cookie的域;用户操作最好都使用POST。

7. getElementsByClassName

获取页面元素的方法:
getElementById() 返回一个对象
getElementsByTagName() 返回集合
getElementsByClassName() 返回集合
querySelector() 返回一个对象
querySelectorAll() 返回集合

8. 前端路由实现的方式

(1)h5: window.history
兼容性:IE<=9 不支持

window.history.pushState(data, title, url); 
window.history.replaceState(data, title, url);

url: 绝对路径/相对路径, 同域。
这两个API可操作浏览器的历史栈,而不会引起页面刷新。
区别:pushState会在历史记录中增加一条,replaceState会替换当前的历史记录。

(2)hash: 当页面的 hash (window.location.hash) 发生变化时,会触发hashchange事件。
兼容性:IE<=7 不支持

window.onhashchange = fn;  
window.addEventListener("hashchange", fn, false);

9. 一个DOM元素绑定既绑定了冒泡事件,又绑定了捕获事件,执行顺序是?

绑定在同一个DOM元素上的事件,是按照事件声明的顺序执行的,无论是捕获还是冒泡;
这个DOM元素能够“感知”到的绑定在其他元素上的事件(比如绑定在其父元素上的事件),会按照先捕获事件,后冒泡事件的顺序执行。

var box = document.getElementById('box');    // 容器
var btn = document.getElementById('button'); // 容器内的按钮
// btn
btn.addEventListener('click', function(){   //1
    console.log('bubble','btn');
}, false);
btn.addEventListener('click', function(){   //2
    console.log('capture','btn');
}, true);
// box
box.addEventListener('click', function(){   //3
    console.log('bubble','box');
}, false);
box.addEventListener('click', function(){   //4
    console.log('capture','box');
}, true);

//点击按钮,console.log:  
  "capture" "box"  //4
  "bubble" "btn"   //1
  "capture" "btn"  //2
  "bubble" "box"   //3

//调换1、2顺序,打印结果顺序也会调换
//调换3、4顺序,打印结果不调换

10. HTTP及HTTP的缓存机制

11.apply、call、bind的区别

call、apply和bind都可以改变函数内部this的指向。第一个参数都是this要指向的对象。

call和apply都可以改变某个函数运行的上下文,函数内部的this指向call/apply的第一个参数。创建的时候会立即调用函数。
区别:函数的参数传入call/apply时,call第二个及其以后的参数位置依次传入函数的参数。apply的第二个参数是一个数组,是函数参数的数组。

bind会创建一个新的函数(绑定函数),创建的时候不会立即调用。当调用这个函数时,绑定函数会以创建时传入bind()方法的第一个参数作为this,第二个及其以后的参数依次传入原函数的参数。

call/apply:

// 获取数组中的最大或最小值
var numbers = [1, 2, 3, 100, -100];

Math.max(...numbers);
Math.max.call(null, ...numbers);   // 100
Math.max.apply(null, numbers);   // 100
// 判断是否是数组
function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
}

bind:

var x = 1;
var module = {
    x: 2,
    getX: function(){
        return this.x;
    }
}
var fn = module.getX.bind(module);
fn();   // 2

12. 一个DOM元素注册多个事件,怎样做到只执行第一个事件,后面事件不执行?

(1)设置一个全局变量,同一个事件的所有回调函数都会判断这个条件,条件满足就执行,执行的时候就将这个条件置为false,这样就能保证只有第一个回调函数会执行。

var btn = document.getElementById('button');
var flag = true;

btn.addEventListener('click', function(){
    console.log(1);
    if(flag) console.log('1-inner');
    flag = false;
}, false);

btn.addEventListener('click', function(){
    console.log(2);
    if(flag) console.log('2-inner');
}, false);

btn.addEventListener('click', function(){
    console.log(3);
    if(flag) console.log('3-inner');
}, false);

// console.log:
  1
  1-inner
  2
  3

我觉得,这不是个好方法。因为对于注册在元素上的多个同名事件,其实每个事件都执行了。在执行到回调函数内部再进行条件判断,并不算真正意义上的只执行了第一个事件吧。

(2)执行某个回调函数时取消事件监听

// 同一元素注册多个事件,同一个回调函数
var btn = document.getElementById('button');
var handler = function(){
    console.log('1')
    btn.removeEventListener('click', handler, false);
}
btn.addEventListener('click', handler, false);
btn.addEventListener('click', handler, false);
btn.addEventListener('click', handler, false);

// console.log:
   1

这种方法,需要保证多个绑定事件的回调函数是同一个。如果多个事件绑定多个回调函数,则无效。

(3)利用Promise.race()

Promise.race()方法简介:

Promise.race函数返回一个Promise,这个Promise的完成方式,取决于传递进去的多个Promise哪个先完成,可以是成功resolve,也可以是失败reject

var p1 = new Promise(function(resolve, reject){
    setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise(function(resolve, reject){
    setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise(function(resolve, reject){
    setTimeout(reject, 500, 'three');  // 最快执行
});
var p4 = new Promise(function(resolve, reject){
    setTimeout(reject, 1000, 'four');
})

Promise.race([p1, p2, p3, p4]).then(function(value){
    console.log(value);
}, function(reason){
    console.log(reason);
});

// console.log:
  'three'

一个DOM元素注册多个事件,只执行第一个事件。利用Promise.race()实现:

var btn = document.getElementById('btn');

var handler = function(){
    console.log('done');
};
var handler2 = function(){
    console.log('done2');
};
var handler3 = function(){
    console.log('done3');
};

var p1 = new Promise(function(resolve, reject){
    console.log(1);
    btn.addEventListener('click', handler, false);
    resolve();
});
var p2 = new Promise(function(resolve, reject){
    console.log(2);
    btn.addEventListener('click', handler2, false);
    resolve();
});
var p3 = new Promise(function(resolve, reject){
    console.log(3);
    btn.addEventListener('click', handler3, false);
    resolve();
});

Promise.race([p1, p2, p3]).then(function(){
    console.log('race');
    btn.removeEventListener('click', handler2, false);
    btn.removeEventListener('click', handler3, false);
})

// 点击按钮,依次打印:
  1
  2
  3
  race
  done

你可能感兴趣的:(2017.10.1)