一、变量类型和变量计算 值类型和引用类型 常见值类型 1 2 3 4 5 let  a const  str = 'abc'  const  n = 100  const  b = true  const  s = Symbol ('s' ) 
 
常见引用类型 1 2 3 4 const  obj = {x :100 }const  arr = ['a' , 'b' , 'c' ]const  n = null  function  fn ( ) {} 
 
值类型和引用类型的区别 值类型的数据存在栈中,引用类型值只存地址,数据存在堆中
typeof和深拷贝 typeof能判断哪些类型 识别所有值类型 undefined string number boolean symbol 1 2 3 4 5 let  a                       typeof  a    const  str = 'abc'            typeof  str  const  n = 100                typeof  n    const  b = true               typeof  b    const  s = Symbol ('s' )       typeof  s   
 
能判断函数 1 function  fn ( ) {}             typeof  arr  
 
能识别引用类型(不能再细分) 1 2 3 const  obj = {x :100 }         typeof  obj  const  arr = ['a' , 'b' , 'c' ] typeof  arr  const  n = null               typeof  n    
 
深拷贝 
判断是值类型还是引用类型 
判断是数组还是对象 
递归 
 
本地安装一个服务 
1 2 npm install http-server -g http-server -p 8001 
 
深拷贝代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 let  obj1 = {    name: 'bob' ,     age: 20 ,     address: {         city: 'beijing' ,         home: 'changping'      },     tech: ['c' , 'js' , 'html' , 'css' , 'vue' ] } let  obj2 = deepClone(obj1)obj2.address.city = 'shanghai'   console .log(obj1.address.city)function  deepClone (obj ) {    if ( typeof (obj) !== 'object'  || obj == null  ){         return  obj              }          let  result     if (obj instanceof  Array ){         result = []     }else {         result = {}     }     如果obj是对象,key为键,是数组,key为下标     for (let  key in  obj){         if (obj.hasOwnProperty(key)){                                       result[key] = deepClone(obj[key])         }     }          return  result } 
 
变量计算-类型转换 字符串拼接 1 2 3 let  a = 100  + 10     let  b = '100'  + 10   let  c = true  + '10'  
 
== 1 2 3 4 5 100  == '100'         0  == ''              0  == false           false  == ''          null  == undefined    
 
何时使用 === 何时使用 == 只有一种情况使用 == 
1 2 3 4 <!-- 除了 == null  之外,其他一律使用 === --> const  obj = {x :100 }if (obj.a == null ){}<!-- 相当于 if (obj.a === null  || obj.a === undefined ) --> 
 
if语句和逻辑运算 truly变量: !!a === true 的变量 falsely变量: !!a === false 的变量 以下为falsely变量
1 2 3 4 5 !!0  !!NaN  !!''  !!undefined  !!false  
 
if语句实际上是判断truely变量和falsely变量 逻辑判断 1 2 3 console .log(0  && 10 )        console .log(''  || 'abc' )    console .log(!window .abc)    
 
二、原型和原型链 题目 
如何判断一个变量是不是数组 
手写一个jquery,考虑插件和扩展性 
class的原型本质,怎么理解 
 
知识点 
class和继承 
类型判断 instanceof 
原型和原型链 
 
class和继承 class 
constructor 
属性 
方法 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  Student  {    constructor (name, number){         this .name = name         this .number = number     }     sayHi(){         console .log(             `我叫 ${this .name}  , 我的学号是 ${this .number} `          )     } } const  xialuo = new  Student('夏洛' , 100 )console .log(xialuo.name, xialuo.number)xialuo.sayHi() 
 
继承 
extends 
super 
扩展或重写方法 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class  People  {    constructor (name){         this .name = name     }     eat(){         console .log(`${this .name}  eat something` )     } } class  Student  extends  People  {    constructor (name, number){         super (name)         this .number = number     }     sayHi(){         console .log(             `我叫 ${this .name}  , 我的学号是 ${this .number} `          )     } } const  xialuo = new  Student('夏洛' , 100 )console .log(xialuo.name, xialuo.number)xialuo.sayHi() xialuo.eat() class  Teacher  extends  People  {    constructor (name, major){         super (name)         this .major = major     }     teach(){         console .log(`${this .name}  教授 ${this .major} ` )     } } let  wanglaoshi = new  Teacher('王老师' , '语文' )console .log(wanglaoshi.name, wanglaoshi.major)wanglaoshi.eat() wanglaoshi.teach() 
 
原型 类型判断-instanceof 1 2 3 4 5 6 7 xialuo instanceof  Student    xialuo instanceof  People     xialuo instanceof  Object      [] instanceof  Array           [] instanceof  Object          {} instanceof  Object          
 
class 实际上是 function ,可见是语法糖
1 2 3 4 5 6 7 8 typeof (Student)     typeof (People)      console .log(xialuo.__proto__)console .log(Student.prototype)console .log(xialuo.__proto__ === Student.prototype)
 
原型关系 
每个class都有显式原型prototype 
每个实例都有隐式原型proto  
实例的proto 指向class的prototype 
 
基于原型的执行规则 获取xialuo.name或执行xialuo.sayHi()时
先在自身属性和方法寻找 
找不到就自动去proto 寻找 
 
原型链 1 2 3 4 5 6 console .log(Student.prototype.__proto__)console .log(People.prototype)console .log(Student.prototype.__proto__ === People.prototype)xialuo.hasOwnProperty('name' )     xialuo.hasOwnProperty('sayHi' )    
 
通过显示原型向上找隐式原型,一层一层向上找,最后object的proto 是null
instanceof 通过隐式原型向上找,能不能找到显示原型,能找到,就返回true
手写一个jquery,考虑插件和扩展性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class  jQuery   {    constructor (selector) {         const  result = document .querySelectorAll(selector)         const  length = result.length         for  (let  i = 0 ; i < length; i++) {             this [i] = result[i]         }         this .length = length         this .selector = selector     }     get (index) {         return  this [index]     }     each(fn) {         for  (let  i = 0 ; i < this .length; i++) {             const  elem = this [i]             fn(elem)         }     }     on(type, fn) {         return  this .each(elem  =>  {             elem.addEventListener(type, fn, false )         })     }      } jQuery.prototype.dialog = function  (info )  {     alert(info) } class  myJQuery  extends  jQuery   {    constructor (selector) {         super (selector)     }          addClass(className) {     }     style(data) {              } } 
 
三、作用域和闭包 题目 
this在不同的应用场景下,如何取值 
手写bind函数 
实际开发中闭包的应用场景 
 
知识点 
作用域和自由变量 
闭包 
this 
 
作用域 
全局作用域 
函数作用域 
块级作用域 
 
自由变量 
一个变量在当前作用域没有定义,但被使用了 
向上级作用域,一层一层寻找,直到找到为止 
如果到全局作用域都没找到,报错 xx is not defined 
 
闭包 作用域应用的特殊情况
函数作为参数被传递 
函数作为返回值被返回 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function  create ( ) {    let  a = 100      return  function  ( ) {         console .log(a)     } } const  fn = create()const  a = 200 fn() function  print (fn ) {    const  a = 200      fn() } const  a = 100 function  fn ( ) {    console .log(a) } print(fn) 
 
所有自由变量的查找,是在函数定义的地方向上查找,不是在执行的地方向上去找
this 
作为普通函数 
使用call apply bind 
作为对象方法被调用 
在class方法中调用 
箭头函数 
 
this取什么样的值,在函数执行时确定,不是在函数定义时确定的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 function  fn1 ( ) {    console .log(this ) } fn1()  fn1.call({x :100 })  const  fn2 = fn1.bind({x :200 })  fn2()  const  zhangsan = {    name: '张三' ,     sayHi(){                  console .log(this )     },     wait(){         setTimeout(function ( ) {                          console .log(this )         })     } } const  zhangsan = {    name: '张三' ,     sayHi(){                  console .log(this )     },     wait(){         setTimeout(() => {                                       console .log(this )         })     } } class  People  {    constructor (name){         this .name = name     } } const  zhangsan = new  People('张三' )
 
手写bind函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function  fn1 (a,b,c ) {    console .log('this' ,this )     console .log(a,b)     return  'this is fn1'  } const  fn2 = fn1.bind({x :100 },10 ,20 ,30 )const  res = fn2()console .log(res)Function .prototype.bind1 = function ( ) {         const  args = Array .prototype.slice.call(arguments )          const  t = args.shift()          const  self = this           return  function ( ) {         return  self.apply(t, args)     } } 
 
闭包的应用 
隐藏数据 
做一个简单的cache工具 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function  createCache ( ) {    const  data = {}      return  {         set : function(key, val){             data[key] = val         },         get : function(key){             return  data[key]         }     } } const  c = createCache()c.set('a' ,100 ) console .log(c.get('a' ))
 
从0到9,点击每个元素时,弹出对用的数字
1 2 3 4 5 6 7 8 9 10 for (let  i = 0 ;i < 10 ; i++){    let  a = document .createElement('a' )     a.innerHTML = i + '<br>'      a.addEventListener('click' , function (e ) {         e.preventDefault()         alert(i)     })     document .body.appendChild(a) } 
 
四、同步和异步 题目 
同步和异步的区别是什么? 
手写用promise加载一张图片 
前端使用异步的场景有哪些? 
 
1 2 3 4 5 6 7 8 9 10 11 console .log(1 )setTimeout(function ( ) {     console .log(2 ) },1000 ) console .log(3 )setTimeout(function ( ) {     console .log(4 ) },0 ) console .log(5 )
 
知识点 单线程和异步 js是单线程语言,只能同时做一件事 浏览器和nodejs已支持js启动进程,如web worker js和dom渲染公用同一个线程,因为js可修改dom结构 遇到等待(网络请求,定时任务)不能卡住,所以需要异步 基于callback函数形式
1 2 3 4 5 6 7 8 9 10 11 console .log(100 )setTimeout(function ( ) {     console .log(200 ) }) console .log(300 )console .log(100 )alert(200 ) console .log(300 )
 
异步不会阻塞代码执行,同步会阻塞代码执行
应用场景 网络请求,如ajax图片加载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 console .log('start' )$.get ('./data.json', function(data){     console .log(data) }) console .log('end' )console .log('start' )let  img = document .createElement('img' )img.onload = function ( ) {     console .log('loaded' ) } img.src = 'xxx.png'  comsole.log('end' ) 
 
定时任务,如setTimeout callback hell 和 promise callback hell 1 2 3 4 5 6 7 8 9 10 11 12 13 $.get (url1, (data1)=>{     console .log(data1)          $.get (url2, (data2)=>{         console .log(data2)                  $.get (url3, (data3)=>{             console .log(data3)             ...         }     }) }) 
 
promise 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function  getData ( ) {    return  new  Promise ((resolve,reject )=> {         $.ajax({             url,             success(data){                 resolve(data)             },             error(err){                 reject(err)             }         })     }) } const  url1 = 'data1.json' const  url2 = 'data2.json' const  url3 = 'data3.json' getData(url1).then(data1  =>  {     console .log(data1)     return  getData(url2) }).then(data2  =>  {     console .log(data2)     return  getData(url3) }).then(data3  =>  {     console .log(data3) }).catch(err  =>  console .error(err) 
 
手写promise加载图片 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 const  url = 'xxx.png' function  loadImg (src ) {    const  p = new  Promise ((resolve,reject )=> {         const  img = document .createElement('img' )         img.onload = ()  =>  {             resolve(img)         }         img.onerror = ()  =>  {             reject(new  Erroe('图片加载失败' )))         }         img.src = src     })     return  p } loadImg(url).then(img  =>  {     console .log(img.width) }).then(img  =>  {     console .log(img.height) }).catch(ex  =>  {     console .log(ex) }) const  url2 = 'xxx2.png' loadImg(url1).then(img1  =>  {     console .log(img1.width)     return  img1  }).then(img1  =>  {     console .log(img1.height)     return  loadImg(url2)  }).then(img2  =>  {     console .log(img2.width)     return  img2  }).then(img2  =>  {     console .log(img2.height) }).catch(ex  =>  {     console .log(ex) })