JavaScript试题记录待续。。。

355 阅读6分钟

本文摘抄并总结一些JavaScript试题,答案在最下面。本文难免有不注意或有错的地方或有更好的方法,望指出更正学习。

虽然你变秃了,但是你变强了!!!

一、下面输出什么

1.let和var区别

var a
if (a) {
 let a = 20
} else {
 let a = 30
}
console.log(a) // undefined 
// var是全局,let局部作用域,a在全局中未赋值,所以undefined

function fun(){
  console.log(name)  // undefined // var变量提升,相当于var name;console.log(name);name = 'lxf';赋值在后
  console.log(age)  // ReferenceError // let变量没有提升
  var name = 'lxf'
  let age = 18
}

var num = 10
var num = 20
console.log(num) // 20

var fn = NaN
function fn(){}
console.log(typeof fn) // number
var fn = function(){}
console.log(typeof fn) // function

2.setTimeout(类似setInterval。。。)

setTimeout 回调会在遍历结束后才执行,var是在全局作用域下的,等循环结束后直接输出最后值3,let在每一次循环内作用域中执行

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1) // 3 3 3
}

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1) // 0 1 2
}

3.箭头函数与普通函数

let b = 1
let obj = {
  b: 10,
  fn: function(){  // fn: function(){} <==> fn () {}
    console.log(this.b)
  },
  fnn: () => {
    console.log(this.b)
  }
}
obj.fn() // 10
obj.fnn() // undefined  this指window

4.对象调用

let c = 12
let obj = {
  c: 45,
  a: function(){
    console.log(this.c)
  }
}
let b = obj.a
b() // undefined,此时this是window(window调用obj里的a函数),this一般谁调用那属于谁

5.隐式符作用

console.log(+true) // 1  算数运算符(+)把true变成number类型,true变成1,false为0
console.log(+undefined) // NaN
console.log(!'lxf') // false  字符串'lxf'是一个真值,真值取反那么就假返回 false

let a = new Number(666) // 一个内建的函数构造器,是一个对象而不是number类型
let b = 666
console.log(a === b) // false
console.log(a == b) // true

function sum(a, b) {
  return a + b
}
sum(1, '2') // 12  js中加号(+)是连字符

6.++a和a++区别(前者先加再赋值,后者先赋值再加)

let a = 10
b = 20 // 没有声明,就成了全局变量
console.log(b) // 20
let d = ++b+a++
console.log(d) // 31

let c = 0
consolelog(c++) // 0
consolelog(++c) // 2
consolelog(c) // 2

7.数组添加

let arr = [1, 2, 3]
arr[10] = 11
console.log(arr) // [ 1, 2, 3, <7 empty items>, 11 ]

8.对象取值

let a = {}
let b = {
  key: 'jkl'
}
let c = {
  key: 'iop'
}
a[b] = 123
a[c] = 456
console.log(a) // { '[object Object]': 456 }
console.log(a[c]) // 456

const obj1 = {
  name: 'lxf',
  love: true
}
const obj2 = {
  name: 'wqq',
  islove: 'love'
}
console.log(obj1[obj2["islove"]])  // true
console.log(obj1[obj2.islove])  // true
console.log(obj2['islove'])  // love
console.log(obj1.obj2.islove) // Cannot read property 'islove' of undefined  // obj1中没有obj2

9.hasOwnProperty和has和Set

const obj = {
  1: 'a',
  2: 'b',
  3: 'c'
}
const set = new Set([1, 2, 3, 4, 5])
console.log(obj.hasOwnProperty('1')) // true
console.log(obj.hasOwnProperty(1)) // true
console.log(set.has('1')) // false
console.log(set.has(1)) // true

10.对象赋值

let a = {
  name: 'lxf'
}
let b
b = a
a.name = 'wqq'
console.log(b.name) // wqq  // 对象浅度复制,当设置两个对象彼此相等时,它们会通过引用进行交互,一边另一个也跟着变。避免这情况就是深度复制。

11.对象中有同名键

const obj = {
  a: "one",
  b: "two",
  a: "three"
}
console.log(obj) // { a: "three", b: "two" }  // 如果你有两个名称相同的键,则键会被替换掉。它仍然位于第一个键出现的位置,但是值是最后出现那个键的值。

12.continue跳过本次迭代

for (let i = 1; i < 5; i++) {
  if (i === 3) continue
  console.log(i) // 1, 2, 4  // 如果某个条件返回 true,则 continue 语句跳过本次迭代。
}

13.事件冒泡

<div onclick="console.log('div')">
  <p onclick="console.log('p')">
    Click here!
  </p>
</div>
// p div

14.闭包

function foo(x) {
  let a = 3
  return function (y) {
    console.log(x + y + (++a))
  }
}
let bar = foo(2)
bar(10) // 16

15.基本类型

console.log(null + 1) // 1
console.log(undefined + 1) // NaN
console.log(NaN + 1 !== NaN + 1) // true      NaN !== NaN

16.instanceof

console.log([] instanceof Object) // true
console.log([] instanceof Array) // true
console.log('somestr' instanceof String) //false

17.构造函数

function Study(){
  Study.prototype.hello = function(){
    console.log('hello')
  }
}
let s = new Study()
console.log(Study.prototype) // Study { hello: [Function] }
console.log(s.hello) // [Function]
s.hello() // hello

18.基本类型

console.log([] === [])  // false
console.log(null == 0)  // false
console.log(null == undefined)  // true
console.log(undefined == '0')  // false
console.log(NaN == false)  // false
console.log([] == false)  // true

19.扩展运算符(es6)

let obj = {a: '1', b: '2', c: '3'}
let obj1 = {...obj}
console.log(obj === obj1) // false
obj1.a = 8
console.log(obj)  // {a: '1', b: '2', c: '3'}
console.log(obj1)  //  {a: '8', b: '2', c: '3'}

20.解构赋值(es6)

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }
console.log(x)  // 1
console.log(y)  // 2
console.log(z)  // {a: 3, b: 4}

21.对象合并(Object.assign)

let a = {a: '1'}
let b = {b: '2'}
let c = {c: '3'}
let obj = Object.assign(a, b, c)    // 同名属性,则后面的属性会覆盖前面的属性
console.log(obj)  // { a: '1', b: '2', c: '3' }

20.运算优先顺序

console.log('Value is ' + (NaN === NaN) ? 'Something' : 'Nothing')   // Something
// 字符串连接比三目运算有更高的优先级

二、选择题

1.函数是对象

function fun() {
  console.log('hello')
}
fun.name = 'lxf'

A: 正常运行!
B: SyntaxError. 你不能通过这种方式给函数增加属性。
C: undefined
D: ReferenceError

// A,函数是对象(除了基本类型之外其他都是对象),函数是一个拥有属性的特殊对象,并且属性也可被调用。

三、编程题

1.选择排序

首先从未排序序列中找到最大的元素,放到已排序序列的末尾,重复上述步骤,直到所有元素排序完毕。

时间复杂度均为o(n^2) 空间复杂度为o(1) 不稳定

function selectSort(arr){
  let len = arr.length
  let index
  for (let i = 0; i < len - 1; i++) {
    index = i
    for (let j = i + 1; j < len; j++) {
      if (arr[index] > arr[j]) index = j
      if (index !== i) {
        let res = arr[i]
        arr[i] = arr[index]
        arr[index] = res
      }
    }
  }
  return arr
}

2.冒泡排序

比较相邻的两个元素,如果前一个比后一个大,则交换位置。再进入下一轮循环比较。

function bubbleSort(arr){
  let len = arr.length
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] > arr[j]) {
        let temp = arr[i]
        arr[i] = arr[j]
        arr[j] = temp
      }
    }
  }
  return arr
}

3.插入排序

每次将一个数插入到有序的数组中去

function insertSort(arr){
  let j, len = arr.length, temp
  for(let i = 1; i < len; i++){
    j = i
    temp = arr[j]
    while (--j > -1) {
      if (arr[j] > temp) {
        arr[j+1] = arr[j]
      } else {
        break
      }
    }
    arr[j+1] = temp
  }
  return arr
}

4.快速排序

将待排序数组逐步划分两个部分,其中左半部分都要小于右半部分,再将左右部分分别进行快速排序,整个过程可采用递归进行,直到排成一个有序数列。

function quickSort(arr){
  if (arr.length <= 1) return arr
  let pivotIndex = Math.floor(arr.length / 2) // 取基准点
  let pivot = arr.splice(pivotIndex, 1)[0] // 取基准点的值,splice(index,1)函数可以返回数组中被删除的那个数
  let left = [] // 存放比基准点小的数组
  let right = [] // 存放比基准点大的数组 
  for (let i = 0; i < arr.length; i++) { // 遍历数组,进行判断分配 
    if (arr[i] < pivot) {
      left.push(arr[i]) // 比基准点小的放在左边数组 
    } else {
      right.push(arr[i]) // 比基准点大的放在右边数组 
    }
  }
  //递归执行以上操作,对左右两个数组进行操作,直到数组长度为<=1
  return quickSort(left).concat([pivot], quickSort(right))
}

5.随机打乱数组

let arr = [1, 3, 2, 4, 2, 3, 1]

function randomArr(arr){
  return arr.sort(()  => 0.5 - Math.random())
}

6.牙刷5元,香皂2元、洗发水15元 100元正好花完有多少种可能?

let num = 0
for (let i=0; i<=20; i++) {
  for (let j=0; j<=50; j++) {
    for (let x=0; x<=6; x++) {
      if (5*i+2*j+15*x === 100) {
        num++
      } 
    }
  }
}
console.log(num)  // 44

7.根据json数组中两个key相同进行去重

法一:
let arr = [
    {x: 11, y: 9, z: 1},
    {x: 12, y: 9, z: 2},
    {x: 13, y: 9, z: 2},
    {x: 13, y: 10, z: 2},
    {x: 13, y: 11, z: 1},
    {x: 13, y: 10, z: 1}
  ]
const uniqueTwoKey = (arr, a, b) => {
  const dict = {}
  for (const item of arr) {
    dict[item[a] + ',' + item[b]] = item
  }
  return Object.values(dict)
}
console.log(uniqueTwoKey(arr, 'x', 'y'))
法二:
const uniqueTwoKey = (arr, a, b) => {
  const dict = {}
  return arr.filter(e => {
    const key = [e[a], e[b]].join("|")
    if (dict[key]) return false
    dict[key] = true
    return true
  })
}
console.log(uniqueTwoKey(arr, 'x', 'y'))

结果:
[
  { x: 11, y: 9, z: 1 },
  { x: 12, y: 9, z: 2 },
  { x: 13, y: 9, z: 2 },
  { x: 13, y: 10, z: 1 },
  { x: 13, y: 11, z: 1 }
]