前端面试总结(js基础篇)

js 中的堆和栈

基本数据类型:

undefined、null、number、boolean、string;

基本数据类型值指保存在栈内存中的简单数据段。访问方式是按值访问。

引用数据类型:

Object、array、function、data

引用数据类型值指保存在堆内存中的对象。也就是,变量中保存的实际上的只是一个指针,这个指针指向内存中的另一个位置,该位置保存着对象。访问方式是按引用访问

== 和 === 区别

1、对于string,number等基础类型,==和===是有区别的1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等2)同类型比较,直接进行“值”比较,两者结果一样2、对于Array,Object等高级类型,==和===是没有区别的进行“指针地址”比较3、基础类型与高级类型,==和===是有区别的1)对于==,将高级转化为基础类型,进行“值”比较2)因为类型不同,===结果为false

————————————————
版权声明:本文为CSDN博主「Bliss_妍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yyychocolate/article/details/108089477

== 比较规则

"0" == null   // false
"0" == undefined // false
"0" == false // false -> 0 比较 “0” == 0 =》"0" -> 0 => 0==0 => true
"0" == NaN  // false
"0" == 0 // ''0" -> 0 => 0 == 0=>0===0 => true
"0" == "" // "0" === "" => falsefalse == null // false null 和任意都不等(除undefined和null)
false == undefinded // false
false == NaN // false 
false == 0 //   false -> 0 => 0== 0 => 0===0 => true
false == "" // false -> 0 => 0 == "" => "" -> 0  => 0 == 0 => 0 === 0 => true
false == [] 
// false -> 0 => 0 == [] => [].toString() = '' => 0 == '' => 0 === 0 => true
false == {} 
// false -> 0 => 0 == {} => Object.prototype.toString.call({})="[object Object]"
// 0=="[object Object]" = >Number( "[object Array]" ) = NaN 
// => 0 == NaN =>  false"" == null  // false
"" == undefined //false
"" == NaN //false
"" == 0 // ''-> 0 => 0===0 => true
"" == [] // [] -> '' => ""=="" => true
"" == {} // {} -> NaN => "" == NaN => false0 == null // false
0 == undefinded //false
0 == NaN // false
0 == [] // [] -> "" => 0 == "" => 0 == 0 => 0===0 => true
0 == {} // {} -> NaN => 0 == NaN => false
  • undefined/ null 除了彼此和自身相等外和任何值都不相等
  • [] 和字符串比较,最终转成空字符串 “”, 和数字比较最终转换成0
  • {}和基本类型比较,最终转换成 NaN, NaN和 谁都不等;

空数组、空对象和 false 之间使用==判定规律总结

引用类型变量的复制:

复制的是存储在栈中的指针,将指针复制到栈中未新变量分配的空间中,而这个指针副本和原指针指向存储在堆中的同一个对象;复制操作结束后,两个变量实际上将引用同一个对象。因此,在使用时,改变其中的一个变量的值,将影响另一个变量。

对象值都是引用,所以的对象的比较也叫引用的比较,当且当他们都指向同一个引用时,即都引用的同一个基对象时,它们才相等

let a=[0,1,2,3,4],b=a
console.log(a===b);  //true
a[0]=1;
console.log(a,b); [1,2,3,4] , [1,2,3,4]
let a1 = {name:'aa',age:18}
let b1 = {name:'aa',age:18}
alert(a1===b1); //false
a. 引用类型的值是可以改变的,例如对象就可以通过修改对象属性值更改对象。
b. 引用类型可以添加属性和方法。
c. 引用类型的赋值是对象引用,即声明的变量标识符,存储的只是对象的指针地址。
d. 引用类型的比较是引用(指针地址)的比较。
e. 引用类型是同时保存在栈区和堆区中的,栈区保存变量标识符和指向堆内存的地址。

js 中深拷贝和浅拷贝的区别

浅拷贝:
只是增加了一个指针指向已存在的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。

深拷贝:
在计算机中开辟一块新的内存地址用于存放复制的对象。

实现浅拷贝的方法:

1、for···in只循环第一层

// 只复制第一层的浅拷贝
function simpleCopy(obj1) {var obj2 = Array.isArray(obj1) ? [] : {};for (let i in obj1) {obj2[i] = obj1[i];}return obj2;
}
var obj1 = {a: 1,b: 2,c: {d: 3}
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4

2、直接用=赋值

let a=[0,1,2,3,4],b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);

3、赋值与浅拷贝的区别

  • 当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
  • 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。

实现深拷贝的方法

1、采用递归去拷贝所有层级属性

function deepClone(obj){let objClone = Array.isArray(obj)?[]:{};if(obj && typeof obj==="object"){for(key in obj){if(obj.hasOwnProperty(key)){//判断ojb子元素是否为对象,如果是,递归复制if(obj[key]&&typeof obj[key] ==="object"){//所谓的递归函数就是在函数体内调用本函数objClone[key] = deepClone(obj[key]);}else{//如果不是,简单复制objClone[key] = obj[key];}}}}return objClone;
}    
let a=[1,2,3,4],b=deepClone(a);
a[0]=2;
console.log(a,b);

2、通过JSON对象来实现深拷贝

var test ={name:{xing:{ first:'张',second:'李'},ming:'老头'},age :40,friend :['隔壁老王','宋经纪','同事']}var result = JSON.parse(JSON.stringify(test))result.age = 30result.name.xing.first = '往'result.friend.push('fdagldf;ghad')console.dir(test)console.dir(result)

缺点: 无法实现对对象中方法的深拷贝,会显示为undefined

3、通过jQuery的extend方法实现深拷贝

var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝

js 中防抖节流

防抖

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

  • 防抖的中心思想在于:我会等你到底。在某段时间内,不管你触发了多少次回调,我都只认最后一次。
/*** @desc 函数防抖* @param func 函数* @param wait 延迟执行毫秒数* @param immediate true 表立即执行,false 表非立即执行*/
function debounce(func,wait,immediate) {let timeout;return function () {let context = this;let args = arguments;if (timeout) clearTimeout(timeout);if (immediate) {var callNow = !timeout;timeout = setTimeout(() => {timeout = null;}, wait)if (callNow) func.apply(context, args)}else {timeout = setTimeout(function(){func.apply(context, args)}, wait);}}
}

简单版

	function debounce(fn,wait){let timeOut = nullreturn args =>{if(timeOut) clearTimeout(timeOut)timeOut = setTimeout(fn,wait)}}

节流

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。

  • throttle 的中心思想在于:在某段时间内,不管你触发了多少次回调,我都只认第一次,并在计时结束时给予响应

对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。

function throttle(func, wait) {let timeout;return function() {let context = this;let args = arguments;if (!timeout) {timeout = setTimeout(() => {timeout = null;func.apply(context, args)}, wait)}}
}

防抖应用场景

文本输入搜索联想
文本输入验证(包括 Ajax 后端验证)

节流应用场景

鼠标点击
监听滚动 scroll
窗口 resize
mousemove 拖拽

xss攻击和csrf攻击的区别与防范

CSRF(Cross-site request forgery):跨站请求伪造。

(1)、攻击原理:

用户访问登录信任网站A,验证成功后会产生A的cookie
用户在没有的登出A网站的情况下访问危险网站B,而网站B诱导用户访问A并发出请求
浏览器会带着A网站产生的cookie去执行这个请求
A网站会根据用户权限去处理这个请求,这样网站B就达到了模拟用户操作的目的了

(2)、防御措施:

  • token验证:登陆成功后服务器下发token令牌存到用户本地,再次访问时要主动发送token,浏览器只能主动发cookie,做不到主动发token
  • referer验证:判断页面来源是否自己站点的页面,不是不执行请求
  • 隐藏令牌: 令牌放在http header头中,而不是链接中

XSS(Cross Site Scripting):跨域脚本攻击。

(1)、攻击原理:

不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、html代码块等)。

(2)、防御措施:

设置Cookie的属性为Http only,这样js就无法获取Cookie值;
严格检查表单提交的类型,并且后端服务一定要做,不能信任前段的数据;
对用户提交的数据就行Html encode处理,将其转化为HTML实体字符的普通文本;
过滤或移除特殊的HTML标签,如
                    

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部