JS答过的笔试题

答过的笔试题

1. 写出打印的值

1.1 变量定义提升

console.log(a);
function a() {}
var a = 5;
function b() {
    console.log(a);
    var a = 3;
    console.log(a);
}
b();

// 输出结果:
// function a() {}
// undefined
// 3

变量提升,全局中,函数声明会提升,变量定义会提升,当发现一个变量已经定义后,便不在提升,所以第一个输出了函数定义。

在函数内部,变量定义也会提升到函数内部的顶部,所以在内部变量a已经定义,覆盖了全局的定义,

1.2 箭头函数绑定问题

var c = (v) => {
    console.log(this.name)
    console.log(v)
}
var d = {name: 1}
c.call(d, 2)

// 输出结果:
// undefined // node里面输出是undefined, Chrome终端里面输出的是空
// 2

1.3 var变量for循环输出问题

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

// 输出结果:
// 5 马上输出
// 5 5 5 5 5 1秒后,输出5个5

上面代码修改成输出1 2 3 4 5

第一个解决办法是,for循环中定义的i使用let来声明。

第二种解决办法,是setTimeout方法使用立即执行函数包裹上,传一个变量

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

1.4 async异步函数问题

async function async1() {
   console.log('1')
   await async2()
   console.log('2') 
}
async function async2() {
   console.log('3') 
}
console.log('4')  
setTimeout(() => {
    console.log('5') 
},0)
async1()
new Promise((resolve) => {
    console.log('6') 
    resolve()
}).then(() => {
    console.log('7')  
})
console.log('8')

// 输出结果:
// 4、1、3、6、8、2、7、5

执行过程:

第一步:执行同步:1、输出4、setTimeout回调放入回调队列,2、执行async1(),输出1,执行async2(),输出3,返回一个Promise,async1()函数的await处处于Promise的then,放入回调队列等待执行。3、执行new Promise输出6,then放入回调队列。执行console.log(‘8’),输出8。总体输出:4、1、3、6、8

第二步:开始去回调队列执行可执行的回调:

是否有可执行的微任务(主要是Promise),有的话取出所有微任务执行,发现有2个,执行async1()中的微任务输出2,执行new Promise()回调,输出7。没有可执行的微任务了,结束微任务。

取出一个宏任务,发现有一个setTimeout,取出执行,输出5.

1.5 setTimeout和async

console.log(1)
setTimeout(() => {console.log('2')},1000) // 第一个setTimeout回调
async function fn() {
   console.log('3');
   setTimeout(() => {console.log('4')},20) // 第二个setTimeout回调
}
async function run() {
   console.log('5');
   await fn()
   console.log('6');
}
run()
var time = (new Date()).getTime()
// 等待150毫秒
while(true) {
    if (time + 150 < (new Date()).getTime()) {
	    break;
    }
}
setTimeout(() => {		// 三个setTimeout回调
    console.log('7');
    new Promise((resolve) => {
        console.log('8') 
        resolve()
    }).then(() => { console.log('9') })
},0)
console.log('10')

// 输出结果:
// 1、5、3、10、6、4、7、8、9、2

执行过程:

1、执行一个宏任务(同步任务): 执行console输出1,执行run()异步函数,执行console输出5,执行函数fn(),执行console输出3,一个setTimeout放入回调队列,fn()函数执行完毕,await等待到一个Promise回调,放入到回调队列,run()执行完毕,等待状态。while循环,消耗了150毫秒,接着执行,遇到一个setTimeout放到回调队列,执行console输出10.

第一个宏任务执行结束,输出:1、5、3、10。此时回调队列有3个setTimeout回调。

2、查看是否有微任务可执行,经查找,没有,忽略。

3、执行一个宏任务,有一个setTimeout可执行,执行console输出4。

4、查看是否有微任务,没有,执行一个宏任务,发现有一个可执行的,执行:执行console输出7,执行new Promise,执行console输出8,一个微任务放到回调队列。

5、查看是否有微任务可执行,经查找有一个可以执行,执行微任务:执行console输出9。

6、执行一个宏任务,有一个可以执行了,执行console输出2.

7、执行结束。

1.6 let变量不会绑定到window上

let obj = {
  foo: function() {
    console.log(this.bar)
  },
  bar: 1
}
let foo = obj.foo;
let bar = 2;
obj.foo() // 1
foo() // undefined

由于foo方法中输出this.bar,全局中,使用let声明的bar不会绑定到window上面,所以单独调用foo方法中,输出undefined

2. 写出几个vue或react常用的声明周期狗子函数

  • 挂载阶段

    constructor:初始化构造函数

    static getDerivedStateFromProps:调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用

    render():渲染的html元素,react类组件唯一必须实现的方法

    componentDidMount():会在组件挂载后(插入 DOM 树中)立即调用

  • 更新阶段

    getDerivedStateFromProps():上面有说明

    shouldComponentUpdate():props或state变化,render()渲染之前调用,返回默认true(需要渲染页面)

    render():上面有说明

    getSnapshotBeforeUpdate():在render()之后,渲染输出(提交到DOM节点)之前调用

    componentDidUpdate(): 更新后调用,首次渲染不会执行此方法

  • 卸载阶段

    componentWillUnmount():组件卸载及销毁之前直接调用

3. 写一个递归方法,把数组[1,2,[3,[4,5],6],7],变成一维数组[1,2,3,4,5,6,7]

function func(arr) {
    var newArr = []
    for(var i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {
            newArr = newArr.concat(func(arr[i]))
        } else {
            newArr.push(arr[i])
        }
    }
    return newArr
}
var arr = [1,2,[3,[4,5],6],7];
var newArr = func(arr)
console.log('newArr:', newArr)

4. 字符串相邻字符去重aaabbdebb=>abdeb

给一个字符串,把字符串中相邻重复的字符去掉,比如aaabbdebb 变成abdeb

var str = 'aaabbdebb'
function deleteRepeat(str) {
  var newStr = str[0]
  var tmp = str[0]
  for (var i = 1; i < str.length; i++) {
    if (tmp !== str[i]) {
      newStr += str[i]
      tmp = str[i]
    }
  }
  return newStr;
}
var t = deleteRepeat(str);
console.log(t)

5. get1_by2_list334_android7删除偶数和_

给一个字符串:get1_by2_list334_android7(每个单词后偶棉携带一个数字),删除其中偶数和_,不用不用循环,只用正则,如何实现输出get1bylistandroid7

var str = 'get1_by2_list334_android7';
var result = str.replace(/(\d*[02468])*_*/g, '')
console.log(result);

6.不用循环语句和迭代器实现0到1000数组赋值

不使用任何循环控制语句和迭代器的情况下,实现一个0到1000的数组赋值。

var i = 0;
var arr = [];
function fn() { 
  arr[i] = i
  i++;
  if (i > 1000) {
    clearInterval(id)
    console.log(arr)
  }
}
var id = setInterval (fn, 0);

7. JSON格式的树状结构生成一个dom树

将类似以下JSON表示的树状结构(可以无限层级)通过parseDOM函数(使用document.createElement,document.createTextNode,appendChild等方法)生成一颗DOM树(返回一个element元素)

const jsonTree = {
    "tagName": "ul",
    "props": {
      "className": "list",
      "data-name": "jsontree"
    },
    "children": [{
        "tagName": "li",
        "children": [{
          "tagName": "img",
          "props": {
            "src": "//img.alicdn.com/tps/TB1HwXxLpXXXXchapXXXXXXXXXX-32-32.ico",
            "width": "16px"
          }
        }]
      },
      {
        "tagName": "li",
        "children": [{
          "tagName": "a",
          "props": {
            "href": "https://www.aliyun.com",
            "target": "_blank"
          },
          "children": "阿里云"
        }]
      }
    ]
  };
  
  function parseDOM(jsontree){
    const {tagName,props,children} = jsontree;
    const element = document.createElement(tagName);
    // 添加属性
    if (typeof props === 'object') {
      for (var key in props) {
        element.setAttribute(key, props[key]);
      }
    }
    // 添加子元素
    if (children) {
      if (typeof children === 'string') {
        element.innerHTML = children;
      } else if (Array.isArray(children)) {
        children.forEach(function(e) {
          element.appendChild(parseDOM(e))
        })
      }
    }
    return element;
  }
  var one = document.getElementById('one');
  one.appendChild(parseDOM(jsonTree));

http://js.jirengu.com/juyeki/edit?html,js,output

  • 33
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值