前端面试项目总结+this指向总结

文章目录

  • 做过的工作
    • 项目重点:
    • 项目分工:
    • 框架选型:
    • 以multipart/form-data形式post上传文件及其相关参数
    • 大文件上传是如何实现的 - 非全详细的博文
      • Blob.prototype.slice实现切片
      • 分片上传流程总结
      • 问题-多个服务器扩容保证服务端的文件存储如何保证可控
    • 文件上传总结
    • websocket上传文件(补充,非项目应用)
    • websocket连接在项目中的使用+Echarts动态折线图
      • 项目中使用的http1.1 和 websocket
      • websocket和http2.0的服务器推送的对比分析
        • http/2, SSE服务器推送(Server-sent Events)
    • MongoDB和mysql的区别
      • MySQL是关系型数据库。
      • Mongodb是非关系型数据库(nosql), 属于文档型数据库。
      • Mysql和Mongodb主要应用场景
    • python的flask框架
    • 对前端实习的要求
  • vue/js相关问题
    • vue的优点
    • vue2如何实现数据双向绑定
      • 1. Object.defineProperty()
      • 2. Vue 不能检测数组和对象的变化
      • 3. 声明响应式property
      • 4. 异步更新队列
    • vue3如何实现数据绑定- proxy代理
    • vue虚拟dom, diff算法-比较那些部分找出差异
    • vue循环中的key的作用, 与index对比
    • js判断变量的数据类型
      • 1.typeof
      • 2.instanceof
      • 3.constructor
      • 4.toString 即Object.prototype.toString.call
    • 箭头函数和普通函数的区别
    • callback,promise,async&await三者的区别?
    • promise.all() 同时发两个请求, promise.race()两个请求中有一个就可以回复
    • 跨域请求
  • this的指向
    • this在全局作用域中
    • this在函数function中
    • this在构造函数中
    • this在事件处理器(event handler)中的指向

做过的工作

前端面试项目总结+this指向总结_第1张图片

2020.01-2020.12 AIZOO 可视化机器学习平台
项目介绍:实现用户自定义上传算法模型和数据资源,通过可视化界面拖拽组件构建模型,提交任务,使用 slurm 集群管理自动部署模型训练,查看训练结果以及分析图表等的一站式机器学习平台。
负责内容:
(1) 前端开发:采用 Vue 框架+iview 组件库,基于 WebSocket 即时通讯和 Echarts 图表库绘制动态折线图,通过 API 接口与 Java 后台交互。
(2) 可视化构建模型:使用 svg 绘图和 Cytoscape.js 图库, 通过拖拽(H5的原生拖拽事件)组件构建模型图。

项目重点:

  1. 大文件的分块上传
  2. websocket实现即时通讯, 通过Echarts动态折线展示模型运行过程中的gpu/cpu利用率等数据
  3. Cytoscape.js图库拖拽实现模型绘制, 实现节点上的端点连线并提示用户是否可以连接; canvas图片导出, 自己绘制svg图标
    画图库从jsplumb.js转换为Cytoscape.js, 因为jsplumb.js节点和端点是自己标注的不能区分, 界面不稳定.
  4. 前端通过api-blueprint模拟接口,前后端分离开发

项目分工:

前端主要是两个人, 后台有三个同学, 有两个负责java开发, 一个负责slurm集群管理

框架选型:

vue + Cytoscape.js

以multipart/form-data形式post上传文件及其相关参数

什么是multipart/form-data请求–https://www.cnblogs.com/tylerdonet/p/5722858.html
前端面试项目总结+this指向总结_第2张图片
项目中使用截图:
前端面试项目总结+this指向总结_第3张图片
前端面试项目总结+this指向总结_第4张图片

前端面试项目总结+this指向总结_第5张图片
前端面试项目总结+this指向总结_第6张图片

大文件上传是如何实现的 - 非全详细的博文

Blob.prototype.slice实现切片

  • 前端
    前端大文件上传核心是利用 Blob.prototype.slice 方法,和数组的 slice 方法相似,调用的 slice 方法可以返回原文件的某个切片, 这样就可以根据预先设置好的切片最大数量将文件切分为一个个切片,然后借助 http 的可并发性,同时上传多个切片,这样从原本传一个大文件,变成了同时传多个小的文件切片,可以大大减少上传时间.
    另外由于是并发,传输到服务端的顺序可能会发生变化,所以我们还需要给每个切片记录顺序, 每次传参包括当前分片计数chunkNumber, 分片大小chunkSize, 总分片数chunkTotalNumbers以及分片文件等.
  • 服务端
    服务端需要负责接受这些切片,并在接收到所有切片后合并切片
    这里又引伸出两个问题
    • 何时合并切片,即切片什么时候传输完成
      第一个问题需要前端进行配合,前端在每个切片中都携带切片最大数量的信息,当服务端接受到这个数量的切片时自动合并,也可以额外发一个请求主动通知服务端进行切片的合并
    • 如何合并切片
      第二个问题,具体如何合并切片呢?这里可以使用 nodejs 的 读写流(readStream/writeStream),将所有切片的流传输到最终文件的流里

分片上传流程总结

  • 大文件上传

    • 前端上传大文件时使用 Blob.prototype.slice 将文件切片,并发上传多个切片,最后发送一个合并的请求通知服务端合并切片
    • 服务端接收切片并存储,收到合并请求后使用流将切片合并到最终文件
    • 原生 XMLHttpRequest 的 upload.onprogress 对切片上传进度的监听
    • 使用 Vue 计算属性根据每个切片的进度算出整个文件的上传进度
  • 断点续传

    • 使用 spark-md5 根据文件内容算出文件 hash
    • 通过 hash 可以判断服务端是否已经上传该文件,从而直接提示用户上传成功(秒传)
    • 通过 XMLHttpRequest 的 abort 方法暂停切片的上传
    • 上传前服务端返回已经上传的切片名,前端跳过这些切片的上传

目前项目里的服务器合并文件是先建立一个临时目录存放上传的分片文件, 上传完成以后合并merge,再挪到项目存放路径下.

问题-多个服务器扩容保证服务端的文件存储如何保证可控

分片的临时文件存在服务器上, 最后合并请求以后挪到项目存放路径下.若用户量巨大, 服务器单点无法完成任务,需要扩容到多台服务器.
每个人访问服务器可以路由到不同服务器上, 分片成200个文件可能50个文件在服务器1上, 150个文件在服务器2上.

解决方案(蚂蚁二面面试官的解决方案):
1- 阿里云(爱sei爱思?)/亚马逊(s3?)等有一些专门做存储的云服务, 可以直接把文件存到云服务上面, 这样无论应用层扩展到多少层, 这样存储永远都是分布式的云存储, 就可以借用这种已经存在的标准的服务和接口来实现.
2- 通过一些方式把用户路由到一台服务器上, 确保用户所有的临时文件都存在一个服务器上,需要保证这一个用户同一时刻只在一个服务节点上. 但这种方案会把整个应用集群从无状态变成有状态,需要去感知当前我服务的是哪些用户以及用户在哪些机器上, 这样会导致比较高的复杂度.

前端面试项目总结+this指向总结_第7张图片

实现一个大文件上传和断点续传- https://juejin.cn/post/6844904046436843527

针对上一个链接的扩展-https://juejin.cn/post/6844904055819468808#heading-8

大文件上传项目github地址-https://github.com/yeyan1996/file-upload
前端面试项目总结+this指向总结_第8张图片

前端面试项目总结+this指向总结_第9张图片

文件上传总结

各种文件上传攻略,从小图片到大文件断点续传-https://juejin.cn/post/6844903968338870285

websocket上传文件(补充,非项目应用)

使用Html5的WebSocket在浏览器上传文件
文件上传的步骤: 打开websocket–连接websocket服务器–在浏览器里选择文件–将文件读入到内存中(以arraybuffer的形式)–在socket里发送文件–完毕!

服务器端:

配置好websocket的服务器, 使用一个java的开源websocket服务器: Java-WebSocket
根据该项目的快速教程可以建立一个websocket服务器, 就是里面的一个ChatServer.java文件. 一个聊天室服务器.

客户端(html): 先建立websocket连接, 然后使用new FileReader()通过readAsArrayBuffer以二进制形式读取文件
前端面试项目总结+this指向总结_第10张图片

websocket连接在项目中的使用+Echarts动态折线图

项目中使用的http1.1 和 websocket

很好的参考链接websocket+HTTP2+grpc解析-https://ryan4yin.space/posts/websocket-http2-and-grpc/
前端面试项目总结+this指向总结_第11张图片

// WebSocket API
var socket = new WebSocket('ws://websocket.example.com');

// Show a connected message when the WebSocket is opened.
socket.onopen = function(event) {
     
  console.log('WebSocket is connected.');
};

// Handle messages sent by the server.
socket.onmessage = function(event) {
     
  var message = event.data;
  console.log(message);
};

// Handle any error that occurs.
socket.onerror = function(error) {
     
  console.log('WebSocket Error: ' + error);
};

前端面试项目总结+this指向总结_第12张图片
前端面试项目总结+this指向总结_第13张图片
前端面试项目总结+this指向总结_第14张图片

前端面试项目总结+this指向总结_第15张图片
前端面试项目总结+this指向总结_第16张图片
前端面试项目总结+this指向总结_第17张图片

websocket和http2.0的服务器推送的对比分析

http/2, SSE服务器推送(Server-sent Events)

https://www.haorooms.com/post/long_lianjie_websocket
https://www.cnblogs.com/goody9807/p/4257192.html
https://www.cnblogs.com/goloving/p/9196066.html
https://my.oschina.net/u/4581713/blog/4594420
前端面试项目总结+this指向总结_第18张图片
在这里插入图片描述
前端面试项目总结+this指向总结_第19张图片
前端面试项目总结+this指向总结_第20张图片

MongoDB和mysql的区别

前端面试项目总结+this指向总结_第21张图片
前端面试项目总结+this指向总结_第22张图片
前端面试项目总结+this指向总结_第23张图片
前端面试项目总结+this指向总结_第24张图片

前端面试项目总结+this指向总结_第25张图片
前端面试项目总结+this指向总结_第26张图片
前端面试项目总结+this指向总结_第27张图片

MySQL是关系型数据库。

优势:

在不同的引擎上有不同的存储方式。

查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。

开源数据库的份额在不断增加,mysql的份额页在持续增长。

缺点:

在海量数据处理的时候效率会显著变慢。

Mongodb是非关系型数据库(nosql), 属于文档型数据库。

文档是mongoDB中数据的基本单元,类似关系数据库的行,多个键值对有序地放置在一起便是文档,语法有点类似javascript面向对象的查询语言,它是一个面向集合的,模式自由的文档型数据库。

存储方式:虚拟内存+持久化。

查询语句:是独特的Mongodb的查询方式。

适合场景:事件的记录,内容管理或者博客平台等等。

架构特点:可以通过副本集,以及分片来实现高可用。

数据处理:数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。

成熟度与广泛度:新兴数据库,成熟度较低,Nosql数据库中最为接近关系型数据库,比较完善的DB之一,适用人群不断在增长。

优点:

快速!在适量级的内存的Mongodb的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。高扩展性,存储的数据格式是json格式!

缺点:

不支持事务,而且开发文档不是很完全,完善。

Mysql和Mongodb主要应用场景

1.如果需要将mongodb作为后端db来代替mysql使用,即这里mysql与mongodb 属于平行级别,那么,这样的使用可能有以下几种情况的考量:
(1)mongodb所负责部分以文档形式存储,能够有较好的代码亲和性,json格式的直接写入方便。(如日志之类)
(2)从datamodels设计阶段就将原子性考虑于其中,无需事务之类的辅助。开发用如nodejs之类的语言来进行开发,对开发比较方便。
(3)mongodb本身的failover机制,无需使用如MHA之类的方式实现。

2.将mongodb作为类似redis ,memcache来做缓存db,为mysql提供服务,或是后端日志收集分析。 考虑到mongodb属于nosql型数据库,sql语句与数据结构不如mysql那么亲和 ,也会有很多时候将mongodb做为辅助mysql而使用的类redis memcache 之类的缓存db来使用。 亦或是仅作日志收集分析。

python的flask框架

博客园-https://www.cnblogs.com/sss4/p/8097653.html
海信空调报障系统采用了python-Flask 框架,使用 SQLAlchemy + Flask-SQLAlchemy 来控制数据库。

Python主流WEB框架对比

  • Django:1个重武器,包含了web开发中常用的功能、组件的框架;(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType…);
  • Tornado:2大特性就是异步非阻塞、原生支持WebSocket协议;
  • Flask:封装功能不及Django完善,性能不及Tornado,但是Flask可扩展性强,因为flask的第三方开源组件丰富;
  • Bottle:比较简单;
  • 总结:
    小型web应用设计的功能点不多使用Flask;
    大型web应用设计的功能点比较多使用的组件也会比较多,使用Django(自带功能多不用去找插件); 如果追求性能可以考虑Tornado;
    前端面试项目总结+this指向总结_第28张图片

flask框架简单使用

from flask import Flask

app=Flask(__name__) #创建1个Flask实例

@app.route('/')      #路由系统生成 视图对应url,1. decorator=app.route() 2. decorator(first_flask)
def first_flask():    #视图函数
    return 'Hello World'  #response


if __name__ == '__main__':
    app.run()              #启动socket

对前端实习的要求

先问在项目里遇到的问题你是怎么解决的, 有什么方法, 比较方法的不同, 技术选型对比, 优缺点, 选择最适合的方法, 没有最好的方法只有最合适的方法, 了解差异以后才能更好的进行技术选型.
看解决问题时的思考和总结.

vue/js相关问题

vue的优点

在开发方面的优势
与jquery对比:
jQuery是MVC模式即model,view,control,vue是MVVM模式,即model, view, ViewModel,
前端面试项目总结+this指向总结_第29张图片
前端面试项目总结+this指向总结_第30张图片

在性能方面的优势
数据驱动, 不会影响渲染, 整体更加流程
虚拟dom节点, 可以追踪依赖关系

vue2如何实现数据双向绑定

vue源文档的解释
https://cn.vuejs.org/v2/guide/reactivity.html

1. Object.defineProperty()

vue.js 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
前端面试项目总结+this指向总结_第31张图片

2. Vue 不能检测数组和对象的变化

前端面试项目总结+this指向总结_第32张图片
前端面试项目总结+this指向总结_第33张图片

3. 声明响应式property

前端面试项目总结+this指向总结_第34张图片

4. 异步更新队列

前端面试项目总结+this指向总结_第35张图片
前端面试项目总结+this指向总结_第36张图片

vue3如何实现数据绑定- proxy代理

https://www.cnblogs.com/mlw1814011067/p/11283528.html
前端面试项目总结+this指向总结_第37张图片
Proxy是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。 Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。

vue虚拟dom, diff算法-比较那些部分找出差异

https://www.cnblogs.com/gxp69/p/11325381.html

https://www.cnblogs.com/fs0196/p/12416187.html
前端面试项目总结+this指向总结_第38张图片
前端面试项目总结+this指向总结_第39张图片
前端面试项目总结+this指向总结_第40张图片

前端面试项目总结+this指向总结_第41张图片

https://www.cnblogs.com/wind-lanyan/p/9061684.html

vue循环中的key的作用, 与index对比

作用:用唯一标识标记每一个节点,可以高效渲染虚拟DOM树, 默认用“就地复用”策略,方便了diff算法更高效的比对dom元素

使用v-for更新已渲染的元素列表时,默认用就地复用策略;列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素.

为什么设置key值

Vue 和 React 都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面, 其原理是Diff算法, 总体来说是指只会同级比较,不会跨级比较。

Vue 和 React 的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设:
1.两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
2.同一层级的一组节点,他们可以通过唯一的id进行区分。

基于以上这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)。

用一张图简单说明一下:

在这里插入图片描述

当页面的数据发生变化时,Diff算法只会比较同一层级的节点:

如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点。

如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
前端面试项目总结+this指向总结_第42张图片

举例:
前端面试项目总结+this指向总结_第43张图片

如上图:在同级A,B,C,D四个节点中,在B和C之间插入E,没有key的时候:C更新成了E,D更新成了C,最后插入D,这样效率很低。
加上key之后,就能准确的找到节点的位置:发现ABCD都没变化,直接插入E就可以了。
所以key的作用主要是为了唯一标识每个节点, 以能够高效的更新虚拟DOM

为什么不能用index作为key
例如一组数:

list:[
	{
     
		id: 1,
		name: 'a',
		//index: 0
	},
	{
     
		id: 2,
		name: 'b',
		//index: 1
	},
	{
     
		id: 3,
		name: 'c',
		//index: 2
	},
	{
     
		id: 4,
		name: 'd',
		//index: 3
	},
]

这样的页面显示的是:a,b,c,d(默认选中c)
如果key绑定的是index, 删掉index=1的第二组数(b),除了b之外,c和d的index变化了(c变为1了,d的变为2了),所以c和d也都要重新渲染一遍,影响了性能。
刚开始默认选中c(index原来为2),删除b后,d的index变为2了,这时候页面上默认就选中d了,这就产生了bug
前端面试项目总结+this指向总结_第44张图片

js判断变量的数据类型

掘金-instanceOf 和 typeof的原理

js判断变量的数据类型
前端面试项目总结+this指向总结_第45张图片

1.typeof

typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:number、boolean、symbol、string、object、undefined、function
前端面试项目总结+this指向总结_第46张图片
前端面试项目总结+this指向总结_第47张图片

2.instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 instanceof 检测的是原型。
instanceof 主要的作用就是判断一个实例是否属于某种类型

let person = function () {
     
}
let nicole = new person()
nicole instanceof person // true

instanceof 也可以判断一个实例是否是其父类型或者祖先类型的实例。

let person = function () {
     
}
let programmer = function () {
     
}
programmer.prototype = new person()
let nicole = new programmer()
nicole instanceof person // true
nicole instanceof programmer // true

3.constructor

当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。

4.toString 即Object.prototype.toString.call

比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call 方法

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

Object.prototype.toString.call(1) // "[object Number]"

Object.prototype.toString.call('hi') // "[object String]"

Object.prototype.toString.call({
     a:'hi'}) // "[object Object]"

Object.prototype.toString.call([1,'a']) // "[object Array]"

Object.prototype.toString.call(true) // "[object Boolean]"

Object.prototype.toString.call(() => {
     }) // "[object Function]"

Object.prototype.toString.call(null) // "[object Null]"

Object.prototype.toString.call(undefined) // "[object Undefined]"

Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

箭头函数和普通函数的区别

前端面试项目总结+this指向总结_第48张图片

callback,promise,async&await三者的区别?

1.callback 经过深层次的嵌套,会产生回调地狱,需手动检查err参数。
2.promise 通过链式调用,直接在 then 中返回一个 promise 来进行成功之后的回调函数,用 catch 来做错误处理。
3.async/await 是基于Promise实现的,它不能用于普通的回调函数,直接将其变成了同步的写法,使得异步代码看起来像同步代码,既可以用.catch又可以用try-catch捕捉,简洁,可读性强,写法更加优雅 。

原文链接:https://blog.csdn.net/m0_48076809/article/details/106439990
掘金文章-浅谈Promise与async/await的区别

promise.all() 同时发两个请求, promise.race()两个请求中有一个就可以回复

跨域请求

跨域请求

8种跨域解决方法
项目中用过websocket
前端面试项目总结+this指向总结_第49张图片

this的指向

var obj = {
     
  fn: function () {
     
    console.log(this) // obj, function定义的函数, this指向调用环境
    // obj.fn()返回了一个箭头函数, 所以下面调用时是obj.fn()()
    return () => {
     
      console.log(this); // obj, 箭头函数中的this,指向定义箭头函数时的环境
      (function () {
      console.log(this) })() // windows, 立即调用函数
      setTimeout(function () {
      console.log(this) }, 1) // windows
    }
  }
}
obj.fn()()

前端面试项目总结+this指向总结_第50张图片
前端面试项目总结+this指向总结_第51张图片
前端面试项目总结+this指向总结_第52张图片
参考有道云笔记-this指向

Whenever a function is called, we must look at the immediate left side of the brackets / parentheses “()”. If on the left side of the parentheses we can see a reference, then the value of “this” passed to the function call is exactly of which that object belongs to, otherwise it is the global object.

每当函数被调用时,我们必须查看方括号/圆括号()的左侧。
如果在括号左侧可以看到一个引用,那么传递给函数调用的this的值就是该对象所属的值,否则它就是全局对象。

对于函数中的this,通过查看()左边所属的对象去确定,真的很好用。

而实质上,this是在创建函数的执行环境时,在创建阶段确定的,因此,弄透执行环境,去思考执行环境创建阶段的this的指向,this的指向就不会弄错了吧。

this在全局作用域中

在全局作用域/全局环境(global scope| global context)中,this指向的就是全局变量

在浏览器里,指向window对象
Node.js里,指向global对象
前端面试项目总结+this指向总结_第53张图片

this在函数function中

1.例一
前端面试项目总结+this指向总结_第54张图片
在任何函数中,this的指向都不是静态的(static)。它总是在你调用一个函数,但尚未执行函数内部代码前被指定。(查看参考链接中的执行环境的文章,这个阶段,实际就是初始化变量对象,在初始化变量对象的时候,确定了this的指向)
实际上,this是 被调用的函数的父作用域 提供的,更重要的是,我们要看看函数调用时是怎么写的。

当一个函数被调用时,应该立马看函数名()左边的部分。
如果()左边是一个引用(reference),那么,函数的this指向的就是这个引用所属的对象,否则this指向的就是全局对象(window|global)

2.例二

function bar() {
     
    console.log(this);
}
bar(); // windows- because the method bar() belongs to the windows object when invoked
// 这里,this指向的是全局对象。我们先看()的左边,是bar, bar属于全局对象,所以this指向的就是全局对象。

var foo = {
     
    baz: function() {
     
        console.log(this);
    }
}
foo.baz(); // foo - because the method baz() belongs to the object foo when invoked
// 这里,this指向的是foo,先看()左边是baz,baz属于foo,所以baz里的this指向的就是foo

前端面试项目总结+this指向总结_第55张图片
3.例三
前端面试项目总结+this指向总结_第56张图片
4.例四

var anum = 0;

var foo = {
     
    anum: 10,
    baz: {
     
        anum: 20,
        bar: function() {
     
        	console.log(this)
            console.log(this.anum);
        }
    }
}
foo.baz.bar(); // 20 - because left side of () is bar, which belongs to baz object when invoked
// ()左边是bar,bar属于foo.baz,所以this就是foo.baz,因此this.anum = foo.baz.anum = 20

var hello = foo.baz.bar;
hello(); // 0 - because left side of () is hello, which belongs to global object when invoked
// ()左边是hello,hello属于全局对象,所以this指向全局对象,this.anum = window.anum = 0

前端面试项目总结+this指向总结_第57张图片
5.例五
内部匿名函数无法直接访问外部函数的thisarguments, 在非严格模式下内部匿名函数的this指向Window, 严格模式下指向undefined.

const obj = {
     
  name: 'spike',
  friends: ['deer', 'cat'],
  loop: function() {
     
    console.log(this); // 这个this指向obj
    this.friends.forEach(
      function( friend ) {
      // 这个this指向Window
        console.log(this);
        console.log(`${
       this.name} knows ${
       friend}`);
      }
    )
  }
}

obj.loop();
// ()左边是loop,属于obj,所以loop函数中的this指向obj

前端面试项目总结+this指向总结_第58张图片

this在构造函数中

当使用new关键字去执行构造函数时,构造函数中的this指向的的就是新建的那个对象实例。

var savedThis;
function Constr() {
     
	// 保存构造函数中的this
	savedThis = this;
}
// 通过new关键字执行构造函数
var inst = new Constr();
    
// 构造函数中的this指向的就是新创建的对象实例inst
console.log(savedThis === inst); // true

如果没有用new关键字去执行构造函数,那么就要分析函数被调用时所属的作用域了

function Point(x, y) {
     
	this.x = x;
    this.y = y;
}
var p = Point(7, 5); // 没有用new关键字去执行构造函数!
    
console.log(p === undefined); // 没有用new,所以构造函数没有返回一个实例对象, 所以p === undefined
    
// 没有用new关键字,Point(7,5);就只是把函数执行了一遍
// ()左边是Point,属于全局对象,所以this指向全局对象
console.log(x); // 7
console.log(y); // 5

this在事件处理器(event handler)中的指向

<div id="test">I am an element with id #test</div>

function doAlert() {
      
    alert(this.innerHTML); 
} 

doAlert(); // undefined 
// doAlert()属于全局对象

var myElem = document.getElementById('test'); 
myElem.onclick = doAlert; 

alert(myElem.onclick === doAlert); // true 
myElem.onclick(); // I am an element
// ()左边是onclick也就是doAlert,属于myElem,所以this指向myElem

哪个元素触发事件,this就指向那个元素

你可能感兴趣的:(前端实习)