11、原型和原型链
1)、原型:
每个函数都会有一个属性prototype。这个属性就是原型属性。JavaScript在实现面向对象时,会经常使用原型。每个对象(实例)的有一个属性( __ proto __)指向构造函数的prototype属性(prototype指向的内存区域)。prototype属性里保存着所有对象(实例)共享的属性和方法。
2)、原型链:当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的 __ proto __ 隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的 __ proto __中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
12、作用域和作用域链
原生js面试题:作用域和作用域链,let声明的全局变量不是window对象的属性_jiang7701037的博客-CSDN博客_let不影响作用域链
作用域,就是变量起作用的区域(范围)。或者说,js代码执行时,查找变量的范围。
作用域链是指:当js编译器在寻找变量时,先在最近的作用域(花括号)里找,如果找不到,则朝上一级作用域(花括号)里找,依次类推,直到找到或者找不到为止。这就是作用域链。
13、Ajax的步骤与封装 AJAX中的200和4分别是什么意思
1)、AJAX的步骤:
ajax的流程,readyState和status的意思 1、创建XMLHttpRequest let xhr = new XMLHttpRequest() 2、设置(请求方式,请求路径,请求参数) xhr.open("get", "regSave.php?username=jzm&userpass=123", true) 3、设置回调函数(后端有响应时,调用的回调函数) xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { xhr.responseText //后端响应的内容,如:php中的echo 后面跟的内容 } } 4、发送 xhr.send(); //readyState:请求响应的状态(请求响应进行到哪一步了) //status:响应结果的描述,是个状态码(数字)
2)、封装ajax的代码:
function ajax2110UseObj(obj){ let defaultObj = { method:"get", url:"#", params:"", callback:null, isAsync:true } for(let key in defaultObj){ // 把obj里没有传入的属性使用defaultObj的对应属性。 if(obj[key]==undefined){ obj[key]=defaultObj[key]; } } // 1、创建XMLHttpRequest对象 let xhr = new XMLHttpRequest(); // 2、设置请求相关信息 let urlAndParams = obj.url; if(obj.method.toLowerCase()=="get"){ urlAndParams += "?"+obj.params } xhr.open(obj.method,urlAndParams,obj.isAsync); // 3、设置回调函数(后端响应时,调用的函数) xhr.onreadystatechange = function(){ if(xhr.readyState==4 && xhr.status==200){ obj.callback && obj.callback(xhr.responseText); } } if(obj.method.toLowerCase()=="get"){ // 4、发送请求 xhr.send(); }else if(obj.method.toLowerCase()=="post"){ // 如果是post方式,必须设置请求头。 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.send(obj.params); } }
3)、200和4分别是什么意思
readyState属性:表示ajax从请求到响应过程中的状态,即:请求响应过程中进行到了哪一步?readyState的取值是0 ---- 4。
0:表示刚创建好对象XMLHttpRequest
1:open函数调用完毕后,
2:表示后端接收到了响应
3:表示后端正在处理
4:表示后端处理完毕(即:请求响应的过程结束了)
readyState==4:表示请求响应的过程完毕
status属性: 这是表示http的响应状态码。200表示执行成功。关于其它HTTP状态码,可以查看文章:
HTTP请求响应系列02_响应报文的详解_jiang7701037的博客-CSDN博客
14、深浅拷贝 区别以及如何进行深拷贝
面试题:深拷贝和浅拷贝(超级详细,有内存图)_jiang7701037的博客-CSDN博客_深拷贝和浅拷贝
场景:
说深拷贝和浅拷贝,特指引用类型。
区别:
深拷贝: 把引用类型的地址及其它的数据都拷贝一份
浅拷贝: 只拷贝了引用类型的地址
如何进行深拷贝:
深拷贝的思路:
创建空对象,循环原对象的每个键,一一 赋值给空对象,并使用递归的方式,把对象属性也进行复制,以下为示例代码:
// 功能:封装一个深拷贝的函数 // 参数:被拷贝的对象 // 返回值:拷贝的对象 function copyObj(obj){ let newObj ={}; for(let key in obj){ if(typeof obj[key] == "object"){ //如果说当前属性是对象的话,那么再做深拷贝 newObj[key] = copyObj(obj[key]); }else{ newObj[key] = obj[key]; } } return newObj; } var obj1= { name:"张三疯", sex:"男", address:{ province:"陕西", city:"西安" } } let obj2 = copyObj(obj1);
面试题:深拷贝和浅拷贝(超级详细,有内存图)_jiang7701037的博客-CSDN博客_深拷贝和浅拷贝
15、promise都有哪几种状态 其执行状态
概述:
Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,可以获取异步操作的消息
作用:
(1)、避免回调地狱的问题
(2)、Promise对象提供了简洁的API,使得控制异步操作更加容易
Promise有三种状态:
pendding :正在进行中,
rejected :失败,
resolved : 成功
基础用法:
new Promise(function(resolve,reject){
异步代码
})
16、数组去重的方法
①利用数组indexof方法
function unique(arr) { var arr1 = []; for (var i = 0; i < arr.length; i++) { if (arr1.indexOf(arr[i]) == -1) { arr1.push(arr[i]); } } return arr1; } console.log(unique([1,1,2,2,3,3,3,4,5,6,6,6,7]));//1,2,3,4,5,6,7
②ES6的Set
function unique(arr){ return [...new Set(arr)] } console.log(unique([1,2,1,2,2,3,2,1]));
数组去重的方法比较多,大家可以自行再思考
17、js如何创建数组,js数组都有哪些方法?
1、有两种创建方式:
①字面量创建: var arr=[];
②构造函数创建: var arr1=new Array();
2、js数组的方法:
push 尾增
pop 尾删
unshift 头增
shift 头删
concat 数组拼接
join 数组转字符串
reverse 逆序
sort 按字符串UniCode码排序
map 对数组的每个元素做某个处理,参数是回调函数,并且有返回值
slice 复制
indexOf 查找数组中的元素,找到返回该元素下标, 没找到返回-1
splice 截取
filter 过滤
every 对数组中的每一项进行判断,若都符合则返回true,否则返回false
some 对数组中的每一项进行判断,若都不符合则返回false,否则返回true
reduce:将数组所有数值进行叠加返回
forEach 对数组的每个元素做某个处理,参数是回调函数
18、同一个数组,同样的限制条件,map和filter find返回值有什么区别
相同点:都不会改变原数组
不同点:
map返回值是一个新的数组,新数组中的元素为原始数组中的元素调用函数处理后的值。
find返回值:方法返回数组中满足提供的测试函数的第一个元素的值,否则返回 undefined。返回值不是数组!
const array1 = [5, 12, 8, 130, 44]; const found = array1.find(element => element > 10); console.log(found);//12
filter返回值:返回一个新数组 是原数组中符合条件的所有元素。
19、延时器(宏任务微任务)
javascript的事件循环(event loop)_jiang7701037的博客-CSDN博客
1)、宏任务(macrotask )
宏任务一般包括: setTimeout,setInterval,I/O 操作(包括AJAX请求)。
2)、微任务(microtask )
微任务一般包括:promise.then() 里的操作
20、闭包 什么情况下会使用闭包
概念:定义在一个函数内部的函数,并且这个内部函数能够访问到外层函数中定义的变量
作用:
①让外部访问函数内部变量成为可能
②局部变量会常驻在内存中
③可以避免使用全局便变量,防止全局变量污染
缺点:
会造成内存泄露(内存空间长期被占用,而不被释放)
场景:
1)、只有一个方法的对象
因为闭包允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
示例:
//面向对象的类 // class Person{ // constructor(){ // this.name = "陈琳" // } // eat(){ // console.log(this.name+"在吃,天在看……"); // } // } // let p1 = new Person(); // p1.eat(); //使用闭包 function person(str){ var name = str; return function(){ console.log(name+"在吃,天在看……"); } } let eat = person("陈琳"); eat();
2)、如果某些数据,只希望某些函数操作使用
3)、用闭包模拟私有方法
编程语言中,比如 Java,是支持将方法声明为私有的,即它们只能被同一个类中的其它方法所调用。
而 JavaScript 没有这种原生支持,但我们可以使用闭包来模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分
function person(str){ var name = str; var age = 20; function setAge(transAge){ fn2(); age = transAge; } function getAge(){ fn2(); return age; } function fn2(){ console.log("fn2"); } return { setAge:setAge, getAge:getAge } } let p = person("陈琳"); p.setAge(18); console.log(p.getAge()); p.fn2();