前端面试题(js)

1、call、apply、bind的区别

这三个都是用来定义上下文的,call、apply会指定上下文并执行函数;而bind终身定 死上下文但是不执行函数,并返回新的函数。 其中call和apply传入参数的形式有别,call是单独罗列,逗号隔开参数;apply是数 组。 函数.call(上下文对象,参数,参数,参数); 函数.apply(上下文对象,[参数,参数,参数]);

var obj = {
 a: 10
}
​
function fun(b, c){
 console.log(this.a + b + c);
}
​
fun.call(obj, 3, 4);
fun.apply(obj, [3, 4]);
fun = fun.bind(obj); // 返回新的函数
fun(3,4);
 相同点:
     作用相同,都是动态修改this指向;都不会修改原先函数的this指向。
 不同点
    执行方式不同
         call和apply是改变后页面加载之后就立即执行,是同步代码。
         bind是异步代码,改变后不会立即执行;而是返回一个新的函数
    传参方式不同
        call和bind传参是一个一个逐一传入,不能使用剩余参数的方式传参。
        apply可以使用数组的方式传入的,只要是数组方式就可以使用剩余参数的方式传入。
    修改this的性质不同
        call、apply只是临时的修改一次,也就是call和apply方法的那一次;当再次调用原函数的时候,它的指向还是原来的指向。
        bind是永久修改函数this指向,但是它修改的不是原来的函数;而是返回一个修改过后新的函数,此函数的this永远被改变了,绑定了        就修改不了。


2、数据类型有哪些

基本类型:数字number、字符串string、布尔boolean、undefined、null、symbol

引用类型:数组array、函数function、对象object


3、如何检测数据类型

typeof 能够检测:数字、字符串、布尔、undefined、symbol、function

instanceof 能够检测:数组

Object.prototype.toString.call() 万能法


4、各语句的区别

4.1、for和for...in和for...of的区别

for循环,遍历整个数组

for...in加强循环,不光可以遍历数组,还可以遍历对象和其原型上的方法

for...of遍历数组和可枚举的对象

4.2、switch和if的区别

switch用于判断精准的值

if用于判断值的范围

4.3、while和do...while的区别

while当符合条件时则执行

do...while先执行一次,然后再判断是否符合条件,比while要多执行一次

4.4、break和continue的区别

break是跳出当前循环并终止循环

continue是跳出当前循环并执行下一次循环


5、闭包

闭包就是函数能够记忆住当初定义时候的作用域,不管函数到哪里执行了,永远都能够 记住那个作用域,并且会遮蔽新作用域的变量。可预测状态容器;实现模块化,实现变量的私有封装;可以实现迭代器。 闭包缺点:1.闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅 因为它常驻内存,更重要的是,对闭包的使用不当的话会造成无效内存的产生;2.性能问题 使用闭包时,会涉及到跨作用域访问,每次访问都会导致性能损失。 因此在脚本中,最好小心使用闭包,它同时会涉及到内存和速度问题。不过我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。

    
  function foo(){
        var a = 0;
        function f(){
          a++;
          return a;
        }
        return f;
      }
      var res = foo();
      res(); 
      res();
      res();
      console.log(res()); // 4 a的值被存储在内存中不会被释放掉
能够访问其他函数内部变量的函数
优点:会延伸变量的使用范围,一直存储在全局变量中 避免全局污染
缺点:会造成内存泄漏,浪费性能


6、原型和原型链

原型:每一个引用类型都有一个隐式原型__ proto __ ,每一个函数都有一个显示原型prototype,该属性指向它的原型对象。

原型链:某个对象的原型又有自己的原型,直到某个对象的原型为null为止,组成这条的最后一环,这种一级一级的链就是原型链。

原型:在函数声明时,会自动创建一个共享空间,用于存储共享的属性和方法
​
原型链:一种查找机制,先找实例本身,如果找不到在__proto__中查找,没有再去构造函数中查找,都找不到就返回undefined


7、继承

7.1、原型链继承

创建父类和子类的构造函数
让子类继承父类  让子类的prototype = 父类的实例化对象
实例化子类
缺点:不能传参, 创建的对象都是一样的,一改全改

/**
 * 缺点:引用类型的属性被所有实例共享,
 * 在创建Child 的实例时, 不能向Person传参
 */
   function Person() {
    this.name = "哈哈";
   }
   Person.prototype.getName = function () {
    console.log(this.name);
   };
   function Child() {}
   Child.prototype = new Person();

7.2、借用构造函数继承(经典继承,对象冒充继承)

创建父类和子类的函数
在子类里面添加父类  使用:父类.call(this,参数...)
优点:可以传参,避免了引用类型的属性被所有实例共享
缺点:获取不到父类的prototypr中的方法,浪费内存

/*
优点:
1.避免了引用类型的属性被所有实例共享
2.可以在Child中向Parent传参
缺点:
1.只是子类的实例,不是父类的实例
2.方法都在构造函数中定义,每次创建实例都会创建一遍方法
*/
   function Child() {
    Person.call(this);
   }

7.3、组合继承

创建父类和子类(使用对象冒充继承,父类.call)的构造函数
让子类的prototype = 父类的实例化对象
缺点:调用了俩次父类的构造函数

/*
优点:融合原型链继承和构造函数的优点,是JavaScript中最常用的继承模式
缺点:调用了两次父类构造函数
组合继承最大的问题是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子
类型原型的时候,另一次是在子类型构造函数内部)
*/
  
 function Child(name, age) {
    Parent.call(this, name); // 第二次调用 Parent()
    this.age = age;
   }
   Child.prototype = new Parent(); // 第一次调用 Parent()

7.4、原型式继承

 // 缺点: 包含引用类型的属性值始终都会共享相应的值, 这点跟原型链继承一样
   function CreateObj(o) {
    function F() {}
    F.prototype = o;
    return new F();
   }
   var person = {
    name: "xiaopao",
    friend: ["daisy", "kelly"],
   };
   var person1 = CreateObj(person);

7.5、寄生式继承 可以理解为在原型式继承的基础上增加一些函数或属性

 // 缺点:跟借用构造函数一样,每次创建对象都会创建一遍方法
​
   var ob = {
    name: "xiaopao",
    friends: ["lulu", "huahua"],
   };
​
   function CreateObj(o) {
    function F() {} // 创建一个构造函数F
    F.prototype = o;
    return new F();
   }
​
   // 上面CreateObj函数 在ECMAScript5 有了一新的规范写法,Object.create(ob) 效果是一样的 , 看下面代码
   var ob1 = CreateObj(ob);
   console.log(ob1.name); // xiaopao

7.6、寄生组合式继承

在混合继承的基础上,把原型链的继承该成在父类的原型的基础上创建
子类.prototype = object.create(父类.peototype)

// 优点:完美继承
// 缺点:代码繁多,使用起来十分麻烦
   function Parent(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
   }
​
   Parent.prototype.sayName = function () {
    console.log(this.name);
   };
​
   function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
   }
​
   function CreateObj(o) {
    function F() {}
    F.prototype = o;
    return new F();
   }
​
​
   // Child.prototype = new Parent(); // 这里换成下面
   function prototype(child, parent) {
    var prototype = CreateObj(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
   }
   prototype(Child, Parent);
​
​
   var child1 = new Child("xiaopao", 18);
​
   console.log(child1);

7.7、es6 继承

 class Child extends Parent {}


8、递归和递归优化

递归就是函数自己调用自己。但是又不能无限的调用自己,需要有一个出口,否则会成为死循环。函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

递归:在函数内部自己调用自己 一定要有结束条件

// 循环求1-5的所有数的和
var sum = 0;
for(var i = 1; i <= 5; i++){
    sum += i;
}
console.log(sum) // 15
​
//递归实现1-5的所有数的和
function sum(n){
    if(n === 1){
        return 1;
    }
    return n + sum(n-1);
}
console.log(sum(5)); //15

尾递归优化是解决递归调用栈溢出的方法。尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

// 上例递归进行尾递归优化
function sum(n, m = 0){
    if(n === 1){
        return 1 + m;
    }
    return sum(n-1, n + m);
}
console.log(sum(5)); //15
​
// 或者while优化
function sum(n, m = 0){
    while(n >= 1){
        return sum(n - 1, n + m);
    }
    return m;
}
console.log(sum(5)); // 15


9、ajax工作原理和封装

1.创建XMLHttpRequest对象。 2.设置请求方式。open() 3.调用回调函数。onreadystatechange 4.发送请求。send()

  function ajax(options) {
        const { type, dataType, data, timeout, url, success, error } = options;
        var params = formatParams(data);
        var xhr;
        //考虑兼容性
        if (window.XMLHttpRequest) {
          xhr = new XMLHttpRequest();
        } else if (window.ActiveObject) {
          //兼容IE6以下版本
          xhr = new ActiveXobject("Microsoft.XMLHTTP");
        }
        //启动并发送一个请求
        if (type == "GET") {
          xhr.open("GET", url + "?" + params, true);
          xhr.send();
        } else if (type == "POST") {
          xhr.open("post", url, true);
          //设置表单提交时的内容类型
          //Content‐type数据请求的格式
          xhr.setRequestHeader(
            "Content‐type",
            "application/x‐www‐form‐urlencoded"
          );
          xhr.send(params);
        }
​
        // 设置有效时间
        setTimeout(function () {
          if (xhr.readySate != 4) {
            xhr.abort();
          }
        }, timeout);
​
        // 接收
        // options.success成功之后的回调函数 options.error失败后的回调函数
        //xhr.responseText,xhr.responseXML 获得字符串形式的响应数据或者XML形式的响应数据
        xhr.onreadystatechange = function () {
          if (xhr.readyState == 4) {
            var status = xhr.status;
            if ((status >= 200 && status < 300) || status == 304) {
              success && success(xhr.responseText, xhr.responseXML);
            } else {
              error && error(status);
            }
          }
        };
      }
​
      //格式化请求参数
      function formatParams(data) {
        var arr = [];
        for (var name in data) {
          arr.push(
            encodeURIComponent(name) + "=" + encodeURIComponent(data[name])
          );
        }
        arr.push(("v=" + Math.random()).replace(".", ""));
        return arr.join("&");
      }


10、跨域

跨域:协议域名端口号只要有一个不一样就会产生跨域问题
解决方法:
    1.cors  就是服务端在HTTP返回头上加上“AccessControll-Allow-Origin:*”
    2.通过proxy代理
    3.jsonp  利用script的src属性没有跨域限制,将要访问的地址 赋值给src ,服务器返回一个函数,调用函数,传递一个jsonp格式的参数
    4.cors中间件:哪个响应头被拦截 就头设置cors响应头,解除浏览器的限制

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。其 实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。同源策略SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR 等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地 址,也非同源。

方法1:跨域资源共享CORS跨域,就是服务端在HTTP返回头上加上“AccessControll-Allow-Origin:*”。 “Access-Controll-Allow-METHODS:GET, POST” DELETE、PATCH请求类型会发出OPTIONS预检请求。

方法2:代理跨域,webpack-dev-server里面的proxy配置项。config中的 ProxyTable

方法3:JSONP,利用页面srcipt没有跨域限制的漏洞,用script的src引入它,然后页 面内定义回调函数,jQuery中$.ajax({dataType: ‘jsonp’})。

方法4: iframe跨域,配合window.name或者 location.hash或者document.domain 一起使用

方法5:nginx反向代理接口跨域,通过nginx配置一个代理服务器(域名与domain1 相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中 domain信息,方便当前域cookie写入,实现跨域登录。

方法6:jquery的ajax跨域,dataType:'jsonp'


11、事件流和事件委托

事件流一般分三个阶段:1、捕获阶段(由外向内) 2、目标阶段 (执行阶段) 3、冒泡阶段(由内向外)

阻止事件冒泡e.stopPropagation() 阻止默认动作e.preventDefault()

事件委托:就是把事件委托给父级,利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

事件委托:将事件加给父元素,事件发生时,通过事件目标e.target找到对应的子元素去做
事件流一般分三个阶段:1、捕获阶段(由外向内)  2、目标阶段 (执行阶段) 3、冒泡阶段(由内向外) 
​
阻止事件冒泡e.stopPropagation()  阻止默认动作e.preventDefault()


12、事件循环

同步任务进入主线程,异步任务进入Event Table并注册函数 当指定的事情完成时,Event Table会将这个函数移入Event Queue。 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执 行。 上述过程会不断重复,也就是常说的Event Loop(事件循环)。

同步任务进入主线程执行,异步任务放在任务队列中等待执行,等主线程的同步任务执行完毕之后,再去执行任务队列中的异步任务,此上操作重复执行, 被称为事件循环

   
   console.log("script start");
​
      setTimeout(function () {
        console.log("setTimeout");
      }, 0);
​
      Promise.resolve()
        .then(function () {
          console.log("promise1");
        })
        .then(function () {
          console.log("promise2");
        });
​
      console.log("script end");
      /* 执行结果为:script start, script end, promise1, promise2, setTimeout因为Promise是微任务,主线程会在同步任务做完后先清空微任务队列,再执行宏任务队列 */

微任务是由JavaScript自身发起,包括:process.nextTick、promise、MutationObserver

宏任务是由宿主发起的,如浏览器、node。包括:setTimeout、setInterval、setImmediate、postMessage

事件循环又叫消息循环,是浏览器渲染主线程的工作方式。
在谷歌浏览器的源码中,他开启一个不会结束的for循环,每次循环从消息队列中取出第一个任务执行,而其他线程只需要在合适的时候将任务加入到队列末尾即可。
过去把消息队列简单分为宏队列和微队列,这种说法目前已无法满足复杂的浏览器环境,取而代之的是一种更加多变的处理方式。
根据w3c官方的解释,每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。不同任务对列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务。但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调用执行。
​
露件循环又叫做消息循环,是浏览器渲染主线程的工作方式。
在 Chrome 的源码中,它开启一个不会结束的 for 循,每次循环从消息队列中取出第一个任务执行,而其他线程只需要在合适的时候将任务加入到队列未尾即可。
过去把消息队列简单分为宏队列和微队列,这种说法目前已无法满足复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式。
根据 W3C官方的解释,每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。不同任务队列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务。但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调度执行。
先执行微任务  在执行宏任务


13、防抖和节流

防抖:事件发生时开启一个定时器,如果定时器没有执行完就有触发该事件,定时器会重新计算时间
节流:事件发生时开启一个定时器,如果定时器没有执行完就有触发该事件,此事件会被禁止,当定时器执行完时,会解封事件

// 节流:在计时器内部清除计时器,有节奏的执行事件
      
  function throttle(callback, delay = 1000){
            let timer = null;
            function f(){
                if(!timer){
                    timer = setTimeout(() => {
                        callback && callback.call(this);
                        clearTimeout(timer);
                        timer = null;
                    }, delay);
                }
            }
            return f;
        }
      
// 防抖:在计时器前边清除计时器,只执行最后一次事件,能够无限延长执行时间
       
 function debounce(callback, delay = 1000) {
            let timer = null;
            function f() {
                clearTimeout(timer);
                timer = setTimeout(() => {
                    callback && callback.call(this);
                }, delay);
            }
            return f;
        }
 防抖的原理
     在事件处理函数中添加一个定时器 在定时器中执行代码 延迟一定的时间执行代码
     如果你在定时器执行过程中再次触发事件  把原先的定时器清除,再重新定义
    
 function debounce(fun, wait) {
            var timer;
            function show() {
                // 如果timer有值 定时器没有走完 
                if (timer) {
                    clearTimeout(timer)
                }
                timer = setTimeout(fun, wait)
            }
            return show
        }
节流的原理
     在事件处理函数中添加一个延时定时器,延迟一定的时间执行代码
     在当前定时器没有完成之前 禁止事件执行 等定时器完成之后再允许事件执行
    
 function throttle(fun, wait) {
            var timer;
            function show() {
                //  如果timer有值 定时器没有结束  没有值的时候才去执行
                if (!timer) {
                    timer = setTimeout(function () {
                        fun();//要做的事有很多  放入函数执行
                        timer = undefined;
                    }, wait)
                }
            }
            return show
        }


14、深克隆和浅克隆

深拷贝:如果对象是复杂数据类型,拷贝的则是内容 不会一改全改
浅拷贝:如果对下行那个是复杂数据类型,拷贝的则是同一内存地址  会一改全改

浅克隆:同值也同址。浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。如:Object.assign;=等号赋值;slice截取。

深克隆:同值不同址。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。如:JSON.parse(JSON.stringify());

    
  function deepClone(target) {
        // 定义一个变量
        let result;
        // 如果当前需要深拷贝的是一个对象的话
        if (typeof target === "object") {
          // 如果是一个数组的话
          if (Array.isArray(target)) {
            result = []; // 将result赋值为一个数组,并且执行遍历
            for (let i in target) {
              // 递归克隆数组中的每一项
              result.push(deepClone(target[i]));
            }
            // 判断如果当前的值是null的话;直接赋值为null
          } else if (target === null) {
            result = null;
            // 判断如果当前的值是一个RegExp对象的话,直接赋值
          } else if (target.constructor === RegExp) {
            result = target;
          } else {
            // 否则是普通对象,直接for in循环,递归赋值对象的所有值
            result = {};
            for (let i in target) {
              result[i] = deepClone(target[i]);
            }
          }
          // 如果不是对象的话,就是基本数据类型,那么直接赋值
        } else {
          result = target;
        }
        // 返回最终结果
        return result;
      }
  function deepCopy(data) {
            // 创建一个空间,判断是创建空数组还是空对象,判断data参数的数据类型
            if (getType(data) === "[object Array]") {
                var res = [];
            } else if (getType(data) === "[object Object]") {
                var res = {};
            } else {
                return data;
            }
            // 判断data参数中的元素是不是复杂数据类型,如果是复杂数据类型将之前的逻辑再走一次
            for (var i in data) {
                if (getType(data[i]) === "[object Array]" || getType(data[i]) === "       [object Object]") {
                    res[i] = deepCopy(data[i]);
                } else {
                    res[i] = data[i];
                }
            }
            return res;
        }
        // 检测数据类型封装
        function getType(data) {
            return Object.prototype.toString.call(data);
        }


15、cookie、sessionStorage和localStorage的区别

localstorage  本地存储.长期存储在浏览器 需要手动销毁
除非被清除,否则永久保存  一般为5MB       
sessionstorage  会话存储  关闭当前会话就会销毁
cookie 
        存储在客户端
        过期时间默认浏览器关闭过期
        大小4kb
        个数50个
        数据格式只能是字符串
        不同浏览器不共享cookie
        相同项目不同页面之间可共享cookie
        Cookie
​
cookie 它的大小限制为4KB左右。它的主要用途有保存登录信息,
一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 
每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题
大小4kb

15.1、cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下 15.2、存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大 15.3、数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭 15.4、作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的 15.5、web Storage支持事件通知机制,可以将数据更新的通知发送给监听者 15.6、web Storage的api接口使用更方便


16、get和post请求的区别

GET在浏览器回退时是无害的,而POST会再次提交请求。

GET产生的URL地址可以被Bookmark,而POST不可以。

GET请求会被浏览器主动cache,而POST不会,除非手动设置。

GET请求只能进行url编码,而POST支持多种编码方式。

GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

GET请求在URL中传送的参数是有长度限制的,而POST么有。

对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

GET参数通过URL传递,POST放在Request body中


17、new操作符都做了哪些事情

构造函数中没有显示的创建Object对象,实际上后台自动创建了一个空对象,直接给this对象赋值属性和方法,this即指向创建的对象。没有return返回值,后台自动返回了该对象,该对象继承构造函数的原型

// 模拟构造函数实现
 var Book = function(name) {
   this.name = name;
 };
 //正常用法
 var js = new Book('js');
 //使用代码模拟,在非IE浏览器中测试,IE浏览器不支持
 var javascript = {};
 javascript.__proto__ = Book.prototype;
 Book.call(javascript, 'js');
1、隐式创建了一个空对象,让this指向这个空对象
2、执行构造函数中的代码
3、让实例的__proto__指向构造函数的prototype
4、隐式的返回这个对象


18、XSS攻击和CSRF攻击

XSS:跨站脚本攻击Cross site script,因叫css容易让人误会所以改成了xss。比如一个JSON数据:

      var obj = [
        {
          id: 1,
          name: "<script>alert('哈哈哈')</script>",
          age: 12,
        }
      ];

在不该出现script代码的地方出现了,引发一些潜在的危险。 XSS漏洞,能让人们在网页里面插入一段有功能的语句。 XSS 全称“跨站脚本”,是注入攻击的一种。其特点是不对服务器端造成任何伤害, 而是通过一些正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文本。这时服务器端如果没有过滤或转义掉这些脚本,作为内容发布到了页面上,其他用户访问这个 页面的时候就会运行这些脚本。 防范: ① 用正则表达式阻止用户提交带有<、eval、script等危险字眼的语句 ② 显示的时候不要直接用innerHTML,而是用innerText,或者将<转义。

CSRF 的全称是“跨站请求伪造”,而 XSS 的全称是“跨站脚本”。看起来有点相 似,它们都是属于跨站攻击——不攻击服务器端而攻击正常访问网站的用户,但前面说 了,它们的攻击类型是不同维度上的分类。CSRF 顾名思义,是伪造请求,冒充用户在站内 的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务 器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。 所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即 拥有身份 cookie 的浏览器端)发起用户所不知道的请求。 就是说,如果用户不老老实实写姓名,写了一个个<script>叫做XSS。如果进一步的,写了一个$.post()发了document.cookie就是CSRF了。解决方法: ① 用token验证,验证用户的IP地址生成MD5码,更安全的验证方法 ② 防住XSS。

什么是XSS
Cross-Site Scripting(跨站脚本攻击),简称XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如Cookie、SessionID等,进而危害数据安全
​
什么是CSRF
Cross-site request forgery(跨站请求伪造),是一种挟持用户在当前已登陆的Web应用程序上执行非本意的操作的攻击方法。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
​


19、垃圾回收机制

一般来说没有被引用的对象就是垃圾,就是要被清除, 有个例外如果几个对象引用形成一个环,互相引用,但根本访问不到它们,这几个对象也是垃圾,也要被清除。 垃圾回收的方法主要有两种:一种是标记清除,即用完之后的变量 赋值成null,另一种 是引用计数,将使用完的对象的引用计数,如果为0则回收

js的垃圾回收机制:
是js中定义回收资源的一种机制,每隔一段时间 js的执行环境就会去清理没用的数据
垃圾回收机制有两种方法:标记清除回收  引用计数回收
引用计数回收:每次使用变量  计数+1  当计数是0 就会被回收掉


20、常用DOM操作

createElement 创建

appendChild末尾添加

insertBefore 前边插入

cloneNode(true) 克隆

removeChild() 移除

parentNode父节点

childNodes // 全部子节点

firstChild // 第一个子节点

lastChild // 最后一个子节点

previousSibling // 上一个兄弟节点

nextSibling // 下一个兄弟节点

获取dom节点:document.getElementById() 、document.getElementsByTagName() 、document.getElementsByClassName() 、document.getElementsByName() 、document.querySelector() 、document.querySelectorAll()


21、AMD、CMD、ES6、CommonJS的区别

CommonJS:模块引用(require) 模块输出(exports) 模块标识(module) ES6:模块引用(import) 模块输出(export) 前者支持动态导入,也就是 require(${path}/xx.js),后者目前不支持。 前者是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线 程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同 步导入会对渲染有很大影响。 前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以 如果想更新值,必须重新导入一次。但是后者采用实时绑定的方式,导入导出的值都 指向同一个内存地址,所以导入值会跟随导出值变化 AMD、CMD都使用define定义模块,require引入模块,区别在于AMD是前置依赖, CMD是就近依赖

      // AMD   依赖必须一开始就声明
      define(["./a", "./b"], function (require, factory) {
        // do something...
      });
​
      // CMD  
      define(function(require, factory) {
        var a = require('./a'); // 依赖就近书写
        // do something...
      });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值