前端基础拾遗90问

本文转载于掘金的一位id为“写代码像蔡徐坤”的作者。链接为:https://juejin.im/post/5e8b261ae51d4546c0382ab4#heading-0

本文将从以下十一个维度为读者总结前端基础知识 

JS基础

  1.   如何在ES5环境下实现let

这个问题实质上是在回答let和var有什么区别,对于这个问题,我们可以直接查看babel转换前后的结果,看一下在循环中通过let定义的变量是如何解决变量提升的问题。

babel在let定义的变量前加了道下划线,避免在块级作用域外访问到该变量,除了对变量名的转换,我们也可以通过自执行函数来模拟块级作用域。

(function(){
  for(var i = 0; i < 5; i ++){
    console.log(i)  // 0 1 2 3 4
  }
})();

console.log(i)      // Uncaught ReferenceError: i is not defined

不过这个问题并没有结束,我们回到var和let/const的区别上:

  • var声明的变量会挂到window上,而let和const不会
  • var声明的变量存在变量提升,而let和const不会
  • let和const声明形成块作用域,只能在块作用域里访问,不能跨块访问,也不能跨函数访问
  • 同一作用域下let和const不能声明同名变量,而var可以
  • 暂时性死区,let和const声明的变量不能在声明前被使用

babel的转化,其实只实现了第2、3、5点。

  1. 2.      如何在ES5环境下实现const

实现const的关键在于Object.defineProperty()这个API,这个API用于在一个对象上增加或修改属性。通过配置属性描述符,可以精确地控制属性行为。Object.defineProperty() 接收三个参数:

 

 

 

对于const不可修改的特性,我们通过设置writable属性来实现

function _const(key, value) {    
    const desc = {        
        value,        
        writable: false    
    }    
    Object.defineProperty(window, key, desc)
}
    
_const('obj', {a: 1})   //定义obj
obj.b = 2               //可以正常给obj的属性赋值
obj = {}                //无法赋值新对象
  1.    手写call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数

语法:function.call(thisArg, arg1, arg2, ...)

call()的原理比较简单,由于函数的this指向它的直接调用者,我们变更调用者即完成this指向的变更:

//变更函数调用者示例
function foo() {
    console.log(this.name)
}

// 测试
const obj = {
    name: '写代码像蔡徐抻'
}
obj.foo = foo   // 变更foo的调用者
obj.foo()       // '写代码像蔡徐抻'

基于以上原理, 我们两句代码就能实现call()

Function.prototype.myCall = function(thisArg, ...args) {
    thisArg.fn = this              // this指向调用call的对象,即我们要改变this指向的函数
    return thisArg.fn(...args)     // 执行函数并return其执行结果
}

但是我们有一些细节需要处理:

Function.prototype.myCall = function(thisArg, ...args) {
    const fn = Symbol('fn')        // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
    thisArg = thisArg || window    // 若没有传入this, 默认绑定window对象
    thisArg[fn] = this              // this指向调用call的对象,即我们要改变this指向的函数
    const result = thisArg[fn](...args)  // 执行当前函数
    delete thisArg[fn]              // 删除我们声明的fn属性
    return result                  // 返回函数执行结果
}

//测试
foo.myCall(obj)     // 输出'写代码像蔡徐抻'

 

posted @ 2020-05-31 21:07  MQK  阅读(232)  评论(0)    收藏  举报