前端常见面试题-js-es6

JS

延迟加载js

<script src="" defer> </script>
<script src="" async> </script>

defer 异步并行下载,在document解析完后执行,多脚本按顺序执行,
async 异步并行下载,只要下载完就执行,不分顺序。

输出结果

console.log(typeof NaN)
console.log(typeof undefined)
console.log(typeof null)

number , undefined obj
null 是特殊的object 类型

输出结果

console.log(true + 1)
console.log('jason' + true)
console.log(undefined + 1)

2 , jasontrue , NaN
基本上处理字符串优先转化,剩下的都是Number转化,
Number(true) = 1
Number(undefined) 结果为NaN ,NaN+什么数字都是NaN

输出结果

var bar = 1 
function test() {
  console.log(bar)
  var bar = 2;
  console.log(bar);
}

undefined , 2
在test方法里,定义的var bar = 2 被变量提升了。

输出结果

for(var i= 0; i<3; i++) {
  setTimeout(function () {
          console.log(i)
  },1000)
}

3,3,3 间隔为1秒
因为访问的是for 里定义的var i 所有定时起

输出结果

  var foo = function() {
    console.log(1)
  }
function foo() {
    console.log(2)
}
foo()

1
声明的优先

输出结果

  function c() {
    var b = 1;
     function a() {
          console.log(b)
          var b = 2 
          console.log(b)
    }
    console.log(b)
  } 
c()

undefined , 2 ,1

输出结果

var name = 'aaa'
(function(){
      if(typeof name == 'undefined') {
              var name = 'java'
              consolo.log("111",name)
      }else {
              consolo.log("222",name)
      }
})()

输出:111java
匿名函数是一个块作用域的模拟,if没有作用域,但是下面有定义了var,所以变量只能提升到匿名函数内,name为undefined

输出结果

var f = true 
if( f === true) {
   var a = 10;
}
function fn() {
    var b = 20;
    c = 30;
}
fn()
console.log(a)
console.log(c)
console.log(b)

10, 20,报错
var 没有块概念,所以a全局能拿到,
c是直接绑定在window上,所以也能拿到
b由于是定义在方法,外部无法找到,直接找不到定义,报错

输出结果

var a = {}
var b = { key : 'a'}
var c = {key:'c'}
a[b] = '111'
a[c] = '222'
console.log(a[b])

222
注意这里的a[b]里面的b 对象会被转化成字符串'[object Object]' 。
同理 a[c] 里的c 也会被转化成 '[object Object]'
所以 结果是 a['[object Object]'] = '111' ; a['[object Object]'] = '222'
所有最后等于222

js数组去除重复的方法

//方法1  new Set
  function unique(array) {
       let set = new Set(array)
       return Array.form(set)
   }
//方法2 遍历 indexOf
    function unique(array) {
        let lastList = []
       array.foreach( (item) => {
            if(lastList.indexOf(item) < 0) {
              lastList.push(item)
           } 
       })
       return lastList
   }
//方法3 递归删除法
function unique(array) {
   array = array.sort()
   var len = array.length
   function loop(index) {
    if(index >= 1) {
        if(array[index] === array[index - 1 ]) {
            array.splice(index,1)
            }
            loop(index - 1)
        } 
   }
   loop(len - 1)
   return array
}
console.log(unique2([3,4,4,1,2,4,1,100,3])) 

//方法4 两数组对比法
function unique3(array) {
    array = array.sort()
    let lastList = [array[0]] //初始化 就保存第一元素 然后逐一跟数组对比,有重复 
    for(var i = 0; i < array.length; i++) { 
        if(lastList[lastList.length - 1] !== array[i]) {//如果当前last里面没有则加入
            lastList.push(array[i]) 
        }
    }
    return lastList
 }
 console.log(unique3([3,4,4,1,2,4,1,100,3])) 

给字符串添加addPre方法,实现 "job".addPre("good") 输出 good job

通过原型链的方法实现

String.prototype.addPre = function(str) {
  return str + this
}

把嵌套的二维数组转化成一维数组

let a =
[
[4,5,6,7],
[7,8,9],
[1,2,3],
]
输出
[4,5,6,7,7,8,9,1,2,3]
//方法1 
 function arr2ToArr(arr) {
     let newList = [] 
    arr.forEach(item => { 
        newList = newList.concat(item)
    })
    return newList
 }
console.log(arr2ToArr(a))

把嵌套的二维数组 里面最大的取出,组成新数组

let a =
[
[4,5,6,7],
[7,8,9],
[1,2,3],
]
输出
[7,9,3] 

 function arr2ToMaxArr(arr) {
     let newList = [] 
    arr.forEach(item => { 
        newList = newList.push(Math.max.apply(null,item)) //这里apply可以解构数组为动态参数
    })
    return newList
 }
console.log(arr2ToMaxArr(a))

闭包

定义:一个函数可以调用另外一个函数的作用域中的变量
函数内还有函数,两个函数作用域相连,形成闭包
形成条件:函数嵌套,内部函数调用外部函数变量

for(var i= 0; i<3; i++) {
  (function (i){
       setTimeout(function () {
          console.log(i)
      },1000)
  })(i) 
}

能够正常输出 1,2,3 间隔1秒,因为形成闭包,i 变量被保留下来。

call apply bind区别

三个都是改变执行的上下文对象,可以实现继承
call和apply都是立即调用
call(obj,parm1,parm2) 第二个参数可以是 动态参数,适合解构
apply(obj,arr) 第二个参数必须是数组
bind 和call使用类似,只提前绑定,返回新函数,但不立即调用方法。

js判断变量是否为数组

// 
var arr = []
arr instanceof Array
// true

var arr = []
Object.prototype.toString.call(arr)
//"[object Array]"

var arr = []
Array.prototype.isPrototypeOf(arr)
//true

var arr = []
arr.constructor.toString()
//"function Array() { [native code] }"

var arr = []
Array.isArray(arr)
//true

new操作做了什么事情

  1. 创建一个空对象
  2. 将this 指向这个对象
  3. 通过this给对象添加属性
  4. 通过this,将proto属性指向构造函数的原型对象
/*
  create函数要接受不定量的参数,第一个参数是构造函数(也就是new操作符的目标函数),其余参数被构造函数使用。
  new Create() 是一种js语法糖。我们可以用函数调用的方式模拟实现
*/
function create(Con,...args){
    //1、创建一个空的对象
    let obj = {}; // let obj = Object.create({});
    //2、将空对象的原型prototype指向构造函数的原型
    Object.setPrototypeOf(obj,Con.prototype); // obj.__proto__ = Con.prototype
    //3、改变构造函数的上下文(this),并将剩余的参数传入
    let result = Con.apply(obj,args);
    //4、在构造函数有返回值的情况进行判断
    return result instanceof Object?result:obj;
}

proto和constructor属性是对象所独有的;
② prototype属性是函数所独有的。但是由于JS中函数也是一种对象,所以函数也拥有proto和constructor属性。

proto属性都是由一个对象指向一个对象,即指向它们的原型对象(也可以理解为父对象),
它的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的proto属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的proto属性所指向的那个对象里找,如果还没找到,则继续往上找…直到原型链顶端null,再往上找就相当于在null上取值,会报错.
由以上这种通过proto属性来连接对象直到null的一条链即为我们所谓的原型链。

prototype属性它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,
也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象,
由此可知:f1.proto === Foo.prototype,它们两个完全一样。
作用:让该函数所实例化的对象们都可以找到公用的属性和方法。任何函数在创建的时候,其实会默认同时创建该函数的prototype对象。

constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function

因为创建对象的前提是需要有constructor,而这个constructor可能是对象自己本身显式定义的或者通过proto在原型链中找到的。而单从constructor这个属性来讲,只有prototype对象才有。每个函数在创建的时候,JS会同时创建一个该函数对应的prototype对象,而函数创建的对象.proto === 该函数.prototype,该函数.prototype.constructor===该函数本身,故通过函数创建的对象即使自己没有constructor属性,它也能通过proto找到对应的constructor,所以任何对象最终都可以找到其构造函数(null如果当成对象的话,将null除外)。

原型链

当访问对象属性时候,会先在对象本身属性找,没有则去proto隐式原型找,即构造函数的prototype ,没有继续在prototype的proto找,这样一层层查找形成链式。
总结:

  1. 一直往上找,直到null都没有,就返回undefined
  2. Object.prototype.proto === null

js继承判断

  1. 原型链继承
  2. 构造函数继承
  3. 实例继承
  4. 组合继承
  5. 寄生组合
  6. es6 extends

== 和 === 区别

== 是语法糖,会转化成对应的数据类型,再比较。
=== 是完全匹配

cookie 和 session区别

cookie 是保留在客户端,而且容量大小有限制,不安全,明文可以篡改。
session保留在服务端,访问多了,会响应服务端性能。通过客户端记录ID 在cookie 实现用户登陆态记录。

sort背后的原理

js自带的排序方法。
通过 unicode编码进行排序 ,默认是从小到大排序

slice和splice区别

slice 切割数组,返回切割后的内容,但原数组不改变
splice 可以删除和插入数据,替换,并返回删除的数据,原数组也会变化。

深度拷贝和浅拷贝区别

浅拷贝: 对于对象,只是复制对象的引用,修改属性,会导致两边修改。一般用Object.assign()
深度拷贝:完全复制对象的每一个属性,每一个值,并且嵌套对象依然是完全拷贝。并且被复制对象与拷贝对象无关联。修改不影响。
通过字符串转化再转对象 JSON.stringify JSON.parse可以实现。但是如果拷贝对象包含正则表达式,函数,或者undefined等值,此方法就会出现问题
自己实现递归遍历每一个属性

ES6

1.var,let,const 区别

var

  1. 存在变量提升
  2. 可以重复定义同一个var 变量名
  3. var 在全局定义,会直接添加到window

let

  1. 不存在变量提升
  2. 不能重复定义一样的变量名
  3. 不会添加到window
  4. 存在块作用域
  5. 有暂时性死区
var temp = 0
if(true){
  temp = 10
  let temp ;//由于这里定义了let 所以在 if块内 let上面的代码都会变成死区
}

const

和 let 差不多,但是cost不能被修改

看看结果

function demo(){
  let n = 2
  if (true) {
    let n = 1 
  }
  console.log(n)//以当前块范围取值
}
demo()

//输出2

输出结果

const demo = (first,...num) => {
  return [first,num]
}
demo(1,2,3,4,5)

输出:[1,[2,3,4,5]]

合并对象方法

Object.assign()

  Object.assign(tragetObj,inputObj)

解构

  let newObj = {...a, ...b}

遍历属性赋值

 for (var key in souce) {
  targetObj[key] = souceObj[key]
}

promise的几个状态

有三个状态 pending(进行中) fulfilled rejected

箭头函数和普通函数区别

箭头:

  1. 是匿名函数,不能做构造函数,不能用new
  2. 没有arguments,使用的是rest参数
    rest 参数(形式为...变量名),用于获取函数的多余参数
const test = (...arg) => {
  console.log(arg[0])
}
test(1,2)
  1. 不绑定 this 获取其所在最近上下文的this使用
  2. 通过call apply 方法调用函数,只需传一个参数,对this没有影响
let obj = {
  name: "qianzhixiang",
  func: (a,b) => {
      console.log(this.name,a,b);
  }
};
obj.func(1,2); // 1 2
let func = obj.func;
func(1,2); //   1 2
let func_ = func.bind(obj);
func_(1,2);//  1 2
func(1,2);//   1 2
func.call(obj,1,2);// 1 2
func.apply(obj,[1,2]);//  1 2
  1. 箭头函数没有原型属性
  2. 函数不能做generator函数,不能使用yied

foreach map filter 区别

map返回新的数组对象
foreach和map都是遍历数组
filter 返回原数组的子集合,通过返回的ture/ false 判断添加返回的数组里。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容