牛客最新前端笔试题解析(一) this指向题目解析及扩展

本文涉及的产品
云解析DNS-重点域名监控,免费拨测 20万次(价值200元)
简介: 牛客最新前端笔试题解析(一) this指向题目解析及扩展

前言


这篇文章主要来解析牛客笔试题部分的 this 指向题目。首先我们先从宏观上了解一下 JavaScript 中得 this 指向问题。


牛客最新前端JS笔试百题


JavaScriptthis 共有四种绑定(包括隐式绑定丢失)加 ES6 新增得箭头函数绑定,如果把这几种绑定全学会了,this 指向完全不成问题。 this 指向更详细的讲解,可以去看前面写过的一篇博文,里面还有 38 道题目,详细完整的讲解了 this 指向问题。


传送门: 《2w字大章 38道面试题》彻底理清JS中this指向问题


  • 默认绑定: 非严格模式下 this 指向全局对象,严格模式下 this 会绑定为 undefined
  • 隐式绑定: 满足 XXX.fn() 格式,fnthis 指向 XXX。如果存在链式调用, this 永远指向最后调用它的那个对象
  • 隐式绑定丢失:起函数别名,通过别名运行;函数作为参数会造成隐式绑定丢失。
  • 显式绑定: 通过 call/apply/bind 修改 this 指向
  • new绑定: 通过 new 来调用构造函数,会生成一个新对象,并且把这个新对象绑定为调用函数的 this
  • 箭头函数绑定: 箭头函数没有 this ,它的 this 是通过作用域链查到外层作用域的 this ,且指向函数定义时的 this 而非执行时


题目一. 隐式绑定与隐式绑定丢失


var x = 1;
var obj = {
    x: 3,
    fun:function () {
        var x = 5;
        return this.x;
    }
};
var fun = obj.fun;
console.log(obj.fun(), fun());
复制代码


解析


JavaScript 对于引用类型,其地址指针存放在栈内存中,真正的本体是存放在堆内存中的。fun = obj.fun 相当于将 obj.fun 指向得堆内存指针赋值给了 fun,此后 fun 执行与 obj 不会有任何关系,发生隐式绑定丢失。


  • obj.fun(): 隐式绑定,fun 里面的 this 指向 obj,打印 3
  • fun(): 隐式绑定丢失: fun 默认绑定,非严格模式下,this 指向 window,打印 1


答案


3 1
复制代码


题目二: 隐式绑定丢失


var person = {
  age: 18,
  getAge: function() {
    return this.age;
  }
};
var getAge = person.getAge
console.log(getAge())
复制代码


简单的隐式绑定丢失问题


答案


undefined
复制代码


题目三: 隐式绑定丢失


var obj = {
    name:"zhangsan",
    sayName:function(){
        console.log(this.name);
    }
}
var wfunc = obj.sayName;
obj.sayName();
wfunc();
var name = "lisi";
obj.sayName();
wfunc();
复制代码


简单的隐式绑定问题,不多做赘述了。


答案


zhangsan
undefined
zhangsan
lisi
复制代码


题目四:new绑定


var a = 5;
function test() { 
    a = 0; 
    console.log(a); 
    console.log(this.a); 
    var a;
    console.log(a); 
}
new test();
复制代码


解析


使用new来构建函数,会执行如下四部操作:


  1. 创建一个空的简单JavaScript对象(即{});
  2. 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this


通过 new 来调用构造函数,会生成一个新对象,并且把这个新对象绑定为调用函数的 this


  • console.log(a): 打印变量 a 的值,当前 testAO 中存在 a 变量,打印 0
  • console.log(this.a): new 绑定 this 指向新的实例对象,当前题目没有给实例对象添加 a 属性,打印 undefined
  • console.log(a): 同第一个,打印 0


答案


0
undefined
0
复制代码


题目五:箭头函数与显式绑定


function fun () {
    return () => {
        return () => {
            return () => {
                console.log(this.name)
            }
        }
    }
}
var f = fun.call({name: 'foo'})
var t1 = f.call({name: 'bar'})()()
var t2 = f().call({name: 'baz'})()
var t3 = f()().call({name: 'qux'})
复制代码


  1. 箭头函数没有 this ,它的 this 是通过作用域链查到外层作用域的 this ,且指向函数定义时的 this 而非执行时。
  2. 箭头函数,不能通过 call\apply\bind 来修改 this 指向,但可以通过修改外层作用域的 this 来达成间接修改。
  3. JavaScript 是静态作用域,即函数的作用域在函数定义的时候就决定了,而箭头函数的 this 是通过作用域链查到的,因此箭头函数定义后,它的作用域链就定死了。


  • f = fun.call({name: 'foo'}): 将 fun 函数的 this 指向 {name: 'foo'},并返回一个箭头函数,因此箭头函数的 this 也指向 {name: 'foo'}
  • t1 = f.call({name: 'bar'})()(): 对第一层箭头函数执行 call 操作,无效,当前 this 仍指向 {name: 'foo'},第二层、第三层都是箭头函数,第三层的 this 也指向 {name: 'foo'},打印 foo
  • 后续 t2 t3 分别对第二层、第三层箭头函数使用 call ,无效,最终都打印 foo


答案


foo
foo
foo
复制代码


题目六:箭头函数


let obj1 = {
    a: 1,
    foo: () => {
        console.log(this.a)
    }
}
// log1
console.log(obj1.foo())
const obj2 = obj1.foo
// log2
console.log(obj2())
复制代码


解析


  1. obj1.foo 为箭头函数,obj1 为对象,无法提供外层作用域,因此 obj.foo 里面的 this 指向 window


  • obj1.foo(): 箭头函数,this 指向 window,打印 undefined
  • obj2 隐式绑定丢失: 打印 undefined


答案


undefined
undefined
复制代码


题目七: 综合题(推荐看)


var name = 'global';
var obj = {
    name: 'local',
    foo: function(){
        this.name = 'foo';
        console.log(this.name);
    }.bind(window)
};
var bar = new obj.foo();
setTimeout(function() {
    console.log(window.name);
}, 0);
console.log(bar.name);
var bar3 = bar2 = bar;
bar2.name = 'foo2';
console.log(bar3.name);
复制代码


解析


这个题的整体出题质量还是挺高的,首先咱们来把涉及到的知识罗列一下:


  1. bind 是显式绑定,会修改 this 指向,但 bind() 函数不会立即执行函数,会返回一个新函数
  2. setTimeout 是异步任务,同步任务执行完毕后才会执行异步任务
  3. 绑定优先级: new绑定 > 显式绑定 > 隐式绑定 > 默认绑定


解析


  • obj.foo 将它的 this 通过 bind 显式的绑定为 window,但 bind 不会立即执行
  • var bar = new obj.foo(): new 绑定优先级大于 bind ,因此 bind 失效了,此时 this 指向 new 实例,因此 obj.foo 内部的 console 打印 foo
  • barnew obj.foo() 的实例,console.log(bar.name) 打印 foo
  • setTimeout 异步任务,等到同步执行完毕再来调用它的回调
  • bar3 = bar2 = bar,将 bar2,bar3,bar 的地址都指向 bar 所指向的空间。
  • bar2.name = 'foo2',修改地址指向堆内存的值
  • console.log(bar3.name): 由于三个变量指向同一块地址,bar3 修改了 namebar3 也随之改变,打印 foo2
  • setTimeout 的回调执行,打印 global


答案


foo
foo
foo2
global
复制代码


题目八: 综合题目七修改


题目六虽然出的很有质量,但是我感觉有几个地方考察的让人不满足,咱们来改一下题目。


改法一: 去除 new 绑定


var name = 'global';
var obj = {
    name: 'local',
    foo: function(){
        this.name = 'foo';
        console.log(this.name);
    }.bind(window)
};
obj.foo();
setTimeout(function() {
    console.log(this.name);
}, 0);
console.log(name);
复制代码


  • obj.foo 没有做修改,它的 this 通过 bind 显式的绑定为 window,但 bind 不会立即执行
  • obj.foo() 执行,显式绑定优先级大于隐式绑定,因此此时 foo 函数 this -> window
  • this.name 相当于 window.name,修改了全局的 name 变量值,打印 foo
  • setTimeout 回调等同步代码执行完毕
  • 全局的 name 已经修改为 foo ,打印 foo
  • 执行 setTimeout 的回调,默认绑定,打印 foo


答案


foo
foo
foo
复制代码


改法一: 修改 bind 为 call


var name = 'global';
var obj = {
    name: 'local',
    foo: function(){
        this.name = 'foo';
        console.log(this.name);
    }
};
obj.foo.call(window);
var bar = new obj.foo();
setTimeout(function() {
    console.log(window.name);
}, 0);
console.log(bar.name);
var bar3 = bar2 = bar;
bar2.name = 'foo2';
console.log(bar3.name);
复制代码


callbind 的区别就在于 call 函数会立即执行


因此 obj.foo.call(window) 会立即执行函数,同时也修改了全局的 name 值。其他部分与上面所讲类似,不多做赘述了。


答案


foo
foo
foo
foo2
foo
复制代码


往期精彩文章




相关文章
|
存储 前端开发 安全
前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
本文全面解析前端三种数据存储方式:Cookie、LocalStorage与SessionStorage。涵盖其定义、使用方法、生命周期、优缺点及典型应用场景,帮助开发者根据登录状态、用户偏好、会话控制等需求,选择合适的存储方案,提升Web应用的性能与安全性。(238字)
508 0
|
6月前
|
Web App开发 前端开发 JavaScript
前端性能优化利器:图片懒加载实战解析
前端性能优化利器:图片懒加载实战解析
|
5月前
|
人工智能 JSON 前端开发
如何解决后端Agent和前端UI之间的交互问题?——解析AG-UI协议的神奇作用
三桥君指出AG-UI协议通过SSE技术实现智能体与前端UI的标准化交互,解决流式传输、实时进度显示、数据同步等开发痛点。其核心功能包括结构化事件流、多Agent任务交接和用户中断处理,具有"一次开发到处兼容"、"UI灵活可扩展"等优势。智能体专家三桥君认为协议将AI应用从聊天工具升级为实用软件,适用于代码生成、多步骤工作流等场景,显著提升开发效率和用户体验。
1111 0
|
7月前
|
存储 前端开发 JavaScript
|
8月前
|
存储 前端开发 JavaScript
调用DeepSeek API增强版纯前端实现方案,支持文件上传和内容解析功能
本方案基于DeepSeek API增强版,提供纯前端实现的文件上传与内容解析功能。通过HTML和JavaScript,用户可选择文件并调用API完成上传及解析操作。方案支持多种文件格式(如PDF、TXT、DOCX),具备简化架构、提高响应速度和增强安全性等优势。示例代码展示了文件上传、内容解析及结果展示的完整流程,适合快速构建高效Web应用。开发者可根据需求扩展功能,满足多样化场景要求。
2573 64
|
6月前
|
JSON 前端开发 安全
前端开发中常用的鉴权方式解析与实践要点
本文深入探讨了前端开发中常用的鉴权方式,包括HTTP基本鉴权、Session-Cookie鉴权、Token验证、JWT(JSON Web Tokens)、单点登录(SSO)和OAuth等。文章首先明确了认证、授权、鉴权和权限控制的概念及关系,随后详细解析每种鉴权方式的工作原理、优缺点及适用场景。例如,HTTP基本鉴权简单但安全性低,适合内部网络;Session-Cookie鉴权易受CSRF攻击,适用于同域Web应用;Token和JWT无状态且扩展性好,适合分布式系统;SSO提升用户体验,适用于多系统统一登录;OAuth安全方便,适合第三方授权接入。
428 2
|
12月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
12月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
12月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
机器学习/深度学习 编解码 前端开发
探索无界:前端开发中的响应式设计深度解析####
【10月更文挑战第29天】 在当今数字化时代,用户体验的优化已成为网站与应用成功的关键。本文旨在深入探讨响应式设计的核心理念、技术实现及最佳实践,揭示其如何颠覆传统布局限制,实现跨设备无缝对接,从而提升用户满意度和访问量。通过剖析响应式设计的精髓,我们将一同见证其在现代Web开发中的重要地位与未来趋势。 ####
241 7

热门文章

最新文章

  • 1
    前端工程化演进之路:从手工作坊到AI驱动的智能化开发
  • 2
    Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
  • 3
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
  • 推荐镜像

    更多
  • DNS