1. JS面试题
发布于 2022年 04月 01日 08:18
1. 简述同步和异步的区别
- 同步的思想:阻塞模式,等所有的操作都做完,才返回给用户。这样用户在线等待的时间太长;
- 异步思想:非阻塞模式,将用户请求放入消息队列,不需要一直等下去, 可以继续执行下面的操作;
这么看下来异步的好处要多,但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据在进行操作的。这些是异步所无法解决的。
2.怎么添加、移除、复制、创建、和查找节点
1.创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
2.添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入
3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
3.实现一个函数clone 可以对Javascript中的五种主要数据类型(Number、string、Object、Array、Boolean)进行复制
function clone(obj) {
var o;
switch (typeof obj) {
case "undefined":
break;
case "string":
o = obj + "";
break;
case "number":
o = obj - 0;
break;
case "boolean":
o = obj;
break;
case "object": // object 分为两种情况 对象(Object)或数组(Array)
if (obj === null) {
o = null;
} else {
if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
o = [];
for (var i = 0; i < obj.length; i++) {
o.push(clone(obj[i]));
}
} else {
o = {};
for (var k in obj) {
o[k] = clone(obj[k]);
}
}
}
break;
default:
o = obj;
break;
}
return o;
4.如何消除一个数组里面重复的元素
//1. new Set(Infinity)
let x = Array.from(new Set(arr));
//2.indexOf
var arr = [1, 1, 1, 2, 2, 2, 1, 2]
// 准备一个新的空数组
var newArr = []
for (var i = 0; i < arr.length; i++) {
var cur = arr[i]
// 如果新数组里,还没有当前这一项 就将它添加到新数组里
if (newArr.indexOf(cur) === -1) {
newArr.push(cur)
}
}
console.log(newArr) // [1, 2]
//
let arr = [1,2,34,5,3,2,1,3,2,1,3,2,1]
function checkArr(arr) {
for (var i = 0; i < arr.length; i++) {
arr.sort();
if (arr[i] === arr[i + 1]) {
arr.splice(i, 1);
i--;
}
}
return arr;
}
console.log(checkArr(arr));
5.写一个返回闭包的函数
闭包的特点:
1. 函数嵌套函
2. 函数内部可以引用外部的参数和变量
3. 参数和变量不会被垃圾回收机制回收
function outer(x=0){
function Inner(){
++x;
return x;
}
return Inner;
}
var s = outer(x);
console.log(s);
6.使用递归完成1到100的累加
function add(n) {
if (n <= 1) {
return 1
}
return n + add(n - 1)
}
var result = add(100)
console.log(result) // 5050
7.Javascript有哪几种数据类型
基本类型:String、Number、Boolean、Symbol、Undefined、Null
引用类型:Object
8.如何判断数据类型
* typeof
* instanceof
* constructor
* Object.prototype.toString.call()
**优缺点**
+ typeof
+ 大部分都可以实现,尤其是在检测基本类型值(除null之外)和函数类型值的时候
- 无法细分当前值是普通对象还是数组对象等=>'Object'; typeOf null =>'Object'
+ instanceof
用来检测某个实例是否属于这个类(对象类型)
- 不能处理基本数据类型值;
- 只要在当前实例的原型链(_proto_)中出现过的类,检测结果都是true(用户可能会手动修改原型链的指向:example.proto 或者 在类的继承中 等情况)
+ constructor
在类的原型上一般都会带有CONSTRUCTOR属性,存储当前类本身,我们也是利用这一点,获取某的实例CONSTRUCTOR属性值,验证是否为所属的类,从而进行数据类型检测
- 可以去随意修改对应的constructor值或者是手动给ary增加一个私有的constructor属性等;
+ Object.prototype.toString.call([value])
信息模板:"[object 所属类]" ,例如:"[object Array]"...
所有的数据类型上都有toString方法,只有Object原型上的toString是检测当前实例所属类的详细信息的,其它原型的方法仅仅是转换为字符串;
+ 所有数据类型隶属的类信息检测的一清二楚
console.log(Object.prototype.toString.call(1)) // "[object Number]"
9.console.log(1+'2')和console.log(1-'2')的打印结果
console.log(1+'2') // 字符串拼接 =>12
console.log(1-'2') // 数学运算 -1
10.Js的事件委托是什么,原理是什么
如果在需要有多个DOM事件需要监听的情况下(比如几百条微博点击事件注册),给每一个DOM都绑定监听函数,对性能会有极大的影响,因此,有一解决方案为事件委托。
利用冒泡【当下级节点触发某个事件的时候,该事件会逐级向上触发上级节点的同类事件】的原理,把事件加到父级上,触发执行效果;
11.如何改变函数内部的this指针的指向
=> window
+ 全局直接打印this
+ 函数直接打印this,并调用
+ 定时器中普通函数
+ 匿名函数自执行
=> 事件中的this:
+ 哪个对象触发,this就是那个对象
=> 实例:
+ new 构造函数 this 就是实例
=> 箭头函数
+ this走定义箭头函数的域(本身无this)
=> 对象中的this
let obj = {fn:function(){console.log(this)}}
1、给某个元q素绑定方法,当事件触发方法执行的时候,方法中的this是当前操作的元素本身;
2、当方法执行的时候,我们看方法前面是否有没有点,没有点的this是window或者是undefined,有点,点前边是谁this就是谁;
原型上提供的三个公有属性方法 call / apply / bind 这些方法都是用来改变函数中的THIS指向的
12.列举几种解决跨域问题的方式,且说明原理
1. 什么是同源策略及其限制内容?
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制内容有:
- 1、Cookie、LocalStorage 和 IndexDB 无法读取
- 2、DOM 和 Js对象无法获得
- 3、AJAX 请求不能发送
但是有三个标签是允许跨域加载资源:
<img src=XXX>
<link href=XXX>
<script src=XXX>
跨域解决方案
1. jsonp
利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的**服务器**做支持才可以。
+ 优点: 简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。
— 缺点: 仅支持get方法,**不安全**可能会遭受XSS攻击。
JSONP的实现流程
+ 声明一个回调函数,其函数名(如show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。
+ 创建一个<script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=show)。
+ 服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是show('我不爱你')。
+ 最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。
2. CORS
CORS 需要浏览器和后端同时支持
浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
可参考:www.cnblogs.com/fundebug/p/…
13.谈谈垃圾回收机制的方式及内存管理
- 定义: 执行环境负责管理代码执行过程中使用的内存。
- 原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
- 垃圾回收策略:标记清除(较为常用)和引用计数。
- 当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:“离开环境”。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。
- 引用计数是跟踪记录每个值被引用的次数。
内存管理
什么时候触发垃圾回收?
垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。
IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。
IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。
14.写一个function ,清除字符串前后的空格
function trim(str) {
if (str && typeof str === "string") {
return str.replace(/(^\s*)|(\s*)$/g,""); //去除前后空白符
}
}
15.js实现继承的方法有哪些
1、原型链继承
核心: 将父类的实例作为子类的原型
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
var cat = new Cat();
console.log(cat.name);
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
特点:
+ 实例是子类的实例,也是父类的实例
+ 父类新增原型方法/原型属性,子类都能访问到
- 原型对象的所有属性被所有实例共享
- 创建子类实例时,无法向父类构造函数传参
- 要想为原型新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
- 无法实现多继承
2、构造继承
核心: 使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
var cat = new Cat();
console.log(cat.name);
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
特点:
+ 解决了1中,子类实例共享父类引用属性的问题
+ 创建子类实例时,可以向父类传递参数
+ 可以实现多继承(call多个父类对象)
- 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
3、实例继承
核心: 为父类实例添加新特性,作为子类实例返回
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
var cat = new Cat();
console.log(cat.name);
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
特点:
+ 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
- 实例是父类的实例,不是子类的实例
- 不支持多继承
4、拷贝继承
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}
var cat = new Cat();
console.log(cat.name);
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
特点:
+ 支持多继承
- 效率较低,内存占用高(因为要拷贝父类的属性)
- 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
5、组合继承
核心: 通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat = new Cat();
console.log(cat.name);
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
特点:
+ 可以继承实例属性/方法,也可以继承原型属性/方法
+ 既是子类的实例,也是父类的实例
+ 不存在引用属性共享问题
+ 可传参
+ 函数可复用
- 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
6、寄生组合继承
核心: 通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();
Cat.prototype.constructor = Cat;
var cat = new Cat();
console.log(cat.name);
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
16.判断一个变量是否是数组,有哪些办法
arr instanceof Array // true 不推荐
arr.constructor === Array // true 不推荐
Array.isArray(arr) // true 考虑兼容
// 看是否可以使用数组的方法
typeof arr === 'object' && arr.sort === Array.prototype.sort
Object.prototype.toString.call(arr) // "[object Array]"
17.let ,const ,var 有什么区别
1. var存在变量提升,let,const不存在
2. var允许重复声明,而let,const是不允许的
3. let/const会产生块级作用域,var不会;
4. let 可以解决暂时性死区问题;
5. 带var相当于在window设置一个属性,同时声明一个变量;但使用let/const相当于只声明一个变量,没有给window增加属性(全局下);
18.箭头函数与普通函数有什么区别
+ 没有this,this为定义时所在的对象;
+ 没有arguments,可以通过...arg实现;
+ 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
+ 不可以使用 new 命令
+ 没有自己的 this,无法调用 call,apply。
+ 没有 prototype 属性 ,而 new 命令在执行时需要将构造函数的 prototype 赋值给新的对象的 __proto__
19.随机取1-10之间的整数
Math.round(Math.random() * (max - min)) + min
20.new操作符具体干了什么
创建一个空对象obj
设置原型链 即 obj . _proto _ = 构造函数.prototype ;
让构造函数中的this指向obj
返回对象obj
21.Ajax原理
原理: 简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面,不用页面刷新,并且在等待页面传输数据的同时可以进行其他操作。
XMLHttpRequest是ajax的核心机制,也就是javascript可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。
那Ajax是如何从浏览器发送Http请求到服务器呢?
XMLHttpRequest对象的属性和方法:
-
readyState属性有五个状态值。
* 0 :unsend未发送(创建一个XHR,初始状态是0) * 1 :opend 已经打开(执行了xhr.open); * 2 :headers_received 响应头信息 已经返回给客户端(发送请求后,服务器会一次返回响应头和响应主体的信息) * 3 :loading 正在接受响应,但是还不完整。 * 4:done 接受响应完毕
-
responseText:服务器返回的响 应文本。只有当readyState>=3的时候才有值,根据readyState的状态值,可以知道,当readyState=3,返回的响应文 本不完整,只有readyState=4,完全返回,才能接受全部的响应文本。
-
responseXML:响应信息是xml,可以解析为Dom对象。
-
status:服务器的Http状态码,若是200,则表示OK,404,表示为未找到。
-
statusText:服务器http状态码的文本。比如OK,Not Found。
ajax的使用
-
创建Ajax实例, XMLHttpRequest对象 =>创建异步调用对象
-
调用ajax对象的open方法,配置发送请求的信息(请求方法,url,验证信息)
* method: HTTP请求方式 * url: 请求地址(API接口地址) * async : 设置同步或者异步,默认是TRUE异步,FALSE同步 * user-name: 传递给服务器的用户名; * user-pass: 传递给服务器的密码;
-
监听AJAX状态
监听AJAX的状态,在状态为xxx的时候,获取服务器响应的内容; AJAX状态码:0 1 2 3 4 当HTTP状态码为2或者3开头,并且AJAX状态码为4时,获取响应内容;
-
调用ajax对象的send()方法,发送http请求
let xhr = new XMLHttpRequest();
xhr.open('GET','./json/xxx.json',true); // 默认异步
// 如果使用post请求,就一定要设置请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=gb2312");
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && /^(2|3)\d{2}$/.test(xhr.status)){
let result = xhr.responseText; // =>响应内容
}
}
//SEND中放的是请求主体的内容
xhr.send();
AJAX任务:发送一个请求给服务器,从服务器获取到对应的内容,从send后开始,到xhr.readystate === 4 的时候算任务结束;
22.模块化开发怎么做
所谓的模块化开发就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是实现某一特定的功能。模块化开发的基础就是函数 =>CommonJS
- 使用函数封装
- 使用对象封装
- 立即执行函数写法
23.异步加载Js的方式有哪些
-
动态创建script标签
-
<script>
标签的async="async"属性该属性是HTML5中新增的异步支持;但是这种加载方式执行完之前会阻止onload事件的触发,而现在很多页面的代码都在onload时还执行额外的渲染工作,所以还是会阻塞部分页面的初始化处理。需要Chrome、FireFox、IE9+浏览器支持
-
<script>
标签的defer="defer"属性defer 属性规定是否对脚本执行进行延迟,直到页面加载为止;
-
onload时的异步加载
这种方法只是把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。
注:DOMContentLoaded与load的区别。前者是在document已经解析完成,页面中的dom元素可用,但是页面中的图片,视频,音频等资源未加载完,作用同jQuery中的ready事件;后者的区别在于页面所有资源全部加载完毕。
-
es6模块type="module"属性
浏览器对于带有type="module"的
<script>
,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>
标签的defer属性 。
24.xml和 json的区别
它们都是一种数据交换格式。
- XML
- 格式统一,符合标准;
- 容易与其他系统进行远程交互,数据共享比较方便。
- XML文件庞大,文件格式复杂,传输占带宽
- 服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
- 客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
- JSON
- 数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
- 易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;
- 支持多种语言,便于服务器端的解析;
- 因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。
25.webpack如何实现打包的
webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖的文件,使用loaders来处理它们,最后打包成一个或多个浏览器可识别的js文件
核心思想:
一切皆模块: 正如js文件可以是一个“模块(module)”一样,其他的(如css、image或html)文件也可视作模 块。我们可以将事物(业务)分割成更小的易于管理的片段,从而达到重复利用等的目的。
按需加载: 因此Webpack使用许多特性来分割代码然后生成多个“bundle”文件,而且异步加载部分代码以实现按需加载。
打包原理
- 把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载。
26.常见web安全及防护原理
- sql注入原理
通过把sql命令插入到web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意sql命令
1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。
2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息
- xss
恶意攻击者往Web页面插入恶意script代码,当用户浏览页面时会被执行,从而达到恶意攻击;
1.首先代码里对用户输入的地方和变量都需要仔细检查长度和对”<” , ”>” , ”;” , ”’” 等字符做过滤;其次任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。这一个层面做好,至少可以堵住超过一半的XSS 攻击。
2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息
- csrf
跨站请求伪造
通过sxx和链接欺骗用户,挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。通过验证码的方法
XSS与CSRF的区别
1.XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。
CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。
2.要完成一次CSRF攻击,受害者必须依次完成两个步骤:
a.登录受信任网站A,并在本地生成Cookie。
b.在不登出A的情况下,访问危险网站B。
3. xss目标是服务器,csrf目标是用户;
27.用过哪些设计模式
- 工厂模式
目的是批量生成多个实例,通过传参去描述具体的实例,把生产后的对象返回到外界使用。
function fn(name, age) {
let obj = {}
obj.name = name;
obj.age = age;
return obj;
}
let 机器人1 = fn('小白', 11)
let 机器人2 = fn('小hei', 10)
let 机器人3 = fn('小ly', 9)
- 构造函数
把属性或者方法挂在this上,然后去new这个函数
function CreatePerson(name,age){
this.name = name;
this.age = age;
}
CreatePerson('蓝蓝',15); // this=>window 普通函数执行;
let person1 = new CreatePerson('黄黄',12);
console.log(person1)
- 原型模式
当构造函数中添加方法的时候,每new一次就生成一个同类,这些方法虽然同类但是各自不相等,这就导致如果new若干次,那么就会生成若干个一模一样的方法,这样对性能是不友好的所以我们要使用原型的方式去把方法挂在原型上。
原型: 当定义一个函数的时候,这个函数自身有一些属性 或者方法,其中有一个属性叫做prototype,这个 属性就叫原型
prototype它是一个对象, 如果实例化对象上没有某个属性或者方法 =>还会去这个实例化对象的构造函数中的原型下去查找 该属性或者方法=>如果构造函数的原型上没有这个方法,那么还会去 原型下的原型链(proto)中查找,找到Object.prototype
function Police(name,id){
this.name = name;
this.job = '警察';
this.uniform = '警服';
this.id = id;
this.zongzhi = '为人民服务'
}
Police.prototype.wq = function(){
console.log('带枪');
}
Police.prototype.wg = function(){
console.log('胸口碎大石');
}
Police.prototype.cadd = function(){
console.log('抓贼');
}
let p1 = new Police('黑猫警长',001);
- 发布订阅模式 参考 www.cnblogs.com/Decmber/p/4…
28.为什么要同源限制
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。
29.offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别
offsetWidth/offsetHeight返回值包含content + padding + border ,如果有滚动条,也不包含滚动条
clientWidth/clientHeight返回值只包含content + padding,如果有滚动条,也不包含滚动条
scrollWidth/scrollHeight返回值包含content + padding + 溢出内容的尺寸
30.javascript有哪些方法定义对象
方式一: 通过对象字面量表示法(又称为直接量、原始方式)。
var obj = {name:"mo~};
方式二: 通过new和构造函数Object()、Object.create等。
var obj = new Object();
let obj = Object.create(null);
方式三:
自定义一个对象的构造函数,然后实例化对象。
function a(o){
this.name = "mo~"
}
var obj = new a();
31.说说你对promise的了解
Promise的诞生就是为了解决异步请求中的回调地狱问题,它是一种设计模式,用来管理异步编程的,它本身不是异步的; juejin.cn/post/684490…
32.谈谈你对AMD、CMD的理解,
AMD 是提前执行,CMD是延迟执行。
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块;
CMD推崇就近依赖,只有在用到某个模块的时候再去移入。
CommonJS是服务器端模块的规范,Node.js采用了这个规范。CommonJS规范加载模块是同步的;
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
目前这些规范的实现都能达成浏览器端模块化开发的目的。
AMD、CMD都是异步加载;
对于依赖的模块AMD是提前执行
AMD在加载模块完成后就会执行该模块,所有模块都加载执行完后会进入require的回调函数,依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行。
CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的
载完就执行,而cmd是在require语句的时候进行的。所以cmd的执行顺序和定义顺序相同。
AMD
// 定义模块 myModule.js
define(['dependency'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName
};
});
// 加载模块
require(['myModule'], function (my){
  my.printName();
CMD
// 定义模块 myModule.js
define(function(require, exports, module) {
var $ = require('jquery.js')
$('div').addClass('active');
});
// 加载模块
seajs.use(['myModule.js'], function(my){
33.web开发中会话跟踪的方法有哪些
cookie
session
url重写
隐藏input
ip地址
34.介绍js有哪些内置对象?
JS内置对象分为数据封装类对象和其他对象
数据封装类对象:String,Boolean,Number,Array,和Object;
其他对象:Function,Arguments,Math,Date,RegExp,Error
35.说几条写JavaScript的基本规范?
(1)不要在同一行声明多个变量。
(2)请使用 ===/!==来比较true/false或者数值
(3)使用对象字面量替代new Array这种形式
(4)不要使用全局函数。
(5)Switch语句必须带有default分支
(6)函数不应该有时候有返回值,有时候没有返回值。
(7)For循环必须使用大括号
(8)If语句必须使用大括号
(9)for-in循环中的变量,应该使用var关键字明确限定作用域,从而避免作用域污染。
36.eval是做什么的?
eval()的作用
- 把字符串参数解析成JS代码并运行,并返回执行的结果;
eval("2+3");//执行加运算,并返回运算值。
eval("var age=10");//声明一个age变量
- 由JSON字符串转换为JSON对象的时候可以用eval,
var json="{name:'Mr.CAO',age:30}";
var jsonObj=eval("("+json+")");
console.log(jsonObj);
注意事项 :
应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
37.null,undefined 的区别?
相同点:
+ if 判断语句中,两者都会被转换为false
+ 值判断(==)结果相等
不同点:
+ Number转换的值不同 null => 0 , undefined=> NaN
+ 类型不同
+ null的类型是Object,表示"没有对象",即该处不应该有值。
+ 作为函数的参数,表示该函数的参数不是对象
+ 清空对象直接赋值为null
+ 作为对象原型链的终点
+ undefined的类型为Undefined,表示"缺少值",就是此处应该有一个值,但是还没有定义。
+ 变量被声明了,但没有赋值时,就等于undefined
+ 调用函数时,参数未赋值,该参数等于undefined
+ 对象没有赋值的属性
+ 函数没有返回值时,默认返回undefined
38.javascript 代码中的”use strict”;是什么意思 ? 使用它区别是什么?
比如说 将”use strict”放在函数体的第一行,则整个函数以”严格模式”运行
优点
+ 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
+ 消除代码运行的一些不安全之处,保证代码运行的安全;
+ 提高编译器效率,增加运行速度;
+ 为未来新版本的Javascript做好铺垫。
缺点: 现在网站的 JS 都会进行压缩,一些文件用了严格模式,而另一些没有。这时这些本来是严格模式的文件,被 merge 后,这个串就到了文件的中间,不仅没有指示严格模式,反而在压缩后浪费了字节。
限制内容
变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀0表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用fn.caller和fn.arguments获取函数调用的堆栈
增加了保留字(比如protected、static和interface)
39.defer和async?
40.attribute和property的区别是什么?
41.ECMAScript6 怎么写class么,为什么会出现class这种东西? blog.csdn.net/u014328357/…
42.常见兼容性问题 blog.csdn.net/Calla_Lj/ar…
43.函数防抖节流的原理 blog.csdn.net/suwu150/art…
44.原始类型有哪几种?null是对象吗?
原始类型:
undefined、null、string、number、boolean、symbol(es6新增)
null并不是对象:
null其实并不是一个对象,尽管typeof null 输出的是object,但是这其实是一个bug。在js最初的版本中使用的是32位系统,为了性能考虑地位存储变量的类型信息,000开头表示为对象类型,然而null为全0,故而null被判断为对象类型。
45.为什么console.log(0.2+0.1==0.3) //false blog.csdn.net/axiba01/art…
46.说一下JS中类型转换的规则?
- 转换为数值类型:Number(mix)、parseInt(string,radix)、parseFloat(string)
- 转换为字符串类型:toString(radix)、String(mix)
- 转换为布尔类型:Boolean(mix)
1. Number
+ Boolean : true => 1 false => 0
+ null : => 0
+ undefined : => NaN
+ 字符串 : 只要字符串中包含任意一个非有效数字字符(第一个点除外)结果都是NaN,空字符串会变成数字零;
+ 对象 : 则调用对象的valueOf()方法,然后依据前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,再次依照前面的规则转换返回的字符串值。
+parseInt(string, radix)
(1)忽略字符串前面的空格,直至找到第一个非空字符
(2)如果第一个字符不是数字符号或者负号,返回NaN
(3)如果第一个字符是数字,则继续解析直至字符串解析完毕或者遇到一个非数字符号为止
(4)如果上步解析的结果以0开头,则将其当作八进制来解析;如果以x开头,则将其当作十六进制来解析
(5)如果指定radix参数,则以radix为基数进行解析
+parseFloat(string)
它的规则与parseInt基本相同,但也有点区别:字符串中第一个小数点符号是有效的,另外parseFloat会忽略所有前导0,如果字符串包含一个可解析为整数的数,则返回整数值而不是浮点数值。
2.String
1) 如果有toString()方法,则调用该方法(不传递radix参数)并返回结果
2) 但是和undefined 一样转换为字符串的结果就是 字符串 null/undefined,只是不让用
3) Object “[object objectname]”
3.Boolean
只有 0、NaN、''、null、undefined 五个值转换为FALSE,其余都转换成TRUE(而且没有任何的特殊情况)
47.深拷贝和浅拷贝的区别?如何实现
深拷贝和浅拷贝最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用地址(深拷贝拷贝值,浅拷贝拷贝址);
深拷贝在计算机中开辟了一块内存地址用于存放复制的对象,而浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。
浅拷贝 : Object.assign、 扩展运算符 ... 、 Array.prototype.slice()、 Array.prototype.concat() 等
深拷贝
- 递归
let arr = [1,2,3,4,[5,{ary:[{name:'小强'}]}]];
function deepClone(arr){
//先声明一个数组,去存克隆出来的内容
let arr2 = [];
//循环传进来的对象
for(let i=0;i<arr.length;i++){
//判断对象中的某个值是否为引用类型
//如果是,就继续调用deepClone把引用值传到函数中
if(arr[i] && typeof arr[i] === 'object'){
arr2[i] = deepClone(arr[i])
}else{
//如果是简单类型就直接赋值
arr2[i] = arr[i];
}
}
return arr2;
}
Object.prototype.xxoo = '哈哈';
function deepClone(obj){
//先声明一个数组,去存克隆出来的内容
//判断obj是否为数组,是数组就o就为[],否则为{}
let o = obj.push?[]:{};
//循环传进来的对象
for(let attr in obj){
// for(let i=0;i<arr.length;i++){
//判断对象中的某个值是否为引用类型
//如果是,就继续调用deepClone把引用值传到函数中
if(obj.hasOwnProperty(attr)){
if(typeof obj[attr] === 'object'){
o[attr] = deepClone(obj[attr])
}else{
//如果是简单类型就直接赋值
o[attr] = obj[attr];
}
}
}
return o;
}
let arr2 = deepClone(arr);
let arr2 = JSON.parse(JSON.stringify(arr));
48.如何判断this?箭头函数的this是什么
**window:**
- 1、直接在全局输出this;
- 2、函数打印this,并直接调用;
- 3、定时器中**普通函数**为window;
- 4、匿名函数自执行;
**事件中的this:**
- 哪个对象触发,this就是那个对象
**new 构造函数**
- -this 就是实例
**箭头函数:**
- this走定义箭头函数的域;
- 箭头函数不能new,一new就报错;
- 箭头函数也没有arguments
**对象中的this**
let obj = {fn:function(){console.log(this)}}
1、给某个元q素绑定方法,当事件触发方法执行的时候,方法中的this是当前操作的元素本身;
2、当方法执行的时候,我们看方法前面是否有没有点,没有点的this是window或者是undefined,有点,点前边是谁this就是谁;
49. == 和 ===的区别
== 相对比较
在判断的时候对数值做了 "隐式转换"
1.其他类型跟数字进行比较时 先转换成数字 再进行比较
2.其他类型跟boolean值进行比较 两边值都转换成数字 再比较
3.字符串和引用类型进行比较 把引用类型转换成字符串
4.引用类型和引用类型比较 比较的是引用地址
5.特殊记 null== undefined NaN 跟任何值都不相等(包括跟自己)
null 和 undefined 相对比较 为true,它两和其他类型都不相等; === 绝对比较
不做任何转换,值与类型必须完全相同,比较严格
50. 什么是闭包
函数套函数,子函数使用父函数的参数或变量,并且子函数被外界所引用,此时父级形成闭包环境,父级的参数或变量不被浏览器的垃圾回收机制回收,此时,打印父函数的返回值,有个属性为scopes,scopes下有个closure的属性,就是闭包;
+ 使用闭包可以存储父级的参数或变量,不被外界干扰;
+ 避免代码冲突
51. JavaScript原型,原型链 ? 有什么特点?
原型
+ 每一个函数数据类型的值都有一个天生自带的对象属性:prototype (用来存储实例公用的属性和方法的);
原型链
+ 每一个对象数据类型的值,也有一个天生自带的属性:__proto__,指向所属类的prototype,prototype也是一个对象,它的__proto__指向prototype的原型,就这样可以一直通过__proto__想上找,这就是原型链,当向上找找到Object的原型的时候,这条原型链就算到头了。
原型链查找机制;
1、先找自己私有的属性,有则调取使用,没有继续找;
2、基于\__proto\__找所属类原型上的方法(Fn.prototype),如果还没有则继续基于\__proto__往上找,一直找到Object.prototype为止;
原型链实现了继承。原型链存在两个问题:
1.包含引用类型值的原型属性会被所有实例共享。
2.在创建子类型时,无法向超类型的构造函数中传递参数。
52. call、apply以及bind函数内部实现是怎么样的
都可以改变函数this的指向,并且可以传递参数。
不同的是:call和apply改变了函数的this,并且执行了该函数,而bind是改变了函数的this,并返回一个函数,但不执行该函数。
call 的实现原理;改变this指向,并把调用函数执行;
1.设置默认this = window;
2.接收剩余arguments,预做参数传递;
3.改变this=> 把当前this(实际调用函数)当作属性值传递给,新指定的this,最后调用此属性的方法,即调用该函数;
~ function () {
/*生成随机函数名:时间戳的方式*/
function queryRandomName(){
let time=new Date().getTime();
return '$fn'+time;
}
/*模拟CALL方法改变函数中的THIS*/
function call(context) {
context = context || window;
let args = Array.from(arguments).slice(1),
result = null,
ran = queryRandomName();
context[ran] = this;
result = context[ran](...args);
delete context[ran];
return result;
}
Function.prototype.call = call;
}();
bind实现
~ function () {
function bind(context) {
context = context || window;
let outerArgs = [].slice.call(arguments, 1),
_this = this;
return function anonymous() {
let innerArgs = [].slice.call(arguments, 0);
//=>在这里要把FUNC执行
_this.apply(context, outerArgs.concat(innerArgs));
}
};
Function.prototype.bind = bind;
}();
// document.body.onclick = func.bind(obj, 100, 200);
53.为什么会出现setTimeout倒计时误差?如何减少
定时器是属于 宏任务(macrotask) 。如果当前 执行栈 所花费的时间大于 定时器 时间,那么定时器的回调在 宏任务(macrotask) 里,来不及去调用,所有这个时间会有误差。
setTimeout(function () {
console.log('setTime');
}, 1000);
某个执行时间很长的函数();
如果定时器下面的函数执行要 5秒钟,那么定时器里的log 则需要 5秒之后再执行,函数占用了当前 执行栈 ,要等执行栈执行完毕后再去读取 微任务(microtask),等 微任务(microtask) 完成,这个时候才会去读取 宏任务(macrotask) 里面的 setTimeout 回调函数执行。setInterval 同理,例如每3秒放入宏任务,也要等到执行栈的完成。
53. 谈谈你对JS执行上下文栈和作用域链的理解
一、JS执行上下文
执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行。
执行上下文类型分为:全局执行上下文和函数执行上下文。
执行上下文创建过程中,需要做以下几件事:
(1)创建变量对象:首先初始化函数的参数arguments,提升函数声明和变量声明。
(2)创建作用域链(Scope Chain):在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。
(3)确定this的值,即 ResolveThisBinding
二、作用域
作用域就是变量和函数的可访问范围,控制这个变量或者函数可访问行和生命周期。
分为:全局作用域、函数作用域、块级作用域。
+ 全局作用域顾名思义,浏览器下就是 window ,作用域链的顶级就是它,那么只要不是被函数包裹的变量或者函数,它的作用域就是全局。
+ 而函数作用域,就是在函数的体内声明的变量、函数及函数的参数,它们的作用域都是在这个函数内部。
三、作用域链
我们知道函数在执行时是有个执行栈,在函数执行的时候会创建执行环境,也就是执行上下文,在上下文中有个大对象,保存执行环境定义的变量和函数,在使用变量的时候,就会访问这个大对象,这个对象会随着函数的调用而创建,函数执行结束出栈而销毁,那么这些大对象组成一个链,就是作用域链。那么函数内部未定义的变量,就会顺着作用域链向上查找,一直找到同名的属性。
54. new的原理是什么?通过new的方式创建对象和通过字面量创建有什么区别?
55. prototype 和 proto 区别是什么?
+ js里所有的对象都有proto属性(对象,函数),指向构造该对象的构造函数的原型。
+ 只有函数function才具有prototype属性。这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
56. 使用ES5实现一个继承?
function Father(name) {
this.name = name
this.attr = "father's attr."
}
Father.prototype = {
eat:function(){
console.log(this.name+' eat something.')
}
}
function Super() {
this.constructor = Child
}
Super.prototype = Father.prototype
Child.prototype = new Super() // 继承父类的原型方法
function Child() {
Father.apply(this, arguments) // 继承父类的属性
this.attr = "child's attr"
}
57. 取数组的最大值(ES5、ES6)
// ES5
Math.max.apply(null, arr);
//ES6
Math.max(...arr);
arr.reduce((accumulator, currentValue)=>{
return accumulator = accumulator > currentValue ? accumulator : currentValue
});
58. ES6新的特性有哪些?
1.新增了块级作用域(let,const)
2.提供了定义类的语法糖(class)
3.新增了一种基本数据类型(Symbol)
4.变量的解构赋值
5.函数参数允许设置默认值,引入了rest参数,新增了箭头函数。
6.数组新增了一些API,如isArray / from / of 方法;数组实例新增了 entries(),keys() 和 values() 等方法。
7.对象和数组新增了扩展运算符
8.ES6新增了模块化(import / export)
9.ES6新增了Set和Map数据结构。
10.ES6原生提供Proxy构造函数,用来生成Proxy实例
11.ES6新增了生成器(Generator)和遍历器(Iterator)
59. promise 有几种状态, Promise 有什么优缺点 ?
Promise的三种状态:
1.初始化,状态:pending
2.当调用resolve(成功),状态:pengding=>fulfilled
3.当调用reject(失败),状态:pending=>rejected
promise的优缺点
优点:
1.Promise 分离了异步数据获取和业务逻辑,有利于代码复用。
2.可以采用链式写法
3.一旦 Promise 的值确定为fulfilled 或者 rejected 后,不可改变。
缺点:
promise一旦新建,就会立即执行,无法取消
如果不设置回掉函数,promise内部抛出的错误就不会反应到外部
代码冗余,语义不清
60.Promise构造函数是同步还是异步执行,then呢 ?promise如何实现then处理 ?
Promise是用来管理异步编程的,它本身不是异步的;
语法:new Promise( function(resolve, reject) {...} /* executor */ );
1.new Promise的时候回立即把executor函数执行(只不过我们一般会在executor函数中处理一个异步操作)
2. Promise不仅把EXE执行,而且还给EXE传递两个参数(两个参数也是函数类型);
* resolve函数 : 它执行代表Promise处理的异步事情是成功的,把Promise的状态给改为fulfilled
* reject函数:它执行代表Promise处理的异步事情是失败的,把Promise的状态改为rejected
3. EXE函数中放的就是当前要处理的异步操作事情
/*
* new Promise的时候先执行executor函数,在这里开启一个异步操作的任务
(此时不等:把其放入到EventQue任务队列中),继续执行
p1.then基于then方法,存储起来两个函数(此时这两个函数还没有执行);当executor函数中的异步操作结束了,基于resolve/reject控制Promise状态,而决定执行then存储的函数中执行哪一个
*/
let promiseExamp = new Promise((resolve,reject)=>{
// 这里一般存放的都是我们即将要处理的异步任务,任务成我们执行resolve,任务失败我们执行reject(当然写同步的也可以);
let ran = Math.random();
setTimeout(()=>{
if(ran < 0.5){
reject(ran);
return;
}
resolve(ran);
},1000)
});
promiseExamp.then(result => {
//=>状态为FULFILLED成功后执行(RESULT:[[PromiseValue]])
console.log('成功: ' + result);
}, error => {
//=>状态为REJECTED失败后执行
console.log('失败: ' + error);
});
/*
resolve/reject的执行,不论是否放到一个异步操作中,都需要等待then先执行完,把方法存储好,才能更改状态后执行then中对应的方法=> 此处是一个异步操作(所以有人说promise是异步的);
*/
61. Promise和setTimeout的区别 ?
etTimeout和Promise调用的都是异步任务,promise的任务会在当前事件循环末尾中执行,而settimeout中的任务是在下一次事件循环中执行。
62. 如何实现 Promise.all ?
function promiseAll(promises){
return new Promise(function(resolve,reject) {
//promises必须是一个数组
if(!(promises instanceof Array)) {
throw new TypeError("promises must be an Array");
}
var len = promises.length,
resolvedCount = 0,
resolvedArray = new Array(len);
for(var i = 0;i < len ;i++) {
(function(i) {
Promise.resolve(promises[i])
.then(value => {
resolvedCount++;
resolvedArray[i] = value;
if(resolvedCount == len) {
return resolve(resolvedArray);
}
},re => {
return reject(re);
})
.catch(re => {
console.log(re);
})
})(i)
}
})
}
63. 如何实现 Promise.finally ?
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
64. 如何判断img加载完成
65. 如何阻止冒泡?
1.什么是冒泡事件?
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序, 如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播, 从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。
2.默认行为
浏览器的一些默认的行为。例如:点击超链接跳转,点击右键会弹出菜单,滑动滚轮控制滚动条等
3.事件模型
从目标点由下而上 直到window 叫做冒泡阶段 在这个过程中,如果上级和下级同理有祖先关系 绑定同一事件函数 先触发目标 再触发目标的上级 这整个过程叫做事件流
冒泡好处:
在嵌套关系中,给上层元素绑定事件,可以通过事件源查到事件触发的对象(元素),避免把事件处理器添加到多个子级元素上
阻止冒泡:
ev.cancelBubble = true;
它不是一个标准,但是所有浏览器都支持
ev.stopPropagation();
它是标准,但是在低版本IE下是不兼容的
function stopBubble(e) {
if(e && e.stopPropagation){
e.stopPropagation();
} else {
window.event.cancelBubble = true; //默认为false
}
};
如何阻止默认事件?
preventDefault()
但是只有当cancelable属性设置为true的事件,才可以使用preventDefault()来取消事件默认行为event.returnValue = false;
=> IE
function stopDefault(e){
if(e && e.preventDefault) {
e.preventDefault();
} else {
window.event.returnValue = false;
}
return false;
};
66. ajax请求时,如何解释json数据
json是一种轻量级交互格式,本质上都是字符串,常用于前后端的数据交互,本质上就是字符串.
前端在解析后端发来的数据,使用JSON.parse()方法把字符串转为json对象.
前端在向后端发送数据,使用JSON.stringify()方法把json对象转为字符串. blog.csdn.net/qq_38601916…
67. json和jsonp的区别?
JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。 www.jianshu.com/p/c6ac7d344…
68.如何用原生js给一个按钮绑定两个onclick事件?
// 事件监听 绑定多个事件
var btn = document.getElementById("btn4");
btn.addEventListener("click",hello1);
btn.addEventListener("click",hello2);
function hello1(){
alert("hello 1~");
}
function hello2(){
alert("hello 2~");
}
69. 拖拽会用到哪些事件 blog.csdn.net/xiaomo_ay/a…
70. document.write和innerHTML的区别 www.cnblogs.com/fly-xfa/p/6…
71. .jQuery的事件委托方法bind 、live、delegate、on之间有什么区别? blog.csdn.net/qq_39579242…
71. 浏览器是如何渲染页面的? www.jianshu.com/p/b7b7a5904…
72.$(document).ready()方法和window.onload有什么区别?
1.执行时间不同
+ window.onload必须等到页面内的所有元素()加载完毕后才能执行。
注:所有元素是指包括页面结构、内容及所有关联文件,如站内与站外的js与css文件、图片等。
+ $(document).ready()是页面DOM结构绘制完毕后就执行,不必等到加载完毕。
注:DOM结构回执完毕时网页的所有元素对JQuery而言都是可以访问的,但是,这并不意味着这些元素关联的文件都已经下载完毕。
2.执行次数不同
+ window.onload不能同时执行多个,如果同一个页面上面有多个window.onload方法(包括关联js文件中),只会执行最后一个window.onload,也就是向上覆盖。
+$(document).ready()可以同时执行多个,如果同一个页面上有多个$(document).ready()方法(包括关联js文件中),JQuery能够很好地处理这些情况,每次调用$(document).ready()方法都会在现有的行为上追加新的行为,这些行为函数会根据注册的顺序依次执行。
73. jquery中.post()提交有区别吗?
+ 相同点:都是异步请求的方式来获取服务端的数据;
+ 异同点:
1、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。
2、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。
3、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多
4、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。
74.对前端路由的理解?前后端路由的区别
www.jianshu.com/p/e281c4681…
75. XMLHttpRequest:XMLHttpRequest.readyState;状态码的意思 juejin.cn/post/684490…
76. 正则表达式常见面试题 juejin.cn/post/684490…
77. 手写一个类的继承