网站的外链怎么做,图书购物网站开发的业务分析,网络规划设计师考试资料,查公司查企业用什么软件一.热门js面试
1.简述同步和异步的区别? 同步: 浏览器访问服务器请求,用户看到页面刷新 ,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作 异步: 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求,等请求完,页面不刷新,新内容也会出现,用户看到…一.热门js面试
1.简述同步和异步的区别? 同步: 浏览器访问服务器请求,用户看到页面刷新 ,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作 异步: 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求,等请求完,页面不刷新,新内容也会出现,用户看到新内容 2.怎么添加,移除,复制,创建和查找节点 1) 创建节点 createDocumentFragment() // 创建一个DOM片段 createElement() // 创建一个具体的元素 createTextNode() // 创建一个文本节点 2) 添加,移除,替换,插入 appendChild() removeChild() replaceChild() insertBefore() 3) 查找 getElementByTagName() // 通过标签名称 getElementByName() // 通过元素的Name属性的值 getElementById() // 通过元素ID,唯一性 3.实现一个函数clone可以对JavaScript深度克隆 原型链 Object.prototype.clone function() {var o this.constructor Array ? [] : {}for(var e in this) {o[e] (typeof this[e] object this[e] ! null) ? this[e].clone() : this[e];}return o;
}var o1{a:1,b:2,c:{aa:11,bb:22}}
var o2o1.clone()
o2.c.aa33
console.log(o1,o2) 或者function递归 function clone (obj) {var o1if(typeof obj object obj ! null) {o1 Array.isArray(Array) ? [] : {}} else {o1 obj}for (let key in obj) {o1[key] (typeof obj[key] object obj ! null) ? clone(obj[key]) : obj[key]}return o1}var o1{a:1,b:2,c:{aa:11,bb:22}}var o2clone(o1)o2.c.aa33;console.log(o1,o2); 确定对象类型的方法 constructor属性返回创建实例对象的构造函数。通过检查constructor是否为Array代码试图判断对象是否为数组类型。这是一种比较直观的方式来区分对象和数组。例如对于一个数组let arr [1, 2, 3];arr.constructor返回Array对于一个普通对象let obj { key: value };obj.constructor返回Object。 类型判断方法对比 typeof局限性虽然typeof可以区分基本数据类型如number、string、boolean等但对于对象和数组typeof都返回object。例如typeof []和typeof {}都返回object所以仅用typeof无法区分数组和普通对象。instanceof适用性instanceof可以用来检查一个对象是否是某个构造函数的实例。但是instanceof在跨 iframe 或者复杂的继承场景下可能会出现问题并且在判断基本数据类型的包装对象如new Number(1)时可能不符合预期。而这里使用constructor相对简单直接只要对象的constructor属性没有被篡改就可以比较准确地判断是否为数组。Object.prototype.toString.call使用场景更广比如可以判断数据类型是不是Promise var o1 Promise.resolve(1);console.log(Object.prototype.toString.call(o1))
// VM12232:1 [object Promise] 潜在风险和注意事项 constructor属性可能被修改对象的constructor属性是可以被修改的。例如let arr [1, 2, 3]; arr.constructor Object;这样的操作会导致代码中的类型判断出错。所以这种判断方式在一些复杂的、不可控的代码环境中可能存在风险。更安全的替代方法更安全的判断数组的方法可以是使用Array.isArray()函数。例如var o1 Array.isArray(obj)? [] : {};这样的写法会更加可靠因为Array.isArray()不会受到constructor属性被修改的影响。使用Object.prototype.toString.call function clone (obj) {var o1if(typeof obj object obj ! null) {o1 Array.isArray(Array) ? [] : {}} else {o1 obj}for (let key in obj) {o1[key] (typeof obj[key] object obj ! null) ? clone(obj[key]) : obj[key]}return o1}var o1{a:1,b:2,c:{aa:11,bb:22}}var o2clone(o1)o2.c.aa33;console.log(o1,o2); 4.如何消除一个数组中重复的元素 1) arr.indexOf(item) -1时往arr数组push元素item: function qc (arr1) {let arr []for (let i 0;i arr1.length; i) {if (arr.indexOf(arr1[i]) -1) {arr.push(arr1[i])}}return arr
}var arr1 [1,1,3,5,2,24,4,4,a,a,b];console.log(qc(arr1)); 2) Set var arr1 [1,1,3,5,2,24,4,4,a,a,b];var arr [...(new Set(arr1))]console.log(arr) 5.写一个返回闭包的函数 闭包是JavaScript的一个难点,也是它的特色,很多高级应用都要依靠闭包.闭包就是能够读取其他函数内部变量的函数.可以把闭包简单理解为定义在一个函数内部的函数 闭包的三个特性: 函数嵌套函数函数内部可以引用函数外部的参数和变量参数和变量不会被垃圾回收机制回收 闭包就是一个函数的返回值为另一个函数,在outer外部可以通过这个返回的函数访问outer内部的局部变量 function outer() {var val0;return function() {val1document.write(val br /);}
}var outObjouter()
outObj()
outObj()
outObjnull//val被回收var outObj1outer()
outObj1()
outObj1()
outObj1null//val被回收 闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗如果上例中定义很多outer()则内存中会保存很多val变量 JavaScript的垃圾回收机制: 在JavaScript中,如果一个对象不再被引用,那么这个对象就会被GC回收如果两个对象互相引用,而不再被第三者所引用,那么这两个互相引用的对象也会被回收 使用闭包有什么好处: 希望一个变量长期驻扎在内存中避免全局变量的污染私有成员的存在 6.使用递归完成1到100的累加 1) 递归累加 function sum(num) {if(num 1) return 1return num sum(num - 1)
}
console.log(sum(100)) 2) 转换为数组reduce相加 // 创建一个从1到100的数组
const numbers Array.from({ length: 100 }, (_, index) index 1);// 使用 reduce 方法将数组中的数字相加
const sum numbers.reduce((acc, cur) acc cur, 0);
console.log(sum); // 输出: 5050 7.JavaScript有哪几种数据类型 基本数据类型: 字符串 String 数字 Number 布尔 Boolean 复合数据类型: 数组 Array 对象 Object 特殊数据类型: 空对象 Null 未定义 Undefined 引用类型: 数组,对象,function 8.如何判断数据类型 判断js中的数据类型的几种方法: typeof、instanceof、 constructor、 prototype、 $.type()/jquery.type(), 1) 最常见的判断方法typeof 使用场景: typeof 可以判断function的类型在判断除Object类型的对象时比较方便。 2) 判断已知对象类型的方法 instanceof alert(c instanceof Array) --------------- true
alert(d instanceof Date)
alert(f instanceof Function) ------------ true
alert(f instanceof function) ------------ false使用场景: 注意instanceof 后面一定要是对象类型并且大小写不能错该方法适合一些条件选择或分支。 3) 根据对象的constructor判断 constructor alert(c.constructor Array) ---------- true
alert(d.constructor Date) ----------- true
alert(e.constructor Function) ------- true
注意 constructor 在类继承时会出错
egfunction A(){};function B(){};A.prototype new B(); //A继承自Bvar aObj new A();alert(aobj.constructor B) ----------- true;alert(aobj.constructor A) ----------- false;
而instanceof方法不会出现该问题对象直接继承和间接继承的都会报truealert(aobj instanceof B) ---------------- true;alert(aobj instanceof B) ---------------- true;
言归正传解决construtor的问题通常是让对象的constructor手动指向自己aobj.constructor A; //将自己的类赋值给对象的constructor属性alert(aobj.constructor A) ----------- true;alert(aobj.constructor B) ----------- false; //基类不会报true了; 注意: constructor在类继承时会出错解决constructor的问题是让对象的constructor手动指向自己 比如使用Object.create继承后再加一句functionName.prototype.constructorfunctionName: function Animal() {
}
function Cat() {Animal.call(this)
}
Cat.prototype Object.create(Animal.prototype)
var cat new Cat()console.log(cat.constructor) // Animal
console.log(cat instanceof Cat) // true
console.log(cat instanceof Animal) // true// 期望的是cat.constructor应该是Cat类,所以重新让prototype对象的constructor指向自己
Cat.prototype.constructorCat
console.log(cat.constructor) // Cat
console.log(cat instanceof Cat)
console.log(cat instanceof Animal) // true 9.console.log(12)和console.log(1-2)的打印结果 console.log(12) //12
console.log(1-2) //-1 10.js事件委托是什么,原理是什么? 事件委托: 利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件 事件冒泡: 就是事件从最深的节点开始然后逐步向上传播事件。 11.如何改变函数内部的this指针的指向 1) bind fun.bind(thisArg, arg1, arg2, ...) 直接改变这个函数的this指向并且返回一个新的函数,之后再次调用这个函数的时候this都是指向bind绑定的第一个参数,bind传参方式根call方法一致 thisArg当绑定函数被调用时,该函数会作为原函数运行时的this指向.当使用new操作符调用绑定函数时,该参数无效 arg1,arg2,...,当绑定函数被调用时,这些餐宿将置于实参之前传递给绑定的方法 2) call fun.call(thisArg, arg1, arg2, ...)call和apply的用法几乎一样,唯一的不同是传递的参数不同,call只能一个参数一个参数传入thisArg:在fun函数运行时指定的this值,需要注意的是,指定的this值并不一定是该函数执行时真正的this值如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象arg1,arg2,...指定的参数列表 3) apply fun.apply(thisArg, []arg1, arg2, ...])apply则只支持传入一个数组,哪怕一个参数也是数组形式.最终调用函数的时候这个数组会拆成一个个参数分别传入,需要注意的是,指定的this值并不一定是该函数执行时真正的this值如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this值会指向该原始值的自动包装对象[arg1,arg2,...]指定的参数列表 4) 总结 当我们使用一个函数需要改变this指向的时候才会用到call,apply,bind如果你要传递的参数不多,则可以使用fn.call(thisArg,arg1,arg2,...)如果你要传递的参数很多,则可以使用数组将参数整理好调用fn.apply(thisArg,[arg1,arg2,...])如果你想生成一个新函数长期绑定某个函数给某个对象使用,则可以使用const f1fn.bind(thisArg);f1(arg1,arg2,...);call和apply第一个参数为null/undefined,函数this指向全局对象,在浏览器中是window,在node中是global 12.跨域的几种方式? jsonp script标签是不受同源策略影响的它可以引入来自任何地方的js文件。动态添加script 使用window.name来进行跨域 window对象有个name属性该属性有个特征即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的每个页面对window.name都有读写的权限window.name是持久存在一个窗口载入过的所有页面中的并不会因新页面的载入而进行重置。 使用HTML5中新引进的window.postMessage方法来跨域传送数据 window.postMessage(message,targetOrigin) 方法是html5新引进的特性可以使用它来向其它的window对象发送消息无论这个window对象是属于同源或不同源目前IE8、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。 反向代理 websocket cors 13.谈谈垃圾回收机制的方式及内存管理 一、垃圾回收机制—GC Javascript具有自动垃圾回收机制(GC:Garbage Collecation)也就是说执行环境会负责管理代码执行过程中使用的内存。 原理垃圾收集器会定期周期性找出那些不在继续使用的变量然后释放其内存 通常情况下有两种实现方式标记清除和引用计数 标记清除 js中最常用的垃圾回收方式就是标记清除。 当变量进入环境时例如在函数中声明一个变量就将这个变量标记为“进入环境”。从逻辑上讲永远不能释放进入环境的变量所占用的内存因为只要执行流进入相应的环境就可能会用到它们。而当变量离开环境时则将其标记为“离开环境”。 引用计数的含义是跟踪记录每个值被引用的次数。 当声明了一个变量并将一个引用类型值赋给该变量时则这个值的引用次数就是1。如果同一个值又被赋给另一个变量则该值的引用次数加1。相反如果包含对这个值引用的变量又取得了另外一个值则这个值的引用次数减1。当这个值的引用次数变成0时则说明没有办法再访问这个值了因而就可以将其占用的内存空间回收回来。这样当垃圾回收器下次再运行时它就会释放那些引用次数为0的值所占用的内存。 二、内存管理 1、Javascript引擎基础GC方案是simple GCmark and sweep标记清除即 1遍历所有可访问的对象。2回收已不可访问的对象。 2、GC的缺陷 和其他语言一样javascript的GC策略也无法避免一个问题GC时停止响应其他操作这是为了安全考虑。而Javascript的GC在100ms甚至以上对一般的应用还好但对于JS游戏动画对连贯性要求比较高的应用就麻烦了。这就是新引擎需要优化的点避免GC造成的长时间停止响应。 3、GC优化策略 1分代回收Generation GC 这个和Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象多回收“临时对象”区young generation少回收“持久对象”区tenured generation减少每次需遍历的对象从而减少每次GC的耗时2增量GC 这个方案的思想很简单就是“每次处理一点下次再处理一点如此类推” 14.清除字符串左右两端空格
//重写trim方法
if(!String.prototype.trim){String.prototype.trim function(){return this.replace(/^\s/,).replace(/\s$/,); }
}
//写fntrim去掉左右空格
function fntrim(str){return str.replace(/^\s/,).replace(/\s$/,);
}
15.js继承 父类代码如下 // 定义一个动物类
function Animal (name) {// 属性this.name name || Animal;// 实例方法this.sleep function(){console.log(this.name 正在睡觉);}
}
// 原型方法
Animal.prototype.eat function(food) {console.log(this.name 正在吃 food);
}; 1) 原型链继承 核心将父类的实例作为子类的原型 function Cat(){
}
Cat.prototype new Animal();
Cat.prototype.name cat;// Test Code
var cat new Cat();
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true核心将父类的实例作为子类的原型 特点 非常纯粹的继承关系实例是子类的实例也是父类的实例父类新增原型方法/原型属性子类都能访问到简单易于实现 缺点 要想为子类新增属性和方法必须要在new Animal()这样的语句之后执行不能放到构造器中无法实现多继承来自原型对象的所有属性被所有实例共享来自原型对象的引用属性是所有实例共享的详细请看附录代码[示例1](javascript:void(0);)创建子类实例时无法向父类构造函数传参 2) 构造继承 **核心**使用父类的构造函数来增强子类实例等于是复制父类的实例属性给子类没用到原型 function Cat(name){Animal.call(this);this.name name || Tom;
}// Test Code
var cat new Cat();
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;
}// Test Code
var cat new Cat();
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;
}// Test Code
var cat new Cat();
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;
// Test Code
var cat new Cat();
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true 特点 弥补了方式2的缺陷可以继承实例属性/方法也可以继承原型属性/方法既是子类的实例也是父类的实例不存在引用属性共享问题可传参函数可复用 缺点 调用了两次父类构造函数生成了两份实例子类实例将子类原型上的那份屏蔽了 6) 寄生组合继承 **核心**通过寄生方式砍掉父类的实例属性这样在调用两次父类的构造的时候就不会初始化两次实例方法/属性避免的组合继承的缺点 function Cat(name){Animal.call(this);this.name name || Tom;
}
(function(){// 创建一个没有实例方法的类var Super function(){};Super.prototype Animal.prototype;//将实例作为子类的原型Cat.prototype new Super();
})();// Test Code
var cat new Cat();
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
Cat.prototype.constructor Cat; // 需要修复下构造函数特点 堪称完美 缺点 实现较为复杂 16.判断一个变量是否是数组 1) isArray Array.isArray([1,2,3]) //此处返回true 2、但是某些比较老的浏览器比如IE8及以下没有实现Array的isArray方法那么就需要换一种方式来判断 Object.prototype.toString.call([1,2,3]) //返回字符串[object Array] function isArray (value) {if (Object.prototype.toString.call(value) [object Array]) {return true}return false}17.let,const,var有什么区别? let 和 const 定义的变量不会出现变量提升而 var 定义的变量会提升。let 和 const 是JS中的块级作用域let 和 const 不允许重复声明(会抛出错误)let 和 const 定义的变量在定义语句之前如果使用会抛出错误(形成了暂时性死区)而 var 不会。const 声明一个只读的常量。一旦声明常量的值就不能改变(如果声明是一个对象那么不能改变的是对象的引用地址) 18.监听函数和普通函数有什么区别? 箭头函数是匿名函数,不能作为构造函数,不能使用new箭头函数不绑定arguments,取而代之的是rest函数...解决箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值监听函数通过call或者apply方法调用一个函数时,只传入一个参数,对this没有影响箭头函数通过call或apply调用一个函数时,只传入了一个参数,对this并没有影响监听函数没有原型属性箭头函数不能当做Generator函数,不能使用yield关键字 19.随机取1-10的整数 Math.floor(Math.random()*101) 20.new具体做了什么? 创建一个空对象并且this变量引用该对象同时还继承了该函数的原型属性和方法被加入到this引用的对象中新创建的对象由this所引用并且最后隐式的返回this 21.Ajax原理 ajax的原理就是在用户和服务器之间加了一个中间层(ajax引擎),通过XmlHttpRequest对象来向服务器发异步请求,从服务器获取数据,然后使用JavaScript来操作DOM而更新页面.使用户操作与服务器响应异步化.这其中最关键的一步就是从服务器获得请求数据ajax的过程只涉及JavaScript,XMLHttpRequest和DOM,XMLHttpRequest是ajax的核心机制 get请求 var xhr null
xhr new XMLHttpRequest()
// 连接服务器
xhr.open(get, your-api-endpoint, true)
// 发送请求
xhr.send(null)
// 接受请求
xhr.onreadystatechange function() {if(xhr.readyState 4) {if(xhr.status200) {success(xhr.responseText)} else {fail fail(xhr.status)}}
}post请求 var xhr null;
xhr new XMLHttpRequest();// 连接服务器
xhr.open(post, your-api-endpoint, true);// 设置请求头
xhr.setRequestHeader(Content-Type, application/x-www-form-urlencoded);// 发送请求
xhr.send(param1value1param2value2);
// 如果你使用 JSON 数据可以将请求体转换为 JSON字符串
// xhr.send(JSON.stringify({ param1: value1, param2: value2 }));// 接受请求
xhr.onreadystatechange function() {if (xhr.readyState 4) {if (xhr.status 200) {success(xhr.responseText);} else {if (fail) {fail(xhr.status);}}}
};// 定义 success 和 fail 回调函数
function success(response) {console.log(Success:, response);
}function fail(status) {console.error(Error:, status);
} 22模块化开发怎么做?
比如立即执行函数(或闭包函数),不暴露私有成员 var module1 (function(){var _count 0;var m1 function(){//...};var m2 function(){//...};return {m1 : m1,m2 : m2};})(); 23.异步加载js的方式有哪些? defer只支持IEasync创建script插入到DOM中加载完毕后callBack 24.xml和json的区别? 数据体积方面 JSON相对于XML来讲数据的体积小传递的速度更快些。 数据交互方面 JSON与JavaScript的交互更加方便更容易解析处理更好的数据交互 数据描述方面 JSON对数据的描述性比XML较差 传输速度方面 JSON的速度要远远快于XML 25.webpack如何实现打包的? WebPack是一个模块打包工具你可以使用WebPack管理你的模块依赖并编绎输出模块们所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTML、Javascript、CSS以及各种静态文件图片、字体等让开发过程更加高效。对于不同类型的资源webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系最后 生成了优化且合并后的静态资源 26.常见web安全及防护原理 sql注入原理 就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串最终达到欺骗服务器执行恶意的SQL命令 总的来说有以下几点 永远不要信任用户的输入要对用户的输入进行校验可以通过正则表达式或限制长度对单引号和双-进行转换等永远不要使用动态拼装SQL可以使用参数化的SQL或者直接使用存储过程进行数据查询存取永远不要使用管理员权限的数据库连接为每个应用使用单独的权限有限的数据库连接不要把机密信息明文存放请加密或者hash掉密码和敏感的信息 XSS原理及防范 Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意html标签或者javascript代码。比如攻击者在论坛中放一个看似安全的链接骗取用户点击后窃取cookie中的用户私密信息或者攻击者在论坛中加一个恶意表单当用户提交表单的时候却把信息传送到攻击者的服务器中而不是用户原本以为的信任站点 XSS防范方法 首先代码里对用户输入的地方和变量都需要仔细检查长度和对””,””,”;”,”’”等字符做过滤其次任何内容写到页面之前都必须加以encode避免不小心把html tag弄出来。这一个层面做好至少可以堵住超过一半的XSS 攻击 XSS与CSRF有什么区别吗 XSS是获取信息不需要提前知道其他用户页面的代码和数据包。CSRF是代替用户完成指定的动作需要知道其他用户页面的代码和数据包。要完成一次CSRF攻击受害者必须依次完成两个步骤 登录受信任网站A并在本地生成Cookie 在不登出A的情况下访问危险网站B CSRF的防御 服务端的CSRF方式方法很多样但总的思想都是一致的就是在客户端页面增加伪随机数通过验证码的方法 27.用过哪些设计模式? 工厂模式 工厂模式解决了重复实例化的问题但还有一个问题,那就是识别问题因为根本无法主要好处就是可以消除对象间的耦合通过使用工程方法而不是new关键字 构造函数模式: 使用构造函数的方法即解决了重复实例化的问题又解决了对象识别的问题该模式与工厂模式的不同之处在于直接将属性和方法赋值给this对象; 28.为什么同源限制? 同源策略指的是协议域名端口相同同源策略是一种安全协议举例说明比如一个黑客程序他利用Iframe把真正的银行登录页面嵌到他的页面上当你使用真实的用户名密码登录时他的页面就可以通过Javascript读取到你的表单中input中的内容这样用户名密码就轻松到手了。 29.offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别 offsetWidth/offsetHeight返回值包括contentpaddingborder,效果和getBoundingClientRect()相同clientWidth/clientHeight返回值只包含contentpaddingborder,如果有滚动条,也不包含滚动条scrollWidth/scrollHeight返回值包含contentpadding溢出内容的尺寸 30.JavaScript有哪些方法定义对象 对象字面量var obj {};构造函数var obj new Object();Object.create():var obj Object.create(Object.prototype); 31.对Promise的了解? Promise有四种状态: pending:初始状态fullfilled:成功的操作rejected:失败的操作settled: promise已经fullfilled或者rejected,且不是pending 注意:fullfilled和rejected合成settled Promise对象常用来用延迟和异步计算 Promise的构造函数: var promise new Promise(function(resolve, reject) {if (...) { // succeedresolve(result);} else { // failsreject(Error(errMessage));}}); Promise实例拥有then方法具有then方法的对象通常被称为thenable。它的使用方法如下 1promise.then(onFulfilled, onRejected) 接收两个函数作为参数一个在fulfilled的时候被调用一个在rejected的时候被调用接收参数就是futureonFulfilled对应resolve,onRejected对应reject 32.谈谈对AMD,CMD的理解? CommonJS是服务器端模块的规范Node.js采用了这个规范。CommonJS规范加载模块是同步的也就是说只有加载完成才能执行后面的操作。AMD规范则是非同步加载模块允许指定回调函数 AMD推荐的风格通过返回一个对象做为模块对象CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的 33.web开发中会话跟踪的方法有哪些? cookiesessionurl重写隐藏inputip地址 34.介绍js有哪些内置对象? Object是JavaScript中所有对象的父对象数据封装类对象: Object, Array, Boolean, Number和String其他对象: Function, Arguments, Math, Date, RegExp, Error 35.说几条写JavaScript的基本规范? 不要在同一行声明多个变量请使用/!来比较true/false或者数值使用对象字面量替代new Array这种形式不要使用全局函数Switch语句必须带有default分支If语句必须使用大括号for-in循环中的变量 应该使用let关键字明确限定作用域从而避免作用域污 36.JavaScript创建对象的几种方式? javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象当然还可以用JSON但写法有很多种也能混合使用 对象字面量的方式 person{firstname:Mark,lastname:Yun,age:25,eyecolor:black};用function来模拟无参的构造函数 function Person(){}var personnew Person();//定义一个function如果使用new实例化,该function可以看作是一个Classperson.nameMark;person.age25;person.workfunction(){alert(person.name hello...);}
person.work();用function来模拟参构造函数来实现用this关键字定义构造的上下文属性 function Pet(name,age,hobby){this.namename;//this作用域当前对象this.ageage;this.hobbyhobby;this.eatfunction(){alert(我叫this.name,我喜欢this.hobby,是个程序员);}}var maidou new Pet(麦兜,25,coding);//实例化、创建对象maidou.eat();//调用eat方法用工厂方式来创建内置对象 var wcDog new Object();wcDog.name旺财;wcDog.age3;wcDog.workfunction(){alert(我是wcDog.name,汪汪汪......);}wcDog.work();用原型方式来创建 function Dog(){}Dog.prototype.name旺财;Dog.prototype.eatfunction(){alert(this.name是个吃货);}var wangcai new Dog();wangcai.eat();用混合方式来创建 function Car(name,price){this.namename;this.priceprice; }Car.prototype.sellfunction(){alert(我是this.name我现在卖this.price万元);}var camry new Car(凯美瑞,27);camry.sell(); 37.eval是做什么的? 它的功能是把对应的字符串解析成JS代码并运行应该避免使用eval,不安全,非常消耗性能(2次,一次解析成js语句,一次执行)由JSON字符串转换为JSON对象的时候可以使用eval, var obj eval(( str )) 38.null和undefined的区别? undefined表示不存在这个值。 undefined:是一个表示”无”的原始值或者说表示”缺少值”就是此处应该有一个值但是还没有定义。当尝试读取时会返回undefined 例如变量被声明了但没有赋值时就等于undefined null表示一个对象被定义了值为“空值” null: 是一个对象(空对象, 没有任何属性和方法) 例如作为函数的参数表示该函数的参数不是对象 在验证null时一定要使用 因为无法分别null和 undefined 39.[1, 2, 3].map(parseInt)答案是什么? [1, NaN, NaN]因为parseInt需要两个参数(val, radix)其中radix表示解析时用的基数。map传了3个(element, index, array)对应的radix不合法导致解析失败。 40.JavaScript代码中use strict是什么意思?使用它区别是什么? use strict是一种ECMAscript 5添加的严格运行模式,这种模式使得 Javascript 在更严格的条件下运行,使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处减少一些怪异行为 41.js延迟加载的方式有哪些? defer和async、动态创建DOM方式用得最多、按需异步载入js 42.defer和async defer并行加载js文件会按照页面上script标签的顺序执行async并行加载js文件下载完成立即执行不会按照页面上script标签的顺序执行 43.说说严格模式的限制 变量必须声明后再使用函数的参数不能有同名属性否则报错不能使用with语句禁止this指向全局对象 44.attribute和property的区别? attribute是dom元素在文档中作为html标签拥有的属性Property是dom元素在js中作为对象有的属性对于html的标准来说,attribute和Property是同步的,会自动更新的但是对于自定义属性来说,他们是不同步的 45.es6怎么写class,为什么出现class这种东西? 这个语法糖可以让有OOP基础的人更快上手js,至少是一个官方的实现了但对于熟悉js的入人来说,这个东西没啥大影响,一个Object.create也可以继承,也比class简洁 46.常见的兼容性问题? png24位的图片在iE6浏览器上出现背景解决方案是做成PNG8浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一,但是全局效率很低一般是如下这样解决IE下,event对象有x,y属性,但是没有pageX,pageY属性Firefox下,event对象有pageX,pageY属性,但是没有x,y属性. 47.函数防抖节流原理 共同点: 防抖和节流都是防止函数被多次调用 区别: 如果用户一直触发这个函数,且每次触发函数的间隔小于设置的时间,防抖的情况只会调用一次同样的操作,节流会每隔一定的时间调用一次函数 防抖(debounce): n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间 function debounce(func, wait, immediatetrue) {let timeout, context, args;// 延迟执行函数const later () setTimeout(() {timeout nullif (!immediate) {func.apply(context, args);context args null;}}, wait);let debounced function (...params) {if (!timeout) {timeout later();if (immediate) {func.apply(this, params);} else {context this;args params;}} else {clearTimeout(timeout);timeout later();}}debounced.cancel function () {clearTimeout(timeout);timeout null;};return debounced;
}; 防抖的应用场景: 每次resize/scroll触发统计事件文本输入的验证(连续输入文字后发送ajax请求进行验证,验证一次就好) 节流(throttle): 高频事件在规定时间内只执行一次,执行一次后,只有大于设定的执行周期后才会执行第二次 //underscore.js
function throttle(func, wait, options) {var timeout, context, args, result;var previous 0;if (!options) options {};var later function () {previous options.leading false ? 0 : Date.now() || new Date().getTime();timeout null;result func.apply(context, args);if (!timeout) context args null;};var throttled function () {var now Date.now() || new Date().getTime();if (!previous options.leading false) previous now;var remaining wait - (now - previous);context this;args arguments;if (remaining 0 || remaining wait) {if (timeout) {clearTimeout(timeout);timeout null;}previous now;result func.apply(context, args);if (!timeout) context args null;} else if (!timeout options.trailing ! false) {// 判断是否设置了定时器和 trailingtimeout setTimeout(later, remaining);}return result;};throttled.cancel function () {clearTimeout(timeout);previous 0;timeout context args null;};return throttled;
};函数节流的应用场景: DOM元素的拖拽功能实现(mousemove)射击游戏的mousedown/keydown事件(单位时间内只能发射一颗子弹)计算鼠标移动的距离(mousemove)Canvas模拟画板功能(mousemove)搜索联想(keyup)监听滚动事件判断是否到达页面底部加载更多:给scroll加了debounce后,只有用户停止滚动后,才会判断是否到达了页面底部;如果是throttle的话,只要页面滚动就会间隔一段时间判断一次 48.原始类型有哪几种,null是对象吗? .js中5种原始数据类型 number整数/小数/NaN string boolean null undefined Null类型是第二个只有一个值的数据类型这个特殊的值是null从逻辑角度来看null值表示一个空对象指针而这也正是使用typeof操作符检测null值会返回“object”的原因 49.为什么console.log(0.2010.3)结果是false? JavaScript 中的 number 类型就是浮点型JavaScript 中的浮点数采用IEEE-754 格式的规定这是一种二进制表示法可以精确地表示分数比如 1/21/81/1024每个浮点数占 64 位。但是二进制浮点数表示法并不能精确的表示类似 0.1 这样 的简单的数字会有舍入误差。 由于采用二进制JavaScript 也不能有限表示 1/10、1/2 等这样的分数。在二进制中1/10(0.1)被表示为 0.00110011001100110011…… 注意 0011 是无限重复的这是舍入误差造成的所以对于 0.1 0.2 这样的运算操作数会先被转成二进制然后再计算 50.说一下js中类型转换的规则 值转数字转字符串转布尔值undefinedNaN“undefined”falsenull0“null”falsetrue1“true”false0“false”0“0”false-0“0”falseNaN“NaN”falseInfinity“Infinity”true-Infinity”-Infinity”true1(非零)“1”true{}(任意对象)见下文见下文true[](任意数组)0””true[9](包含一个数字元素)9“9”true[”a”](其他数组)NaN使用.join()方法truefunction(){}(任意函数)NaN见下文true Number的原始类型转换规则 数值转换后还是数值字符串如果可以解析为数值则为数值, 空字符串为0, 无法解析的字符串为NaN布尔转数值, true转为1, false转为0null转换为0 原始类型转换Number Number的对象类型转换规则 传入实例M, 先调用M的valueOf(), 如果返回值V为基本数据类型, 则直接使用Number(V), 求最终返回值 如果T不属于基本数据类型, 则调用M的toString(), 如果返回值S为基本数据类型, 则直接使用Number(S),求最后的结果, 如果S不属于基本数据类型, 则直接返回NaN 对象类型转换1 对象类型转换2 String的原始类型转换规则 数值(Number)转为相应的字符串字符串(String) 转换后还是字符串布尔值(Boolean)转换规则: true true, false falseundefine 转换为undefinenull 转换为null String原始类型转换 String 的对象类型转换规则 与Number的对象转换规则类似, 区别是: 先调用对象的toString(), 然后再调用valueOf() 其实正常情况下, 对象调用自身的toString()后, 对象就可以转换为string基本类型, valueOf() 没有机会被调用, 但万事有个例, 如果我们重新定义了对象的toString()方法,使其返回非基本类型的值, 那样就有机会调用对象的valueOf()方法了 String对象类型转换规则 Boolean的原始类型转换 和 对象类型转换 undefined,null,NaN,,-0,0皆为false, 其余为true 隐式类型转换 四则运算, -, *, / 隐式类型转换之四则运算 51.深拷贝和浅拷贝的区别,如何实现? 浅拷贝: 只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存只复制对象的第一层属性 深拷贝: 另外创造一个一模一样的对象,新对象和原对象不共享内存,修改新对象不会改到原对象对对象属性进行递归复制 浅拷贝实现: 1) 简单赋值: function simpleClone(initalObj) { var obj {}; for ( var i in initalObj) {obj[i] initalObj[i];} return obj;}var obj {a: hello,b:{a: world,b: 21},c:[Bob, Tom, Jenny],d:function() {alert(hello world);}}var cloneObj simpleClone(obj); console.log(cloneObj.b); console.log(cloneObj.c);console.log(cloneObj.d);cloneObj.b.a changed;cloneObj.c [1, 2, 3];cloneObj.d function() { alert(changed); };console.log(obj.b);console.log(obj.c);console.log(obj.d); 2.Object.assign(): Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象然后返回目标对象。但是 Object.assign() 进行的是浅拷贝拷贝的是对象的属性的引用而不是对象本身。 var obj { a: {a: hello, b: 21} };var initalObj Object.assign({}, obj);initalObj.a.a changed;console.log(obj.a.a); // changed 注意当object只有一层的时候是深拷贝 深拷贝的实现: 1) 当对象至于一层时,使用Object.assign函数 2.JSON.parse(JSON.stringify(obj)) var obj1 { body: { a: 10 } };
var obj2 JSON.parse(JSON.stringify(obj1));
obj2.body.a 20;
console.log(obj1);
// { body: { a: 10 } } -- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 obj2);
// false
console.log(obj1.body obj2.body);
// false 封装: var cloneObj function(obj){var str, newobj obj.constructor Array ? [] : {};if(typeof obj ! object){return;} else if(window.JSON){str JSON.stringify(obj), //系列化对象newobj JSON.parse(str); //还原} else {for(var i in obj){newobj[i] typeof obj[i] object ? cloneObj(obj[i]) : obj[i]; }}return newobj;
}; 3) 递归拷贝: function deepClone(initalObj, finalObj) { var obj finalObj || {}; for (var i in initalObj) { var prop initalObj[i]; // 避免相互引用对象导致死循环如initalObj.a initalObj的情况if(prop obj) { continue;} if (typeof prop object) {obj[i] (prop.constructor Array) ? [] : {}; arguments.callee(prop, obj[i]);} else {obj[i] prop;}} return obj;
}
var str {};
var obj { a: {a: hello, b: 21} };
deepClone(obj, str);
console.log(str.a); 4) 使用Object.create方法 直接使用var newObj Object.create(oldObj)可以达到深拷贝的效果。 function deepClone(initalObj, finalObj) { var obj finalObj || {}; for (var i in initalObj) { var prop initalObj[i]; // 避免相互引用对象导致死循环如initalObj.a initalObj的情况if(prop obj) { continue;} if (typeof prop object) {obj[i] (prop.constructor Array) ? [] : Object.create(prop);} else {obj[i] prop;}} return obj;
} 5) jQuery的$.extend可以用来做 Deep Copy var $ require(jquery);
var obj1 {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 $.extend(true, {}, obj1);
console.log(obj1.b.f obj2.b.f);
// false 6) lodash 另外一个很热门的函数库lodash也有提供_.cloneDeep用来做 Deep Copy。 var _ require(lodash);
var obj1 {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 _.cloneDeep(obj1);
console.log(obj1.b.f obj2.b.f);
// false这个性能还不错使用起来也很简单。 52.如何判断this?箭头函数的this是什么? 1) 谁作为拥有者调用它就指向谁 2) bind谁就指向谁 3) 没有拥有者,直接调用,指向window 4) call谁就是谁,apply谁,其实bind就是通过call,apply实现的 5) 箭头函数不绑定this, 会捕获所在的上下文的this值,作为自己的this值 53.和的区别? 三个等号我们称为等同符当等号两边的值为相同类型的时候直接比较等号两边的值值相同则返回true若等号两边的值类型不同时直接返回false。 例100“100” //返回false abc“abc” //返回false ‘abc’“abc” //返回true NaNNaN //返回false falsefalse //返回true 两个等号我们称为等值符当等号两边的值为相同类型时比较值是否相同类型不同时会发生类型的自动转换转换为相同的类型后再作比较。 54.什么是闭包? 概念: 闭包就是能够读取其他函数内部变量的函数闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的常见方式就是在一个函数中创建另外一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用域链 闭包的特性: 函数内部再嵌套函数内部函数可以引用外层的参数和变量参数和变量不会被垃圾回收机制回收(解决方式: 使用完毕之后将变量设置为null) 对闭包的理解: 使用闭包主要是为了射击私有的方法和变量.闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏在js中,函数就是闭包,只有函数才会产生作用域的概念闭包的另一个用处,是封装对象的私有属性和私有方法 优点: 实现封装和缓存等 缺点: 消耗内存,不正当使用会造成内存溢出的问题 注意事项: 由于闭包会使函数中的变量被保存在内存中,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄漏解决方案: 在退出函数之前,将不使用的局部变量全部删除 55.JavaScript原型,原型链?有什么特点? 概念: 每个对象都会在其内部初始化一个属性,就是prototype(原型)当我们访问一个对象属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里查找这个属性,这个prototype又会有自己的prototype.于是就这样一直找下去,也就是我们平时所说的原型链的概念关系:instance.constructor.prototypeinstance.__proto__ 特点: JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本.当我们修改原型时,与之相关的对象也会继承这一改变当我们需要一个属性时,JavaScript引擎会先看当前对象中是否有这个属性,如果没有的,就会查找他的prototype对象是否有这个属性,如此递推下去,一直检索到Object内建对象 56.typeof ()和instanceof()用法的区别? typeof(): 是一个一元运算,放在一个运算数之前,运算数可以是任意类型它返回值是一个字符串,该字符串说明运算数的类型 instance(): 运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上.通常来讲,使用instance就是判断一个实例是否属于某种类型 57.什么是变量提升? 变量提升: 函数声明和变量声明总是会被提升到变量的最顶端JavaScript只有声明的变量会提升,初始化的不会 如下: y 输出了undefined这是因为变量声明 (var y) 提升了但是初始化(y 7) 并不会提升所以 y 变量是一个未定义的变量。 var x 5; // 初始化 x
var y; // 声明 yelem document.getElementById(demo); // 查找元素
elem.innerHTML x y; // 显示 x 和 yy 7; // 设置 y 为 7 1) 函数声明会被提升,函数表达式不会 //函数声明, 形如:
function show() {}// 函数表达式:
var showfunction{} 2) 出现同名的函数声明,变量声明的时候,函数声明会被优先提升,变量声明会被忽略 show(); //你好var show;function show(){console.log( 你好 );}show function(){console.log( hello );} 上面这段代码结果为什么会是 你好? 当出现同名的函数声明变量声明的时候 函数声明会被优先提升变量声明会被忽略。 经过编译之后,变为: function show(){console.log( 你好 );}show(); //你好show function(){console.log( hello );}show();//如果这里在调用一次就是hello, 因为show函数体在执行阶段 被 重新赋值了 3) 如果有同名的函数声明,后面的会覆盖前面的 show(); //how are youvar show;function show(){console.log( hello );} show function(){console.log( 你好 );}function show(){console.log( how are you! );} //上面的代码经过编译之后变成如下形式:function show(){console.log( how are you! );}show(); //how are youshow function(){console.log( 你好 );}show(); //如果在这里再执行一次结果你好 58.call,apply以及bind函数内部实现是怎么样的? 相同点: call,apply,bind都是改变函数的上下文,说的直白一点就是改变了函数this的指向 不同点: call和apply改变了函数的this,并且执行了函数bind是改变了函数的this,并返回一个函数,但不执行该函数 call示例: var doThu function(a, b) {console.log(this)console.log(this.name)console.log([a, b])
}
var stu {name: xiaoming,doThu: doThu,
}
stu.doThu(1, 2) // stu对象 xiaoming [1, 2]
doThu.call(stu, 1, 2) // stu对象 xiaoming [1, 2] 由此可见在stu上添加一个属性doThu再执行这个函数就将doThu的this指向了stu。而call的作用就与此相当只不过call为stu添加了doThu方法后执行了doThu然后再将doThu这个方法从stu中删除。 call函数的内部实现原理: Function.prototype.call function(thisArg, args) {// this指向调用call的对象if (typeof this ! function) { // 调用call的若不是函数则报错throw new TypeError(Error)}thisArg thisArg || windowthisArg.fn this // 将调用call函数的对象添加到thisArg的属性中const result thisArg.fn(...[...arguments].slice(1)) // 执行该属性delete thisArg.fn // 删除该属性return result
} aaply的实现原理和call一样,只不过传入的参数不同而已: Function.prototype.apply function(thisArg, args) {if (typeof this ! function) { throw new TypeError(Error)}thisArg thisArg || windowthisArg.fn thislet resultif(args) {result thisArg.fn(...args)} else {result thisArg.fn()}delete thisArg.fnreturn result
} bind的原理比call和apply更复杂,bind需要考虑一些复杂的边界条件.bind后的函数会返回一个函数,而这个函数页可能被用来实例化 Function.prototype.bind function(thisArg) {if(typeof this ! function){throw new TypeError(this must be a function);}// 存储函数本身const _this this;// 去除thisArg的其他参数 转成数组const args [...arguments].slice(1)// 返回一个函数const bound function() {// 可能返回了一个构造函数我们可以 new F()所以需要判断if (this instanceof bound) {return new _this(...args, ...arguments)}// apply修改this指向把两个函数的参数合并传给thisArg函数并执行thisArg函数返回执行结果return _this.apply(thisArg, args.concat(...arguments))}return bound
} 59.为什么会出现setTimeout倒计时误差?如何减少? !DOCTYPE html
htmlheadmeta charsetutf-8title/title/headbodyp idmessage/p/bodyscript typetext/javascriptvar message document.getElementById(message);var count 1000;function animate() {var start new Date();message.innerHTML count--;var finish new Date();setTimeout(animate, 1000 - (finish-start));}animate();/script
/html 本例实现了倒数1000秒的功能我们在使用setTimeout的时候如果要一个函数每每隔1秒执行一次就会这样写 setTimeout(animate, 1000); 但是这样会忽略animate方法本身的运行时间所以我们可以在执行animate方法的时候计算这个方法主要的语句的执行时间之后在setTimeout中减去那个由于运行语句而耽搁的时间从而实现更加精确的计时 使用requestAnimationFrame可以减少倒计时误差: 幕刷新设计的函数它会在浏览器准备重绘之前调用指定的函数这样可以保证动画或倒计时的更新与屏幕刷新同步从而减少误差。requestAnimationFrame的优点包括 高精度计时它能够更好地适应屏幕的刷新率提供更平滑的动画效果。节能优化当页面不可见时requestAnimationFrame会停止执行从而节省CPU资源。避免丢帧现象在处理高频率事件时requestAnimationFrame可以保证每个刷新间隔内函数只执行一次提高效率4。 示例代码展示如何使用requestAnimationFrame减少倒计时误差 let startTime Date.now();
let requestId null;
let endTime startTime 10000; // 设置10秒倒计时function updateTime() {let currentTime Date.now();if (currentTime endTime) {requestId requestAnimationFrame(updateTime);console.log(剩余:, (endTime-currentTime)/1000, s);} else {console.log(倒计时结束);cancelAnimationFrame(requestId);requestId null;}
}requestId requestAnimationFrame(updateTime); 60.对js执行上下文栈和作用域链的理解? 执行上下文: 1) 当前 JavaScript 代码被解析和执行时所在环境, JS执行上下文栈可以认为是一个存储函数调用的栈结构 2) 遵循先进后出的原则。 JavaScript执行在单线程上所有的代码都是排队执行。一开始浏览器执行全局的代码时首先创建全局的执行上下文压入执行栈的顶部。每当进入一个函数的执行就会创建函数的执行上下文并且把它压入执行栈的顶部。当前函数执行-完成后当前函数的执行上下文出栈并等待垃圾回收。浏览器的JS执行引擎总是访问栈顶的执行上下文。全局上下文只有唯一的一个它在浏览器关闭时出栈。 作用域链: 无论是 LHS 还是 RHS 查询都会在当前的作用域开始查找如果没有找到就会向上级作用域继续查找目标标识符每次上升一个作用域一直到全局作用域为止。 61.new的原理是什么?通过new的方式创建的对象和通过字面量创建有什么区别? new: 创建一个新对象这个新对象会被执行原型连接将构造函数的作用域赋值给新对象,即this指向这个新对象如果函数的作用域赋值给新对象,即this指向这个新对象如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象 function new(func) {lat target {};target.__proto__ func.prototype;let res func.call(target);if (typeof(res) object || typeof(res) function) {return res;}return target;
} 字面量创建对象,不会调用Object构造函数,简洁且性能更好new Object()方式创建对象本质上是方法调用,涉及到在proto链中遍历该方法当找到该方法后,又会生产方法调用必须得堆栈信息,方法调用结束后,还要释放该堆栈,性能不如字面量的方式通过对象字面量定义对象时,不会调用Object构造函数 62.prototype和__proto__的区别? prototype 是构造函数的属性 __proto__ 是每个实例都有的属性,可以访问prototype属性 实例的__proto__与其构造的prototype指向的是同一个对象 function Student(name) {this.name name;
}
Student.prototype.setAge function(){this.age20;
}
let Jack new Student(jack);
/**
console.log(Jack.__proto__);
console.log(Object.getPrototypeOf(Jack));
console.log(Student.prototype);
都是:
{setAge: ƒ}
setAge: ƒ ()
constructor: ƒ Student(name)
[[Prototype]]: Object
*/
console.log(Jack.__proto__);
console.log(Object.getPrototypeOf(Jack));
console.log(Student.prototype);console.log(Jack.__proto__ Student.prototype);//true 63.使用es5实现一个继承 寄生组合继承: function SuperType(name) {this.name name;this.colors [red, blue, green];
}SuperType.prototype.sayName function() {console.log(this.name);
};function SubType(name, age) {SuperType.call(this, name);this.age age;
}SubType.prototype.sayAge function() {console.log(this.age);
};(function() {var Super function() {};Super.prototype SuperType.prototype;SubType.prototype new Super();
})();SubType.prototype.constructor SubType;var sub1 new SubType(alice, 12);
console.log(sub1); //SubType {name: alice, colors: Array(3), age: 12} 64.取数组的最大值(es5,es6) // ES5 的写法
Math.max.apply(null, [14, 3, 77, 30]);// ES6 的写法
Math.max(...[14, 3, 77, 30]);// reduce
[14,3,77,30].reduce((acc, cur){return acc acc cur ? acc : cur
}); 65.es6新特性有哪些? 新增块级作用域:let, const类的语法糖: class基本数据类型: Symbol变量解构赋值函数参数允许设置默认值,引入rest参数,新增箭头函数数增了一些api,如isArray/from,of方法;数组新增了entries(),keys(),values()方法对象和数组新增扩展运算符es6新增了Set和Map数据结构es6原生提供了Proxy构造函数,用来生成Proxy实例es6新增了生成器(Generator)和遍历函数(Iterator) 66.Promise有几种状态,Promise有什么缺点? Promise有三种状态: fullfilled, rejected, pending Promise优点: 一旦状态改变,就不会再变,任何时候都可以得到这个结果可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数 Promise缺点: 无法取消Promise当处于pending状态时,无法得知目前进展到哪一阶段 67.Promise构造函数是同步还是异步,then呢?Promise如何实现then处理 Promise构造函数同步执行的,then是异步执行的 68.Promise和setTimeout的区别? Promise是微任务,setTimeout是宏任务,同一个事件循环中,Promise.then总是先于setTimeout执行 69.如何实现Promise.all? 要实现Promise.all,首先我们要知道Promise.all的功能: 如果传入的参数是一个空的可迭代对象,那么Promise对象回调完成(resolve),只有此情况,是同步执行的,其他都是异步返回的如果传入的参数不包含任何Promise,则返回一个异步完成 Promise中所有的promise都完成时或参数中不包含promise时回调完成 如果参数中有一个promise失败,那么Promise.all返回的promise对象失败在任何情况下,Promise.all返回的Promise的完成状态的结果都是一个数组 Promise.all function (promises) {return new Promise((resolve, reject) {let index 0;let result [];if (promises.length 0) {resolve(result);} else {setTimeout(() {function processValue(i, data) {result[i] data;if (index promises.length) {resolve(result);}}for (let i 0; i promises.length; i) {//promises[i] 可能是普通值Promise.resolve(promises[i]).then((data) {processValue(i, data);}, (err) {reject(err);return;});}})}});
} 常见面试问题: 如何让promise.all 抛出异常后依然有效 处理多个并发请求时我们一般会用Promise.all()方法。 该方法指当所有在可迭代参数中的 promises 已完成或者第一个传递的 promise指 reject失败时返回 promise。 但是当其中任何一个被拒绝的话。Promise.all([…])就会立即被拒绝并丢弃来自其他所有promis的全部结果。 也就是说promise.all 中任何一个 promise 出现错误的时候都会执行reject导致其它正常返回的数据也无法使用。 如何让Promise.all在抛出异常后依然有效呢 方案一:在promise.all队列中使用map每一个过滤每一个promise任务其中任意一个报错后return一个返回值 在promise.all队列中使用map每一个过滤每一个promise任务其中任意一个报错后return一个返回值确保promise能正常执行走到.then中。 效果图 示例代码 // 模拟返回示例
function getData(api) {return new Promise((resolve, reject) {setTimeout(() {Math.random() 0.5 ? resolve(get api success) : reject(error)}, 200)})
}
function getDatas(arr) {return Promise.all(arr.map(one one.catch(e e))).then(values values).catch(error error)
}async function initData() {let result await getDatas([getData(./api1), getData(./api2), getData(./api3)]) //模拟请求console.log(result);
}initData() 方案二:使用 Promise.allSettled 替代 Promise.all()。 Promise.allSettled()方法返回一个promise该promise在所有给定的promise已被解析或被拒绝后解析并且每个对象都描述每个promise的结果。 let allSettled Promise.allSettled([getData(./api1), getData(./api2), getData(./api3)]) //模拟请求allSettled.then(res {console.log(res)}) 70.如何实现Promise.finally 不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then,并且会将值原封不动的传递给后面的then Promise.prototype.finally function (callback) {return this.then((value) {return Promise.resolve(callback()).then(() {return value;});}, (err) {return Promise.resolve(callback()).then(() {throw err;});}); 71.如何判断img加载完成 onload事件 一、load事件!DOCTYPE HTMLhtml head meta charsetutf-8titleimg - load event/title/head bodyimg idimg1 srchttp://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpgp idp1loading.../pscript typetext/javascriptimg1.onload function() {p1.innerHTML loaded}/script/body/html 测试所有浏览器都显示出了“loaded”说明所有浏览器都支持img的load事件。 readystatechange事件 !DOCTYPE HTMLhtml head meta charsetutf-8titleimg - readystatechange event/title/head bodyimg idimg1 srchttp://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpgp idp1loading.../pscript typetext/javascriptimg1.onreadystatechange function() {if(img1.readyStatecomplete||img1.readyStateloaded){ p1.innerHTML readystatechange:loaded}}/script/body/html readyState为complete和loaded则表明图片已经加载完毕。测试IE6-IE10支持该事件其它浏览器不支持。 三、img的complete属性 !DOCTYPE HTMLhtml head meta charsetutf-8titleimg - complete attribute/title/head bodyimg idimg1 srchttp://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpgp idp1loading.../pscript typetext/javascriptfunction imgLoad(img, callback) {var timer setInterval(function() {if (img.complete) {callback(img)clearInterval(timer)}}, 50)}imgLoad(img1, function() {p1.innerHTML(加载完毕)})/script/body/html 轮询不断监测img的complete属性如果为true则表明图片已经加载完毕停止轮询。该属性所有浏览器都支持。 72.如何阻止冒泡 冒泡事件: 事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发 w3c的方法是e.stopPropagation(),ie则是e.cancelBubbletrue //阻止冒泡行为
function stopBubble(e) {
//如果提供了事件对象则这是一个非IE浏览器
if ( e e.stopPropagation ) //因此它支持W3C的stopPropagation()方法 e.stopPropagation();
else //否则我们需要使用IE的方式来取消事件冒泡 window.event.cancelBubble true;
} 73.如何阻止默认事件 w3c的方法是e.preventDefault()IE则是使用e.returnValue false //阻止浏览器的默认行为
function stopDefault( e ) { //阻止默认浏览器动作(W3C) if ( e e.preventDefault ) e.preventDefault(); //IE中阻止函数器默认动作的方式 else window.event.returnValue false; return false;
} 74.ajax请求时,如何解释json数据 使用eval parse,但是鉴于安全性考虑,使用parse更靠谱 75.json和jsonp的区别? json返回的是一串json数据;而jsonp返回的是脚本代码(包含一个函数调用)jsonp的全名叫做json with padding,就是把json对象用符合js语法的形式包裹起来以使其他的网站可以请求到,也就是将json封装成js文件传过去 76.如何使用原生js给按钮绑定两个click事件? Var btndocument.getElementById(‘btn’);
//事件监听 绑定多个事件
var btn4 document.getElementById(btn4);
btn4.addEventListener(click,hello1);
btn4.addEventListener(click,hello2);
function hello1(){alert(hello 1);
}
function hello2(){alert(hello 2);
}77.拖拽会用到哪些事件? dragstart: 拖拽开始时在被拖拽元素上触发此事件,监听器需要设置拖拽所需的数据,从操作系统拖拽文件到浏览器时不触发此事件dragenter: 拖拽鼠标进入元素时在该元素上触发,用于给拖放元素设置视觉反馈,比如高亮dragover: 拖拽时鼠标在目标元素上移动时触发.监听器通过阻止浏览器默认行为设置元素为可拖放元素dragleave: 拖拽时鼠标移出目标元素时在目标元素上触发,此时监听器可以取消掉前面设置的视觉效果drag: 拖拽期间在被拖拽元素上连续触发drop: 鼠标在拖放目标上释放时,在拖放目标上触发,此时监听器需要收集数据并且执行所需操作,如果是从操作系统拖放文件到浏览器,需要取消浏览器默认行为dragend: 鼠标在拖放目标上释放时,在拖放元素上触发,将元素从浏览器拖放到操作系统时不会触发此事件 78.document.write和innerHTML的区别? document.write是直接写入到页面的内容流如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数会导致页面被重写。innerHTML则是DOM页面元素的一个属性代表该元素的html内容。你可以精确到某一个具体的元素来进行更改。如果想修改document的内容则需要修改document.documentElement.innerElement。innerHTML将内容写入某个DOM节点不会导致页面全部重绘innerHTML很多情况下都优于document.write其原因在于其允许更精确的控制要刷新页面的那一个部分。 79.jQuery的事件委托方法bind 、live、delegate、on之间有什么区别 (1)、bind 定义和用法主要用于给选择到的元素上绑定特定事件类型的监听函数 语法bind(type,[data],function(eventObject)) 特点 (1)、适用于页面元素静态绑定。只能给调用它的时候已经存在的元素绑定事件不能给未来新增的元素绑定事件。 (2)、当页面加载完的时候你才可以进行bind()所以可能产生效率问题。 实例如下$( #members li a ).bind( click, function( e ) {} ); (2)、live 定义和用法主要用于给选择到的元素上绑定特定事件类型的监听函数 语法live(type, [data], fn); 特点 (1)、live方法并没有将监听器绑定到自己(this)身上而是绑定到了this.context上了。 (2)、live正是利用了事件委托机制来完成事件的监听处理把节点的处理委托给了document新添加的元素不必再绑定一次监听器。 (3)、使用live方法但却只能放在直接选择的元素后面不能在层级比较深连缀的DOM遍历方法后面使用即$(“ul”).live...可以但$(body).find(ul).live...不行 实例如下$( document ).on( click, #members li a, function( e ) {} ); (3)、delegate 定义和用法将监听事件绑定在就近的父级元素上 语法delegate(selector,type,[data],fn) 特点 (1)、选择就近的父级元素因为事件可以更快的冒泡上去能够在第一时间进行处理。 (2)、更精确的小范围使用事件代理性能优于.live()。可以用在动态添加的元素上。 实例如下 $(#info_table).delegate(td,click,function(){/显示更多信息/}); $(table).find(#info).delegate(td,click,function(){/显示更多信息/}); (4)、on 定义和用法将监听事件绑定到指定元素上。 语法on(type,[selector],[data],fn) 实例如下$(#info_table).on(click,td,function(){/显示更多信息/});参数的位置写法与delegate不一样。 说明on方法是当前JQuery推荐使用的事件绑定方法附加只运行一次就删除函数的方法是one()。 总结 .bind(), .live(), .delegate(),.on()分别对应的相反事件为.unbind(),.die(), .undelegate(),.off() 80.浏览器是如何渲染页面的 渲染的流程如下: 解析HTML文件,创建dom树--自上而下,遇到任何样式(link,style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)解析css.优先级: 浏览器默认设置 用户设置 外部样式 内联样式 HTML中的style样式将css和dom合并,构建渲染树(render tree)布局和绘制,重绘(repait)和重排(reflow) 81.$(document).ready()方法和window.onload有什么区别? (1)、window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。 (2)、$(document).ready() 方法可以在DOM载入就绪时就对其进行操纵并调用执行绑定的函数。 82.jQuery中$.get()提交和$.post()提交有区别吗? 相同点: 都是异步请求的方式来获取服务端的数据 不同点: 请求方式不同: $.get()方法使用GET方法来进行异步请求的,$.post()方法使用POST方法来进行异步请求的参数传递方式不同: get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给web服务器的,这种传递是对用户不可见的数据传输大小不同: get方式传输的数据大小不超过2KB而POST大的多安全问题: GET方式请求的数据会被浏览器缓存起来,因此有安全问题 83.对前端路由的理解 前端的路由和后端的路由在实现技术上不一致但是原理是一样的。在html5的history api出现之前前端的路由是通过hash实现的hash能够兼容低版本的浏览器 服务端路由 每跳转到不同的url都是重新访问服务端然后服务端返回页面页面也可以是服务端获取数据然后和模板组合返回html也可以是直接返回模板html然后由前端js再去请求数据使用前端模板和数据进行组合生成想要的html 前端路由 每跳转到不同的url都是使用前端的描点路由实际上只是js根据url来操作dom元素根据每个页面需要的去服务端请求数据返回数据后和模板进行组合当然模板可能是请求服务端返回的这就是SPA单页程序 在js可以通过window.location.hash读取路径, 解析之后就可以响应不同路径的逻辑处理 history是HTML5才有的新API,可以用来操作浏览器的session history(会话历史),基于history来实现的路由可以和最初的例子中提到的路径规则一样 html5还新增了一个hashchange事件,也是很有用的一个新事件: 当页面hash发生变化时,会触发hashchange,锚点hash起到引导浏览器这次记录推入历史记录栈顶的作用 window.location.hash的改变不会重新加载页面,而是将之当成新页面,放入历史栈里.并且,当前进或后退或者触发hashchange事件时,我们可以在对应事件处理函数中注册ajax等操作 但是hashchange这个事件不是每个浏览器都支持的,低级浏览器需要使用轮询检测url是否在变化,来检测描点的变化. 当锚点内容(location.hash)被操作时,如果锚点内容发生改变浏览器才会将其放入历史栈中,如果锚点内容没有发生变化,历史栈并不会增加,并且不会触发hashchange事件 84.手写一个类的继承? function Animal(name){this.name name;this.eat function(){console.log(this.name 吃饭);}
}function Cat(name){Animal.call(this, name);
}Cat.prototype Object.create(Animal.prototype);
Cat.prototype.constructor Cat
var cat new Cat(maomi);
cat.name;
cat.eat(); 85.XMLHttpRequest.readyState状态码的意思 状态码readyState 当一个XMLHttpRequest初次创建时,这个属性的值是从0开始,直到接收完整的http响应,这个值增加到4. 有5种状态: 状态0: 请求初始 化 XMLHttpRequest对象已经创建或者已被abort()方法重置,但还没有调用open方法 状态1: 载入服务器连接已经建立 已调用open方法,但是send方法还未调用 状态2: 载入完成,请求已接收 send方法已调用,http请求已发送到web服务器,请求已经发送完成,未接收到响应 状态3: 交互,请求处理中 所有响应头部都已经接收到,响应体开始接收但未完成,即可以接收到部分响应数据; 状态4: 请求完成,且响应已就绪 已经接收到全部数据,并且连接已经关闭 86.正则表达式常见面试题
86-1给一个连字符串例如get-element-by-id转化成驼峰形式。 var str get-element-by-id;
var reg /-\w/g; // 匹配横杆以及之后的一个字符全局匹配
console.log(str.replace(reg,function($0){return $0.slice(1).toUpperCase();// 匹配到到是-e -b -i 形式截取后一个字符转成大写
})); function toCamelCase(str) {return str.split(-) // 将字符串按连字符分割成数组.map((word, index) {if (index 0) {return word.toLowerCase(); // 第一个单词保持小写}return word.charAt(0).toUpperCase() word.slice(1).toLowerCase(); // 其他单词首字母大写}).join(); // 将数组重新拼接成字符串
}const result toCamelCase(get-element-by-id);
console.log(result); // 输出: getElementById 86-2匹配二进制数字 var str 10101111;
var reg /^[01]$/g;
console.log(reg.test(str)); 86-3非零数字的十进制数字(至少一位数字,但不能以0开头) var str 81;
var reg /^[1-9][0-9]?$/g;
console.log(reg.test(str)); 86-4匹配一年中的12月 var str 12;
var reg /^(0?[1-9]|1[0-2])$/g;
console.log(reg.test(str)); 86-5匹配qq号最长13位 var str 10009093283333;
var reg /^[1-9][0-9]{4,12}$/g;
console.log(reg.test(str)); 86-6匹配常见的固定电话号码 var str 000-12344562;
// \(? 匹配左括号一次或0次然后以0开头后面加两个数字再匹配右括号或空格或减号一次或0次随后匹配8个数字
var reg /\(?0\d{2}[) -]?\d{8}/g;
console.log(str.match(reg)); 86-7匹配ip地址 var str 255.221.221.12;
// [01]?\d\d?表示匹配小于199的数可以说两位数或一位数2[0-4]\d表示从200到249配合25[0-5]就表示小于255的数了。
var reg /(([01]?\d\d?|2[0-4]\d|25[0-5])\.){3}([01]?\d\d?|2[0-4]\d|25[0-5])/g;
console.log(str.match(reg)); 86-8匹配使用尖括号括起来的以a开头的字符串 var str a herfwww.baidu.com;
var reg /a[^]/g;
console.log(str.match(reg)); 86-9分割数字每三个以一个逗号划分 var str 12345678901;
function numSplit(str){var re /(\d)(?(\d{3})$)/g;//(\d{3})$ 的意思是连续匹配 3 个数字且最后一次匹配以 3 个数字结尾。//要找到所有的单个字符这些字符的后面跟随的字符的个数必须是3的倍数并在符合条件的单个字符后面添加,return str.replace(re,$1,);
}
console.log(numSplit(str)); 86-10 判断字符串是否包含数字 function containsNumber(str) {var regx /\d/;return regx.text(str);
} 86-11判断电话号码
function isPhone(tel) {var regx /^1[34578]\d{9}$/;return regx.test(tel);
}
86-12判断是否符合指定格式 给定字符串str检查其是否符合如下格式 XXX-XXX-XXXX其中X为Number类型 function matchesPattern(str) {return /^(\d{3}-){2}\d{4}/.test(str);
} 86-13.判断是否符合USD格式 给定字符串 str检查其是否符合美元书写格式 以 $ 开始整数部分从个位起满 3 个数字用 , 分隔如果为小数则小数部分长度为 2正确的格式如$1,023,032.03 或者 $2.03错误的格式如$3,432,12.12 或者 $34,344.3** function isUSD(str) {var regx /^\$\d{1,3}(,\d{3})*(\.\d{2})?$/;return regx.test(str);
} 86-14.js实现千位分隔符 相关概念: ? 是一个正向肯定预查positive lookahead的语法。它用于匹配某个位置该位置后面紧跟着指定的模式但不包括该模式本身。换句话说? 用于检查某个模式是否存在但不会消耗字符即不会将其作为匹配结果的一部分。 $表示与regx相匹配的字符串 注意事项 正向肯定预查 (?expression) 不会消耗字符即不会将其作为匹配结果的一部分。如果需要匹配某个模式且该模式本身也包含在结果中可以使用捕获组 ( )。 对比 正向肯定预查 (?expression)匹配某个位置该位置后面紧跟着指定的模式但不包括该模式本身。正向否定预查 (?!expression)匹配某个位置该位置后面不跟着指定的模式。负向肯定预查 (?expression)匹配某个位置该位置前面紧跟着指定的模式但不包括该模式本身ES2018 引入。负向否定预查 (?!expression)匹配某个位置该位置前面不跟着指定的模式ES2018 引入。 function format(number) {var regx /\d{1,3}(?(\d{3})$)/g;return (number ).replace(regx, $,) // $表示与regx相匹配的字符串
} 86-15获取url参数 获取 url 中的参数 指定参数名称返回该参数的值 或者 空字符串不指定参数名称返回全部的参数对象 或者 {}如果存在多个同名参数则返回数组 function getUrlParam(url, key) {var arr {};url.replace(/\??(\w)(\w)?/g, function(match, matchKey, matchValue) {if (!arr[matchKey]) {arr[matchKey] matchValue;} else {var temp arr[matchKey];arr[matchKey] [].concat(temp, matchValue);}});if (!key) {return arr;} else {for (ele in arr) {if (ele key) {return arr[ele];}}return ;}
} 86-16验证邮箱
function isEmail(email) {var regx /^([a-zA-Z0-9_\-])([a-zA-Z0-9_\-])(\.[a-zA-Z0-9_\-])$/;return regx.test(email);
}
86-17验证身份证号码 身份证号码可能为15位或18位15位为全数字18位中前17位为数字最后一位为数字或者X function isCardNo(number) {var regx /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;return regx.test(number);
} 86-18匹配汉字
var regx /^[\u4e00-\u9fa5]{0,}$/;86-19去除首尾的/
var str /asdf//;
str str.replace(/^\/*|\/*$/g, );
86-20.判断日期格式是否符合 2017-05-11的形式简单判断只判断格式
var regx /^\d{4}\-\d{1,2}\-\d{1,2}$/86-21.判断日期格式是否符合 2017-05-11的形式严格判断比较复杂
var regx /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/;86-22.ipv4地址正则
var regx /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;86.23.十六进制颜色正则
var regx /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;86-24.车牌号正则
var regx /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;86-25.过滤HTML标签
var strpdasdsa/pnice br test/br
var regx /[^]/g;
str str.replace(regx, );
86-26.密码强度正则最少6位包括至少1个大写字母1个小写字母1个数字1个特殊字符
var regx /^.*(?.{6,})(?.*\d)(?.*[A-Z])(?.*[a-z])(?.*[!#$%^*? ]).*$/;86-27.URL正则
var regx /^((https?|ftp|file):\/\/)?([\da-z\.-])\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;86-28.匹配浮点数
var regx /^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0|0)$/;
87.js编程
87-1.请写出代码的运行结果如何改进 for(var i0;i5;i){setTimeout(function(){console.log(i)},1000)}//输出结果为五个5 原因是 settimeout是异步执行1s后往任务队列里面添加一个任务
只有主线上的全部执行完才会执行任务队列里的任务
当主线执行完成后i是5所以此时再去执行任务队列里的任务时i全部是5了。改进 for(let i0;i5;i){setTimeout(function(){console.log(i)},1000)}//输出 0,1,2,3,4解析 for循环头部的let不仅将i绑定到for循环块中
它也将其重新绑定到 **循环体的每一次迭代** 中确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域
通过 var 定义的变量是无法传入到这个函数执行域中的
而通过使用 let 来声明块变量这时候变量就能作用于这个块
所以 function就能使用 i 这个变量了 87-2.请写出打印结果并解释为什么 let length 10;function fn(){console.log(this.length);
}
var obj {length:5,method:function(){return fn;}
}
obj.method()(); //输出结果0解析 this永远指向调用他的对象在执行obj.method()方法时如果函数内部有this则this确实是指向obj但是method()内部执行的是fn()函数而fn()函数绑定的对象是window即window.fn() 所以this指的事window 但是为什么没有显示10而是显示的0是因为 let声明变量会形成块级作用域且不存在声明提升而var存在声明提升。所以当使用let声明变量时不存在声明提升length属性实际上并没有添加到window对象中。 87-3.请写出打印结果并解释为什么 var name clobal;var object {name:local,fn:function(){return this.name;},getName:function(){alert(1. this.name);return function(){return this.name;}},getFn:function(){return this.fn;}};var fun object.getName();alert(2.fun());alert(3.fun.apply(object));alert(4.fun.call(object));var fn object.getFn();alert(5.fn())输出结果 1.local 2.clocal 3.local 4.local 5.clocal 解析 this对象是在运行时基于函数的执行环境绑定的 匿名函数的执行环境具有全局性 因此匿名函数的this指向window 88.重写map方法 先看一下map的用法 //语法array.map(function(currentValue,index,arr), thisValue)
//用法
var arr [1,2,3,4];
arr.map((item,index,arr) {return item*10 //新数组为10,20,30,40
})
//map遍历数组返回一个新数组不改变原数组的值。用js实现 Array.prototype.fakeMap function(fn,context) {let arr this;let temp [];for(let i0;iarr.length;i){let result fn.call(context,arr[i],i,arr);temp.push(result);}return temp;
} 二.ES6面试
ES6新增方法:
1.let,const,var比较 2.反引号
3.函数默认参数
4.箭头函数
5.属性简写
6.方法简写
7.Object.keys方法,获取对象的所有属性名和方法名
8.Object.assign()原对象的属性和方法都合并到了目标对象
9.for...of循环
10.import和export
11.Promise
12.结构赋值
13.Set数据结构
14.Spread Operator展开运算符
15.字符串新增方法
ES6数组面试题:
1.forEach()
2.map()
3.filter()
4.reduce()
5.some()
6.every()
7.all()方法
ES6编程题:
1.使用解构,实现两个变量值的交换
let a 1;
let b 2;
[a,b] [b,a];
2.利用数组推导,计算出数组
var arr1 [1, 2, 3, 4];
var arr2 [for (i of arr1) i * i];
console.log(arr2);
3.使用es6改下面的模板 let iam 我是;
let name 王德发;
let str 大家好iamname,多指教。;改: let iam 我是;
let name 王德发;
let str 大家好${iamname},多指教。; 4.把下面代码使用两种方法,来依次输出0到9? var funcs []for (var i 0; i 10; i) {funcs.push(function() { console.log(i) })}funcs.forEach(function(func) {func()})答分别使用es5的闭包和es6的let // ES5告诉我们可以利用闭包解决这个问题var funcs []for (var i 0; i 10; i) {func.push((function(value) {return function() {console.log(value)}}(i)))}// es6for (let i 0; i 10; i) {func.push(function() {console.log(i)})} 5.http1.0,http1.1,http2.0,http3.0的区别 http1.0 默认使用短连接--无状态,无连接每个请求都需要新建TCP连接,性能较低不支持多路复用基于文本的协议不支持头部压缩请求头不支持Host头域不支持服务器端推送不支持请求优先级不允许断点续传默认不加密,可使用https加密 http1.1 默认使用长连接允许在一个TCP连接上发送多个请求和响应,仍旧要求请求顺序发送和接收,即存在对头阻塞问题,这意味着一个请求的延迟可能会阻塞后续的请求,影响整体加载速度基于文本协议请求头支持Host头域不支持头部压缩增加更多的请求头和响应头来改进和扩充HTTP1.0的功能,比如身份证,状态管理和cache缓存等提供了丰富的缓存控制机制,比如cache-control,ETag等不支持服务器推送不支持请求优先级支持断点续传默认不加密,可使用HTTPS加密 http2.0 采用二进制格式: 实现方便且健壮,与基于文本的http1.x协议不同对头部进行高效压缩一个tcp连接能够处理多个http请求,实现了多路连接共享,多个请求和响应可以在一个TCP连接上交错发送,解决了队头阻塞问题依然基于TCP协议,受其拥塞控制和重传机制影响,可能存在延迟和性能瓶颈支持服务端推送,服务端可主动向客户端发送消息允许指定请求优先级支持流量控制 http3.0 不依赖TCP,基于QUIC协议,不用TCP作为传输层协议,使用基于UDP的QUIC协议,QUIC继承了TLS加密,流量控制,多路复用等功能,并在用户空间实现了快速连接建立,前向纠错,更精细的拥塞控制等特性 降低了网络延迟 解决了HTTP2.0中前一个stream丢包导致后一个stream被拥塞的问题 不再用tcp四元组确定一个连接,而是使用一个64位随机数来确定一个连接 支持头部压缩, 更强的抗丢包能力 支持服务端推送: 服务端可主动向客户端发送消息 允许指定请求优先级 采用TLS1.3作为默认的安全层协议,提供更强的安全性 6.跨域的option是什么? 概念: OPTIONS请求指的是Method为OPTIONS的http请求 作用: 它的作用是用于web服务器是否支持某些header,也可以叫做预检查请求(顾名思义:提前检测) MDN定义: HTTP的OPTIONS方法用于获取目的资源所支持的通信选项 OPTIONS请求的幅面影响: 请求数据会多一次往返的时间消耗具体消耗多长时间取决与用户到服务器端到端的网络延迟及服务的响应时长。 通常在 50ms~500ms 之间。后端程序员或一些 nginx 规则经常不处理 OPTIONS 请求 导致请求返回 404后续请求失败。 浏览器发起OPTIONS请求的条件: 请求跨域且 2、3 满足一个请求方法不是HEAD、GET、POSTHTTP 的头信息超出以下几种字段 AcceptAccept-LanguageContent-LanguageLast-Event-ID
Content-Type只限于三个值:
application/x-www-form-urlencoded、
multipart/form-data、
text/plain 大部分前后端程序员碰到OPTIONS请求是浏览器自动发起的 为什么只有跨域请求浏览器才会自动发起OPTIONS请求? 可以理解为,浏览器默认不同域名的服务器不是你维护的,保险起见需要先检查一下目标域名的服务器是否支持你自定义的header(或其他) 如何避免OPTIONS 配置网关转发规则,避免跨域将请求转换简单请求,比如自定义的header提供query参数传递如果你不需要读取该请求的返回内容,可设置mode:no-cors mode: no-cors---保证请求对应的Method只有HEAD,GET或者POST方法,请求请求的headers只能有简单请求头 mode: no-cors会忽略自定义的header 如果OPTIONS请求无法避免,设置缓存尽量降低其影响,比如缓存一年: Access-Control-Max-age: 31536000,这样后续相同url的请求就不会发起OPTIONS请求了 注意: 缓存是针对URL的,URL一旦发生缓存就会失效(比如URL中有时间戳),会重复发起OPTIONS请求 7.协商缓存和强制缓存 背景介绍 浏览器和服务器进行交互的过程 时间开销的瓶颈往往出现在数据的传输的过程之中。 这个场景类似介于 A城 到 B城 之间只有一座 “通道” 每次想从A城 到 B城 必须按照人数交付高昂的路费. 如果要减少这种高昂的路费开销的话 核心思想就是尽可能的减少通过这座 “通道” 的次数又或者减少通过这座通道的“人数”。基于这种理念在 http协议的基础上 提出了一种协议缓存这种协议缓存又可以细分为 强制缓存 和 协商缓存 两种分别对应上述减少过桥次数和减少过桥人数的理念。 http缓存机制简介 1) 强制缓存 强制缓存的思想是在浏览器内置数据库中缓存每次请求中 “可以被缓存”的静态资源如 image, css, js 文件等当第二次请求被缓存过的资源时候会通过校验两个字段 Expires 和 Cache-Control 的max-age字段(注意Expires 是 http1.0 的产物 Cache-Control 则是 http1.1 的产物)。Expires /Cache-Control 两者同时存在 或者只存在其中之一 都可以触发强制缓存当满足字段约束的情况下 浏览器就不会向服务器发送请求而是直接从服务器返回数据 同时其状态码为 200当不满足字段约束的情况下 浏览器则会向服务器正常发送请求. Expires 字段会存在失效的可能性? 当两个字段同时存在得到时候 Cache-Control 中的 max-age 字段字段优先级会稍微高一点 当 Cache-Control 中的 max-age 字段校验成功会直接返回浏览器内置数据库的缓存 失效时才会将决策权传递给 Expires 字段判断。 这样设计的原因大概是因为 Expires 字段在设计时存在了这么一个缺陷——Expires字段返回是服务器的时间 而非客户端的本机时间。当存在时差 或者客户修改本地时间的情况下 Expires 字段会存在失效的可能性比如 当同一时刻下的服务器时间为 2022/4/26 06:00:00 客户端时间为 2022/4/26 12:00:00 过期时间为两个小时之后 则服务器会返回 2022/4/26 08:00:00 这个时间对应的值。由于浏览器运行在客户环境下对于客户而言 这个缓存已经过期了虽然缓存确实有效 但是对于浏览器而言这个缓存确确实实是 “过期了” 这会导致强制缓存永远不会生效为了解决这个问题 http 1.1 协议中添加了 Cache-Control 中的 max-age 他是一个相对值 即客户端获取到这个文件多少秒后失效 其判别权力全权交由浏览器 这会相对更准确些。 2) 协商缓存 协商缓存主要由 ETag 和 Last-Modified 两个字段来实现ETag 是一个用于映射 web 资源的映射 token这个 token 应该满足唯一对应到一 个web服务器上的静态资源具体实现通常是提取文件相关信息进行hash和base64编码等操作Last-Modified 则通常是文件最后更新的日期时间戳通过上述两个字段就可以判断当前文件是否是最新的数据 流程: 浏览器首次向服务器请求数据 A 服务器正常返回数据同时在响应头中放入 ETag 和 Last-Modified 两个新字段。当浏览器第二次向服务器请求数据 A 时 浏览器会自动地在请求头附上 If-None-Match 和 If-Modified-Since 两个字段分别对应的是 ETag 和 Last-Modified 的值两两相等 然后由服务器端进行校验 校验通过的话表明数据有效 服务器会直接返回 状态码 304 且不携带响应体的报文段 这相当于告诉浏览器当前缓存有效 可以直接使用 校验失败则会和首次请求一样 返回状态码为200且携带数据响应体的报文段 同时这个响应头会带上新的ETag 和Last-Modified 为下一次协商缓存做好铺垫 。 注意: 在不用框架的情况下 协商缓存需要由后端开发人员手动实现因此 ETag 和 Last-Modified 两个字段的优先级取决于开发者 但是 Last-Modified 这个字段可以记录的时间戳精确度是有一定限制的如果连续多次数据更新在精确度范围外 会产生精确度丢失 因此通常会让ETag 的优先级高于 Last-Modified 字段类似于Cache-control中max-age一样 属于是后续改进协议的一个新字段 因此优先级一般会高点 3) 强制缓存 协商缓存 强制缓存和协商缓存联合: 默认情况下 浏览器会优先考量强制缓存的情况 当强制缓存生效的情况下 请求并不会到达服务器 因此也就不会触发协商缓存。 当强制缓存失效的时候 浏览器便会将请求传递到服务器 于是服务器又会开始校验 If-Modified-Since 和 If-None-math 两个字段 重复上述协商缓存的一个执行流程 乍一看两者并存的情况 有点像是两个协议的简单叠加此时的协商缓存更像是强制缓存的兜底策略 很可能协商缓存很长一段时间都不会生效强制缓存过期时间设置过长的情况下 因为强制缓存的优先级是要高于协商缓存的。 当然这并不是我们想看到的 比方说当后端数据确实变更了 而此时的浏览器由于使用了强制缓存则会出现数据不一致的情况 因此在这里引入了请求头中的两个字段 no-cache 当使用了 no-cache 字段的时候 浏览器将不再使用强制缓存 而是直接去请求服务器 这个时候就会用到协商缓存了顺带一提的是 还有一个 no-store 字段 用了这个字段浏览器则不会在使用缓存的数据也不缓存数据即强制缓存和协商缓存都失效了 缓存机制之间的一些区别: 强制缓存在缓存有效的情况下不会去请求服务器 其数据来源则是浏览缓存的本地磁盘。而协商缓存会向服务器请求但是在协商缓存成功的情况下 服务器只会返回一个不带响应体的报文结合开头的背景来说 强制缓存选择“减少过桥次数”的策略 而协商缓存则是采用 ‘减少过桥人数’的策略强制缓存在浏览器强制刷新的情况下不会生效 而协商缓存则不受影响。调试代码测试时候要注意强制缓存返回的报文状态码为 200 协商缓存返回的报文状态码为 304 前端使用fetch请求的情况 协商缓存的 状态码304 会转成 200强制缓存发生在浏览器端 协商缓存发生在服务器端 小结: 强制缓存存在一个瓶颈 当浏览器用户强刷新时浏览器会直接跳过强制缓存 这点不注意很容易会被忽视掉。强制缓存不适合 SPA 应用的入口文件 因为重新部署后 用户如果没有强制刷新 则无法在第一时间内看到新的网页内容。作为一个前端开发者可以通过设置请求头中的 no-cache 和 no-store 字段选择使用协商缓存或者不使用缓存 8.js正则-断言 ? 零宽先行断言省流: 后面是什么,理解为正则表达式的条件语句真正的内容在(?xxx)的左边 eg: 百度,后边是地址的加上链接 let str百度地址链接在左边;
let reg/百度(?地址链接在左边)/g;
let result;
console.log(resultstr.replace(reg,a hrefhttp://www.baidu.com$/a)); (?xx)只是条件,不会放在组中 常见的千分位面试题: var str1111000.12
var pattern new RegExp(\\B(?(\\d{3})(?!\\d)), g)
var strstr.replace(pattern,$,)
console.log(str)? 零宽后行断言省流: 前面是什么,用来判断前面的条件真正的内容在(?xxx)的右边 注意: 断言,匹配结果是看不到的,不要把它当成组 eg: 把网址全部换成www.baidu.com var stra hrefhttps://www.a.com百度1/aa hrefhttps://www.b.com百度2/a
;
/**
正则表达式中的反向引用概念:
在正则表达式中\1在某些正则表达式引擎中也可能是$1是一种反向引用。它用于引用前面捕获组匹配到的内容。
捕获组:
在这个正则表达式/(?href([])).(?\1)/gi中(?href([]))是一个正向零宽度断言它匹配href后面跟着一个单引号或者双引号的位置。这里的([])是一个捕获组它会捕获这个单引号或者双引号。
\1在这个表达式中是引用前面捕获组也就是([])捕获到的单引号或者双引号。这样(?\1)部分就表示匹配一个或多个字符直到遇到前面捕获组所捕获的那个引号为止。
*/
var reg/(?href([])).(?\1)/gi;
console.log(str.match(reg));
// replace的部分是(?href([]))右边,(?\1)右边的内容,即href内容中去掉左边的href,再去掉右边的,只替换内容
console.log(str.replace(reg,https://www.badiu.com)); ?! 零宽负向先行断言省流: 理解为后面不是什么 使用场景和示例 匹配不以特定字符开头的字符串 例如要匹配不以a开头的字符串可以使用[^a]。 匹配不以特定单词结尾的字符串 例如要匹配不以end结尾的字符串可以使用(?!end)。 eg: 不能出现哈喽: (?!.*哈喽)是一个前瞻否定断言它确保在当前位置之后的字符串中不存在 “哈喽” 这个词。这里的.*表示匹配任意数量的任何字符所以这个断言的意思是在整个字符串中从当前位置开始不能有任何字符序列最终导致出现 “哈喽”。如果返回true,表示不包含哈喽如果返回false,就表示包含哈喽 var str 这是一段文本没有哈喽。;
var regex /^(?!.*哈喽).*$/;
console.log(regex.test(str)); ?! 零宽负向后行断言省流:前面不是什么作为前面正则的附加条件内容为(?!xxx)左边(?!xxx)右边,(?xxx)左边(即改为类似https://www.xx.com的格式)与?相反 eg: // 不包含www: (?!www) // 可以包含斜杠/ (?\/) 真正需要替换的内容部分是(?!www)右边,(?\/)左边的,即中间\..匹配的字符串进行replace var stra hrefhttps://www.a.com/xx.jpgxx.jpg/aa hrefhttps://oss.a.com/xx.jpgxx.jpg/aa hrefhttps://cdn.a.com/xx.jpgxx.jpg/aa hrefhttps://a.com/xx.jpgbaidu/avar reg/(?hrefhttps:\/\/).*(?a.com)/gm
console.log(str.match(reg));
console.log(str.replace(reg,www.));
// 或者
reg/https:\/\/([a-z])?(?!www)\..?(?\/)/g
console.log(str.match(reg));
console.log(str.replace(reg,https://www.badu.com)); 9.格式化网址的query字符串
eg1:
// 格式化query字符串要考虑到同名key的情况 // 例?a1a2b3 最终结果为 { a: [1, 2], b: 3 }
// 格式化query字符串要考虑到同名key的情况
// 例?a1a2b3 最终结果为 { a: [1, 2], b: 3 }
function parseQueryString(queryString) {var str queryStringvar idx1 str.indexOf(?)str1 idx1 0 ? str.substring(1) : strvar query {}// 先组成一个新的对象数组格式为 [{key: a, value: 1}, {key: a, value: 2}, {key: b, value: 3}]var arr str1.split().map((item, index) {var idx item.indexOf()// 获取key值var key item.substring(0, idx)// 获取value值var value item.substring(idx 1)return {key: key,value: value,}})// 遍历对象数组筛选key值一致的分组并组成新的对象数组// 如果key值筛选出来只有一项则值为字符串// 如果key值筛选出来由多项相同则值为数组// 给query对象赋值// 最终预期结果为 { a: [1, 2], b: 3 }arr.forEach((item) {var arr0 arr.filter(ee ee.key item.key)query[item.key] arr0.length 1? arr0.map(ee ee.value): item.value});return query
}var str ?a1a2b3
console.log(parseQueryString(str)) eg2:
// 格式化query字符串 // 例?a1b2c3 最终结果为 { a:1, b: 2,c3 }
// 格式化query字符串
// 例?a1a2b3 最终结果为 { a: 1, b: 2, c:3 }
function parseQueryString(queryString) {var str queryStringvar idx1 str.indexOf(?)str1 idx1 0 ? str.substring(1) : strvar query {}str1.split().forEach((item) {var idx item.indexOf()// 获取key值var key item.substring(0, idx)// 获取value值var value item.substring(idx 1)query[key] value})return query
}var str ?a1b2c3
console.log(parseQueryString(str))
10.基本数据类型和引用类型地址是栈还是堆? 基本数据类型: 如 number, string, boolean, null, undefined 和 symbol的值直接存储在栈内存中。 引用类型: 如 object, array, function的值存储在堆内存中但在栈内存中会存储一个指向堆内存中实际数据的引用。 地址的区别: 栈内存中的地址 存储的是基本数据类型的值。存储的是引用类型的引用指针。栈内存中的地址是固定的由编译器管理。 堆内存中的地址 存储的是引用类型的实际数据。堆内存中的地址是动态分配的由垃圾回收机制管理。 三、大前端面试笔试题
1. 前端工程化 什么是前端工程化 指的是将前端开发过程中的一系列流程和工具进行规范和自动化从而提高开发效率减少重复劳动降低出错率。前端工程化的目标是让前端开发更高效 1 定义 将开发的流程工具和规范化并使用相关技术实现自动化包括代码编写测试构建部署等环节以提高前端开发效率提高代码质量和可维护性 2 为什么需要前端工程化 提高开发效率 提高代码质量和可维护性减少出错和重复工作减轻开发人员的工作负担专注业务逻辑的开发 核心概念 模块化打包构建自动化部署自动化测试持续集成 模块化 将一个大的应用程序分成多个小的模块每个模块都有自己的功能和特点可以独立开发测试和维护。常见的模块化方案 CommonJSES6模块AMD等 打包构建 多个模块组合起来生成可以在浏览器中运行的代码过程 压缩文件合并资源管理等常见的打包工具 webpack rollup等 自动化部署 将打包后的代码部署到生产环节或者测试/开发环节中的自动化过程自动化部署可以减少手动部署的错误和工作量同时也可以缩短部署的时间自动化部署工具 Jenkins Drone GitLab CICD 自动化测试 使用自动化工具对代码进行测试确保在开发中不会出现问题部署到生产环境也不会出现问题分为两类 单元测试和端对端测试单元测试指的是应用程序最小的可测试单元比如一个函数或类 端对端测试指的是应用程序的整个流程包括用户界面和后端逻辑优势 提高开发效率和代码质量 持续集成 开发过程中频繁将代码集成到共享代码库中每次集成都会自动化构建和自动化测试确保代码稳定性和质量更快速地检测和修复错误优势提高开发效率加速代码部署减少错误加强团队协作性更高效地响应客户需求 工程化主要工具 包管理 npm yarn构建 webpack rollup Parcel, Gulp, Grunt自动化测试 Jest Mocha Karma Cpress Puppeteer集成 Jenkins GitLab CI/CD Github Actions 常见的工程化的应用方案: 模块化: CommonJS, AMD,ES6模块等打包构建:webpack, rollup等自动化部署: Jenkins等自动化测试: Jest等持续集成: Jenkins等 打包构建优化: 使用webpack将多个模块打包,对代码进行压缩,代码分割,异步加载,懒加载,cdn配置等减少页面加载时间和提高性能使用Jest实现自动化测试,即使发现和处理问题Jenkins实现自动化部署,自动构建并部署代码到服务器 学习工程化: 掌握基本前端技术学习相关的工具和框架多做实战学点运维知识 2.微任务,宏任务笔试题 注意: 很容易误会new Promise函数是异步,其实是同步,然后误以为是第一个打印的是5(很容易中招) new Promise如果没有使用.then/.catch/.finally这种链式调用就不是异步,而是同步
setTimeout(function () {
console.log(1);
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for (var i 0; i 10000; i) {
i 9999 resolve();
}
console.log(3);
}).then(function () {
console.log(4);
});
console.log(5); 还有一个类似的例子: 宏任务微任务笔试题示例(console.log输出顺序)_微任务红任务的代码题-CSDN博客 3.数组筛选分组 根据parentId将数据分组一般用于树形下拉框地数据格式化 注意 使用var是为了在浏览器控制台多次粘贴过去测试 var array [
{ id: 1, name: child1, parentId: 0 },
{ id: 3, name: child3, parentId: 1 },
{ id: 2, name: child2, parentId: 1 },
{ id: 0, name: parent0 },
{ id: 4, name: child4, parentId: 3 },
{ id: 8, name: child8, parentId: 0 },
{ id: 10, name: parent10 },
{ id: 5, name: child5, parentId: 2 },
{ id: 6, name: child6, parentId: 1 },
{ id: 11, name: child11, parentId: 10 },
{ id: 12, name: child12, parentId: 10 },
{ id: 13, name: child13, parentId: 8 },
{ id: 14, name: child14, parentId: 0 }
];var obj {} // 利用对象的key是唯一性进行去重筛选
for(let item of array) {var children array.filter(its its.parentId item.id)if(typeof item.parentId undefined) {obj [item.id] {id: item.id,name: item.name,children,}}
}// 将对象转换为期望的数组结构
var arr Object.values(obj)
console.log(arr); 4.数组去重 题目在不使用任何 API 和es6 新特性的情况下实现数组去重用最原始的方法实现 思路 利用arr.includes(item)数组中是否包含itemtrue表示包含false表示不包含如果是false就往arr中push元素利用arr.indexOf(item),如果为-1表示数组中不存在item如果是大于等于0就表示数组中包含item如果是-1就往arr中push元素 function getArr (arr0) {let arr []for (let item of arr0) {!arr.includes(item) arr.push(item)}return arr
}
console.log(getArr([1,3,3,5,1,2,3,5,9,8,7,6,4,3])) // [1, 3, 5, 2, 9, 8, 7, 6, 4]function getArr (arr0) {let arr []for (let item of arr0) {arr.indexOf(item) -1 arr.push(item)}return arr
}
console.log(getArr([1,3,3,5,1,2,3,5,9,8,7,6,4,3])) // [1, 3, 5, 2, 9, 8, 7, 6, 4] 5.简述几种http请求地方式比如getpost...? HTTPHyperText Transfer Protocol是一种用于传输超文本的应用层协议定义了客户端和服务器之间通信的标准。HTTP 请求方法也称为 HTTP 动词用于指示客户端希望对资源执行的操作。以下是几种常用的 HTTP 请求方法及其用途 GET 用途请求指定的资源通常用于获取数据。特点 请求参数附在 URL 中长度有限制。请求是幂等的即多次相同的 GET 请求应该返回相同的结果。请求是可缓存的。不适合传输敏感数据因为 URL 可能会被记录在浏览器历史和服务器日志中。 POST 用途向指定资源提交数据通常用于创建新资源或提交表单数据。特点 请求参数放在请求体中没有长度限制。请求不是幂等的多次相同的 POST 请求可能会产生不同的结果。不可缓存。适合传输敏感数据因为数据不在 URL 中。 PUT 用途向指定资源提交数据通常用于更新现有资源。特点 请求参数放在请求体中没有长度限制。请求是幂等的多次相同的 PUT 请求应该返回相同的结果。不可缓存。通常用于完全替换资源。 DELETE 用途请求服务器删除指定的资源。特点 请求参数可以放在 URL 中也可以放在请求体中。请求是幂等的多次相同的 DELETE 请求应该返回相同的结果。不可缓存。 HEAD 用途请求指定资源的头部信息而不返回资源本身。特点 类似于 GET 请求但不返回消息体。用于获取资源的元数据如内容长度、最后修改时间等。请求是幂等的。可缓存。 OPTIONS 用途请求指定资源支持的 HTTP 方法。特点 用于预检请求通常用于跨域请求。服务器响应中包含 Allow 头列出支持的方法。请求是幂等的。不可缓存。 PATCH 用途向指定资源提交部分修改数据通常用于更新资源的部分属性。特点 请求参数放在请求体中没有长度限制。请求不是幂等的多次相同的 PATCH 请求可能会产生不同的结果。不可缓存。适用于部分更新资源。 总结 GET获取资源。POST创建资源或提交数据。PUT更新资源完全替换。DELETE删除资源。HEAD获取资源的头部信息。OPTIONS获取资源支持的 HTTP 方法。PATCH更新资源的部分属性。 6.OPTIONS请求方式示例 OPTIONS 请求方法在跨域请求中主要用于预检请求Preflight Request。预检请求是浏览器在发送实际请求之前为了确保实际请求的安全性而发送的一种特殊请求。预检请求可以帮助浏览器确定实际请求是否安全是否会被服务器允许。 跨域预检请求的流程 1客户端发送预检请求 浏览器在发送实际的跨域请求之前会先发送一个 OPTIONS 请求。OPTIONS 请求的目的是询问服务器是否允许即将发送的实际请求。 2服务器响应预检请求 服务器会检查 OPTIONS 请求中的 Access-Control-Request-Method 和 Access-Control-Request-Headers 头。服务器会根据这些头信息决定是否允许实际请求并在响应中设置相应的 CORSCross-Origin Resource Sharing头。 3客户端发送实际请求 如果服务器允许实际请求浏览器会发送实际的请求如 GET、POST 等。如果服务器不允许实际请求浏览器会阻止实际请求的发送并抛出一个跨域错误。 客户端发送POST请求 const xhr new XMLHttpRequest();
xhr.open(POST, http://127.0.0.1:3000/data, true);
xhr.setRequestHeader(Content-Type, application/json);
xhr.setRequestHeader(X-Custom-Header, custom-value);xhr.onreadystatechange function() {if (xhr.readyState 4) {if (xhr.status 200) {console.log(Success:, xhr.responseText);} else {console.error(Error:, xhr.status);}}
};xhr.send(JSON.stringify({ key: value })); 服务器端需要处理 OPTIONS 请求并设置适当的 CORS 头。 const express require(express);
const app express();app.use((req, res, next) {// 设置 CORS 头res.header(Access-Control-Allow-Origin, *);res.header(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS);res.header(Access-Control-Allow-Headers, Content-Type, X-Custom-Header);// 处理 OPTIONS 请求if (req.method OPTIONS) {res.status(200).end();} else {next();}
});app.post(/data, (req, res) {// 处理实际的 POST 请求const body req.body;console.log(Received data:, body);res.json({ message: Data received successfully });
});app.listen(3000, () {console.log(Server is running on port 3000);
}); package.json {dependencies: {express: ^4.21.1},scripts: {start: node server.js}
}将index.html放进xampp中启动apache !DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
body/body
scriptconst xhr new XMLHttpRequest();xhr.open(POST, http://127.0.0.1:3000/data, true);xhr.setRequestHeader(Content-Type, application/json);xhr.setRequestHeader(X-Custom-Header, custom-value);xhr.onreadystatechange function() {if (xhr.readyState 4) {if (xhr.status 200) {console.log(Success:, xhr.responseText);} else {console.error(Error:, xhr.status);}}};xhr.send(JSON.stringify({ key: value }));
/script
/html 解析 1客户端代码 创建一个 XMLHttpRequest 对象。设置请求方法为 POSTURL 为 https://api.example.com/data。设置请求头 Content-Type 为 application/json并添加自定义头 X-Custom-Header。设置 onreadystatechange 回调函数处理响应。发送请求体数据。 2服务器端代码 使用中间件设置 CORS 头允许所有来源的请求并允许 GET, POST, PUT, DELETE, OPTIONS 方法。允许 Content-Type 和 X-Custom-Header 头。处理 OPTIONS 请求返回状态码 200。处理实际的 POST 请求读取请求体数据并返回响应。 四、代码规范化
1.babelrc配置支持reacttypescript语法 .babelrc {presets: [babel/preset-react, babel/preset-typescript,babel/preset-env],plugins: [[babel/plugin-proposal-decorators, { legacy: true }],babel/plugin-proposal-nullish-coalescing-operator,babel/plugin-proposal-optional-chaining,babel/plugin-proposal-class-properties,babel/plugin-proposal-object-rest-spread,babel/plugin-transform-runtime]
} 2.eslint配置
.eslintrc.js
module.exports {parser: typescript-eslint/parser,extends: [eslint:recommended,plugin:react/recommended,plugin:typescript-eslint/recommended],plugins: [react, react-hooks, typescript-eslint],settings: {react: {version: 16.8 // 指定 React 版本}},rules: {react-hooks/rules-of-hooks: error, // 检查 Hooks 的使用react-hooks/exhaustive-deps: warn, // 检查 useEffect 等 Hook 的依赖项prefer-const: off, // 关闭 prefer-const 规则typescript-eslint/explicit-function-return-type: off, // 关闭 explicit-function-return-type 规则react/prop-types: off, // 关闭 prop-types 规则typescript-eslint/no-unused-vars: off, // 关闭 no-unused-vars 规则typescript-eslint/no-use-before-define: off, // 关闭 no-use-before-define 规则react/display-name: off, // 关闭 display-name 规则no-prototype-builtins: off, // 关闭 no-prototype-builtins 规则typescript-eslint/camelcase: off // 关闭 camelcase 规则},env: {browser: true,es6: true},parserOptions: {ecmaVersion: 2018,sourceType: module,ecmaFeatures: {jsx: true}}
}
下载插件
eslint: ^6.8.0,eslint-plugin-react: ^7.37.2,eslint-plugin-react-hooks: ^1.7.0,husky: ^9.1.6,lint-staged: ^15.2.10,
pre-commit相关配置
scripts: {test: echo \Error: no test specified\ exit 1,prepared: husky install,eslint:fix: eslint --fix,lint: eslint src/**/*.ts src/**/*.tsx,prettier-format: prettier --write},husky: {hooks: {pre-commit: lint-staged}},lint-staged: {*.{js,jsx,,ts,tsx}: [npm run eslint:fix,npm run prettier-format]},eslintConfig: {extends: react-app},
2.styleint配置
下载插件
stylelint: ^16.10.0,stylelint-config-recommended-less: ^3.0.1,stylelint-less: ^3.0.1,stylelint-order: ^6.0.4,husky: ^9.1.6,lint-staged: ^15.2.10,
.stylelintrc.js
module.exports {overrides: [{customSyntax: postcss-scss,files: [**/*.css, **/*.scss]},{customSyntax: postcss-less,files: [**/*.less]},{customSyntax: postcss-html,files: [**/*.html, **/*.vue, **/*.nvue]}],plugins: [stylelint-order],rules: {// 禁止未知单位unit-no-unknown: null,// 为适用的颜色功能指定现代或传统符号color-function-notation: legacy,// 禁止无效的十六进制颜色color-no-invalid-hex: true,// 不允许未知的规则at-rule-no-unknown: [true,{ignoreAtRules: [content,each,error,extend,for,function,if,include,mixin,return,while,tailwind,apply,variants,responsive,screen]}],order/properties-order: [{// Must be first.properties: [all]},{// Position.properties: [position,inset,inset-block,inset-inline,top,right,bottom,left,z-index]},{// Display mode.properties: [box-sizing, display]},{// Flexible boxes.properties: [flex,flex-basis,flex-direction,flex-flow,flex-grow,flex-shrink,flex-wrap]},{// Grid layout.properties: [grid,grid-area,grid-template,grid-template-areas,grid-template-rows,grid-template-columns,grid-row,grid-row-start,grid-row-end,grid-column,grid-column-start,grid-column-end,grid-auto-rows,grid-auto-columns,grid-auto-flow,grid-gap,grid-row-gap,grid-column-gap]},{// Gap.properties: [gap, row-gap, column-gap]},{// Layout alignment.properties: [place-content,place-items,place-self,align-content,align-items,align-self,justify-content,justify-items,justify-self]},{// Order.properties: [order]},{// Box model.properties: [float,width,min-width,max-width,height,min-height,max-height,aspect-ratio,padding,padding-block,padding-block-start,padding-block-end,padding-inline,padding-inline-start,padding-inline-end,padding-top,padding-right,padding-bottom,padding-left,margin,margin-block,margin-block-start,margin-block-end,margin-inline,margin-inline-start,margin-inline-end,margin-top,margin-right,margin-bottom,margin-left,overflow,overflow-x,overflow-y,-webkit-overflow-scrolling,-ms-overflow-x,-ms-overflow-y,-ms-overflow-style,overscroll-behavior,overscroll-behavior-x,overscroll-behavior-y,overscroll-behavior-inline,overscroll-behavior-block,clip,clip-path,clear]},{// Typography.properties: [font,font-family,font-size,font-variation-settings,font-style,font-weight,font-feature-settings,font-optical-sizing,font-kerning,font-variant,font-variant-ligatures,font-variant-caps,font-variant-alternates,font-variant-numeric,font-variant-east-asian,font-variant-position,font-size-adjust,font-stretch,font-effect,font-emphasize,font-emphasize-position,font-emphasize-style,-webkit-font-smoothing,-moz-osx-font-smoothing,font-smooth,hyphens,line-height,color,text-align,text-align-last,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-decoration,text-decoration-line,text-decoration-thickness,text-decoration-style,text-decoration-color,text-underline-position,text-underline-offset,text-indent,text-justify,text-outline,-ms-text-overflow,text-overflow,text-overflow-ellipsis,text-overflow-mode,text-shadow,text-transform,text-wrap,-webkit-text-size-adjust,-ms-text-size-adjust,letter-spacing,word-break,word-spacing,word-wrap, // Legacy name for overflow-wrapoverflow-wrap,tab-size,white-space,vertical-align,list-style,list-style-position,list-style-type,list-style-image,src,font-display,unicode-range,size-adjust,ascent-override,descent-override,line-gap-override]},{// Accessibility Interactions.properties: [pointer-events,-ms-touch-action,touch-action,cursor,visibility,zoom,table-layout,empty-cells,caption-side,border-spacing,border-collapse,content,quotes,counter-reset,counter-increment,resize,user-select,nav-index,nav-up,nav-right,nav-down,nav-left]},{// Background Borders.properties: [background,background-color,background-image,-ms-filter:\\progid:DXImageTransform.Microsoft.gradient,filter:progid:DXImageTransform.Microsoft.gradient,filter:progid:DXImageTransform.Microsoft.AlphaImageLoader,filter,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,background-blend-mode,isolation,border,border-color,border-style,border-width,border-block,border-block-start,border-block-start-color,border-block-start-style,border-block-start-width,border-block-end,border-block-end-color,border-block-end-style,border-block-end-width,border-inline,border-inline-start,border-inline-start-color,border-inline-start-style,border-inline-start-width,border-inline-end,border-inline-end-color,border-inline-end-style,border-inline-end-width,border-top,border-top-color,border-top-style,border-top-width,border-right,border-right-color,border-right-style,border-right-width,border-bottom,border-bottom-color,border-bottom-style,border-bottom-width,border-left,border-left-color,border-left-style,border-left-width,border-radius,border-start-start-radius,border-start-end-radius,border-end-start-radius,border-end-end-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,box-shadow,mix-blend-mode,filter:progid:DXImageTransform.Microsoft.Alpha(Opacity,-ms-filter:\\progid:DXImageTransform.Microsoft.Alpha,opacity,-ms-interpolation-mode]},{// SVG Presentation Attributes.properties: [alignment-baseline,baseline-shift,dominant-baseline,text-anchor,word-spacing,writing-mode,fill,fill-opacity,fill-rule,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,color-interpolation,color-interpolation-filters,color-profile,color-rendering,flood-color,flood-opacity,image-rendering,lighting-color,marker-start,marker-mid,marker-end,mask,shape-rendering,stop-color,stop-opacity]},{// Transitions Animation.properties: [transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction]}]}
}pre-commit配置:
scripts: {prepared: husky install,lint:styles: stylelint \**/*.less\,lint:fix: stylelint \**/*.less\ --fix},husky: {hooks: {pre-commit: lint-staged}},lint-staged: {*.{css,less}: [npm run lint:styles]},
3.prettier配置
.prettierrc.js
// .prettierrc.js
module.exports {printWidth: 100,semi: true,singleQuote: true,tabWidth: 2,
};下载插件
prettier: ^3.3.3,
pre-commit配置
scripts: {prepared: husky install,prettier-format: prettier --write},husky: {hooks: {pre-commit: lint-staged}},lint-staged: {*.{js,jsx,,ts,tsx}: [npm run prettier-format]},