每天10个前端小知识(5day)

一、异步函数始终返回一个promise

来看下面的例子

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!"

二、push()方法返回新数组的长度

还是先来看例子

function addToList(item, list) {
  return list.push(item);
}

const result = addToList("apple", ["banana"]);
console.log(result);

这时候打印出来的是‘2’,这是因为

push()方法返回新数组的长度。一开始,数组包含一个元素(字符串"banana"),长度为1。 在数组中添加字符串"apple"后,长度变为2,并将从addToList函数返回。 push方法修改原始数组,如果你想从函数返回数组而不是数组长度,那么应该在push item之后返回list

三、Object.freeze

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的值不是对象,所以我们不能修改属性x。 x仍然等于10{x:10,y:20}被打印。 注意,上述例子我们对属性x进行修改,可能会导致抛出TypeError异常(最常见但不仅限于严格模式下时)。

四、记忆函数

对于一种纯函数(即只要是同一种输入就能得到唯一一个相同的结果的函数),我们可以设置记忆函数来节约资源,当输入的参数不变时,我们就可以采用缓存的结果,当输入参数有所变化时才重新计算。一种记忆函数如下所示:

const add = () => {
  const cache = {};
  return num => {
    if (num in cache) {
      return `From cache! ${cache[num]}`;
    } else {
      const result = num + 10;
      cache[num] = result;
      return `Calculated! ${result}`;
    }
  };
};

const addFunction = add();
console.log(addFunction(10));
console.log(addFunction(10));
console.log(addFunction(5 * 2));

我们发现此时输出的是Calculated! 20 From cache! 20 From cache! 20

在这个例子中,add函数是一个记忆函数。 通过记忆化,我们可以缓存函数的结果,以加快其执行速度。上述情况,我们创建一个cache对象,用于存储先前返回过的值。 如果我们使用相同的参数多次调用addFunction函数,它首先检查缓存中是否已有该值,如果有,则返回缓存值,这将节省执行时间。如果没有,那么它将计算该值,并存储在缓存中。 我们用相同的值三次调用了addFunction函数: 在第一次调用,num等于10时函数的值尚未缓存,if语句num in cache返回false,else块的代码被执行:Calculated! 20,并且其结果被添加到缓存对象,cache现在看起来像{10:20}。 第二次,cache对象包含10的返回值。 if语句 num in cache 返回trueFrom cache! 20被打印。 第三次,我们将5 * 2(值为10)传递给函数。 cache对象包含10的返回值。 if语句 num in cache 返回trueFrom cache! 20被打印。

五、for in 和for of的区别

通过for-in循环,我们可以遍历一个对象自有的继承的可枚举的非Symbol的属性。

通过for-of循环,我们可以迭代可迭代对象(包括 ArrayMapSetStringarguments等)

来看下面的例子

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, 因此“☕”“💻”“🍷”“🍫”被打印。

六、默认情况下,如果不给函数传参,参数的值将为undefined

我们来看一下下面这个函数会输出什么

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

console.log(sayHi())

运行这个函数,发现输出的结果是Hi there, undefined

默认情况下,如果不给函数传参,参数的值将为undefined。 上述情况,我们没有给参数name传值。 name等于undefined,并被打印。 在ES6中,我们可以使用默认参数覆盖此默认的undefined值。 例如: function sayHi(name =“Lydia”){...} 在这种情况下,如果我们没有传递值或者如果我们传递undefinedname总是等于字符串Lydia

七、类是构造函数的语法糖

类是构造函数的语法糖,如果用构造函数的方式来重写Person类则将是:

function Person() {
  this.name = name
}

通过new来调用构造函数,将会生成构造函数Person的实例,对实例执行typeof关键字将返回"object",上述情况打印出"object"

下面这个例子可以充分说明

class Person {
  constructor(name) {
    this.name = name
  }
}

const member = new Person("John")
console.log(typeof member)

八、箭头函数和普通函数的prototype

我们来看一下,下面这个例子会打印出来什么

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

九、Object.entries()

首先来看一个例子,看会打印出什么

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

十、... args只能作为最后一个参数

来看下面的例子会输出什么

function getItems(fruitList, ...args, favoriteFruit) {
  return [...fruitList, ...args, favoriteFruit]
}

getItems(["banana", "apple"], "pear", "orange")

运行之后,我们发现报错了,这是因为

... args是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,并且只能作为最后一个参数。上述示例中,剩余参数是第二个参数,这是不可能的,并会抛出语法错误。

function getItems(fruitList, favoriteFruit, ...args) {
  return [...fruitList, ...args, favoriteFruit]
}
getItems(["banana", "apple"], "pear", "orange")

上述例子是有效的,将会返回数组:[ 'banana', 'apple', 'orange', 'pear' ]

以上所有内容参考

首页 - 前端面试题宝典《前端面试题宝典》的目标是做全网最专业的的前端面试题库,为初、中级前端工程师提供面试题的刷题及面试技巧指导服务https://fe.ecool.fun/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值