【JS常见面试题(二)】

本文详细介绍了JavaScript中的作用域、预解析和闭包的概念及应用。作用域决定了变量的可见性和生命周期,分为全局和局部作用域。预解析包括变量和函数的提升,而闭包则允许函数访问外部作用域的变量,常用于实现回调、私有变量等场景。同时,文中还提及了深拷贝和浅拷贝的区别,以及this指向问题的复杂性,包括全局环境、函数调用、对象方法和箭头函数中的不同行为。最后,讨论了JavaScript中的防抖和节流技术,以及数组去重和数据结构转换的方法。
摘要由CSDN通过智能技术生成

什么是js作用域

一、含义:通常来说,一段程序当中所用到的变量名并不总是有效和可用的,意思就说有的时候在这行代码可以用,可能在同一个文件,别的行就是没有用的,那也就是说:变量名可用且有效的那个代码范围,就是变量的作用域
二、作用域的意义:增强了代码的局部性、可靠性。减少了变量名字的冲突。同一个名字可以在同一大段代码中出现两次甚至多次。
三、作用域的分类:全局作用域、局部作用域,
全局作用域就是指的一整个script标签或者一整个js文件
局部作用域:就是函数内部
根据作用域的不同,变量又可以分为全局变量(在全局作用域下)和局部变量(在局部作用域下有效)
如果在函数内部,没有关键字修饰声明,直接名字=值(赋值),那也算全局变量。
函数的形参算作是局部变量
局部变量当函数执行完,就会被销毁,但是全局变量只有浏览器关闭的时候才会销毁
四、作用域链
含义:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值,这种现象我们称之为作用域链。其实就是你用到一个变量的时候,它的值你要去找,就得链式查找,一层一层向上找。

js预解析

一、了解js的运行机制
浏览器的js解析器在运行js代码的时候分为两步,预解析和代码执行。
js引擎会把js里面的所有var 还有function提升到当前作用域的最前面。而代码执行就是从上到下代码的书写顺序。
预解析就是变量提升,预解析分为变量预解析(变量提升)和函数预解析(函数提升)
(1)变量预解析,就是把所有的变量声明提到当前作用域的最前面,不需要赋值操作。
(2)函数提升,把所有的函数声明提升到作用域的最前面,不调用函数,也就是使用function关键字声明的整个大括号都会被提升。
(3)函数表达式调用必须写在函数表达式的下面
例如:
var a=b=c=9;相当于var a = 9; b = 9; c= 9;
b和c没有直接赋值,没有关键字声明,相当于全局变量。
想要集体声明,可以:var a=9,b=9,c=9;

js闭包

什么是闭包?简单来说,闭包是一种函数,是一种有着特殊形态的函数,就好像我们把大型烧油的三轮称之为三马,四个轮子的称为轿车,但本质,还是车。
到底什么是闭包呢?能够访问到其他函数作用域中的对象的函数,称作闭包。定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。
闭包的使用场景有哪些?
1.setTimeout传参
下面展示一些 内联代码片

// 原生的setTimeout是不带参数的
SetTimeout(function(params){
   alert(params)},1000)
//这样肯定是不行的,为了实现传参,就需要像下面这样子做
function f1(params){
   
	function f2(){
   
	alert(params)
	}
	return f2;
}
var f3 = f1(3);
setTimeout(f3,1000);

2.回调函数,所谓回调函数就是,在别的函数里被当作参数的那个函数:

function A(name){
   
	console.log(name);
}
function B(A){
   
	var name=prompt('请输入你的名字')
	A(name)
}
B(A)


function changeSize(size){
   
        return function(){
   
            document.body.style.fontSize = size + 'px';
        };
    }

    var size12 = changeSize(12);
    var size14 = changeSize(14);
    var size16 = changeSize(16);

    document.getElementById('size-12').onclick = size12;
    document.getElementById('size-14').onclick = size14;
    document.getElementById('size-16').onclick = size16;

3.用闭包能够访问私有函数和私有变量的公有函数

// 用闭包能够访问私有变量和私有函数的公有函数
var counter = (function(){
   
	var privateCounter = 0;//私有变量
	function changeVal(value){
   
    reprivateCounter + =value;
    }
    return {
   
	increment:function(){
   
	changeVal(1);
	},
	decrement:function(){
   
	changeVal(-1);
	},
	value:function(){
   
	return privateCounter;
	}
	}
}();)
console.log(counter.value)
counter.increment();
counter.decrement();

4.为节点循环绑定click事件

// 点击不同的框显示不同的信息
<p id="info">123</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>
<script>
function showContent(content){
   
	document.getElementById("info").innerHTML = content; 
}

function setContent(){
   
var infoArr =[
		{
   'id':'email','content':'your email address'},
        {
   'id':'name','content':'your name'},
        {
   'id':'age','content':'your age'}
]
for (var i=0;i<infoArr.length;i++){
   
var item=infoArr[i];
 document.getElementById(item.id).onfocus=function(){
   
	showContent(item.content)
}
}
}

</script>

这样写不行,因为每一次循环都是将聚焦事件加入事件队列中,所以item的item.content一直都是一个变量。
解决办法1:工厂函数,所谓工厂函数,就是可以创建对象的函数。则函数为每一个回调函数创建一个新的词法环境。

function showContent(content){
   
    document.getElementById('info').innerHTML = content;
};
function callback(content){
   
	return function(){
   
	showContent(content);
	}
}
function setContent(){
   
	var infoArr = [
	{
   'id':'email','content':'your email address'},
	{
   'id':'name','content':'your name'},
	{
   'id':'age','content':'your age'}
	]
for(var i=0;i<infoArr.length;i++){
   
	var item=infoArr[i];
	document.getElementById(item.id).onfocus=callback(item.content)
}

解决办法2:绑定事件放在立即执行函数中
立即执行函数就是指的是(function(){})();

function showContent(content){
   
    document.getElementById('info').innerHTML = content;
};

function setContent(){
   
    var infoArr = [
        {
   'id':'email','content':'your email address'},
        {
   'id':'name','content':'your name'},
        {
   'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
   
        (fun
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值