在我心中---JS经典问题

必问

(零) AMD、CMD、CommonJs、ES6的对比

对模块定义的规范化
解决:模块化主要解决两个问题,命名冲突文件依赖

AMD CMD CommonJs ES6
requireJS SeaJS Nodejs
define define module.exports export/import
AMD是预加载 CMD是懒加载
优:加载快速,并行加载 并且执行 同AMD ,不执行
缺:执行顺序不可控,容易埋坑 顺序执行,等待时间较长

注意:Commonjs 中 module.exportexports的区别?

返回对象不同 module.export 可以返回单独返回一个数据类型,而 export只能返回 Object

(一)闭包

参考:https://www.cnblogs.com/shuls/p/9099176.html

简单来说闭包就是函数套函数。
一个函数在执行开始 会给其内部的变量分配一部分内存空间,被后面语句使用,当函数执行完毕,这些变量 为被引用后,则会释放这些内存空间,但是,若在函数内存在一个子函数 在调用主函数的变量的时候,这些变量如果被引用 则这个子函数和这些变量 会被解析器 保存起来 形成一个闭包
优势: 变量私有化
劣势:容易内存泄漏, 解决方法,退出函数之前,变量删除

(二)原型链

参考-面试题:https://www.cnblogs.com/wjyz/p/10219106.html
基础:https://www.jianshu.com/p/08c07a953fa0

什么是原型链?

每个对象都有原型 _proto_,而 原型 还可以由原型 ,以此类推 ,就形成了原型链

prototype 原型指针:是函数独有 的,是一个函数指向一个对象 

(三)手写继承

参考:https://www.jianshu.com/p/6925ed009f1e
参考:https://blog.csdn.net/p312011150/article/details/83579313


1. 组合继承

//一般情况 都是使用 call this 变量来进行变量参数传递 
 	function animal(name) {
      this.name = name || "动物";
      this.run = () => {
        console.log(this.name + "==>跑啊");
      };
    }
    // 原型方法
    animal.prototype.eat = function(food) {
      console.log(this.name + "正在吃:" + food);
    };
    function Dog() {
      animal.call(this);
      this.name = "狗狗";
    }
    Dog.prototype = new animal();

    let dog = new Dog();
    console.log(dog);
    console.log(dog.name);
    console.log(dog.run());
    console.log(dog.eat("6666"));

2. Object.create()

var Parent = {
    getName: function() {
        return this.name;
    }
}

var child = Object.create(Parent, {
    name: { value: "Benjamin"},
    url : { value: "http://www.zuojj.com"}
});
console.log(child);
console.log(child.getName());

3. ES6 Class Extend

class Parent {
  constructor(name){
    this.name = name;
    static sayHello(){
        console.log(this.name)
    }
  }
}


class Child extends Parent {
  constructor(name, age){
    super(name);
    this.age = age;
  }
  sayAge(){
    console.log(this.age)
    return this.age;
  }
}
let parent = new Parent("Parent");
let child = new Child("Child", 18);


(四)深copy 浅 Copy

参考:https://www.cnblogs.com/ljx20180807/p/9790239.html
参考:https://mp.weixin.qq.com/s/vXbFsG59L1Ba0DMcZeU2Bg

Object.assign({},srcObj);
如果对象的属性值为简单类型 得到的新对象为深拷贝;
如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的

  • 深copy
简单版本

	  const deepClone = obj => {
        let clone = Array.isArray(obj) ? [] : {};
        for (let key in obj) {
          clone[key] = deepClone(obj[key]);
        }

        return clone;
      };

//对于数组而言 还可以使用
slice(0),concat


(五) Event Loop

参考:https://segmentfault.com/a/1190000016278115
参考:https://segmentfault.com/a/1190000018675871
Event Loop 是一个执行模型


注意:可以将 EventLoop 看成一个单线程结构 ,他将 IO 操作抛出给其他线程,继续执行 他的 方法,在IO 先出现结束后 EventLoop 再把结果抛出主线程


Promise所有的then的回调函数是在一个microtask函数中执行的,但是每一个回调函数的执行,又按照情况分为立即执行,微任务(microtask)和宏任务(macrotask)。

我太难了:这个解释太不靠谱了,需要深入了解一下

  • 宏队列: setTimeOut setInterval I/O 等
  • 微队列:Promise Object.observe 等

调用栈Stack
浏览器执行代码的过程
:1.执行 全部 JS 代码, 遇到 微任务 ,宏任务,全部抛出到其各自的栈中,继续执行
:2.JS Stack 为空后,再次执行 微任务 ,执行完后 (一个一个的放入Stack 执行)
:3:在执行 为首的 一个宏任务,放入Stack中执行
:4:Stack 为空后继续 2-4

(五)常见算法

  • 数组去重
let unique = (array)=>{
  return Array.from(new Set(array))
} 

unique = (array)=>{
 const res = new Map();//WeakSet  

 return array.filter(curr=>{
   let isIn = res.has(curr);
   if(!isIn) res.set(curr,0)//0 不重要
   return !isIn
})


}
  • 数组排序
//冒泡排序
const sortWay = (array)=>{
   for(let i=0,len =array.length;i<(len-1);i++ ){
      let curr = array[i],currNext = array[i+1];
      if(curr < currNext){//降序
          array[i]= currNext;
          array[i+1]= curr;
      }
       
   }

}

//数组自带的sort
array = array.sort((a,b)=>{return a-b})

//数组打乱的算法
//随机取出 20个 数
let a = [1,2,3,4,5....,50];

a = a.map((curr,index)=>{ 
  	return {value:curr,radom:Math.radom()}
})).sort((a,b)=>{
return a.radom -b-radom;
}).map(curr=>{
return curr.value;
}).slice(0,20);



谈谈你对js堆和栈的理解

基本问题

(一) typeof 和 instanceof 区别

  • typeof在判断 null、array、object以及函数实例(new + 函数)时,得到的都是object
  • instanceof 判断一个实例是否属于某种类型 string arrray

(二)es6 常见问题

  • 基本数据类型

Number,String, Null, Undefined, Symbol, Boolean

(三)new 做了什么

  • 创建一个新的对象
  • 新对象的 _proto_ 指向 构造对象的 prototype
  • 构造函数的作用域 赋值给新对象
  • 执行构造函数的代码
  • 返回这新的对象

(四) arguments与arguments转化成数组的方法

第一:这个问题很奇葩, 但是问了,不会 就尴尬了

function a(){
console.log(arguments)
}
a([1,2,3,4,5,6,7])

在这里插入图片描述

转换为数组


function a(){
 let newResult = [];
 for(let i =0,len = arguments.length;i<len;i++){
	newResult.push(arguments[i])
 }
 return newRresult;
}
a(1,2,3,4,5,6,7)

(五)数据结构

(六)跨域 和cros

参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

跨域

跨域:不同源 就跨域,同源是指 同 协议,同 域名,同端口,

Cros

Cros :跨域资源共享(Cross-origin resource sharing)是一种机制,出于安全原因,浏览器限制从JS内发起的跨源HTTP请求,并不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了

衍生问题

  • 为什么要跨域 优缺点是?
  • 怎么解决跨域的问题
  • 什么情况需要Cros

跨域 xhr 请求,下载图片 ,css 中的字体引用

  • 什么是简单请求 什么 预检请求

简单请求 :不会 发送预检请求 的请求 (GET、HEAD、POST)
预检请求:会发出( OPTIONS 请求进行预先判断允许跨域)(DELETE、PUT,OPTIONS)

  • http 常见的请求方式

HTTP请求方法并不是只有GET和POST,只是最常用的。据RFC2616标准(现行的HTTP/1.1)得知,通常有以下8种方法:OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT。
官方定义
HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。一个HEAD请求的响应中,HTTP头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。
一个HEAD请求的响应可被缓存,也就是说,响应中的信息可能用来更新之前缓存的实体。如果当前实体跟缓存实体的阈值不同(可通过Content-Length、Content-MD5、ETag或Last-Modified的变化来表明),那么这个缓存就被视为过期了。
简而言之
HEAD请求常常被忽略,但是能提供很多有用的信息,特别是在有限的速度和带宽下。主要有以下特点:
1、只请求资源的首部;
2、检查超链接的有效性;
3、检查网页是否被修改;
4、多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等

  • 这么配置 允许Cros

Access-Control-Allow-Origin: http://foo.example – 限制允许的域名
Access-Control-Allow-Methods: POST, GET, OPTIONS – 限制允许的请求类型
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400 – 请求结果缓存时间

(七)web安全

参考:https://developer.mozilla.org/zh-CN/docs/Web/Security
例子写得好:https://blog.csdn.net/freeking101/article/details/86537087

  • xss 攻击 跨站脚本攻击 是一种代码注入攻击

存储型 XSS :恶意代码存储到 数据库中 服务端执行
反射型 XSS :恶意代码存在 URL 里。服务端执行
DOM型XSS :恶意代码伪造在URL里, 在浏览器端执行

  • CSRF攻击 跨站请求伪造

由字面上的意思 就能理解了吧应该


注意:CSRF攻击是源于Web的隐式身份验证机制 ,,大部分是走的cookie 做验证机制
而Cookie 的本身会随着域名下的所有请求达到服务端,这样 就伪造了请求

解决方法

CSRF XSS
reffer验证 输入转义
身份代码放在 localstorage、html 或者其他位置(不放在cookie)自定义xhr header 输入内容长度控制
动态签名 避免拼接 HTML
- 对 各种插入数据进行编码

(八)ES6 的箭头函数 this 指向

=> function
window 父级
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章