2024年前端最新每天10个前端小知识 【Day 11】_前端开发每日必学,前端开发原则

JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】


js 文件的下载不会阻塞前面 HTML 和 CSS 的解析:



test

**需要注意的点**


* 第一,GUI 渲染线程会尽可能早的将内容呈现到屏幕上,并不会等到所有的 HTML 都解析完成之后再去构建和布局 Render Tree,而是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。下面 test1 会在 js 文件下载完成前渲染完成,而 test2 则会在 js 文件下载并执行完之后渲染:



test1
test2

* 第二,文件的下载是不会被阻塞的,不管是 css 还是 js 文件,浏览器的主线程会在页面解析前开启下载,所以就算在外部脚本执行前删除脚本,脚本也还是会下载。




### 6. forEach 中能否使用 await ?



function test() {
let arr = [3, 2, 1];
arr.forEach(async (item) => {
const res = await fetch(item);
console.log(res);
});
console.log(“end”);
}

function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 500 * x);
});
}

test();


上面代码的输出结果是:



end
1
2
3


**为什么**


其实原因很简单,**那就是 forEach 只支持同步代码。**


我们可以参考下 Polyfill 版本的 forEach,简化以后类似就是这样的伪代码



while (index < arr.length) {
callback(item, index) //也就是我们传入的回调函数
}


从上述代码中我们可以发现,forEach 只是简单的执行了下回调函数而已,并不会去处理异步的情况。 并且即使你在 callback 中使用 break 也并不能结束遍历。


**怎么解决**


一般来说解决的办法有2种:


* for…of



//因为 for…of 内部处理的机制和 forEach 不同,forEach 是直接调用回调函数,for…of 是通过迭代器的方式去遍历。
async function test() {
let arr = [3, 2, 1];
for (const item of arr) {
const res = await fetch(item);
console.log(res);
}
console.log(“end”);
}


* for循环



async function test() {
let arr = [3, 2, 1];
for (var i = 0; i < arr.length; i++) {
const res = await fetch(arr[i]);
console.log(res);
}
console.log(“end”);
}

function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 500 * x);
});
}

test();


### 7. 如何中断Promise?


Promise 有个缺点就是一旦创建就无法取消,所以本质上 Promise 是无法被终止的,但我们在开发过程中可能会遇到下面两个需求:


* 中断调用链


就是在某个 then/catch 执行之后,不想让后续的链式调用继续执行了。



somePromise
.then(() => {})
.then(() => {
// 终止 Promise 链,让下面的 then、catch 和 finally 都不执行
})
.then(() => console.log(‘then’))
.catch(() => console.log(‘catch’))
.finally(() => console.log(‘finally’))


一种方法是在then中直接抛错, 这样就不会执行后面的then, 直接跳到catch方法打印err(但此方法并没有实际中断)。但如果链路中对错误进行了捕获,后面的then函数还是会继续执行。


Promise的then方法接收两个参数:



Promise.prototype.then(onFulfilled, onRejected)


若onFulfilled或onRejected是一个函数,当函数返回一个新Promise对象时,原Promise对象的状态将跟新对象保持一致,详见Promises/A+标准。


因此,当新对象保持“pending”状态时,原Promise链将会中止执行。



Promise.resolve().then(() => {
console.log(‘then 1’)
return new Promise(() => {})
}).then(() => {
console.log(‘then 2’)
}).then(() => {
console.log(‘then 3’)
}).catch((err) => {
console.log(err)
})


* 中断Promise


注意这里是中断而不是终止,因为 Promise 无法终止,这个中断的意思是:在合适的时候,把 pending 状态的 promise 给 reject 掉。例如一个常见的应用场景就是希望给网络请求设置超时时间,一旦超时就就中断,我们这里用定时器模拟一个网络请求,随机 3 秒之内返回。



function timeoutWrapper(p, timeout = 2000) {
const wait = new Promise((resolve, reject) => {
setTimeout(() => {
reject(‘请求超时’)
}, timeout)
})
return Promise.race([p, wait])
}


### 8. Object.create 和 new 有什么区别?


js中创建对象的方式一般有两种Object.create和new



const Base = function(){};
const o1 = Object.create(Base);
const o2 = new Base();


在讲述两者区别之前,我们需要知道:


* 构造函数Foo的原型属性Foo.prototype指向了原型对象。
* 原型对象保存着实例共享的方法,有一个指针constructor指回构造函数。
* js中只有函数有 prototype 属性,所有的对象只有 proto 隐式属性。


那这样到底有什么不一样呢?


#### Object.create


先来看看 Object.create 的实现方式



Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};


可以看出来。Object.create是内部定义一个对象,并且让F.prototype对象 赋值为引进的对象/函数 o,并return出一个新的对象。


#### new


再看看 const o2 = new Base() 的时候,new做了什么。



var o1 = new Object();
o1.[[Prototype]] = Base.prototype;
Base.call(o1);


new做法是新建一个obj对象o1,并且让o1的\_\_proto\_\_指向了Base.prototype对象。并且使用 call 进行强转作用环境。从而实现了实例的创建。


区别



//看似是一样的。我们对原来的代码进行改进一下。
var Base = function () {
this.a = 2
}
var o1 = new Base();
var o2 = Object.create(Base);
console.log(o1.a); // 2
console.log(o2.a); // undefined


可以看到Object.create 失去了原来对象的属性的访问。


再进行下改造:



var Base = function () {
this.a = 2
}
Base.prototype.a = 3;
var o1 = new Base();
var o2 = Object.create(Base);
console.log(o1.a); // 2
console.log(o2.a); // undefined


小结  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7f8929349d6044389b169c1a2c683484.png)


### 9. 箭头函数和普通函数有啥区别?箭头函数能当构造函数吗?


什么是箭头函数?  
 ES6中允许使用箭头=>来定义箭头函数,具体语法,我们来看一个简单的例子:



// 箭头函数
let fun = (name) => {
// 函数体
return Hello ${name} !;
};

// 等同于
let fun = function (name) {
// 函数体
return Hello ${name} !;
};


可以看出,定义箭头函在数语法上要比普通函数简洁得多。箭头函数省去了function关键字,采用箭头=>来定义函数。函数的参数放在=>前面的括号中,函数体跟在=>后的花括号中。


#### 箭头函数与普通函数的区别


**1、语法更加简洁、清晰**  
 从上面的基本语法示例中可以看出,箭头函数的定义要比普通函数定义简洁、清晰得多,很快捷。


**2、箭头函数不会创建自己的this**(重要!!深入理解!!)  
 我们先来看看MDN上对箭头函数this的解释。



> 
> 箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this。
> 
> 
> 


箭头函数没有自己的this,它会捕获自己在定义时(注意,是定义时,不是调用时)所处的外层执行环境的this,并继承这个this值。所以,箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不会改变。


**3、箭头函数继承而来的this指向永远不变**(重要!!深入理解!!)  
 上面的例子,就完全可以说明箭头函数继承而来的this指向永远不变。对象obj的方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。


**4、.call()/.apply()/.bind()无法改变箭头函数中this的指向**  
 .call()/.apply()/.bind()方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this的指向,虽然这么做代码不会报错。


**5、箭头函数不能作为构造函数使用**  
 我们先了解一下构造函数的new都做了些什么?简单来说,分为四步:  
 ① JS内部首先会先生成一个对象;  
 ② 再把函数中的this指向该对象;  
 ③ 然后执行构造函数中的语句;  
 ④ 最终返回该对象实例。  
 但是!!因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!


**6、箭头函数没有自己的arguments**  
 箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。


**7、箭头函数没有原型prototype**



let sayHi = () => {
console.log(‘Hello World !’)
};
console.log(sayHi.prototype); // undefined


**8、箭头函数不能用作Generator函数,不能使用yeild关键字**


### 10. async/await 和 Promise 有什么关系?


#### Promise


Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象


#### async/await


es2017的新语法,async/await就是generator + promise的语法糖


async/await 和 Promise 的关系非常的巧妙,await必须在async内使用,并装饰一个Promise对象,async返回的也是一个Promise对象。


async/await中的return/throw会代理自己返回的Promise的resolve/reject,而一个Promise的resolve/reject会使得await得到返回值或抛出异常。


* 如果方法内无await节点


return 一个字面量则会得到一个{PromiseStatus: resolved}的Promise。  
 throw 一个Error则会得到一个{PromiseStatus: rejected}的Promise。


* 如果方法内有await节点


### JavaScript 和 ES6



在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

![JavaScript部分截图](https://i-blog.csdnimg.cn/blog_migrate/9a07268f0d462781925c33d9877b4343.png)


**[如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值