前端面试题集锦(7)

目录

1、常见的跨域方式 ?

2、对象的遍历方法  

3、数组扁平化 

4、typeof 原理

5、介绍类型转化 

6、闭包的问题和优化

7、浏览器和Node事件循环的区别


1、常见的跨域方式 ?

JSONP
       JSONP 是利用外链脚本,没有跨源限制的特点,来实现跨源请求的一种技术。
CORS
       cors :跨域资源共享,是一种实现跨源请求数据的技术。这就是跨源问题的解决方案之一。也是广泛的解决方案。
正向代理
先搭建一个属于自己的代理服务器
       1 、用户发送请求到自己的代理服务器
       2 、自己的代理服务器发送请求到服务器
       3 、服务器将数据返回到自己的代理服务器
       4 、自己的代理服务器再将数据返回给用户
反向代理
       1 、用户发送请求到服务器(访问的其实是反向代理服务器,但用户不知道)
       2 、反向代理服务器发送请求到真正的服务器
       3 、真正的服务器将数据返回给反向代理服务器
       4 、反向代理服务器再将数据返回给用户
通过postMassage

2、对象的遍历方法  

JavaScript中 对象的遍历方法:
for ...in
基本语法是 for ( 变量 in 对象 ){ 循环体程序 }
这里要注意的是
1 , 变量中存储的键名 通过键名获取对象中存储的键值
因为是变量 点语法取值 不支持解析变量 要使用 对象 [ 键名 ] 获取键值
2 , 循环变量 定义 let var 定义 执行效果是不同的
Object.keys( 对象 )
返回一个数组 是 当前对象 所有键名组成的数组
之后再循环遍历这个数组 再执行操作
Object.value( 对象 )
返回一个数组 是 当前对象 所有键值组成的数组
之后再循环遍历这个数组 再执行操作

3、数组扁平化 

数组扁平化
所谓的数组扁平化就是将多维数组转化为一维数组一般数组扁平化 , 数组中存储的多维数据都是数组 不会是对象或者函数
最常用的方法 就是 数组 .toString() 将数组转化为字符串
结果是 获取数组中的每一个单元的数据 组成一个字符串 使用逗号间隔
再 以逗号为间隔 将字符串 转化为数组
function fun1( arr ){
    let str = arr.toString();
    return str.split(',');
}
还可以使用 数组 .some() 方法 判断数组中是不是还存在数组
在使用 展开运算符 赋值
function fun1(arr) {
     while (arr.some(item => Array.isArray(item))) {
         arr = [].concat(...arr);
     }
     return arr;
}
另外 ES6 语法中 新增的 flat 函数也可以实现数组的扁平化
参数是固定的
const arr = 原始数组.flat( Infinity )

4、typeof 原理

利用 typeof 是根据返回值的结果来判断数据类型
具体返回值 一共是 number, string, object, boolean, function, undefined
其中 数组 null 对象 的返回值 都是 object
这样的话具体的数据类型就不能区分的非常明确 在实际项目中 就不能准确的区分
如果想要具体的 区分 数据类型 需要使用 Object.prototype.toString.call() 方法 返回值是
object String 字符串
object Number 数值类型
object Boolean 布尔类型
object Undefined undefined 类型
object Null null 类型
object Function 函数类型
object Array 数组类型

5、介绍类型转化 

JavaScript 因为是 弱类型计算机语言 存储数据时 对变量储存的数据类型没有设定
因此一个变量中可以存储任意类型的数据
在程序的执行过程中 就会遇到需要数据类型转化的情况
自动转化
    自动转化为字符串
        数据 直接转化为 对应的字符串
自动转化为数值类型
转化为 对应的数值
1 true
0 false null "" ''
符合数字规范的字符串
                                         转化为 NaN
                           不符合数字规范的字符串
                                   undefined
自动转化为数值类型
                                    false:
                                        0 0.0000 '' NaN null undefined
                                    true:
                                           其他情况都转化为 true

强制转化  

强制转化为布尔类型
Boolean( 变量 / 表达式 )
                             转化原则 和 自动转化原则完全相同
                             false : 0 0.000 '' null NaN undefined
                             true : 其他情况都转化为 true
        强制转化为字符串类型
              String( 变量 / 表达式 );
                         转化原则 和 自动转化原则完全相同
                         不会改变 变量中存储的原始数据
              变量 .toString( 进制 ) ;
                          转化原则 和 自动转化原则完全相同
                          不会改变 变量中存储的原始数据
                          如果是 整数类型 可以 设定 转化的进制
                          变量 存储 null 或者 undefined 不支持
          强制转化为数值类型
                    Number()
                             转化原则 和 自动转化完全相同
                             不会改变 变量中存储的原始内容
                     parseInt()
                              从左侧起 获取符合整数语法规范的内容部分
                              如果左起第一个字符就不符合整数语法规范
                              执行结果是 NaN
                     parseFloat()
                              从左侧起 获取符合浮点数语法规范的内容部分
                              如果 左起第一个字符就不符合浮点数语法规范
                              执行结果是 NaN

6、闭包的问题和优化

闭包:是指有权访问另外一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创
建另外一个函数。
作用:
1 、可以读取函数内部的变量 2 、相当于划出了一块私有作用域,避免数据污染; 3 、让变量始终保存在内存中

闭包有三个特性:

1. 函数嵌套函数
2. 函数内部可以引用外部的参数和变量
3. 参数和变量不会被垃圾回收机制回收

闭包的问题 :

闭包会产生不销毁的上下文,会导致栈 / 堆内存消耗过大,有时候也会导致内存泄漏等,影响页面的运行性能,所以在
真实项目中,要合理应用闭包!

闭包的优化 :

原始代码
function MyObject(name, message) {
     this.name = name.toString();
     this.message = message.toString();
     this.getName = function() {
       return this.name;
     };

     this.getMessage = function() {
       return this.message;
     };
 }

优化代码:

function MyObject(name, message) {
    this.name = name.toString();
    this.message = message.toString();
}
MyObject.prototype.getName = function() {
    return this.name;
};
MyObject.prototype.getMessage = function() {
    return this.message;
};

7、浏览器和Node事件循环的区别

一、全局环境下this的指向
node this 指向 global 而在浏览器中 this 指向 window ,这就是为什么 underscore 中一上来就定义了一个root;
而且在浏览器中的 window 下封装了不少的 API 比如 alert document location history 等等还有很多。我们就不能在node 环境中 xxx(); window.xxx(); 了。因为这些 API 是浏览器级别的封装,存 javascript 中是没有的。当然node 中也提供了不少 node 特有的 API

二、js引擎

在浏览器中不同的浏览器厂商提供了不同的浏览器内核,浏览器依赖这些内核解释折我们编写的 js 。但是考虑到不同内核的少量差异,我们需要对应兼容性好在有一些优秀的库帮助我们处理这个问题比如jquery underscore 等等。
nodejs 是基于 Chromes JavaScript runtime ,也就是说,实际上它是对 GoogleV8 引擎(应用于 Google Chrome浏览器 ) 进行了封装。 V8 引 擎执行 Javascript 的速度非常快,性能非常好。
NodeJS 并不是提供简单的封装,然后提供 API 调用,如果是这样的话那么它就不会有现在这么火了。 Node 对一些特殊用例进行了优化,提供了替代的API ,使得 V8 在非浏览器环境下运行得更好。例如,在服务器环境中,处理二进制数据通常是必不可少的,但Javascript 对此支持不足,因此, V8.Node 增加了 Buffer 类,方便并且高效地 处理二进制数据。因此,Node 不仅仅简单的使用了 V8, 还对其进行了优化,使其在各环境下更加给力。

三、DOM操作

浏览器中的js大多数情况下是在直接或间接(一些虚拟DOM的库和框架)的操作DOM。因为浏览器中的代码主要是在表现层工作。但是node是一门服务端技术。没有一个前台页面,所以我门不会再node中操作DOM

四、I/O读写

与浏览器不同,我们需要像其他服务端技术一样读写文件, nodejs 提供了比较方便的组件。而浏览器(确保兼容性的)想在页面中直接打开一个本地的图片就麻烦了好多(别和我说这还不简单,相对路径。。。。。。试试就知道了要么找个库要么二进制流,要么上传上去有了网络地址在显示。不然人家为什么要搞一个js 库呢),而这一切 node 都用一个组件搞定了。

 五、模块加载

javascript 有个特点,就是原生没提供包引用的 API 一次性把要加载的东西全执行一遍,这里就要看各位闭包的功力了。所用东西都在一起,没有分而治之,搞的特别没有逻辑性和复用性。如果页面简单或网站当然我们可以通过一些AMD、 CMD的 js 库(比如 requireJS seaJS )搞定事实上很多大型网站都是这么干的。在nodeJS 中提供了 CMD 的模块加载的 API ,如果你用过 seaJS ,那么应该上手很快。 node 还提供了 npm 这种包管理工具,能更有效方便的管理我们应用的库

猜你喜欢

转载自blog.csdn.net/weixin_48649246/article/details/128236698