02-面试之前端 js

let、const、var 相关

var:ES5 变量声明方式

  1. 在变量未赋值时,变量 undefined(未使用声明变量时也为 undefined)
  2. 作用域:var 的作用域为方法作用域;只要在方法内定义了,整个方法内的定义变量后的代码都可以使用

let:ES6 变量声明方式

  1. 在变量未声明前直接使用会报错
  2. 作用域:let 为块作用域,通常 let 比 var 范围要小
  3. let 禁止重复声明变量,否则会报错;var 可以重复声明

const:ES6 变量声明方式

  1. const 为常量声明方式;声明变量时必须初始化,在后面出现的代码中不能再修改该常量的值
  2. const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动

js 数据类型,区别

  • 基本数据类型:Number,String,Boolean,null,undefined,symbol,bigint(后两个为 ES6 新增)

  • 引用数据类型:

    • object,function(proto Function.prototype)
    • object:普通对象,数组对象,正则对象,日期对象,Math 数学函数对象。
  • 两种数据存储方式:

    • 基本数据类型是直接存储在栈中的简单数据段,占据空间小、大小固定,属于被频繁使用的数据。栈是存储基本类型值和执行代码的空间。
    • 引用数据类型是存储在堆内存中,占据空间大、大小不固定。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。

两种数据类型的区别:

  1. 堆比栈空间大,栈比堆运行速度快。
  2. 堆内存是无序存储,可以根据引用直接获取。
  3. 基础数据类型比较稳定,而且相对来说占用的内存小。
  4. 引用数据类型大小是动态的,而且是无限的。

Object.assign 的理解

作用:Object.assign 可以实现对象的合并。

语法:Object.assign(target, ...sources)

解析

  1. Object.assign 会将 source 里面的可枚举属性复制到 target,如果和 target 的已有属性重名,则会覆盖。
  2. 后续的 source 会覆盖前面的 source 的同名属性。
  3. Object.assign 复制的是属性值,如果属性值是一个引用类型,那么复制的其实是引用地址,就会存在引用共享的问题。

constructor(构造函数)的理解

创建的每个函数都有一个 prototype(原型)对象,这个属性是一个指针,指向一个对象。

在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性是一个指向 prototype 属性所在函数的指针。

当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(继承自构造函数的 prototype),指向构造函数的原型对象。注意当将构造函数的 prototype 设置为等于一个以对象字面量形式创建的新对象时,constructor 属性不再指向该构造函数。

map 和 forEach 的区别

相同点:

  1. 都是循环遍历数组中的每一项
  2. 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)
  3. 匿名函数中的 this 都是指向 window
  4. 只能遍历数组

不同点:

  1. map() 会分配内存空间存储新数组并返回,forEach() 不会返回数据。
  2. forEach() 允许 callback 更改原始数组的元素。map() 返回新的数组。

for of 可以遍历哪些对象

for..of..: 它是 ES6 新增的一个遍历方法,但**只限于迭代器(iterator)**, 所以普通的对象用 for..of 遍历是会报错的。

可迭代的对象:包括 Array、Map、Set、String、TypedArray、arguments 对象等等

静态类型检查

js是动态类型语言

静态类型语言 & 动态类型语言

  • 静态类型语言:类型检查发生在编译阶段,因此除非修复错误,否则会一直编译失败
  • 动态类型语言:只有在程序运行了一次的时候错误才会被发现,也就是在运行时,因此即使代码中包含了会在运行时阻止脚本正常运行的错误类型,这段代码也可以通过编译

js静态类型检查的方法

Flow 是 Facebook 开发和发布的一个开源的静态类型检查库,它允许你逐渐地向 JavaScript 代码中添加类型。

TypeScript 是一个会编译为 JavaScript 的超集(尽管它看起来几乎像一种新的静态类型语言)

使用静态类型的优势

  • 可以尽早发现 bug 和错误
  • 减少了复杂的错误处理
  • 将数据和行为分离
  • 减少单元测试的数量
  • 提供了领域建模(domain modeling)工具
  • 帮助我们消除了一整类bug
  • 重构时更有信心

使用静态类型的劣势

  • 代码冗长
  • 需要花时间去掌握类型

indexof

语法:str.indexOf(searchValue [, fromIndex])

参数:

  • searchValue:要被查找的字符串值。

    如果没有提供确切地提供字符串,searchValue 会被强制设置为"undefined",然后在当前字符串中查找这个值。

    举个例子:'undefined'.indexOf() 将会返回 0,因为 undefined 在位置 0 处被找到,但是 'undefi'.indexOf() 将会返回 -1 ,因为字符串 'undefined' 未被找到

  • fromIndex:可选

    数字表示开始查找的位置。可以是任意整数,默认值为 0。

    如果 fromIndex 的值小于 0,或者大于 str.length,那么查找分别从 0 和 str.length 开始。(译者 注:fromIndex 的值小于 0,等同于为空情况;fromIndex 的值大于或等于 str.length,那么结果会直接返回-1。)

    举个例子:'hello world'.indexOf('o', -5) 返回4,因为它是从位置 0 处开始查找,然后 o 在位置 4 处被找到。另一方面,'hello world'.indexOf('o', 11)(或 fromIndex 填入任何大于 11 的值) 将会返回 -1,因为开始查找的位置 11 处,已经是这个字符串的结尾了。

返回值:

查找的字符串 searchValue第一次出现的索引,如果没有找到,则返回 -1。

若被查找的字符串 searchValue 是一个空字符串,则返回 fromIndex。如果 fromIndex 值为空,或者 fromIndex 值小于被查找的字符串的长度,返回值和以下的 fromIndex 值一样。

如果 fromIndex 值大于等于字符串的长度,将会直接返回字符串的长度 str.length

特点:

  1. 严格区分大小写
  2. 在使用 indexOf 检索数组时,用 === 去匹配,意味着会检查数据类型。

iframe 有什么优点、缺点

优点:

  1. iframe 能够原封不动的把嵌入的网页展现出来。
  2. 如果有多个网页引用 iframe,那么你只需要修改 iframe 的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
  3. 网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用 iframe 来嵌套,可以增加代码的可重用。
  4. 如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由 iframe 来解决。

缺点:

  1. iframe 会阻塞主页面的 onload 事件;
  2. iframe 和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。会产生很多页面,不容易管理。
  3. iframe 框架结构有时会让人感到迷惑,如果框架个数多的话,可能会出现上下、左右滚动条,会分散访问者的注意力,用户体验度差。
  4. 代码复杂,无法被一些搜索引擎索引到,这一点很关键,现在的搜索引擎爬虫还不能很好的处理 iframe 中的内容,所以使用 iframe 会不利于搜索引擎优化(SEO)。
  5. 很多的移动设备无法完全显示框架,设备兼容性差。
  6. iframe 框架页面会增加服务器的 http 请求,对于大型网站是不可取的。

Web Components

Web Components 总的来说是提供一整套完善的封装机制来把 Web 组件化这个东西标准化,每个框架实现的组件都统一标准地进行输入输出,这样可以更好推动组件的复用

包含四个部分

  1. Custom Elements
  2. HTML Imports
  3. HTML Templates
  4. Shadow DOM

Custom Elements

提供一种方式让开发者可以自定义 HTML 元素,包括特定的组成,样式和行为。支持 Web Components 标准的浏览器会提供一系列 API 给开发者用于创建自定义的元素,或者扩展现有元素。

HTML Imports

一种在 HTMLs 中引用以及复用其他的 HTML 文档的方式。这个 Import 很漂亮,可以简单理解为我们常见的模板中的include之类的作用

HTML Templates

模板

Shadow DOM

提供一种更好地组织页面元素的方式,来为日趋复杂的页面应用提供强大支持,避免代码间的相互影响

dva 的数据流流向是怎么样的

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过 dispatch 发起一个 action,如果是同步行为会直接通过 Reducers 改变 State,如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变 State,所以在 dva 中,数据流向非常清晰简明,并且思路基本跟开源社区保持一致。

变量提升

JavaScript 是单线程语言,所以执行肯定是按顺序执行。但是并不是逐行的分析和执行,而是一段一段地分析执行,会先进行编译阶段然后才是执行阶段。在编译阶段阶段,代码真正执行前的几毫秒,会检测到所有的变量和函数声明,所有这些函数和变量声明都被添加到名为 Lexical Environment 的 JavaScript 数据结构内的内存中。所以这些变量和函数能在它们真正被声明之前使用。

作用域

概念:作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6 的到来,为我们提供了‘块级作用域’,可通过新增命令 let 和 const 来体现。

HashMap 和 ArrayMap 有什么区别?

  1. 查找效率。
    HashMap 因为其根据 hashcode 的值直接算出 index,所以其查找效率是随着数组长度增大而增加的。
    ArrayMap 使用的是二分法查找,所以当数组长度每增加一倍时,就需要多进行一次判断,效率下降。

  2. 扩容数量。
    HashMap 初始值 16 个长度,每次扩容的时候,直接申请双倍的数组空间。
    ArrayMap 每次扩容的时候,如果 size 长度大于 8 时申请 size*1.5 个长度,大于 4 小于 8 时申请 8 个,小于 4 时申请 4 个。这样比较 ArrayMap 其实是申请了更少的内存空间,但是扩容的频率会更高。因此,如果数据量比较大的时候,还是使用 HashMap 更合适,因为其扩容的次数要比 ArrayMap 少很多。

  3. 扩容效率。
    HashMap 每次扩容的时候重新计算每个数组成员的位置,然后放到新的位置。
    ArrayMap 则是直接使用 System.arraycopy,所以效率上肯定是 ArrayMap 更占优势。

  4. 内存消耗。
    以 ArrayMap 采用了一种独特的方式,能够重复的利用因为数据扩容而遗留下来的数组空间,方便下一个 ArrayMap 的使用。
    而 HashMap 没有这种设计。由于 ArrayMap 之缓存了长度是 4 和 8 的时候,所以如果频繁的使用到 Map,而且数据量都比较小的时候,ArrayMap 无疑是相当的是节省内存的。

总结:综上所述,数据量比较小,并且需要频繁的使用 Map 存储数据的时候,推荐使用 ArrayMap。而数据量比较大的时候,则推荐使用 HashMap。

HashMap 和 Object

Objects 和 Maps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成 Maps 使用。不过 Maps 和 Objects 有一些重要的区别,在下列情况里使用 Map 会是更好的选择:

Map Object
意外的键 Map 默认情况不包含任何键。只包含显式插入的键。 一个Object有一个原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。注意: 虽然 ES5 开始可以用 Object.create(null) 来创建一个没有原型的对象,但是这种用法不太常见。
键的类型 一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。 一个 Object 的键必须是一个 String 或是 Symbol。
键的顺序 Map 中的 key 是有序的。因此,当迭代的时候,一个Map对象以插入的顺序返回键值。 一个 Object 的键是无序的注意:自ECMAScript 2015规范以来,对象_确实_保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。
Size Map 的键值对个数可以轻易地通过 size 属性获取 Object的键值对个数只能手动计算
迭代 Map 是 iterable 的,所以可以直接被迭代。 迭代一个Object需要以某种方式获取它的键然后才能迭代。
性能 在频繁增删键值对的场景下表现更好。 在频繁添加和删除键值对的场景下未作出优化。

javascript 中 arguments 相关的问题

arguments

在js中,我们在调用有参数的函数时,当往这个调用的有参函数传参时,js 会把所传的参数全部存到一个叫 arguments 的对象里面。它是一个类数组数据

由来

Javascrip 中每个函数都会有一个 Arguments 对象实例 arguments,引用着函数的实参。它是寄生在 js 函数当中的,不能显式创建,arguments 对象只有函数开始时才可用

作用

有了 arguments 这个对象之后,我们可以不用给函数预先设定形参了,可以动态地通过 arguments 为函数加入参数

instanceOf 原理,手动实现 function isInstanceOf (child, Parent)

instanceof 主要作用就是判断一个实例是否属于某种类型

1
2
3
let person = function(){};
let no = new person();
no instanceof person; //true

instanceOf 原理

1
2
3
4
5
6
7
8
9
10
11
12
13
function new_instance_of(leftVaule, rightVaule) { 
let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
while (true) {
if (leftVaule === null) {
return false;
}
if (leftVaule === rightProto) {
return true;
}
leftVaule = leftVaule.__proto__
}
}

其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。

同时还要了解 js 的原型继承原理

我们知道每个 JavaScript 对象均有一个隐式的 proto 原型属性,而显式的原型属性是 prototype,只有 Object.prototype.proto 属性在未修改的情况下为 null 值

手动实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
var O = R.prototype;
L = L.__proto__;
while (true) {
if (L === null)
return false;
if (O === L) // 这里重点:当 O 严格等于 L 时,返回true
return true;
L = L.__proto__;
}
}
// 开始测试
var a = [];
var b = {};

function Foo(){}
var c = new Foo();
function child(){}
function father(){}
child.prototype = new father();
var d = new child();

console.log(instance_of(a, Array)); // true
console.log(instance_of(b, Object)); // true
console.log(instance_of(b, Array)); // false
console.log(instance_of(a, Object)); // true
console.log(instance_of(c, Foo)); // true
console.log(instance_of(d, child)); // true
console.log(instance_of(d, father)); // true

编码和字符集的区别

参考答案:

字符集是书写系统字母与符号的集合,而字符编码则是将字符映射为一特定的字节或字节序列,是一种规则。通常特定的字符集采用特定的编码方式(即一种字符集对应一种字符编码(例如:ASCII、IOS-8859-1、GB2312、GBK,都是即表示了字符集又表示了对应的字符编码,但Unicode不是,它采用现代的模型))

扩展:

字符:在计算机和电信技术中,一个字符是一个单位的字形、类字形单位或符号的基本信息。即一个字符可以是一个中文汉字、一个英文字母、一个阿拉伯数字、一个标点符号等。

字符集:多个字符的集合。例如 GB2312 是中国国家标准的简体中文字符集,GB2312 收录简化汉字(6763个)及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母,共 7445 个图形字符。

字符编码:把字符集中的字符编码为(映射)指定集合中的某一对象(例如:比特模式、自然数序列、电脉冲),以便文本在计算机中存储和通过通信网络的传递。

null 和 undefined 的区别,如何让一个属性变为 null

参考答案:

undefined 表示一个变量自然的、最原始的状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。所以,在实际使用过程中,为了保证变量所代表的语义,不要对一个变量显式的赋值 undefined,当需要释放一个对象时,直接赋值为 null 即可。

解析:

undefined 的字面意思就是:未定义的值。这个值的语义是,希望 表示一个变量最原始的状态,而非人为操作的结果。这种原始状态会在以下 4 种场景中出现:

  1. 声明了一个变量,但没有赋值
  2. 访问对象上不存在的属性
  3. 函数定义了形参,但没有传递实参
  4. 使用 void 对表达式求值

因此,undefined 一般都来自某个表达式最原始的状态值,不是人为操作的结果。当然,你也可以手动给一个变量赋值 undefined,但这样做没有意义,因为一个变量不赋值就是 undefined。

null 的字面意思是:空值。这个值的语义是,希望表示一个对象被人为的重置为空对象,而非一个变量最原始的状态。在内存里的表示就是,栈中的变量没有指向堆中的内存对象

null 有属于自己的类型 Null,而不属于 Object 类型,typeof 之所以会判定为 Object 类型,是因为 JavaScript 数据类型在底层都是以二进制的形式表示的,二进制的前三位为 0 会被 typeof 判断为对象类型,而 null 的二进制位恰好都是 0,因此 null 被误判断为 Object 类型。

数组 和 类数组的区别

  1. 定义

    • 数组是一个特殊对象,与常规对象的区别:
      • 当由新元素添加到列表中时,自动更新 length 属性
      • 设置 length 属性,可以截断数组
      • Array.protoype 中继承了方法
      • 属性为 Array
    • 类数组是一个拥有 length 属性,并且他属性为非负整数的普通对象,类数组不能直接调用数组方法。
  2. 区别

    本质:类数组是简单对象,它的原型关系与数组不同。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 原型关系和原始值转换
    let arrayLike = {
    length: 10,
    };
    console.log(arrayLike instanceof Array); // false
    console.log(arrayLike.__proto__.constructor === Array); // false
    console.log(arrayLike.toString()); // [object Object]
    console.log(arrayLike.valueOf()); // {length: 10}

    let array = [];
    console.log(array instanceof Array); // true
    console.log(array.__proto__.constructor === Array); // true
    console.log(array.toString()); // ''
    console.log(array.valueOf()); // []
  3. 类数组转换为数组

    • 转换方法
      • 使用 Array.from()
      • 使用 Array.prototype.slice.call()
      • 使用 Array.prototype.forEach() 进行属性遍历并组成新的数组
    • 转换须知
      • 转换后的数组长度由 length 属性决定。索引不连续时转换结果是连续的,会自动补位。

    代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let al1 = {
    length: 4,
    0: 0,
    1: 1,
    3: 3,
    4: 4,
    5: 5,
    };
    console.log(Array.from(al1)) // [0, 1, undefined, 3]
    • ②仅考虑 0或正整数 的索引
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 代码示例
    let al2 = {
    length: 4,
    '-1': -1,
    '0': 0,
    a: 'a',
    1: 1
    };
    console.log(Array.from(al2)); // [0, 1, undefined, undefined]
    • ③使用slice转换产生稀疏数组
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 代码示例
    let al2 = {
    length: 4,
    '-1': -1,
    '0': 0,
    a: 'a',
    1: 1
    };
    console.log(Array.prototype.slice.call(al2)); //[0, 1, empty × 2]
  4. 使用数组方法操作类数组注意地方

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let arrayLike2 = {
    2: 3,
    3: 4,
    length: 2,
    push: Array.prototype.push
    };

    // push 操作的是索引值为 length 的位置
    arrayLike2.push(1);
    console.log(arrayLike2); // {2: 1, 3: 4, length: 3, push: ƒ}
    arrayLike2.push(2);
    console.log(arrayLike2); // {2: 1, 3: 2, length: 4, push: ƒ}

介绍下 Set、Map、WeakSet 和 WeakMap 的区别?

Set

  1. 成员不能重复;
  2. 只有键值,没有键名,有点类似数组;
  3. 可以遍历,方法有 add、delete、has

WeakSet

  1. 成员都是对象(引用);
  2. 成员都是弱引用,随时可以消失(不计入垃圾回收机制)。可以用来保存 DOM 节点,不容易造成内存泄露;
  3. 不能遍历,方法有 add、delete、has;

Map

  1. 本质上是键值对的集合,类似集合;
  2. 可以遍历,方法很多,可以跟各种数据格式转换;

WeakMap

  1. 只接收对象为键名(null 除外),不接受其他类型的值作为键名;
  2. 键名指向的对象,不计入垃圾回收机制;
  3. 不能遍历,方法同 get、set、has、delete;

简单说说 js 中有哪几种内存泄露的情况

  1. 意外的全局变量;
  2. 闭包;
  3. 未被清空的定时器;
  4. 未被销毁的事件监听;
  5. DOM 引用;

json 和 xml 数据的区别

  1. 数据体积方面:xml 是重量级的,json 是轻量级的,传递的速度更快些。
  2. 数据传输方面:xml 在传输过程中比较占带宽,json 占带宽少,易于压缩。
  3. 数据交互方面:json 与 javascript 的交互更加方便,更容易解析处理,更好的进行数据交互。
  4. 数据描述方面:json 对数据的描述性比 xml 较差。
  5. xml 和 json 都用在项目交互下,xml 多用于做配置文件,json 用于数据交互。

JavaScript 有几种方法判断变量的类型?

  1. 使用 typeof 检测。当需要判断变量是否是 number,string,boolean,function,undefined 等类型时,可以使用 typeof 进行判断。

  2. 使用 instanceof 检测。instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。

  3. 使用 constructor 检测。constructor 本来是原型对象上的属性,指向构造函数。但是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用 constructor 属性的。

如何创建响应式布局?

  1. 可以通过引用 Bootstrap 实现
  2. 通过看 Bootstrap 源码文件,可知其本质就是通过 CSS 实现的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
/*浏览器窗口宽度大于768,背景色变为 green*/
@media (min-width: 768px) {
.pg-header{
background-color: green;
}
}

/*浏览器窗口宽度大于992,背景色变为 pink*/
@media (min-width: 992px) {
.pg-header{
background-color: pink;
}
}
</style>

什么是 ajax 请求?并使用 jQuery 和 XMLHttpRequest 对象实现一个 ajax 请求

  1. 没用ajax:浏览器访问服务器请求,用户看得到(页面刷新也就等同于重新发请求,刷新看得到,也就等同于请求看得到)。等请求完,页面刷新,新内容出现,用户看到新内容。

  2. 用ajax:浏览器访问服务器请求,用户看不到,是悄悄进行。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

http://www.cnblogs.com/wupeiqi/articles/5703697.html

如何在前端实现轮训?

轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出 HTTP request,然后由服务器返回最新的数据给客户端的浏览器。

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
setInterval(function(){
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
...
};
xhr.send();
},1000)

如何在前端实现长轮训

ajax 实现:在发送 ajax 后,服务器端会阻塞请求直到有数据传递或超时才返回。

客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。

1
2
3
4
5
6
7
8
function ajax(){
var xhr = new XMLHttpRequest();
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
ajax();
};
xhr.send();
}

简述 jsonp 及实现原理

因为有同源策略,所以需要使用 scripy 标签

原理:

  1. 先在客户端注册一个 callback, 然后把 callback 的名字传给服务器。
  2. 此时,服务器先生成 json 数据。
  3. 然后以 javascript 语法的方式,生成一个 function , function 名字就是传递上来的参数 jsonp。
  4. 最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
  5. 客户端浏览器,解析 script 标签,并执行返回的 javascript 文档,此时数据作为参数传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)

注意:

  • JSON 是一种数据格式。
  • JSONP 是一种数据调用的方式。

什么是 cors

跨域资源共享(Cross-Origin Resource Sharing): 其本质是设置响应头,使得浏览器允许跨域请求。

其实浏览器的请求共分为两类:

  1. 简单请求(一次请求)

    1. 请求方式:HEAD、GET、POST
    2. 请求头只包括以下信息:
      Accept
      Accept-Language
      Content-Language
      Last-Event-ID
      Content-Type 对应的值是三个中的任意一个application/x-www-form-urlencodedmultipart/form-datatext/plain
  2. 非简单请求,又叫复杂请求(两次请求)
    除简单请求之外的请求都是非简单请求。非简单请求类请求在发送真正的请求之前,会默认发送一个 options 请求,做’预检’,预检成功后才发送真正的请求
    预检:如果复杂请求是 PUT 等请求,则服务端需要设置允许某请求,参数为 Access-Control-Request-Method,否则“预检”不通过
    如果复杂请求设置了请求头,则服务端需要设置允许某请求头,参数为 Access-Control-Request-Headers,否则“预检”不通过

你曾经使用过哪些前端框架?

  • jQuery
  • BootStrap、H-ui、layui、Element
  • Vue(与vue齐名的前端框架React和Angular)

jQuery this 和 $(this) 的区别

  • this 是 javascript 自身的语法关键字,它指向一个 javascript 对象,所以可以使用所指向的目标 javascript 对象所拥有的方法, 但他自己不是一个普通的变量,所以你无法自己定义一个变量叫 this
  • 所以为了使用 jQuery 对象的方法,你必须传入 jQuery 函数 $(this), 将 javascript 对象包装成为一个 jquery 对象。

02-面试之前端 js
https://flepeng.github.io/interview-20-开发语言类-21-frontend-02-面试之前端-js/
作者
Lepeng
发布于
2020年8月8日
许可协议