做为junior developer,仅仅以为这些问题常常在我面试的时候被问到,好记性不如烂笔头,本身整理记录一遍~~~javascript
1.javascript如何实现继承? 三种方式: 1. 原型继承 // 优势:既继承了父类的模板,又继承了父类的原型对象 // 缺点:父类实例化传参,而不是子类实例化传参(不符合常规语言的写法) function Parent(work, drink) { this.work = function() { console.log(work); } this.drink = drink; } Parent.prototype.draw = function() { alert("I can draw"); } function Child() { this.cry = function() { console.log("the best ability is to cry"); } } Child.prototype = new Parent('code', 'beer'); var xiaoLi = new Child(); xiaoLi.work(); // code xiaoLi.draw(); // I can draw xiaoLi.cry(); // the best ability is to cry 关于原型链的解释:https://www.cnblogs.com/chengzp/p/prototype.html 2. 类继承(借用构造函数的方式继承) // 优势:继承了父类的模板,方便经过子类实例化传参 // 缺点:不能继承父类的原型对象 function Parent(work, drink) { this.work = function() { console.log(work); } this.drink = drink; } Parent.prototype.draw = function() { alert("I can draw"); } function Child(work, drink, sex) { Parent.call(this, work, drink); this.sex = sex; } var xiaoLi = new Child('code', 'beer', 'male'); alert(xiaoLi.drink); // code xiaoLi.work(); // beer // xiaoLi.draw(); //没有继承父类的原型对象,因此,会报错:xiaoLi.draw() is not a function console.log(xiaoLi.sex); // male 3. 混合继承(原型继承和类继承) // 混合继承(原型继承和类继承(借用构造函数的方式继承)) function Parent(eat, sleep) { this.eat = function() { console.log("function 1" + eat); } this.sleep = function() { console.log("function 2" + sleep); } } Parent.prototype.other = "work"; function Child(eat, sleep, age) { Parent.call(this, eat, sleep); this.age = age; } Child.prototype = new Parent(); var xiaoLi = new Child("cake", "want to sleep", "10"); xiaoLi.eat(); xiaoLi.sleep(); console.log(xiaoLi.age); console.log(xiaoLi.other);
2.原生ajax是如何实现的? 特色: 在不从新加载整个网页的状况下,对页面局部进行刷新。 XMLHttpRequest对象是实现ajax的基础,XMLHttpRequest有不少方法,经常使用的有open(),send()等 ajax请求共包含五个步骤: 1.建立XMLHttpRequest对象(一个异步调用对象) 2.设置HTTP请求的参数(请求方法,url,是否异步) 3.设置响应HTTP请求状态变化的回调函数 4.发送HTTP请求 5.获取异步调用返回的数据 6.局部更新页面 var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) { fn.call(this, xhr.responseText); } }; xhr.send(data); post方法必定要用setRequestHeader("header","value");
3.做用域 块级做用域:ES6才支持,在{}大括号内的就是块级做用域 (块级做用域的出现解决了:for循环定义的变量形成的全局污染;不用再经过闭包来保存必要的变量了) 函数做用域:在函数中实现的 全局做用域:在外部声明的,若是没有用var关键字声明,在非严格模式下,也为全局做用域 注意: 在es6以前没有块级做用域这个概念,因此在{}块级做用域中声明的变量其实就是全局变量(举个栗子) for (var i = 1; i <= 10; i++) { console.log (i); // outputs 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; }; // The variable i is a global variable and it is accessible in the following function with the last value it was assigned above function aNumber () { console.log(i); } // The variable i in the aNumber function below is the global variable i that was changed in the for loop above. Its last value was 11, set just before the for loop exited: aNumber (); // 11 关于es6的let和const: let和const没有变量声明的提高; let和const不容许在相同做用域内重复声明;
4.如何理解闭包? 比较经常使用的情景: 在A函数里返回B函数,B函数能够调用A函数的局部变量; 特色: 1.函数嵌套 2.函数内部能够引用外部的参数和变量 3.闭包函数里的参数和变量不会被垃圾回收机制回收(闭包会使变量始终保存在内存中,若是使用不当会增大内存消耗) 闭包的好处: 1.但愿变量长期保存在内存中 2.避免全局变量的污染 3.私有变量的存在
5.回调函数 定义: 函数A做为参数传递给函数B,在函数B中执行函数A,此时函数A就叫作回调函数。若是函数没有名称(函数表达式),就叫作匿名回调函数。 回调函数不必定用于异步,同步(阻塞)场景下也会用到回调函数。好比说要求在执行完某些操做后执行回调函数。 举几个栗子: 同步(阻塞)回调: fn1执行完后执行fn2 在同步场景下,回调函数最后执行 异步回调: ajax请求 在异步回调中,回调函数有可能不执行,由于时间没有被触发或者条件不知足 回调函数的应用场景: 动态加载js后,图片加载完成后,ajax请求等 另外,最好保证回调存在且必须是函数引用或者函数表达式: (callback && typeof(callback) === "function") && callback();
6.es6经常使用新特性: 1.let和const(新的变量声明方式,容许把变量做用域控制在块级里面) 2.解构赋值(对象和数组都适用) 3.promise 一个对象,用来表示并传递异步操做的最终结果 交互方式:将回调函数传入then方法获取最终结果或出错缘由 以链式调用代替回调函数层层嵌套 //生成promise实例 var promise = new Promise(function(resolve, reject) { //...other code... if (/* 异步操做成功 */){ resolve(value);//resolve函数将Promise对象的状态从Pending变为Resolved } else { reject(error);//reject函数将Promise对象的状态从Pending变为Rejected } }); //Promise实例生成之后,用then方法分别指定Resolved状态和Reject状态的回调函数。 promise.then(function(value) { // success }, function(err) { // failure }); jQuery.ajax()方法中运用promise: var http = { get: function(url) { var promise = new Promise(function(resolve, reject) { $.ajax({ url: url, method: 'get', success: function(data) { resolve(data); }, error: function(xhr, statusText) { reject(statusText); } }); }); return promise; } }; http.get('data.php').then(function(data) { document.write(data); }, function(err) { document.write(err); }); 这里是获取的data值: /* data.php文件 */ <?php echo '{"name":"Tom","age":"22"}'; 4.箭头函数(简化函数的写法、修复this的指向,箭头函数里this指向方法原来的做用域,即方法绑定在哪一个对象上,this就指向哪一个对象) 5.多行字符串 6.类(方法名再也不须要function关键字) 7.模板对象(${xxx}) 8.默认参数(把默认值放在函数声明里) 9.iterable类型(Map):具备iterable类型的集合均可以用for...of来循环遍历 举个栗子: var m = new Map(); m.set("name", "lysa");//添加新的key-value; Map对象对应不少的方法,如.set(),.has(),.delete() 10.modules(模块): 举个栗子: 在a.js中, export var aa="test"; export function bb(){ do something; } 在b.js中导入a.js的某个变量并引用:import {aa, bb} from 'a' console.log(aa); 在b.js中导入a.js整个文件并引用:import * as xxx from 'a' console.log(xxx.aa);
7.cookie和web storage的区别? 1.与服务器的交互上 cookie始终会在http同源请求头上携带(即便不须要),在浏览器端和客户端之间传来传去 localStorage和sessionStorage不会主动发送给服务器,仅保存在本地 2.储存大小 cookie因为不一样浏览器的限制,大小在4KB左右 localStorage和sessionStorage储存大小达5MB或以上 3.过时时间 cookie与设置的有效期时间有关 localStorage存储持久数据,除非主动删除 sessionStorage在浏览器关闭后自动删除
8.cookie和session的区别? cookie数据存放在客户的浏览器,session存储在服务器上 考虑到安全性 建议: 将登录等重要信息存放为session 其它信息能够放在cookie中
9.一个页面从输入url到页面加载,这个过程都发生了什么? 简洁版: 1.浏览器根据请求的url向服务器发送请求 2.服务求处理完成后返回数据,浏览器接收文件 3.浏览器对加载到的资源(html, css, js, image等)进行语法解析 4.载入解析到的资源,渲染页面
10.事件委派 优势:减小事件注册;简化DOM更新时,相应事件的更新 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <ul id="lists"></ul> </body> <script> var oUl=document.getElementById("lists"); var fragment=document.createDocumentFragment(); for(i=0;i<10;i++){ var oLi=document.createElement("li"); oLi.innerHTML="this is an item"; oLi.index=i; fragment.appendChild(oLi); } oUl.appendChild(fragment); // oUl.onclick=function(ev){ // console.log("ev是:",ev) // var src=ev.target||ev.srcElement; // if(src.tagName==="LI"){ // console.log(src.index) // } // } oUl.addEventListener("click",function(ev){ var src=ev.target||ev.srcElement; if(src.tagName==="LI"){ console.log(src.index); } },false)//默认false,事件句柄在冒泡阶段执行 </script> </html>
11.拖拽 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style> body{margin:0;} .box{width:100px;height: 100px;background: red;position: relative;cursor: move;} </style> </head> <body> <div class="box"></div> <script> var oBox=document.getElementsByClassName("box")[0]; oBox.onmousedown=function(ev){ // 鼠标按下的状态 var ev=ev||window.event;//兼容ie浏览器 // 元素的x坐标和y坐标 var l_dis=oBox.offsetLeft; var t_dis=oBox.offsetHeight; // 1.记录下鼠标的x坐标和y坐标 // 2.计算鼠标离元素边距的距离 var disX=ev.clientX-l_dis; var disY=ev.clientY-t_dis; var that=this; // 鼠标移动的状态 document.documentElement.onmousemove=function(ev){ var ev=ev||window.event; // 这里的ev.pageX值是否和ev.clientX值一致? // 计算元素如今的位置 let new_l_dis=ev.pageX-disX; let new_t_dis=ev.pageY-disY; // 最大可拖动的距离 let max_l_dis=window.innerWidth-oBox.offsetWidth; let max_t_dis=window.innerHeight-oBox.offsetHeight; // 边界问题 if(new_l_dis<0){ new_l_dis=0; } if(new_l_dis>max_l_dis){ new_l_dis=max_l_dis; } if(new_t_dis<0){ new_t_dis=0; } if(new_t_dis>max_t_dis){ new_t_dis=max_t_dis; } oBox.style.left=new_l_dis+"px"; that.style.top=new_t_dis+"px"; document.documentElement.onmouseup=function(){//鼠标抬起,再也不移动 this.onmousemove=null; this.onmouseup=null; } } } </script> </body> </html>
12.DOM事件 DOM事件(3个级别):DOM0;DOM2;DOM3; DOM0特色:js与html强耦合;绑定的速度快,不须要操做dom,可直接在元素上绑定 dom.onclick=function(){ do something; } DOM2特色:能够在一个元素中添加不一样的事件,事件不会覆盖; dom.addEventListener("click",function(){},false) DOM3特色:在dom2的基础上,添加更多的事件类型;可自定义事件; var event=new Event("test"); dom.addEventListener("test",function(){},false); setTimeout(function(){ oBox.dispatchEvent(event); },2000) DOM事件捕获的具体流程: window->document->html->body->...->目标元素 事件流: 捕获->目标阶段->冒泡 一个节点上注册多个事件: 解决响应优先级:event.stopImmediatePropagation();
13.javascript如何实现一个类,怎么实例化这个类? 1.构造函数法 // 构造函数法(this + prototype) // 用new关键字生成实例 对象 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.info = function() { alert(this.name + this.age); } var xiaoLi = new Person("李佳", 26); xiaoLi.info(); 2.es6语法糖 // es6语法糖 // 用new关键字生成实例化对象 // 优势:避免了使用prototype class Person { constructor(x, y) { this.x = x; this.y = y; } info() { alert(this.x + this.y); } } var xiaoLi = new Person("李佳", 26); xiaoLi.info();
14.解释做用域链 1.全局函数没法查看局部函数的细节,局部函数能够访问全局函数的属性 2.当前做用域没有找到属性或方法,能够向上层乃至全局寻找,这种形式就是做用域链
15. .call()和.apply()的区别? .call()和.apply()是每一个函数都包含而非继承来的方法,用于改变函数的做用域 两方法做用相同 区别在接收参数的方式不一样,call()要求明确传入每个参数; 扩充做用域,举个栗子: window.color = "red"; var o = {color: "blue"}; function sayColor() { alert(this.color); } sayColor(); // red sayColor.call(this); // red sayColor.call(window); //red sayColor.call(o); // blue
15.jsonp的原理 利用script标签能够跨域访问的特性,动态建立script标签,给标签设置src属性。 经过script标签访问跨域的地址,返回一个参数为请求数据的callback的回调函数,而再也不直接是json数据。 具体实现步骤: 原生: $(document).ready(function(){ var url = "http://www.practice-zhao.com/student.php?id=1&callback=jsonhandle"; var obj = $('<script><\/script>'); obj.attr("src",url); $("body").append(obj); }); jquery: $(document).ready(function(){ $.ajax({ type : "get", async: false, url : "http://www.practice-zhao.com/student.php?id=1", dataType: "jsonp", jsonp:"callback", //请求php的参数名 jsonpCallback: "jsonhandle",//要执行的回调函数 success : function(data) { alert("age:" + data.age + "name:" + data.name); } }); });
16.jquery链式调用 原理:对象方法上最后加上return this;语句 优势:节省代码,代码看起来更优雅
17.原型和原型链 先记两个干巴巴的结论: 举个栗子: function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { alert(this.name) } } var person1 = new Person('Zaxlct', 28, 'Software Engineer'); var person2 = new Person('Mick', 23, 'Doctor'); console.log(person1.constructor == Person); //true console.log(person2.constructor == Person); //true 1.实例的构造函数属性(constructor)指向构造函数。 var A = new Person(); Person.prototype = A; 2.原型对象(Person.prototype)是 构造函数(Person)的一个实例。