js 学习 【一】

数组求和

let arr = [1, 2, 3, 4, 5]
let arr2 = eval(arr.join('+'))

console.log(arr2)  //15

数组完全展开

function myFlat(arr) {
  while (arr.some(t => Array.isArray(t))) {
   	arr = ([]).concat.apply([], arr);
  }
  return arr;
}
var arr2 = [1, [2, 3, [4]], 5, 6, [7, 8], [[9, [10, 11], 12], 13], 14];  
console.log(myFlat(arr2)) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

解决键盘弹出后挡表单的问题

window.addEventListener('resize', function () {
if (
  document.activeElement.tagName === 'INPUT' ||
  document.activeElement.tagName === 'TEXTAREA' ||
  document.activeElement.getAttribute('contenteditable') == 'true'
) {
  window.setTimeout(function () {
    if ('scrollIntoView' in document.activeElement) {
      document.activeElement.scrollIntoView();
    } else {
      // @ts-ignore
      document.activeElement.scrollIntoViewIfNeeded();
    }
  }, 0);
}
})

移动端打开指定App或者下载App

navToDownApp() {
      let u = navigator.userAgent
      if (/MicroMessenger/gi.test(u)) {
        // 如果是微信客户端打开,引导用户在浏览器中打开
        alert('请在浏览器中打开')
      }
      if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
        // Android
        if (this.openApp('en://startapp')) {
          this.openApp('en://startapp') // 通过Scheme协议打开指定APP
        } else {
          //跳转Android下载地址
        }
      } else if (u.indexOf('iPhone') > -1) {
        if (this.openApp('ios--scheme')) {
          this.openApp('ios--scheme') // 通过Scheme协议打开指定APP
        } else {
          // 跳转IOS下载地址
        }
      }
    },
    openApp(src) {
      // 通过iframe的方式试图打开APP,如果能正常打开,会直接切换到APP,并自动阻止a标签的默认行为
      // 否则打开a标签的href链接
      let ifr = document.createElement('iframe')
      ifr.src = src
      ifr.style.display = 'none'
      document.body.appendChild(ifr)
      window.setTimeout(function() {
        // 打开App后移出这个iframe
        document.body.removeChild(ifr)
      }, 2000)
    }

数组去重

 var array = [1, 2, 1, 1, '1'];
  function unique(array) {
    var obj = {};
    return array.filter(function(item, index, array){
      return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
  }
  console.log(unique(array))  //[1, 2, "1"]

交换数组指定位置元素位置

  var array = [1, 2, 3, 4];
 // x , y是要交换元素的位置(index+1)
function arrIndexExchange(array, x, y){
    array.splice(x - 1, 1, ...array.splice(y - 1, 1, array[x - 1]));
    return array;
};
console.log(arrIndexExchange(array, 1, 4)) //[4, 2, 3, 1]

 输出是什么

function sayHi() {
  console.log(name)
  console.log(age)
  var name = 'Lydia'
  let age = 21
}

sayHi()  // undefined 和 ReferenceError

在函数内部,我们首先通过 var 关键字声明了 name 变量。这意味着变量被提升了(内存空间在创建阶段就被设置好了),直到程序运行到定义变量位置之前默认值都是 undefined。因为当我们打印 name 变量时还没有执行到定义变量的位置,因此变量的值保持为 undefined。

通过 let 和 const 关键字声明的变量也会提升,但是和 var 不同,它们不会被初始化。在我们声明(初始化)之前是不能访问它们的。这个行为被称之为暂时性死区。当我们试图在声明之前访问它们时,JavaScript 将会抛出一个 ReferenceError 错误。

 输出是什么

 

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

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

// 3 3 3 和 0 1 2

由于 JavaScript 的事件循环,setTimeout 回调会在遍历结束后才执行。因为在第一个遍历中遍历 i 是通过 var 关键字声明的,所以这个值是全局作用域下的。在遍历过程中,我们通过一元操作符 ++ 来每次递增 i 的值。当 setTimeout 回调执行的时候,i 的值等于 3。

在第二个遍历中,遍历 i 是通过 let 关键字声明的:通过 let 和 const 关键字声明的变量是拥有块级作用域(指的是任何在 {} 中的内容)。在每次的遍历过程中,i 都有一个新值,并且每个值都在循环内的作用域中。

输出是什么

const shape = {
  radius: 10,
  diameter() {
    return this.radius * 2
  },
  perimeter: () => 2 * Math.PI * this.radius
}

shape.diameter()
shape.perimeter()  //20 and NaN

 

注意 diameter 的值是一个常规函数,但是 perimeter 的值是一个箭头函数。

对于箭头函数,this 关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。这意味着当我们调用 perimeter 时,this 不是指向 shape 对象,而是它的周围作用域(在例子中是 window)。

在 window 中没有 radius 这个属性,因此返回 undefined。

输出是什么?

+true;
!"Lydia";

//1 and false

 

一元操作符加号尝试将 bool 转为 number。true 转换为 number 的话为 1,false 为 0。

字符串 'Lydia' 是一个真值,真值取反那么就返回 false。

哪一个是无效的?

 

const bird = {
  size: 'small'
}

const mouse = {
  name: 'Mickey',
  small: true
}

A: mouse.bird.size
B: mouse[bird.size]
C: mouse[bird["size"]]
D: All of them are valid

//A: mouse.bird.size

 

在 JavaScript 中,所有对象的 keys 都是字符串(除非对象是 Symbol)。尽管我们可能不会定义它们为字符串,但它们在底层总会被转换为字符串。

当我们使用括号语法时([]),JavaScript 会解释(或者 unboxes)语句。它首先看到第一个开始括号 [ 并继续前进直到找到结束括号 ]。只有这样,它才会计算语句的值。

mouse[bird.size]:首先计算 bird.size,这会得到 small。mouse["small"] 返回 true。

然后使用点语法的话,上面这一切都不会发生。mouse 没有 bird 这个 key,这也就意味着 mouse.bird 是 undefined。然后当我们使用点语法 mouse.bird.size 时,因为 mouse.bird 是 undefined,这也就变成了 undefined.size。这个行为是无效的,并且会抛出一个错误类似 Cannot read property "size" of undefined。

输出什么?

console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol('foo') === Symbol('foo'))
  • A: truetruefalse
  • B: falsetruefalse
  • C: truefalsetrue
  • D: truetruetrue

每个Symbol都是完全唯一的。传递给Symbol的参数只是给Symbol的一个描述。 Symbol的值不依赖于传递的参数。 当我们测试相等时,我们创建了两个全新的符号:第一个Symbol('foo'),第二个Symbol('foo'), 这两个值是唯一的,彼此不相等,因此返回false

 以下是个纯函数么?

function sum(a, b) {
  return a + b;
}
  • A: Yes
  • B: No

答案: A

纯函数一种若输入参数相同,则永远会得到相同输出的函数。

sum函数总是返回相同的结果。 如果我们传递12,它将总是返回3而没有副作用。 如果我们传递510,它将总是返回15,依此类推,这是纯函数的定义。

输出什么?

const myLifeSummedUp = ["☕", "?", "?", "?"]

for (let item in myLifeSummedUp) {
  console.log(item)
}

for (let item of myLifeSummedUp) {
  console.log(item)
}
  • A: 0 1 2 3 and "☕" "?" "?" "?"
  • B: "☕" "?" "?" "?" and "☕" "?" "?" "?"
  • C: "☕" "?" "?" "?" and 0 1 2 3
  • D: 0 1 2 3 and {0: "☕", 1: "?", 2: "?", 3: "?"}

 

答案: A

通过for-in循环,我们可以遍历一个对象自有的继承的可枚举的非Symbol的属性。 在数组中,可枚举属性是数组元素的“键”, 即它们的索引。 类似于下面这个对象:

{0: "☕", 1: "?", 2: "?", 3: "?"}

其中键则是可枚举属性,因此 0123被记录。

通过for-of循环,我们可以迭代可迭代对象(包括 ArrayMapSetStringarguments等)。当我们迭代数组时,在每次迭代中,不同属性的值将被分配给变量item, 因此“☕”“?”“?”“?”被打印。

输出什么?

const list = [1 + 2, 1 * 2, 1 / 2]
console.log(list)
  • A: ["1 + 2", "1 * 2", "1 / 2"]
  • B: ["12", 2, 0.5]
  • C: [3, 2, 0.5]
  • D: [1, 1, 1]

答案: C

数组元素可以包含任何值。 数字,字符串,布尔值,对象,数组,nullundeifned, 以及其他表达式,如日期,函数和计算。

元素将等于返回的值。 1 + 2返回31 * 2返回'2,'1 / 2返回0.5

输出什么?

function sayHi(name) {
  return `Hi there, ${name}`
}

console.log(sayHi())
  • A: Hi there,
  • B: Hi there, undefined
  • C: Hi there, null
  • D: ReferenceError

 

答案: B

默认情况下,如果不给函数传参,参数的值将为undefined。 上述情况,我们没有给参数name传值。 name等于undefined,并被打印。

在ES6中,我们可以使用默认参数覆盖此默认的undefined值。 例如:

function sayHi(name =“Lydia”){...}

在这种情况下,如果我们没有传递值或者如果我们传递undefinedname总是等于字符串Lydia

输出什么?

const person = {
  name: "Lydia",
  age: 21
}

let city = person.city
city = "Amsterdam"

console.log(person)
  • A: { name: "Lydia", age: 21 }
  • B: { name: "Lydia", age: 21, city: "Amsterdam" }
  • C: { name: "Lydia", age: 21, city: undefined }
  • D: "Amsterdam"

 

答案: A

我们将变量city设置为等于person对象上名为city的属性的值。 这个对象上没有名为city的属性,因此变量city的值为undefined

请注意,我们没有引用person对象本身,只是将变量city设置为等于person对象上city属性的当前值。

然后,我们将city设置为等于字符串“Amsterdam”。 这不会更改person对象:没有对该对象的引用。

因此打印person对象时,会返回未修改的对象。

输出什么?

function checkAge(age) {
  if (age < 18) {
    const message = "Sorry, you're too young."
  } else {
    const message = "Yay! You're old enough!"
  }

  return message
}

console.log(checkAge(21))
  • A: "Sorry, you're too young."
  • B: "Yay! You're old enough!"
  • C: ReferenceError
  • D: undefined

答案: C

constlet声明的变量是具有块级作用域的,块是大括号({})之间的任何东西, 即上述情况if / else语句的花括号。 由于块级作用域,我们无法在声明的块之外引用变量,因此抛出ReferenceError

输出什么?

console.log("I want pizza"[0])
  • A: """
  • B: "I"
  • C: SyntaxError
  • D: undefined

 

答案: B

可以使用方括号表示法获取字符串中特定索引的字符,字符串中的第一个字符具有索引0,依此类推。 在这种情况下,我们想要得到索引为0的元素,字符'I'被记录。

请注意,IE7及更低版本不支持此方法。 在这种情况下,应该使用.charAt()

输出什么?

function sum(num1, num2 = num1) {
  console.log(num1 + num2)
}

sum(10)
  • A: NaN
  • B: 20
  • C: ReferenceError
  • D: undefined

 

答案: B

您可以将默认参数的值设置为函数的另一个参数,只要另一个参数定义在其之前即可。 我们将值10传递给sum函数。 如果sum函数只接收1个参数,则意味着没有传递num2的值,这种情况下,num1的值等于传递的值10。 num2的默认值是num1的值,即10。 num1 + num2返回20

如果您尝试将默认参数的值设置为后面定义的参数,则可能导致参数的值尚未初始化,从而引发错误。比如:

function test(m = n, n = 2) {
   console.log(m, n)
}
   test() // Uncaught ReferenceError: Cannot access 'n' before initialization
   test(3) // 3 2
   test(3, 4) // 3 4

输出什么?

let newList = [1, 2, 3].push(4)

console.log(newList.push(5))
  • A: [1, 2, 3, 4, 5]
  • B: [1, 2, 3, 5]
  • C: [1, 2, 3, 4]
  • D: Error

 

答案: D

.push方法返回数组的长度,而不是数组本身! 通过将newList设置为[1,2,3].push(4),实际上newList等于数组的新长度:4

然后,尝试在newList上使用.push方法。 由于newList是数值4,抛出TypeError。


输出什么?

function giveLydiaPizza() {
  return "Here is pizza!"
}

const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."

console.log(giveLydiaPizza.prototype)
console.log(giveLydiaChocolate.prototype)
  • A: { constructor: ...} { constructor: ...}
  • B: {} { constructor: ...}
  • C: { constructor: ...} {}
  • D: { constructor: ...} undefined

 

答案: D

常规函数,例如giveLydiaPizza函数,有一个prototype属性,它是一个带有constructor属性的对象(原型对象)。 然而,箭头函数,例如giveLydiaChocolate函数,没有这个prototype属性。 尝试使用giveLydiaChocolate.prototype访问prototype属性时会返回undefined

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值