前端面试概念收集器

前端面试概念收集器

前端面试三部曲

本文分为 概念原生Javascriptcss知识点http协议网络安全性能优化

概念

Commonjs 在Nodejs服务端上运行,无法在浏览器端运行。为了满足浏览器端模块化的要求,才有了AMD和CMD。

AMD (Asynchronous Module Definition)是 RequireJS 在推广过程中对模块定义的规范化产出。对于依赖的模块,AMD 是提前执行。AMD 推崇依赖前置,把依赖参数以数组形式保存在前半部分。使用规则如下:

define(id?, dependencies?, factory);

CMD (Common Module Definition)是 Seajs 在推广过程中对模块定义的规范化产出。 CMD 是延迟执行,CMD 推崇依赖就近,使用规则如下:

define(function(require, exports, module) {
  // 模块代码
});

Require.jsSea.js都是模块加载器,两者的主要区别如下:

  • 定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。
  • 遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
  • 推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。Sea.js 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
  • 对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。RequireJS 无这方面的明显支持。
  • 插件机制不同。RequireJS 采取的是在源码中预留接口的形式,插件类型比较单一。Sea.js 采取的是通用事件机制,插件类型更丰富。
    来自CMD 模块定义规范

UMD (Universal Module Definition),AMD,CommonJS规范是两种不一致的规范,虽然他们应用的场景也不太一致,但是人们仍然是期望有一种统一的规范来支持这两种规范,对两种情况进行判断,兼容两个规范。

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
    //    methods
    function myFunc(){};

    //    exposed public method
    return myFunc;
}));

原生Javascript

在做项目或者产品的过程当中,可能你对框架和库的使用非常多,往往忽视了基础知识。当然,大公司不仅仅希望你是一个api调用工程师,所以对基础知识的考察越来越重要。随着浏览器的兼容性越来越好,原生js的重要性也日益明显。

原生函数

Array

  • every() 检测数组所有元素是否都符合指定条件,只要有一个不满足则false。
  • some() 检测数组元素中是否有元素符合指定条件,只要有一个满足则true
  • concat() 连接两个或更多的数组,并返回结果。
  • join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
  • pop() 删除并返回数组的最后一个元素
  • push() 向数组的末尾添加一个或更多元素,并返回新的长度。
  • reverse() 颠倒数组中元素的顺序。
  • shift() 删除并返回数组的第一个元素
  • slice() 从某个已有的数组返回选定的元素
  • sort() 对数组的元素进行排序
  • splice() 删除元素,并向数组添加新元素。

Math

  • abs(x) 返回数的绝对值。
  • acos(x) 返回数的反余弦值。
  • asin(x) 返回数的反正弦值。
  • atan(x) 以介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值。
  • atan2(y,x) 返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间)。
  • ceil(x) 对数进行上舍入。
  • cos(x) 返回数的余弦。
  • exp(x) 返回 e 的指数。
  • floor(x) 对数进行下舍入。
  • log(x) 返回数的自然对数(底为e)。
  • max(x,y) 返回 x 和 y 中的最高值。
  • min(x,y) 返回 x 和 y 中的最低值。
  • pow(x,y) 返回 x 的 y 次幂。
  • random()返回 0 ~ 1 之间的随机数。
  • round(x) 把数四舍五入为最接近的整数。
  • sin(x) 返回数的正弦。
  • sqrt(x) 返回数的平方根。
  • tan(x) 返回角的正切。

String

  • anchor() 创建 HTML 锚。
  • big()用大号字体显示字符串。
  • blink() 显示闪动字符串。
  • bold() 使用粗体显示字符串。
  • charAt() 返回在指定位置的字符。
  • charCodeAt() 返回在指定的位置的字符的 Unicode 编码。
  • concat() 连接字符串。
  • fixed() 以打字机文本显示字符串。
  • fontcolor() 使用指定的颜色来显示字符串。
  • fontsize() 使用指定的尺寸来显示字符串。
  • fromCharCode()从字符编码创建一个字符串。
  • indexOf() 检索字符串。
  • italics() 使用斜体显示字符串。
  • lastIndexOf() 从后向前搜索字符串。
  • link() 将字符串显示为链接。
  • localeCompare() 用本地特定的顺序来比较两个字符串。
  • match()找到一个或多个正则表达式的匹配。
  • replace() 替换与正则表达式匹配的子串。
  • search() 检索与正则表达式相匹配的值。
  • slice()提取字符串的片断,并在新的字符串中返回被提取的部分。
  • small() 使用小字号来显示字符串。
  • split() 把字符串分割为字符串数组。
  • strike() 使用删除线来显示字符串。
  • sub() 把字符串显示为下标。
  • substr() 从起始索引号提取字符串中指定数目的字符。
  • substring() 提取字符串中两个指定的索引号之间的字符。
  • sup() 把字符串显示为上标。

原生Javascript求数组最小值和最大值

Math.min.apply(null, array)
Math.max.apply(null, array)

原生Dom操作

  • 删除 removeChild 只删除下一级
  • 移动 appendChild 捕获一个dom插入
  • 复制 cloneNode true 深克隆 false 浅克隆
  • 插入 appendChild 新建一个dom插入
  • 替换 replaceChild
  • 前插后插 insertBefore 后插需要用nextSibling找到下一个节点

查找

  • getElementsByTagName() 通过标签名称
  • getElementsByName() 通过元素的Name属性的值
  • getElementById() 通过元素Id,唯一性

重绘重排

当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。完成重排后,浏览器会重新绘制受影响的部分到屏幕,该过程称为重绘,参考高性能JavaScript DOM编程以及重排与重绘

事件流(捕获冒泡),参考JavaScript的事件机制

从document开始,到document结束。事件流分为三个阶段:

  1. 事件捕获阶段
  2. 处于目标阶段
  3. 事件冒泡阶段

事件流分为两类:捕获型事件和冒泡型事件。

  • 捕获型事件

从根元素向下传播,从body开始往每一个div。方法是addEventListener。(true:捕获,false:冒泡,默认:false)

  • 冒泡型事件

由当前dom向上传播,从div到body。方法是onclick事件

委派代理 参考JavaScript事件代理和委托(Delegation)

 var delegate = function(client, clientMethod) {
        return function() {
            return clientMethod.apply(client, arguments);
        }
    }
    var ClassA = function() {
        var _color = "red";
        return {
            getColor: function() {
                console.log("Color: " + _color);
            },
            setColor: function(color) {
                _color = color;
            }
        };
    };

    var a = new ClassA();
    a.getColor();
    a.setColor("green");
    a.getColor();
    console.log("执行代理!");
    var d = delegate(a, a.setColor);
    d("blue");
    console.log("执行完毕!");
    a.getColor();

兼容性写法

ie下的兼容性问题,js举例,(转载)IE8+兼容经验小结

IE6能识别下划线"_"和星号"\ * ",IE7能识别星号" * ",但不能识别下划线"_",IE6~IE10都认识"\9",但firefox前述三个都不能认识。

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

动画方面,加速度,重力模拟实现

正则,基本用法和相关函数作用

参考深入浅出的javascript的正则表达式学习教程

必须要死记硬背的事\d数字,即“digit”,\w字母,即“word”,\s空格或tab,即“space”。\D是非数字字符,\S是非空白字符,/W是非单词字符。

{3}是指有3个这样的字符,{2,3}至少出现2次但不超过3次,{2,}至少出现2次。?指零个或一个,+指是一个或多个。*是任意个也可以没有。

定义的方法是

new RegExp(pattern,attributes);

其中,参数pattern是一个字符串,指定了正则表达式的模式;参数attributes是一个可选的参数,包含属性 g,i,m,分别使用与全局匹配,不区分大小写匹配,多行匹配。

也可以是/pattern/直接定义。方法包含:

  • test() 用于检索字符串的指定值。
  • exec() 返回找到的值,一般是数组。
  • compile() 用于改变RegExp()

OOP

如果你需要补救Javascript面向对象这一方面,先看廖雪峰老师的Javascript原型继承,以及廖雪峰老师的Javascript面向对象编程(二):构造函数的继承。你必须掌握好一个概念就是原型链

类继承方法
类的继承有4种方法。比较完美的方法是声明一个空对象,作为中间prototype,参考brandonxiang/example-mocha/demo5

私有变量

GlobalScope和LocalScope是指面向对象中的共有或私有变量函数,全局变量的搜索较慢,减少document的访问。私有变量和公有变量是Javascript基础开发的一个重要环节。下面是一个简单的例子,name是公用变量,它是this的一个属性。age是一个私有变量,但是它能被对应的公有方法调用。

function Person(props){
    this.name ='brandon';
    var age = '26';

    this.setAge = function(_age){
        age = _age;
    }
    this.getAge = function(){
        return age;
    }
}

变量提升函数提示作用域

一道容易做错的JavaScript面试题很好地讲述了这个问题。

如果你还是不懂。我举几个简单的例子,来自你不知道的Javascript

变量提升

a=2;
var a;
console.log(a);

结果输出为2。由于var a;变量提升,提升到代码的顶端,而它不会改变数值。代码怎变成了:

var a;
a=2;
console.log(a);

如果题目情况是下面这样。

console.log(a);
var a = 2;

结果输出是undefined。只有var a;才会提升。a=2;并不会提升。

函数提升

foo(); //3

function foo(){
   console.log(1);
}

var foo = function(){
    console.log(2);
}

foo(); //2

function foo(){
   console.log(3);
}

定义为function会直接引起函数提升,提升到文件最上端,第一次foo()输出2。而且后一个会将前一个覆盖。var foo = function(){}不会被提升。在后面的函数调用会覆盖,第二次foo()输出2。

作用域

  • 若apply或者call直接作用于对象,this属性必须是该对象
  • 方法被提取或者出现(a=a)()(a,a)()奇葩的调用一般都是上级或者window
  • 没有var的情况,直接找上级对象
  • 箭头函数需特别注意

闭包

参考前端基础进阶(四):详细图解作用域链与闭包

内存泄漏的原因和场景

  • 频繁操作iframe
  • 动态创建DOM
  • 事件绑定
  • Ext框架本身

h5里一些新增api的了解H5的新特性及部分API详解

cookie,localstorage和sessionstorage

cookie与localstorage区别

  • cookie的大小是受限的
  • 请求一个新的页面的时候cookie都会被发送过去
  • cookie指定作用域,不可以跨域调用
  • cookie是http规范的一部分,localstorage在本地“存储”数据
  • localstorage是html5的新特性,所以旧浏览器不一定兼容

localstorage与sessionstorage区别

存储在 localStorage 里面的数据没有过期时间(expiration time),而存储在 sessionStorage 里面的数据会在浏览器会话(browsing session)结束时被清除,即浏览器关闭时。

浏览器的对象模型

  • window
  • document
  • history
  • location
  • screen

详情参考 《Javascript高级编程》的BOM一章。

CSS知识点

块元素

div center h1 hr table ul ol

内联元素

span a font img strong sub

模型盒

offsetwidth = width + border + padding
clientwidth = width + padding

doctype

html 5 的doctype写法 <!DOCTYPE html>

haslayout

hack写法参考 史上最全的CSS hack方式一览

link和@import的区别

  • link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。

  • link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。

  • link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。

  • link支持使用Javascript控制DOM去改变样式;而@import不支持。

网络安全

XSS

XSS(Cross Site Scripting),是一种注入攻击。没有过滤掉<script>以及其他敏感关键词的忽视,针对对方的cookie和用户缓存信息进行攻击。

CRSF

原理

CSRF(Cross-site request forgery)跨域请求伪造,又叫one click attack或session riding。

CRSF

它们之间的区别在于:XSS利用站点内的信任用户。而CSRF是通过伪装来自受信任用户的请求来利用受信任的网站。这种方式虽然不是很流行,但是却难以防范,其危害也不比其他安全漏洞小。

下面是CSRF的常见特性:

  • 依靠用户标识危害网站
  • 利用网站对用户标识的信任
  • 欺骗用户的浏览器发送HTTP请求给目标站点
  • 另外可以通过IMG标签会触发一个GET请求,可以利用它来实现CSRF攻击。
防范措施
  • 服务端进行CSRF防御,在表单当中增加伪随机数。
  • 验证码
  • One-Time Tokens
  • 持久化的授权方法切换成瞬间的授权方法。
  • 双提交cookie

http协议

报文格式

报文格式分为请求报文响应报文

请求报文

请求报文又分为4个部分。

  • request-line 请求方法get,post,head,put,delete等
  • headers 请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔
  • blank line 最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
  • request-body 请求数据不在GET方法中使用,而是在POST方法中使用。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
响应报文

响应报文报文又分为4个部分。

  • <status-line>状态行
    • 1xx:指示信息--表示请求已接收,继续处理。
    • 2xx:成功--表示请求已被成功接收、理解、接受。
    • 3xx:重定向--要完成请求必须进行更进一步的操作。
    • 4xx:客户端错误--请求有语法错误或请求无法实现。
    • 5xx:服务器端错误--服务器未能实现合法的请求。
    • 200 OK:客户端请求成功。
    • 400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
    • 401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
    • 403 Forbidden:服务器收到请求,但是拒绝提供服务。
    • 404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
    • 500 Internal Server Error:服务器发生不可预期的错误。
    • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,举个例子:HTTP/1.1 200 OK(CRLF)。
  • <headers>消息报头
  • <blank line>
  • [<response-body>] 响应正文

get与post区别

get

要求服务器请求URL定位的资源放在响应报文的数据部分,回送客户端。请求参数和对应的值之间跟在URL后面。利用一个问号(?)代表着url的结束和请求参数的开始。传递参数长度受到限制。长度限制1024个字符。

缺点

  • 不适合传送私密数据
  • 数据量大不适合使用get方式

post

请求行中不包含数据字符串,这些数据保存在请求内容中,各数据之间用&分割开。post也能完成get请求。

关于HTTP请求GET和POST的区别

1.GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头<request-line>中),以?分割URL和传输数据,多个参数用&连接;例如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如: %E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。

POST提交:把提交的数据放置在是HTTP包的包体<request-body>中。上文示例中红色字体标明的就是实际的传输数据

因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变

2.传输数据的大小:

首先声明,HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。 而在实际开发中存在的限制主要有:

GET:特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。

因此对于GET提交时,传输数据就会受到URL长度的限制。

POST:由于不是通过URL传值,理论上数据不受限。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache、IIS6都有各自的配置。

3.安全性:

POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改,而这里安全的含义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存, (2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了。

优化性能

结合移动开发规范概述,我的总结:

  • 图片使用CSS Sprites 或 DataURI
  • 压缩静态资源(HTML/CSS/JS/Image)
  • 外链 CSS 中避免 @import 引入
  • 初始请求资源数 < 4
  • 数据离线化,考虑将数据缓存在 localStorage
  • 考虑内嵌小型的静态资源内容
  • 初始请求资源gzip后总体积<50kb
  • 避免打包大型类库
  • 确保接入层已开启Gzip压缩(考虑提升Gzip级别,使用CPU开销换取加载时间)
  • 尽量使用CSS3代替图片

spa优化

  • 初始首屏之外的静态资源(JS/CSS)延迟加载
  • 初始首屏之外的图片资源按需加载(判断可视区域)
  • 单页面应用(SPA)考虑延迟加载非首屏业务模块
  • 开启Keep-Alive链路复用

运行性能优化, 达到操作足够流畅

  • 避免 iOS 300+ms 点击延时问题
  • 缓存 DOM 选择与计算
  • 避免触发页面重绘的操作
  • Debounce连续触发的事件(scroll / resize / touchmove等),避免高频繁触发执行
  • 尽可能使用事件代理,避免批量绑定事件
  • 使用CSS3动画代替JS动画
  • 避免在低端机上使用大量CSS3渐变阴影效果,可考虑降级效果来提升流畅度
  • HTML结构层级保持足够简单
  • 尽能少的使用CSS高级选择器与通配选择器

参考

Javascript面试题

前端的知识更新太快,此文持续更新

感想

我面试大大小小很多公司,有这么一点感想。面试其实是一个双向的过程,面试官在面试我,检验着我的能力。但是,同时,也是我在面试着面试官。面试官的问题是否专业,是否基础,直接反映出公司对应部门对员工的要求。有些面试官不太懂为啥我会默默的观察着整个办公室的一种工作氛围,有时工作氛围说明很多问题。其中包括工作人员的态度,流动性,实习生的比例。这些种种因素都会影响你的就业选择,也希望各位读者能够认真择业,不只是为了一份工资。

各位GIS开发工程师可能也会考虑往前端全栈的方向发展,可以参考一位同行的博客----前端面试笔记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,293评论 18 399
  • <a name='html'>HTML</a> Doctype作用?标准模式与兼容模式各有什么区别? (1)、<...
    clark124阅读 3,418评论 1 19
  • 艳怀胎十月,终于生下一个漂亮的女宝宝。宝宝是如此漂亮,小脸粉妆玉琢,樱桃小嘴。才一月多的孩子,听到妈妈的声音会撇开...
    红樱桃阅读 294评论 1 2
  • 姓名:李有连 企业名称:东莞耀升机电有限公司 组别:AT努力组 【日精进打卡第105天】 【知~学习】 诵读《六项...
    李有连阅读 233评论 0 0