[终极版]Javascript面试全解

this指向

  • 执行上下文 是代码执行时的运行环境
  • 作用域 是变量和函数的可访问性规则(静态);全局、函数和块状;内层可访问外层,外层不能访问内层
  • 词法环境 是实现作用域的引擎内部机制静态

    执行上下文
    ├─ 变量环境 (VariableEnvironment)
    ├─ 词法环境 (LexicalEnvironment) → 作用域链
    └─ this 绑定
  • 执行上下文是代码运行的临时环境,每次函数调用新建。
  • 作用域是变量访问的规则,分全局/函数/块级作用域,内层可访问外层,外层不能访问内层
    • 词法作用域强调作用域在代码书写时确定闭包基于此实现。
  • 区别:作用域是规则,执行上下文是规则运行时的具体实例。
  • 联系: 执行上下文中的​​作用域链​​基于词法作用域构建,逐层向上查找变量
  • 闭包的本质是函数保留了定义时的词法作用域(即使外层函数已销毁)
    new绑定>显式绑定>隐式绑定>默认绑定
javascript 复制代码
function myNew(constructor,...args){
    // 1.创建一个空对象
    // 2. 将这个空对象的原型设置为构造函数的 prototype 属性  
    let obj =obj.create(constructor.Prototype);
    // 3. 将构造函数的 this 绑定到这个新对象,并执行构造函数  
    let result=constructor.apply(obj,args);
    // 4. 如果构造函数返回一个对象,则返回这个对象,否则返回新创建的对象
    return typeof result ===`object`?result:obj;
}

call&apply:判断调用对象是否为函数(this)->判断context是否为对象

bind:判断调用对象是否为函数(this)->定义一个新函数(根据是否使用new关键字调用设置this)->设置函数原型->返回新函数
bind方法不熟

javascript 复制代码
 /* call函数 */
//  参数区别:call 方法接受一个参数列表,而 apply 方法接受一个包含多个参数的数组
//  bind方法返回一个新函数,而 call 和 apply 方法会立即执行函数


/* Function.prototype.myCall = function (context, ...args) {
    // 判断调用对象是否为函数,this!!!
    if (typeof this !== 'function') {
      throw new TypeError('Error');
    }
    // 判断context是否为空
    context = context || window;
    // 判断context是否为对象!!
    if (typeof context !== 'object') {
      context = new Object(context);
    }
    // 将调用函数作为 context 的一个属性
    const fnSymbol = Symbol('fn');
    context[fnSymbol] = this;
    // 调用函数并传入参数
    const result = context[fnSymbol](...args);
    // 删除临时属性
    delete context[fnSymbol];
    // 返回结果
    return result;
  };

  function greet(message) {
    console.log(`${message}, ${this.name}`);
  }
  
  const person = { name: 'John' };
  greet.myCall(person, 'Hello');  
 */



  /* apply函数 */
 Function.prototype.myApply = function (context, args) {
    // 判断调用对象是否为函数,this!!!
    if (typeof this !== 'function') {
      throw new TypeError('Error');
    }
    // 判断context是否为空
    context = context || window;
    // 判断context是否为对象   
    if (typeof context !== 'object') {
      context = new Object(context);
    }
    // 将调用函数作为 context 的一个属性
    const fnSymbol = Symbol('fn');
    context[fnSymbol] = this;
    // 调用函数并传入参数
    const result = context[fnSymbol](...args);
    // 删除临时属性
    delete context[fnSymbol];
    // 返回结果
    return result;
  }


  //bind函数
  Function.prototype.myBind = function (context = window, ...initialArgs) {
    // 检查调用 myBind 的是否为函数
    if (typeof this!== 'function') {
        throw new TypeError('调用 myBind 的对象必须是函数');
    }
    // 保存调用 myBind 的原始函数
    const originalFunction = this;
    // 返回一个新函数
    const boundFunction = function (...newArgs) {
        // 判断是否使用 new 调用
        //当一个函数使用 new 调用时, this 会指向新创建的实例对象,并且这个实例对象会继承自该函数的原型。
        const isUsingNew = this instanceof boundFunction;
        // 合并预设参数和新传入的参数
        const allArgs = [...initialArgs, ...newArgs];
        // 如果是使用 new 调用,this 指向新创建的实例
        const thisValue = isUsingNew? this : context;
        // 调用原始函数
        return originalFunction.apply(thisValue, allArgs);
    };
    // 复制原函数的原型,确保 boundFunction 作为构造函数时,新实例能继承原函数的原型方法
    if (originalFunction.prototype) {
        boundFunction.prototype = Object.create(originalFunction.prototype);
    }
    return boundFunction;
};
//测试bind方法
function greet(message) {
    console.log(`${message}, ${this.name}`);
}

const person = { name: 'John' };
const greetPerson = greet.myBind(person, 'Hello');
greetPerson(); // 输出: Hello, John

// 测试 new 调用
function Person(name) {
    this.name = name;
}
const BoundPerson = Person.myBind(null);
const newPerson = new BoundPerson('Alice');
console.log(newPerson.name); // 输出: Alice
相关推荐
肠胃炎13 分钟前
认识Vue
前端·javascript·vue.js
sunbyte20 分钟前
Three.js + React 实战系列-3D 个人主页 :完成 Navbar 导航栏组件
开发语言·javascript·react.js
爱上大树的小猪26 分钟前
【前端样式】用 aspect-ratio 实现等比容器:视频封面与图片占位的终极解决方案
前端·css·面试
博越26 分钟前
vue实现日历(仿钉钉考勤日历)
前端·javascript
海底火旺27 分钟前
两种思路的碰撞:从超时分层法到高效双指针的蜕变
前端·javascript·算法
江城开朗的豌豆29 分钟前
CSS篇:HTML与XHTML:关键区别与实际应用解析
前端·css·面试
江城开朗的豌豆32 分钟前
Vue + Node.js 实现埋点功能方案
前端·javascript·架构
JustHappy32 分钟前
「软件设计模式杂谈🤔」和后端吵架失败了,于是乎我写了个适配器模式
前端·javascript·设计模式
一只鱼^_1 小时前
第 28 场 蓝桥月赛
开发语言·数据结构·c++·算法·面试·蓝桥杯
多多米10052 小时前
Vue3项目自定义全局防抖节流
前端·javascript·vue.js·typescript