js面试题

  • document.ready和document.load的区别

    • document.onload 是在结构和样式,外部js以及图片加载完才执行js
    • document.readydom树创建完成就执行的方法,原生种没有这个方法,jquery中有 $().ready(function)
  • 添加 删除 替换 插入到某个接点的方法

    • appendChild
    • removeChild
    • replaceChild
    • inserBefore
  • 可视区大小

    • clientHeight:height+padding
    • offsetHeight:height+padding+border
    • scrollHeigt:无滚动条时,为clientHeight;有滚动条时,不可见部分的元素的高度
    • scrollTop: 当前元素顶部距离最近父元素顶部的距离,和有没有滚动条没有关系
  • null 和 undefined的区别

    • null表示没有对象,即该处不该有值,Number转为0
    • undefined表示此处应该有个值,但还没有定义,Number转为NaN
    • 函数没有返回值,定义了参数没有赋值,变量声明但没有赋值都是undefined
  • 数据类型判断方法

    • 基本数据类型Undefined,Null,Boolean,Number,String;
    • 引用数据类型object,Array,Date,RegExp,Function
    • typeof,对于引用数据类型的判断不太好,除了Function会返回function,其它引用数据类型返回object
    • Object.prototype.toString.call(arg)
    • instanceof用来判断某个构造函数的prototype属性是否存在于要检测对象的原型链上,例如[] instanceof Array就为true
  • 原型与原型链

    • prototype:每个函数都有一个prototype属性,它是一个对象,是调用该构造函数而创建实例的原型(可以将属性或方法暴露成共用的)
    • __proto_:每个对象(除了null)上都带一个属性__proto__,他指向当前实例所属类的原型(即创建它的构造函数的原型对象)
    • constructor:每个原型都有一个 constructor 属性,他指向当前所属类(即关联的构造函数)
    • 每个class都有一个显示原型prototype;每个实例都有隐式原型__proto__,实例的隐式原型__proto__指向class的显示原型prototype
  • 闭包

    • 闭包:有权访问另外一个函数作用域中的变量的函数(可以读取其它函数内部变量的函数)
    • 作用:正常函数执行完毕后,里面声明的变量被垃圾回收机制处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉,常驻内存
    • 函数作为返回值,函数作为参数来执行
    • 自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方
  • this

    • 在对象中this就是对象本身
    • this是在函数执行时决定的,不是在定义时决定;(变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方)
    • 自执行函数中的this指向window
    • 给元素中的某一个事件绑定方法,当事件触发时,执行绑定的方法,this就指向当前对象
    • 箭头函数中的this指向上级作用域
    • callapplybind可以改变this执行
  • call,apply,bind的区别

    • 都是改变函数执行的上下文,即改变this的指向
    • call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为nullundefined的时候,默认指向window
    • apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为nullundefined的时候,默认指向window
    • call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用
        // 将数组转换为类数组
        Array.prototype.slice.call(arguments)
    
    
        // call函数原理,apply与其类似,其本质就是将调用call函数的函数添加到当前所指向的this的属性中
        Function.prototype.call = function(thisArg, args) {
            // this指向调用call的对象
            if (typeof this !== 'function') { // 调用call的若不是函数则报错
                throw new TypeError('Error')
            }
            thisArg = thisArg || window
            thisArg.fn = this   // 将调用call函数的对象添加到thisArg的属性中
            const result = thisArg.fn(...[...arguments].slice(1)) // 执行该属性
            delete thisArg.fn   // 删除该属性
            return result
        }
    
  • 同源策略与跨域

    • 只要协议、域名、端口有任何一个不同,就是跨域
    • 通过jsonp解决跨域,只支持get,因为其本质还是通过script对资源的请求
    • Access-Control-Allow-Origin后台设置允许跨域
    • nginx做代理实现跨域
    • document.domain+iframe 实现跨域(需要页面中嵌套iframe,且iframe的主域,协议,端口相同),页面通过js强制设置document.domain为基础域名
  • 事件冒泡,事件捕获,事件委托

    • 事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。
    • 事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。(即点了最里面的元素,会从最外层的元素开始执行)
    • 事件委托,通过监听一个父元素,来给不同的子元素绑定事件,减少监听次数,从而提升速度(兼容监听ul的click,来对li添加事件)
    • 阻止冒泡:w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
    • 阻止默认事件:w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
  • ajax原理(异步JavaScript和XML)

    • 特点:无需重新加载整个网页的情况下,能够更新部分数据
    • 创建Ajax核心对象XMLHttpRequest
    • 向服务器发送请求
    • 服务器响应处理(区分同步跟异步两种情况)
    	//创建 XMLHttpRequest 对象
    	var xhr = new XMLHttpRequest();
    	//发送信息至服务器时内容编码类型
    	xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
    	//接受服务器响应数据
    	xhr.onreadystatechange = function () {
    		// readyState用于标示当前XMLHttpRequest对象处于什么状态
    	    if (xhr.readyState == 4 && (xhr.status == 200) { 
    	        // let data = xhr.responseText;  
    	    }
    	};
    	//规定请求的类型、URL 以及是否异步处理请求。
    	xhr.open('GET',url,true);
    	//发送请求
    	xhr.send(null); 
    
  • http 常见状态码

    • 2xx 表示成功
    • 3xx 完成请求,需要进一步操作,一般这些状态码用来重定向
    • 4xx 请求错误,表示请求可能出错,妨碍了服务器的处理
    • 5xx 服务器错误,这些状态码表示服务器在尝试处理请求时发生内部错误
    • 200 成功
    • 401 未授权(Unauthorized),当前请求需要用户验证
    • 403 对请求资源的访问被服务器拒绝了
    • 404 服务器上无法找到请求的资源
    • 500 服务器执行请求发生错误
  • get 与 post 请求的区别

    • get传参方式是通过url后加参数进行传递,post传参是放于请求体内
    • get请求对传递的参数有长度限制,post没有
    • get请求可以被缓存,post不可以被缓存
    • get请求的记录会留在历史记录中,post请求不会留在历史记录
    • 一般资源查找使用get请求,表单提交使用post请求
  • 深拷贝和浅拷贝

    • 浅拷贝:拷贝的时候只是拷贝了一份引用,修改拷贝以后的数据会影响原来的数据
    • 深拷贝:拷贝的时候会生成一份新的数据,修改拷贝以后的数据不会原数据
        // 深拷贝的实现
        function deepClone(obj = {}){
            if (typeof obj !== 'object' || obj == null){
                return obj
            }
            let result;
            if (obj instanceof Array){
                result = []
                for (let i=0; i<obj.length; i++){
                    result.push(deepClone[obj[i]]);
                }
            }else {
                result = {}
                for(let key in obj){
                    if (obj.hasOwnProperty(key)){   // 不能是原型链上的属性
                        result[key] =  deepClone(obj[key]);
                    }
                }
            }
            return result;
        }
    
  • == 防抖节流==

    • 防抖:用户输入结束或暂停时,才会出发change事件(最后的时候触发)
    • 防抖原理:设置一个timer,每一次触发事件时,清空原来的timer,并新建timer,那么在最后一次触发事件时到了定时器的时间,就会执行timer
        function debounce (fn, delay=500){
            let timer = null;
            return function(){
                if(timer){
                    clearTimeout(timer);
                }
                timer = setTimeout(() => {
                    fn.apply(this, arguments);   // fn()
                }, delay);
            }
        }
        input1.addEventListener('click', debounce(function(){
            console.log(input1.value)
        }, 500))
    
    • 节流:会保持一个频率频繁触发,比如监听onscroll事件,每100ms触发一次事件
    • 节流原理;设置一个timer,当触发事件时,设置timer,下一次触发如果没有到timer设置的时间,那么返回,当定时器到了时间,执行事件函数并清空timer,当下一次再触发时timer没有值,再次设置timer
      function throttle(fn, delay){
        let timer = null;
        retrun function(){
          if (timer){
            return ;
          }
          timer = setTimeout(() => {
             fn.apply(this, arguments);   // fn()
             timer = null;
          }, delay);
        }
      }
    
  • 函数声明和函数表达式的区别

    • 函数声明会代码执行前预加载,而函数表达式不会
      // 函数声明  function fn(){}
      // 函数表达式  let fn = function(){}
    
  • new Object()和Object.create()的区别

    • 使用Object.create()是将对象继承到__proto__属性上
    • new Object() 就是创建一个对象,和js var obj = {age:7}是一样的
    // 以下obj1和obj2指向的是同一个地址
     var obj1 = {name: 'zhangjie'}
     var obj2 = new Object(obj1);
    
     Object.create(null);  // 没有属性且没有原型
     var obj4 = {name: 'zhangjie'};
     var obj3 = Object.create(obj4);   // 将对象挂在到一个空对象的原型中,即obj3的__proto__和obj4指向同一个内存地址
    
    • 以下是Object.create的一个简单实现
    // 思路:将传入的对象作为原型
    function create(obj) {
      function F() {}
      F.prototype = obj
      return new F()
    }
    
  • xss安全

    • XSS跨站请求攻击
      • 比如在博客中注入了一段script代码
      • script内容获取cookie
      • 将获取到的cookie发送到自己的服务器
      • 将<>替换为&lt和&gt
    • XSRF跨站请求伪造
  • 数据属性和访问器

    • 数据属性:包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性
      • 1、value:包含该属性的数据值,默认为undefined。
      • 2、writable:表示能否修改属性的值。
      • 3、enumerable:表示能否通过for-in循环返回属性。
      • 4、configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为true。
    • 访问器属性:这个属性不包含数据值,包含一对get和set方法,在读写访问器属性时,就是通过这两个方法来进行操作处理的
      • configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为false。
      • enumerable:表示能否通过for-in循环返回属性,默认为false。
      • Get:在读取属性时调用的函数,默认为undefined。
      • Set:在写入属性时调用的函数,默认为undefined。
  • DOM的回流和重绘

    • 当页面中元素的位置,大小或结构、定位发生改变,会引发浏览器对当前页面的结构进行重新的计算;非常耗性能的
    • 当元素的背景、透明度、颜色发生变化,那么浏览器会对元素进行重新描绘;这个过程就是浏览器的重绘
  • 前端性能优化

    • 减少请求次数
    • 减少资源大小
    • 优化资源加载
    • 减少重绘回流
    • webpack优化
  • 谈谈对缓存的理解

    • 缓存读取就是浏览器在向服务器请求资源之前,先查询一下本地缓存中是否存在需要的资源,如果存在,那便优先从缓存中读取。当缓存不存在或者过期,再向服务器发送请求
    • 强缓存:先获取该资源缓存的header信息,判断是否命中缓存(根据cache-controlexpires信息判断),若命中直接从缓存中获取资源信息,包括缓存header信息。本次请求不会与服务器进行通信
      • expires由于是一个绝对时间,所以可能存在用户修改电脑时间而导致页面刷新
      • cache-control:主要max-age发挥作用,它是一个相对时间,表示资源的过期时间
      • cache-controlexpires的优先级别高
    • 协商缓存:如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-SinceEtag/If-None-Match),由服务器根据请求中的相关header信息来比对结果是否缓存命中;若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容。
      • 发请求–>看资源是否过期–>过期–>请求服务器–>服务器对比资源是否真的过期–>没过期–>返回304状态码–>客户端用缓存的老资源
      • last-modified:文件的修改时间,精确到秒
      • ETAG:每个文件有一个,改动文件了就变了,就是个文件hash,每个文件唯一
      • 为什么要有etag:1)一些文件也许会周期性改变,不修改内容,只修改改变时间;2)有些文件修改频繁可能在s级以下的时间内修改
  • js延迟加载的方式

    • deferasync,不让页面等待脚本下载和执行,异步加载页面其它内容,在load之前执行
    • 动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack
  • 浏览器渲染机制

    • 处理HTML标签建立DOM
    • 处理CSS标签建立CSSOM
    • 连接CSSOM树和DOM树形成一个render
    • render树上运行布局来计算每个节点的形状
    • 在屏幕上画每一个节点
  • 从输入一个url到浏览器页面展示都经历了哪些过程

    1. 首先,在浏览器地址栏中输入url
    2. 浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
    3. 在发送http请求前,需要域名解析(DNS解析),解析获取相应的IP地址。
    4. 浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。
    5. 握手成功后,浏览器向服务器发送http请求,请求数据包。
    6. 服务器处理收到的请求,将数据返回至浏览器
    7. 浏览器收到HTTP响应
    8. 读取页面内容,浏览器渲染,解析html源码
    9. 生成Dom树、解析css样式、js交互
    10. 客户端和服务器交互
    11. ajax查询
  • == xhr,ajax,axios,fetch的区别==

    • xhr:与服务器进行交换,最开始是使用的XMLHttpRequest对象
      • 优点:
        • 1)不重新加载页面的情况下更新网页;
        • 2)在页面加载后从服务器请求数据;
        • 3)向后台发送数据
      • 缺点:1)繁琐,设置项多;2)兼容IE浏览器
    • ajax:对XMLHttpRequest对象的封装,可以兼容多种浏览器
      • 优点:
        • 1)对原生XHR封装,简化了使用;
        • 2)增加对jsonp的支持
      • 缺点:
        • 1)多个依赖关系的请求时容易形成回调地狱;
        • 2)使用ajax需要引入整个jquery
    • axios:可以用于浏览器和NODE端,本质还是对XMLHttpRequest对象的封装,是Promise的实现版本
      • 优点:
        • 1)可以在NODE端进行请求;
        • 2)支持promiseAPI;
        • 3)拦截请求和相应;
        • 4)自动转换json数据
      • 缺点:1)只支持高版本浏览器
  • cookie,session,localstorage

  • cookie:完全存在于客户端;cookie保存了登录的凭证,有了它,只需要在下次请求时带着cookie发送

    • cookie属性:expires(过期时间);max-age(多久之后过期);domain(域名);path(路径);
    • cookie缺点:1)每个域名下的cookie数量有限;2)cookie大小有限制;3)每次请求都会携带cookie信息
    • 解决cookie跨域问题(nginx反向代理/jsonp参考链接
    • 如何在子域共享cookie,设置domain.baidu.com
  • session:根本作用就是在服务端存储用户和服务器会话的一些信息

    • 存放于服务端
    • session不支持跨域,仅只在他所在的域内有效
    • 一般用于判断用户是否登录,即购物车功能,根据session_id查找session,如果没有session_id,那么创建session
  • localstorage(HTML5):本地存储,解决了cookie内存不足的问题

    • 仅在本地存储,不与服务器通信,且长期有效
  • cookie,localStorage, sessionStorage三者区别

  1. cookie始终在同源的http请求中携带,即使不需要,cookie在浏览器和服务器中来回传递。而localStoragesessionStora仅仅在本地存储,不会好服务器通信,也不会自动把数据发送给服务器。
  2. 存储大小不同,cookie为4kb左右;localStoragesessionStorage可以达到5M
  3. 数据有效期不同,sessionStorage仅在同源窗口中有效,关闭窗口就消失了,cookie可以设置过期时间, localStorage长期有效
  4. localStoragesessionStorage有现成的API, cookie需要程序员手动封装
  • http的头部有什么字段

  • 请求头

    1. Accept:告知服务端浏览器这边可以接受的数据
    2. Cache-control:告诉服务器是否缓存
    3. referer:当前页面的上一个页面,一般用于服务器判断是否在一个域内
  • 响应头

    1. 返回内容的格式
    2. set-Cookie:服务端像客户端设置cookie
    3. last-modified:文档的最后修改时间
    4. content-length:内容长度
  • 写一个function,清除字符串前后的空格

      String.prototype.trim= function(){
        return this.replace(/^\s+/,"").replace(/\s+$/,"");
      }
    
  • js 实现一个函数 获得url参数的值

      function getQueryString(name) { 
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); 
        var r = window.location.search.substr(1).match(reg); 
        if (r != null) return unescape(r[2]); return null; 
      } 
    


  • 堆:存储引用类型值的空间
  • 栈:存储基本类型值和执行代码的环境
	//==================================
	var a = {};
	var b = 0;
	var c = 0;
	a[b] = '张杰';
	a[c] = '同学';
	console.log(a[b]);  // 输出为同学
	// 扩展:对象和数组的区别

	//============================================
	let a = {};
	b = Symbol('1');   // 创建的是唯一值
	c = Symbol('1');
	a[b] = '张杰';
	a[c] = '同学';
	console.log(a[b]);  // 输出为张杰
	// 自己实现一个Symbol

	//=========================================
	let a = {};
	b = {m:1};   
	c = {n:2};
	a[b] = '张杰';  // 这时会存储为a['object object'] = '张杰'
	a[c] = '同学';  // 所以再次赋值会将原来的值覆盖
	console.log(a[b]);  // 输出为同学
	// 关于Object.prototype.toString / valueOf
	
	//=====================================
	// 闭包;函数执行会形成一个执行上下文
	var test = (function(i){
		return function(){
			alert(i*=2);
		}
	})(2)
	test(5);   // "4"(alert弹出为字符串)
	
	//================================
	var a = 0;
	var b = 0;
	function A(a){
		A = function(){
			alert( a + b++)
		};
		alert(a++);
	}
	A(1);  //"1",在A(1)执行后形成的上下文不销毁,因为形成的函数A被外面的函数A所占用
	A(2);  //"4"
	
	//===================================
	function Foo(){
		getName = function(){
			console.log(1)
		}
		return this;
	}
	Foo.getName = function(){
		console.log(2);
	}
	Foo.prototype.getName = function(){
		console.log(3);
	}
	var getName = function(){
		console.log(4)
	}
	function getName(){
		console.log(5)
	}
	Foo.getName();  //2
	getName();	//4
	Foo().getName();	//1
	getName();	//1
	new Foo.getName(); //2 先执行Foo.getName,再执行new
	new Foo().getName();	//3
	new new Foo().getName();	//3  先执行new Foo(),再new xxx.getName(),这个先执行new xxx.getName, 再执行()

	//===================================
	async function async1(){
		console.log('async1 start');
		await async2();
		console.log('async1 end');
	}
	async function async2(){
		console.log('async2');
	}
	console.log('script start');
	setTimeout(function(){
		console.log('setTimeout');
	}, 0)
	async1();
	new Promise(function(resolve){
		console.log('promise1');
		resolve();
	}).then(function(){
		console.log('promise2');
	})
	console.log('script end');
	// script start; async1 start; async2; promise1; script end; async1 end; promise2; setTimeout
	// == 转换规则:
	// 对象 == 字符串,对象tostring变为字符串
	// null==undefined 相等,但是和其它比较值不相等
	// Nan == NaN 不相等
	// 剩下的都会转换为数字进行比较
	// a为多少,下面的条件可以成立
	var a = null;
	a = {
		i:0,
		toString(){
			return ++this.i
		}
	}
	if (a==1 && a==2 && a==3){
		console.log(3)
	}
	//下面也可以实现
	var i = 0;
	Object.defineProperty(window, 'a', {
		get(){
			// get中不能获取当前属性,不然就会形成死循环
			return ++i;
		}
	})
	// 方式三
	var a = [1, 2, 3];
	a.toString = a.shift();
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值