JS 基础小题

37 篇文章 0 订阅
27 篇文章 0 订阅

JS 基础小题

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

shape.diameter()
shape.perimeter()

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

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

let a = 3
let b = new Number(3)
let c = 3

console.log(a == b)
console.log(a === b)
console.log(b === c)

//C: true false false
  • new Number() 是一个内建的函数构造器。虽然它看着像是一个 number,但它实际上并不是一个真实的 number:它有一堆额外的功能并且它是一个对象

    当我们使用 == 操作符时,它只会检查两者是否拥有相同的。因为它们的值都是 3,因此返回 true

    然后,当我们使用 === 操作符时,两者的值以及类型都应该是相同的。new Number() 是一个对象而不是 number,因此返回 false

class Chameleon {
  static colorChange(newColor) {
    this.newColor = newColor
    return this.newColor
  }

  constructor({ newColor = 'green' } = {}) {
    this.newColor = newColor
  }
}

const freddie = new Chameleon({ newColor: 'purple' })
freddie.colorChange('orange')
//TypeError
  • colorChange 是一个静态方法。静态方法被设计为只能被创建它们的构造器使用(也就是 Chameleon),并且不能传递给实例。因为 freddie 是一个实例,静态方法不能被实例使用,因此抛出了 TypeError 错误。
function getPersonInfo(one, two, three) {
  console.log(one)
  console.log(two)
  console.log(three)
}

const person = 'Lydia'
const age = 21

getPersonInfo`${person} is ${age} years old`
//["", " is ", " years old"] "Lydia" 21
  • 如果使用标记模板字面量,第一个参数的值总是包含字符串的数组。其余的参数获取的是传递的表达式的值!
function checkAge(data) {
  if (data === { age: 18 }) {
    console.log('You are an adult!')
  } else if (data == { age: 18 }) {
    console.log('You are still an adult.')
  } else {
    console.log(`Hmm.. You don't have an age I guess`)
  }
}

checkAge({ age: 18 })
//Hmm.. You don't have an age I guess
  • 在测试相等性时,基本类型通过它们的值(value)进行比较,而对象通过它们的引用(reference)进行比较。JavaScript 检查对象是否具有对内存中相同位置的引用。

    题目中我们正在比较的两个对象不是同一个引用:作为参数传递的对象引用的内存位置,与用于判断相等的对象所引用的内存位置并不同。

    这也是 { age: 18 } === { age: 18 }{ age: 18 } == { age: 18 } 都返回 false 的原因。

function getAge(...args) {
  console.log(typeof args)
}

getAge(21)
//object
  • 扩展运算符(...args)会返回实参组成的数组。而数组是对象,因此 typeof args 返回 "object"
function getAge() {
  'use strict'
  age = 21
  console.log(age)
}

getAge()
//ReferenceError
  • 使用 "use strict",你可以确保不会意外地声明全局变量。我们从来没有声明变量 age,因为我们使用 "use strict",它将抛出一个引用错误。如果我们不使用 "use strict",它就会工作,因为属性 age 会被添加到全局对象中了。
JavaScript 全局执行上下文为你做了两件事:全局对象和 this 关键字。
A: true
B: false
C: it depends
//true
  • 基本执行上下文是全局执行上下文:它是代码中随处可访问的内容。
const a = {}
const b = { key: 'b' }
const c = { key: 'c' }

a[b] = 123
a[c] = 456

console.log(a[b])
//{[object Object]: 456}
  • 对象的键被自动转换为字符串。我们试图将一个对象 b 设置为对象 a 的键,且相应的值为 123

    然而,当字符串化一个对象时,它会变成 "[object Object]"。因此这里说的是,a["[object Object]"] = 123。然后,我们再一次做了同样的事情,c 是另外一个对象,这里也有隐式字符串化,于是,a["[object Object]"] = 456

    然后,我们打印 a[b],也就是 a["[object Object]"]。之前刚设置为 456,因此返回的是 456

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

  • 所有对象的键(不包括 Symbol)在底层都是字符串,即使你自己没有将其作为字符串输入。这就是为什么 obj.hasOwnProperty('1') 也返回 true

// 当点击按钮时,event.target是什么?

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

//当您单击该段落时,日志输出是什么?
//p div
  • 导致事件的最深嵌套的元素是事件的 target。你可以通过 event.stopPropagation 来停止冒泡。
  • 如果我们点击 p,我们会看到两个日志:pdiv。在事件传播期间,有三个阶段:捕获、目标和冒泡。默认情况下,事件处理程序在冒泡阶段执行(除非将 useCapture 设置为 true)。它从嵌套最深的元素向外传播。
setInterval 方法的返回值是什么?
setInterval(() => console.log('Hi'), 1000)
//一个唯一的id
  • setInterval 返回一个唯一的 id。此 id 可被用于 clearInterval 函数来取消定时。
const num = parseInt("7*6", 10);
//输出7
const num = parseInt("s7*6", 10);
//NaN

  • 只返回了字符串中第一个字母. 设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制: 十进制、十六机制、八进制、二进制等等……),parseInt 检查字符串中的字符是否合法. 一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。

    *就是不合法的数字字符。所以只解析到"7",并将其解析为十进制的7. num的值即为7.

// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from "./counter";

myCounter += 1;

console.log(myCounter);

//Error
  • 引入的模块是 只读: 你不能修改引入的模块。只有导出他们的模块才能修改其值

    当我们给myCounter增加一个值的时候会抛出一个异常: myCounter是只读的,不能被修改。

const person = { name: "Lydia" };

Object.defineProperty(person, "age", { value: 21 });

console.log(person);
console.log(Object.keys(person));
//{ name: "Lydia", age: 21 }, ["name"]
  • 通过defineProperty方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用defineProperty方法给对象添加了一个属性之后,属性默认为 不可枚举(not enumerable). Object.keys方法仅返回对象中 可枚举(enumerable) 的属性,因此只剩下了"name".

    defineProperty方法添加的属性默认不可变。你可以通过writable, configurableenumerable属性来改变这一行为。这样的话, 相比于自己添加的属性,defineProperty方法添加的属性有了更多的控制权。

    [1, 2, 3, 4].reduce((x, y) => console.log(x, y));
    
  • reducer 函数接收4个参数:

    1. Accumulator (acc) (累计器)
    2. Current Value (cur) (当前值)
    3. Current Index (idx) (当前索引)
    4. Source Array (src) (源数组)

    reducer 函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。

    reducer 函数还有一个可选参数initialValue, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供initialValue,则将使用数组中的第一个元素。

    在上述例子,reduce方法接收的第一个参数(Accumulator)是x, 第二个参数(Current Value)是y

    在第一次调用时,累加器x1,当前值“y”2,打印出累加器和当前值:12

    例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回undefined。 在下一次调用时,累加器为undefined,当前值为“3”, 因此undefined3被打印出。

    在第四次调用时,回调函数依然没有返回值。 累加器再次为 undefined ,当前值为“4”。 undefined4被打印出。

async function getData() {
  return await Promise.resolve("I made it!");
}

const data = getData();
console.log(data);
//Promise {<pending>}
  • 异步函数始终返回一个promise。await仍然需要等待promise的解决:当我们调用getData()并将其赋值给data,此时datagetData方法返回的一个挂起的promise,该promise并没有解决。

    如果我们想要访问已解决的值"I made it!",可以在data上使用.then()方法:

    data.then(res => console.log(res))
    

    这样将打印 "I made it!"

const box = { x: 10, y: 20 };

Object.freeze(box);

const shape = box;
shape.x = 100;
console.log(shape)
//{ x: 10, y: 20 }
  • Object.freeze使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。

    当我们创建变量shape并将其设置为等于冻结对象box时,shape指向的也是冻结对象。你可以使用Object.isFrozen检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)将返回true

    由于shape被冻结,并且x的值不是对象,所以我们不能修改属性xx仍然等于10{x:10,y:20}被打印。

    注意,上述例子我们对属性x进行修改,可能会导致抛出TypeError异常(最常见但不仅限于严格模式下时)。

const myLifeSummedUp = ["☕", "💻", "🍷", "🍫"]

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

for (let item of myLifeSummedUp) {
  console.log(item)
}
//: 0 1 2 3 and "☕" "💻" "🍷" "🍫"
  • 通过for-in循环,我们可以遍历一个对象自有的继承的可枚举的非Symbol的属性。 在数组中,可枚举属性是数组元素的“键”, 即它们的索引。 类似于下面这个对象:

    {0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
    

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

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

    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)
    //{ constructor: ...} undefined
    
  • 常规函数,例如giveLydiaPizza函数,有一个prototype属性,它是一个带有constructor属性的对象(原型对象)。 然而,箭头函数,例如giveLydiaChocolate函数,没有这个prototype属性。 尝试使用giveLydiaChocolate.prototype访问prototype属性时会返回undefined

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

for (const [x, y] of Object.entries(person)) {
  console.log(x, y)
}
//name Lydia and age 21
  • Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,上述情况返回一个二维数组,数组每个元素是一个包含键和值的数组:

    [['name','Lydia'],['age',21]]
    

    使用for-of循环,我们可以迭代数组中的每个元素,上述情况是子数组。 我们可以使用const [x,y]for-of循环中解构子数组。 x等于子数组中的第一个元素,y等于子数组中的第二个元素。

    第一个子阵列是[“name”,“Lydia”],其中x等于name,而y等于Lydia。 第二个子阵列是[“age”,21],其中x等于age,而y等于21

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值