2019最新前端JavaScript面试题集锦(三)(满满都是干货)

81.请说出三种减低页面加载时间的方法

1、压缩css、js文件

2、合并js、css文件,减少http请求

3、外部js、css文件放在最底下

4、减少dom操作,尽可能用变量替代不必要的dom操作

82.实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括NumberStringObjectArrayBoolean)进行值复制

  

 // 方法一:

Object.prototype.clone = function(){

   var o = this.constructor === Array ? [] : {};

   for(var e in this){

      o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];

   }

   return o;

}

//方法二:

     /**

     * 克隆一个对象

     * @param Obj

     * @returns

     */

    function clone(Obj) {   

        var buf;   

        if (Obj instanceof Array) {   

            buf = [];//创建一个空的数组 

            var i = Obj.length;   

            while (i--) {   

                buf[i] = clone(Obj[i]);   

            }   

            return buf;    

        }else if (Obj instanceof Object){   

            buf = {};//创建一个空对象 

            for (var k in Obj) { //为这个对象添加新的属性 

                buf[k] = clone(Obj[k]);   

            }   

            return buf;   

        }else{ //普通变量直接赋值

            return Obj;   

        }   

    }

 

 

  1. 如何消除一个数组里面重复的元素?

var arr=[1,2,3,3,4,4,5,5,6,1,9,3,25,4];

        function deRepeat(){

            var newArr=[];

            var obj={};

            var index=0;

            var l=arr.length;

            for(var i=0;i<l;i++){

                if(obj[arr[i]]==undefined)

                  {

                    obj[arr[i]]=1;

                    newArr[index++]=arr[i];

                  }

                else if(obj[arr[i]]==1)

                  continue;

            }

            return newArr;

        }

        var newArr2=deRepeat(arr);

        alert(newArr2); //输出1,2,3,4,5,6,9,25

 

 

84.定义一个log方法,让它可以代理console.log的方法。

function log(msg) {

    console.log(msg);

}

log("hello world!") // hello world!

如果要传入多个参数呢?显然上面的方法不能满足要求,所以更好的方法是:

function log(){

    console.log.apply(console, arguments);

};

到此,追问apply和call方法的异同。

对于apply和call两者在作用上是相同的,即是调用一个对象的一个方法,以另一个对象替换当前对象。将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

但两者在参数上有区别的。对于第一个参数意义都一样,但对第二个参数: apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。 如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var2,var3]) 。

85.原生JSwindow.onloadJquery$(document).ready(function(){})有什么不同?如何用原生JS实现Jqready方法?

window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。

$(document).ready()DOM结构绘制完毕后就执行,不必等到加载完毕。

/*

 * 传递函数给whenReady()

 * 当文档解析完毕且为操作准备就绪时,函数作为document的方法调用

 */

var whenReady = (function() {               //这个函数返回whenReady()函数

    var funcs = [];             //当获得事件时,要运行的函数

    var ready = false;          //当触发事件处理程序时,切换为true

    //当文档就绪时,调用事件处理程序

    function handler(e) {

        if(ready) return;       //确保事件处理程序只完整运行一次

        //如果发生onreadystatechange事件,但其状态不是complete的话,那么文档尚未准备好

        if(e.type === 'onreadystatechange' && document.readyState !== 'complete') {

            return;

        }

        //运行所有注册函数

        //注意每次都要计算funcs.length

        //以防这些函数的调用可能会导致注册更多的函数

        for(var i=0; i<funcs.length; i++) {

            funcs[i].call(document);

        }

        //事件处理函数完整执行,切换ready状态, 并移除所有函数

        ready = true;

        funcs = null;

    }

    //为接收到的任何事件注册处理程序

    if(document.addEventListener) {

        document.addEventListener('DOMContentLoaded', handler, false);

        document.addEventListener('readystatechange', handler, false);            //IE9+

        window.addEventListener('load', handler, false);

    }else if(document.attachEvent) {

        document.attachEvent('onreadystatechange', handler);

        window.attachEvent('onload', handler);

    }

    //返回whenReady()函数

    return function whenReady(fn) {

        if(ready) { fn.call(document); }

        else { funcs.push(fn); }

    }

})();

如果上述代码十分难懂,下面这个简化版:

function ready(fn){

    if(document.addEventListener) {//标准浏览器

        document.addEventListener('DOMContentLoaded', function() {

            //注销事件, 避免反复触发

            document.removeEventListener('DOMContentLoaded',arguments.callee, false);

            fn();//执行函数

        }, false);

    }else if(document.attachEvent) {//IE

        document.attachEvent('onreadystatechange', function() {

            if(document.readyState == 'complete') {

                document.detachEvent('onreadystatechange', arguments.callee);

                fn();//函数执行

            }

        });

    }

};

 

 

  1. (设计题)想实现一个对页面某个节点(比如:对某个div)的拖曳?如何做?(使用原生JS

回答出概念即可,下面是几个要点

给需要拖拽的节点绑定mousedown, mousemove, mouseup事件

mousedown事件触发后,开始拖拽

mousemove时,需要通过event.clientX和clientY获取拖拽位置,并实时更新位置

mouseup时,拖拽结束

需要注意浏览器边界的情况

87. 数组和对象有哪些原生方法,列举一下?

  1. Array.concat( ) 连接数组 
  2. Array.join( ) 将数组元素连接起来以构建一个字符串 
  3. Array.length 数组的大小 
  4. Array.pop( ) 删除并返回数组的最后一个元素 
  5. Array.push( ) 给数组添加元素 
  6. Array.reverse( ) 颠倒数组中元素的顺序 
  7. Array.shift( ) 将元素移出数组 
  8. Array.slice( ) 返回数组的一部分 
  9. Array.sort( ) 对数组元素进行排序 
  10. Array.splice( ) 插入、删除或替换数组的元素 
  11. Array.toLocaleString( ) 把数组转换成局部字符串 
  12. Array.toString( ) 将数组转换成一个字符串 
  13. Array.unshift( ) 在数组头部插入一个元素
  14.  
  15. Object.hasOwnProperty( ) 检查属性是否被继承 
  16. Object.isPrototypeOf( ) 一个对象是否是另一个对象的原型 
  17. Object.propertyIsEnumerable( ) 是否可以通过for/in循环看到属性 
  18. Object.toLocaleString( ) 返回对象的本地字符串表示 
  19. Object.toString( ) 定义一个对象的字符串表示 
  20. Object.valueOf( ) 指定对象的原始值

88.JS 怎么实现一个类。怎么实例化这个类

严格来讲js中并没有类的概念,不过js中的函数可以作为构造函数来使用,通过new来实例化,其实函数本身也是一个对象。

89.JS中有哪些会被隐式转换为false

Undefined、null、关键字false、NaN、零、空字符串

90.外部JS文件出现中文字符,会出现什么问题,怎么解决?

会出现乱码,加charset=”utf-8”;

91.写一个通用的事件侦听器函数

// event(事件)工具集,来源:https://github.com/markyun

markyun.Event = {

    // 页面加载完成后

    readyEvent : function(fn) {

        if (fn==null) {

            fn=document;

        }

        var oldonload = window.onload;

        if (typeof window.onload != 'function') {

            window.onload = fn;

        } else {

            window.onload = function() {

                oldonload();

                fn();

            };

        }

    },

    // 视能力分别使用dom0||dom2||IE方式 来绑定事件

    // 参数: 操作的元素,事件名称 ,事件处理程序

    addEvent : function(element, type, handler) {

        if (element.addEventListener) {

            //事件类型、需要执行的函数、是否捕捉

            element.addEventListener(type, handler, false);

        } else if (element.attachEvent) {

            element.attachEvent('on' + type, function() {

                handler.call(element);

            });

        } else {

            element['on' + type] = handler;

        }

    },

    // 移除事件

    removeEvent : function(element, type, handler) {

        if (element.removeEnentListener) {

            element.removeEnentListener(type, handler, false);

        } else if (element.datachEvent) {

            element.detachEvent('on' + type, handler);

        } else {

            element['on' + type] = null;

        }

    },

    // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)

    stopPropagation : function(ev) {

        if (ev.stopPropagation) {

            ev.stopPropagation();

        } else {

            ev.cancelBubble = true;

        }

    },

    // 取消事件的默认行为

    preventDefault : function(event) {

        if (event.preventDefault) {

            event.preventDefault();

        } else {

            event.returnValue = false;

        }

    },

    // 获取事件目标

    getTarget : function(event) {

        return event.target || event.srcElement;

    },

    // 获取event对象的引用,取到事件的所有信息,确保随时能使用event

    getEvent : function(e) {

        var ev = e || window.event;

        if (!ev) {

            var c = this.getEvent.caller;

            while (c) {

                ev = c.arguments[0];

                if (ev && Event == ev.constructor) {

                    break;

                }

                c = c.caller;

            }

        }

        return ev;

    }

};

 

92.JSON 的了解

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它是基于JavaScript的 一个子集。数据格式简单, 易于读写, 占用带宽小

{'age':'12', 'name':'back'}

2.DOM相关

1.targetcurrentTarget区别

target在事件流的目标阶段;currentTarget在事件流的捕获,目标及冒泡阶段。只有当事件流处在目标阶段的时候,两个的指向才是一样的, 而当处于捕获和冒泡阶段的时候,target指向被单击的对象而currentTarget指向当前事件活动的对象(一般为父级)。

 

2. DOM的增删改查操作?

(1)创建新节点

    createDocumentFragment()    //创建一个DOM片段

    createElement()   //创建一个具体的元素

    createTextNode()   //创建一个文本节点

  (2)添加、移除、替换、插入

    appendChild()

    removeChild()

    replaceChild()

    insertBefore() //在已有的子节点前插入一个新的子节点

  (3)查找

    getElementsByTagName()    //通过标签名称

    getElementsByName()    //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)

    getElementById()    //通过元素Id,唯一性

  1. 请描述DOM事件流的过程?

DOM事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。

 

  1. 事件委托的原理,作用,和触发事件的对象是谁?

 

因为事件具有冒泡机制,因此我们可以利用冒泡的原理,把事件加到父级上,触发执行效果。这样做的好处当然就是提高性能了

 

最重要的是通过event.target判断触发事件的对象是谁

 

5.documen.write innerHTML的区别

  document.write只能重绘整个页面

 

  innerHTML可以重绘页面的一部分

3.BOM相关

4.JS高级

1.函数高级

1.闭包

特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃 圾回收机制回收

 

闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。

 

为什么要使用闭包:

 

为了设计私有方法和变量,避免全局变量污染 希望一个变量长期驻扎在内存中

 

view detail: https://segmentfault.com/a/1190000000652891

2.原型与原型链

当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找Prototype.Prototype引用的对象,依次类推,直到Prototype.….Prototype为undefined(Object的Prototype就是undefined)从而形成了所谓的“原型链”。

 

其中foo是Function对象的实例。而Function的原型对象同时又是Object的实例。这样就构成了一条原型链。

 

instanceof 确定原型和实例之间的关系

 

用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上

 

对象的__proto__指向自己构造函数的prototype。obj.__proto__.__proto__...的原型链由此产生,包括我们的操作符instanceof正是通过探测obj.__proto__.__proto__... === Constructor.prototype来验证obj是否是Constructor的实例。

 

function C(){}

 

var o = new C(){}

//true 因为Object.getPrototypeOf(o) === C.prototype

o instanceof C

instanceof只能用来判断对象和函数,不能用来判断字符串和数字

 

isPrototypeOf

 

用于测试一个对象是否存在于另一个对象的原型链上。

 

判断父级对象 可检查整个原型链

3.作用域与作用域链

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。

 全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。

 当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,

 直至全局函数,这种组织形式就是作用域链。

4.apply, callbind有什么区别?

参考答案:三者都可以把一个函数应用到其他对象上,call、apply是修改函数的作用域(修改this指向),并且立即执行,而bind是返回了一个新的函数,不是立即执行.apply和call的区别是apply接受数组作为参数,而call是接受逗号分隔的无限多个参数列表,

 

Array.prototype.slice.call(null, args)

 

function getMax(arr){

  return Math.max.apply(null, arr);

}

//call

function foo() {

  console.log(this);//{id: 42}

}

 

foo.call({ id: 42 });

如果该方法是非严格模式代码中的函数,则null和undefined将替换为全局对象,并且原始值将被包装。 当你调用apply传递给它null时,就像是调用函数而不提供任何对象

5.谈谈对this的理解

this总是指向函数的直接调用者(而非间接调用者);

 

如果有new关键字,this指向new出来的那个对象;

 

在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;

6.那些操作会造成内存泄漏?

 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。

 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

 

 setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。

 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

7.深入贯彻闭包思想,全面理解JS闭包形成过程

https://segmentfault.com/a/1190000009886713

8.下面这个ul,如何点击每一列的时候alertindex?(闭包)

<ul id=”test”>

<li>这是第一条</li>

<li>这是第二条</li>

<li>这是第三条</li>

</ul>

// 方法一:

var lis=document.getElementById('2223').getElementsByTagName('li');

for(var i=0;i<3;i++)

{

    lis[i].index=i;

    lis[i].onclick=function(){

        alert(this.index);

    };

}

//方法二:

var lis=document.getElementById('2223').getElementsByTagName('li');

for(var i=0;i<3;i++){

    lis[i].index=i;

    lis[i].onclick=(function(a){

        return function() {

            alert(a);

        }

    })(i);

}

2.对象高级

1.js继承方式及其优缺点

原型链继承的缺点

一 是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

借用构造函数(类式继承)

借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承

 

组合式继承

组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。

2.上下文环境对象

3.new操作符具体做了什么

1、创建一个空对象,并且this变量引用该对象,同时继承了该函数的原型(实例对象通过__proto__属性指向原型对象;obj.__proto__ = Base.prototype;) 2、属性和方法被加入到 this 引用的对象中。

 

function Animal(name) {

    this.name = name;

}

 

Animal.prototype.run = function() {

    console.log(this.name + 'can run...');

}

 

var cat = new Animal('cat');

//模拟过程

new Animal('cat')=function(){

    let obj={};  //创建一个空对象

    obj.__proto__=Animal.prototype;

    //把该对象的原型指向构造函数的原型对象,就建立起原型了:obj->Animal.prototype->Object.prototype->null

    return Animal.call(obj,'cat');// 绑定this到实例化的对象上

}

4.创建对象的几种方式

 javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON;但写法有很多种,也能混合使用。

 

 

 1、对象字面量的方式

 

    person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};

 

 2、用function来模拟无参的构造函数

 

    function Person(){}

    var person=new Person();//定义一个function,如果使用new"实例化",该function可以看作是一个Class

    person.name="Mark";

    person.age="25";

    person.work=function(){

    alert(person.name+" hello...");

    }

    person.work();

 

 3、用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)

 

    function Pet(name,age,hobby){

       this.name=name;//this作用域:当前对象

       this.age=age;

       this.hobby=hobby;

       this.eat=function(){

          alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员");

       }

    }

    var maidou =new Pet("麦兜",25,"coding");//实例化、创建对象

    maidou.eat();//调用eat方法

 

 

 4、用工厂方式来创建(内置对象)

 

     var wcDog =new Object();

     wcDog.name="旺财";

     wcDog.age=3;

     wcDog.work=function(){

       alert("我是"+wcDog.name+",汪汪汪......");

     }

     wcDog.work();

 

 

 5、用原型方式来创建

 

    function Dog(){

 

     }

     Dog.prototype.name="旺财";

     Dog.prototype.eat=function(){

     alert(this.name+"是个吃货");

     }

     var wangcai =new Dog();

     wangcai.eat();

 

 

 5、用混合方式来创建

 

    function Car(name,price){

      this.name=name;

      this.price=price;

    }

     Car.prototype.sell=function(){

       alert("我是"+this.name+",我现在卖"+this.price+"万元");

      }

    var camry =new Car("凯美瑞",27);

    camry.sell();

3.线程机制

1.同步和异步的区别?

同步:阻塞的

-张三叫李四去吃饭,李四一直忙得不停,张三一直等着,直到李四忙完两个人一块去吃饭

=浏览器向服务器请求数据,服务器比较忙,浏览器一直等着(页面白屏),直到服务器返回数据,浏览器才能显示页面

异步:非阻塞的

-张三叫李四去吃饭,李四在忙,张三说了一声然后自己就去吃饭了,李四忙完后自己去吃

=浏览器向服务器请求数据,服务器比较忙,浏览器可以自如的干原来的事情(显示页面),服务器返回数据的时候通知浏览器一声,浏览器把返回的数据再渲染到页面,局部更新

5.ES6相关

1.谈一谈letvarconst的区别?

let为ES6新添加申明变量的命令,它类似于var,但是有以下不同:

 

let命令不存在变量提升,如果在let前使用,会导致报错

 

暂时性死区的本质,其实还是块级作用域必须“先声明后使用”的性质。

 

let,const和class声明的全局变量不是全局对象的属性。

 

const声明的变量与let声明的变量类似,它们的不同之处在于,const声明的变量只可以在声明时赋值,不可随意修改,否则会导致SyntaxError(语法错误)。

 

const只是保证变量名指向的地址不变,并不保证该地址的数据不变。const可以在多个模块间共享 let 暂时性死区的原因:var 会变量提升,let 不会。

2.箭头函数

箭头函数不属于普通的 function,所以没有独立的上下文。箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 由于箭头函数没有自己的this,函数对象中的call、apply、bind三个方法,无法"覆盖"箭头函数中的this值。 箭头函数没有原本(传统)的函数有的隐藏arguments对象。 箭头函数不能当作generators使用,使用yield会产生错误。

 

在以下场景中不要使用箭头函数去定义:

 

    1. 定义对象方法、定义原型方法、定义构造函数、定义事件回调函数。

    2. 箭头函数里不但没有 this,也没有 arguments, super ……

3. MapSet

Symbol,Map和Set

 

Map 对象保存键值对。一个对象的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。 Set 对象允许你存储任何类型的唯一值,Set对象是值的集合,Set中的元素只会出现一次 Symbol 是一种特殊的、不可变的数据类型,可以作为对象属性的标识符使用(Symbol([description]) )

 

let mySet = new Set()

mySet.add(1)

mySet.add('hello')

mySet.add('hello')

console.log(mySet.size);//2

console.log(mySet);//Set {1,'hello'}

 

//Map保存键值对也不能有重复的

let myMap = new Map();

let key1 = 'China',key2 = 'America';

myMap.set(key1,'welcome')

myMap.set(key2,'gold bless you')

console.log(myMap);//Map { 'China' => 'welcome', 'America' => 'gold bless you' }

console.log(myMap.get(key1));//welcome

console.log(myMap.get(key2));//gold bless you

 

let mySymbol = Symbol('symbol1');

let mySymbol2 = Symbol('symbol1');

console.log(mySymbol == mySymbol2);//false

//Symbols 在 for...in 迭代中不可枚举。

let obj = {}

obj['c'] = 'c'

obj.d ='d'

obj[Symbol('a')] = 'a'

obj[Symbol.for('b')] = 'b'

for(let k in obj){

    console.log(k);//logs 'c' and 'd'

}

for...of可以用来遍历数组,类数组对象,argument,字符串,Map和Set,for...in用来遍历对象

4.Promise实现原理

现在回顾下Promise的实现过程,其主要使用了设计模式中的观察者模式:

 

通过Promise.prototype.then和Promise.prototype.catch方法将观察者方法注册到被观察者Promise对象中,同时返回一个新的Promise对象,以便可以链式调用。

 

被观察者管理内部pending、fulfilled和rejected的状态转变,同时通过构造函数中传递的resolve和reject方法以主动触发状态转变和通知观察者。

 

Promise.then()是异步调用的,这也是Promise设计上规定的,其原因在于同步调用和异步调用同时存在会导致混乱。

 

为了暂停当前的 promise,或者要它等待另一个 promise 完成,只需要简单地在 then() 函数中返回另一个 promise。

 

Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

 

一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法,理由是更接近同步的写法。 then的第二个函数参数和catch等价

 

Promise.all和Promise.race的区别?

Promise.all 把多个promise实例当成一个promise实例,当这些实例的状态都发生改变时才会返回一个新的promise实例,才会执行then方法。 Promise.race 只要该数组中的 Promise 对象的状态发生变化(无论是resolve还是reject)该方法都会返回。

5.Object.is() 与原来的比较操作符“ ===”、“ ==”的区别?

 两等号判等,会在比较时进行类型转换;

  三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);

 

  Object.is 在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,

  但 Object.is(NaN, NaN) 会返回 true.

 

  Object.is 应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。

6.前端面试之ES6

https://juejin.im/post/59c8aec0f265da065c5e965e

6.跨域

1.JSONP

回调函数+数据就是 JSON With Padding,简单、易部署。(做法:动态插入script标签,设置其src属性指向提供JSONP服务的URL地址,查询字符串中加入 callback 指定回调函数,返回的 JSON 被包裹在回调函数中以字符串的形式被返回,需将script标签插入body底部)。缺点是只支持GET,不支持POST(原因是通过地址栏传参所以只能使用GET)

2.document.domain 跨子域

document.domain 跨子域 ( 例如a.qq.com嵌套一个b.qq.com的iframe ,如果a.qq.com设置document.domain为qq.com 。b.qq.com设置document.domain为qq.com, 那么他俩就能互相通信了,不受跨域限制了。 注意:只能跨子域)

3. iframe

window.name + iframe ==> http://www.tuicool.com/articles/viMFbqV,支持跨主域。不支持POST

4.postMessage()

HTML5的postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。适用于不同窗口iframe之间的跨域

5.CORS

CORS(Cross Origin Resource Share)对方服务端设置响应头

设置相应头:”Access-Control-Allow-Origin“

 

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

6.服务端代理

服务端代理 在浏览器客户端不能跨域访问,而服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就没有跨越问题。简单地说,就是浏览器不能跨域,后台服务器可以跨域。(一种是通过http-proxy-middleware插件设置后端代理;另一种是通过使用http模块发出请求)

 

7.Ajax

1.ajax请求和原理

var xhr = new XMLHTTPRequest();

// 请求 method 和 URI

xhr.open('GET', url);

// 请求内容

xhr.send();

// 响应状态

xhr.status

// xhr 对象的事件响应

xhr.onreadystatechange = function() {}

xhr.readyState

// 响应内容

xhr.responseText

 

AJAX的工作原理

Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。 Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。

 

ajax优缺点

优点:无刷新更新数据 异步与服务器通信 前后端负载均衡

 

缺点:

 

1)ajax干掉了Back和history功能,对浏览器机制的破坏 2)对搜索引擎支持较弱 3)违背了URI和资源定位的初衷

2.fetchAjax有什么不同

XMLHttpRequest 是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。

 

fetch 是浏览器提供的一个新的 web API,它用来代替 Ajax(XMLHttpRequest),其提供了更优雅的接口,更灵活强大的功能。 Fetch 优点主要有:

 

    语法简洁,更加语义化

    基于标准 Promise 实现,支持 async/await

 

fetch(url).then(response => response.json())

  .then(data => console.log(data))

  .catch(e => console.log("Oops, error", e))

3.GETPOST的区别

GET和POST的区别

 

GET使用URL或Cookie传参,而POST将数据放在BODY中,这个是因为HTTP协议用法的约定。并非它们的本身区别。

GET方式提交的数据有长度限制,则POST的数据则可以非常大,这个是因为它们使用的操作系统和浏览器设置的不同引起的区别。也不是GET和POST本身的区别。

POST比GET安全,因为数据在地址栏上不可见,这个说法没毛病,但依然不是GET和POST本身的区别。

GET和POST最大的区别主要是GET请求是幂等性的,POST请求不是。(幂等性:对同一URL的多个请求应该返回同样的结果。)因为get请求是幂等的,在网络不好的隧道中会尝试重试。如果用get请求增数据,会有重复操作的风险,而这种重复操作可能会导致副作用

4.GET,POST,PUT,Delete

1.  GET请求会向数据库获取信息,只是用来查询数据,不会修改,增加数据。使用URL传递参数,对所发送的数量有限制,一般在2000字符

 

2.  POST向服务器发送数据,会改变数据的种类等资源,就像insert操作一样,会创建新的内容,大小一般没有限制,POST安全性高,POST不会被缓存

 

3.  PUT请求就像数据库的update操作一样,用来修改数据内容,不会增加数据种类

 

4.  Delete用来删除操作

5.缓存,存储相关(cookieweb storagesession

cookie优点: 1.可以解决HTTP无状态的问题,与服务器进行交互 缺点: 1.数量和长度限制,每个域名最多20条,每个cookie长度不能超过4kb 2.安全性问题。容易被人拦截 3.浪费带宽,每次请求新页面,cookie都会被发送过去

 

cookie和session区别

 

1.cookie数据存放在客户的浏览器上,session数据放在服务器上。 2.session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE。

 

sessionStorage是当前对话的缓存,浏览器窗口关闭即消失,localStorage持久存在,除非清除浏览器缓存。

 

页面缓存原理

 

页面缓存状态是由http header决定的,一个浏览器请求信息,一个是服务器响应信息。主要包括Pragma: no-cache、Cache-Control、 Expires、 Last-Modified、If-Modified-Since。

6.什么是Cookie 隔离?(或者说:请求资源的时候不要让它带cookie怎么做)

  如果静态文件都放在主域名下,那静态文件请求的时候都带有的cookie的数据提交给server的,非常浪费流量,

  所以不如隔离开。

 

  因为cookie有域的限制,因此不能跨域提交请求,故使用非主要域名的时候,请求头中就不会带有cookie数据,

  这样可以降低请求头的大小,降低请求时间,从而达到降低整体请求延时的目的。

 

  同时这种方式不会将cookie传入Web Server,也减少了Web Server对cookie的处理分析环节,

  提高了webserver的http请求的解析速度。

7. Ajax 解决浏览器缓存问题?

  1、在ajax发送请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")。

 

  2、在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。

 

  3、在URL后面加上一个随机数: "fresh=" + Math.random();。

 

  4、在URL后面加上时间戳:"nowtime=" + new Date().getTime();。

 

 5、如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

 

猜你喜欢

转载自blog.csdn.net/qq_42451932/article/details/86180223