71。IE和标准下有哪些兼容性的写法 参考答案:varevevwindow。event;document。documentElement。clientWidthdocument。body。clientWidth;vartargetev。srcElementev。target; 参与互动 72。变量提升 参考答案:变量提升 A、js代码执行的过程1变量提升2代码从上到下依次执行 var关键字和function关键字声明的变量会进行变量提升 B、变量提升发生的环境:发生在代码所处的当前作用域。变量提升1var关键字进行的变量提升,会把变量提前声明,但是不会提前赋值。2function关键字对变量进行变量提升,既会把变量提前声明,又会把变量提前赋值,也就是把整个函数体提升到代码的顶部3有一些代码是不会执行的但是仍旧会发生变量提升,规则适用于1,23。1return之后的代码依旧会发生变量提升,规则适用于1,23。2代码报错之后的代码依旧会发生变量提升,规则适用于1,23。3break之后的代码依旧会发生变量提升,规则适用于1,24有一些代码是不会执行但是仍旧会发生变量提升,但是规则要发生变化4。1if判断语句if判断语句中var关键字以及function关键字声明的变量只会发生提前声明,不会发生提前赋值,也就是不会吧函数体整体提升到当前作用域顶部。规则跟1,2不适用4。2switchcase规则跟1,2不适用4。3dowhile规则跟1,2不适用4。4trycatchcatch中声明的变量只会发生提前声明,不会发生提前赋值。Ps:在条件判断语句和trycatch中的声明的变量不管是否能够执行,都只会发生提前声明,不会发生提前赋值。 解析:如果一个变量声明了但是未赋值,那么输出这个变量就会输出undefinedvarnum;console。log(num);如果一个变量没有声明也没有赋值,那么就会报一个错:console。log(num);输出一个不存在的变量UncaughtReferenceError:numisnotdefinedvar关键字进行的变量提升console。log(num);varnum123;console。log(num);varnum456;console。log(num);变量提升之后的代码:varnum;console。log(num);num123;console。log(num);num456;console。log(num);function关键字的变量提升console。log(fn);functionfn(){console。log(1);}变量提升之后的代码:functionfn(){console。log(1);}console。log(fn);输出fn的函数体3。1return之后的代码依旧会发生变量提升规则适用于1,2functionfn(){console。log(num);return;varnum123;}fn();变量提升之后的代码:functionfn(){varnum;console。log(num);return;num123;}fn();undefinedfunctionfn(){console。log(fo);return;functionfo(){}}fn();变量提升之后的代码:functionfn(){functionfo(){}console。log(fo);return;}fn();输出fo的函数体3。2代码报错之后的代码依旧会进行变量提升,规则适用于1,2console。log(num);xsasfgdsfqdfsdf;报一个错varnum123;console。log(num);变量提升之后的代码:varnum;console。log(num);输出undefineddsagdsqghdwfh;报一个错误,错误之后的代码不会被执行num123;console。log(num);function关键字console。log(fn);sasgfdhwhsdqg;functionfn(){}console。log(fn);变量提升之后的代码:functionfn(){}console。log(fn);输出fn的函数体asdgsdgdfgfdg;报一个错误,报错之后的代码不会被执行console。log(fn);4代码不执行,但是会进行变量提升,不过规则不适用于1,24。1if判断语句console。log(num);if(false){varnum123;}console。log(num)变量提升之后的代码:varnum;console。log(num);undefinedif(false){num123;}console。log(num)undefinedconsole。log(fn);if(false){functionfn(){}}console。log(fn);变量提升之后的代码:varfn;functionfn;console。log(fn)undefinedif(false){functionfn(){}}console。log(fn)undefinedfunctionfnUncaughtSyntaxError:Unexpectedendofinputtrycatchtry{console。log(num);}catch(e){varnum123;}console。log(num);varnum;try{console。log(num);undefined}catch(e){num123;}console。log(num);undefinedtry{console。log(fn);}catch(e){functionfn(){}}console。log(fn);varfn;try{console。log(fn);undefined}catch(e){num123;}console。log(fn);undefined 对应面试题 参与互动 73。如何阻止冒泡与默认行为 参考答案:阻止冒泡行为:非IE浏览器stopPropagation(),IE浏览器window。event。cancelBubbletrue阻止默认行为:非IE浏览器preventDefault(),IE浏览器window。event。returnValuefalse 解析: 当需要阻止冒泡行为时,可以使用functionstopBubble(e){如果提供了事件对象,则这是一个非IE浏览器if(ee。stopPropagation)因此它支持W3C的stopPropagation()方法e。stopPropagation();否则,我们需要使用IE的方式来取消事件冒泡elsewindow。event。cancelBubbletrue;} 当需要阻止默认行为时,可以使用阻止浏览器的默认行为functionstopDefault(e){阻止默认浏览器动作(W3C)if(ee。preventDefault)e。preventDefault();IE中阻止函数器默认动作的方式elsewindow。event。returnValuefalse;returnfalse;} 参与互动 74。js中this闭包作用域 参考答案: this:指向调用上下文 闭包:定义一个函数就开辟了一个局部作用域,整个js执行环境有一个全局作用域 作用域:一个函数可以访问其他函数中的变量(闭包是一个受保护的变量空间)varf(functionfn(){varname1;returnfunction(){name;console。log(name)}})()undefined有疑问 参与互动 75。javascript的本地对象,内置对象和宿主对象 参考答案: 1。本地对象 ECMA262把本地对象(nativeobject)定义为独立于宿主环境的ECMAScript实现提供的对象。简单来说,本地对象就是ECMA262定义的类(引用类型)。它们包括:Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError 2。内置对象 JS中内置了17个对象,常用的是Array对象、Date对象、正则表达式对象、string对象、Global对象 3。宿主对象 由ECMAScript实现的宿主环境提供的对象,可以理解为:浏览器提供的对象。所有的BOM和DOM都是宿主对象。 参与互动 76。javascript的同源策略 参考答案:一段脚本只能读取来自于同一来源的窗口和文档的属性 解析: 同源策略:限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自MDN官方的解释) 简单来说就是:一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合具体解释: (1)源包括三个部分:协议、域名、端口(http协议的默认端口是80)。如果有任何一个部分不同,则源不同,那就是跨域了。 (2)限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:(要记住) Cookie、LocalStorage和IndexDB无法获取。 无法获取和操作DOM。 不能发送Ajax请求。我们要注意,Ajax只适合同源的通信。 同源策略带来的麻烦:ajax在不同域名下的请求无法实现,需要进行跨域操作 参与互动 77。事件冒泡与事件捕获 参考答案: 事件冒泡:由最具体的元素(目标元素)向外传播到最不具体的元素 事件捕获:由最不确定的元素到目标元素 参与互动 78。foofoobar,这行代码是什么意思?为什么要这样写? 参考答案: 这种写法称为短路表达式 解析: 相当于varfoo;if(foo){foofoo;}else{foobar;} 常用于函数参数的空判断 参与互动 79。复杂数据类型如何转变为字符串 参考答案:首先,会调用valueOf方法,如果方法的返回值是一个基本数据类型,就返回这个值如果调用valueOf方法之后的返回值仍旧是一个复杂数据类型,就会调用该对象的toString方法如果toString方法调用之后的返回值是一个基本数据类型,就返回这个值,如果toString方法调用之后的返回值是一个复杂数据类型,就报一个错误。 参与互动 80。javascript中this的指向问题 参考答案:全局环境、普通函数(非严格模式)指向window普通函数(严格模式)指向undefined函数作为对象方法及原型链指向的就是上一级的对象构造函数指向构造的对象DOM事件中指向触发事件的元素箭头函数。。。 解析:1、全局环境 全局环境下,this始终指向全局对象(window),无论是否严格模式;在浏览器中,全局对象为window对象:console。log(thiswindow);truethis。a37;console。log(window。a);372、函数上下文调用 2。1普通函数 普通函数内部的this分两种情况,严格模式和非严格模式。 (1)非严格模式下,没有被上一级的对象所调用,this默认指向全局对象window。functionf1(){returnthis;}f1()window;true (2)严格模式下,this指向undefined。functionf2(){usestrict;这里是严格模式returnthis;}f2()undefined;true 2。2函数作为对象的方法 (1)函数有被上一级的对象所调用,那么this指向的就是上一级的对象。 (2)多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象,而非window)。方式1varo{prop:37,f:function(){returnthis。prop;}};当o。f()被调用时,函数内的this将绑定到o对象。console。log(o。f());logs37方式2varo{prop:37};functionindependent(){returnthis。prop;}函数f作为o的成员方法调用o。findependent;console。log(o。f());logs37方式3this的绑定只受最靠近的成员引用的影响o。b{g:independent,prop:42};console。log(o。b。g());42 特殊例子例子1varo{a:10,b:{a:12,fn:function(){console。log(this。a);undefinedconsole。log(this);{fn:}}}};o。b。fn();例子2varo{a:10,b:{a:12,fn:function(){console。log(this。a);undefinedconsole。log(this);window}}};varjo。b。fn;j();this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子2中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子1是不一样的,例子1是直接执行了fn 2。3原型链中的this (1)如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。varo{f:function(){returnthis。athis。b;}};varpObject。create(o);p。a1;p。b4;console。log(p。f());5 上述例子中,对象p没有属于它自己的f属性,它的f属性继承自它的原型。当执行p。f()时,会查找p的原型链,找到f函数并执行。因为f是作为p的方法调用的,所以函数中的this指向p。 (2)相同的概念也适用于当函数在一个getter或者setter中被调用。用作getter或setter的函数都会把this绑定到设置或获取属性的对象。 (3)call()和apply()方法:当函数通过Function对象的原型中继承的方法call()和apply()方法调用时,其函数内部的this值可绑定到call()apply()方法指定的第一个对象上,如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。functionadd(c,d){returnthis。athis。bcd;}varo{a:1,b:3};add。call(o,5,7);135716add。apply(o,〔10,20〕);13102034functiontt(){console。log(this);}第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。tt。call(5);内部转成Number{〔〔PrimitiveValue〕〕:5}tt。call(asd);内部转成String{0:a,1:s,2:d,length:3,〔〔PrimitiveValue〕〕:asd} (4)bind()方法:由ES5引入,在Function的原型链上,Function。prototype。bind。通过bind方法绑定后,函数将被永远绑定在其第一个参数对象上,而无论其在什么情况下被调用。functionf(){returnthis。a;}vargf。bind({a:azerty});console。log(g());azertyvaro{a:37,f:f,g:g};console。log(o。f(),o。g());37,azerty 2。4构造函数中的this 当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。 构造器返回的默认值是this所指的那个对象,也可以手动返回其他的对象。functionC(){this。a37;}varonewC();console。log(o。a);37为什么this会指向o?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。functionC2(){this。a37;return{a:38};手动设置返回{a:38}对象}onewC2();console。log(o。a);38 特殊例子 当this碰到return时例子1functionfn(){this。user追梦子;return{};}varanewfn();console。log(a。user);undefined例子2functionfn(){this。user追梦子;returnfunction(){};}varanewfn();console。log(a。user);undefined例子3functionfn(){this。user追梦子;return1;}varanewfn();console。log(a。user);追梦子例子4functionfn(){this。user追梦子;returnundefined;}varanewfn();console。log(a。user);追梦子例子5functionfn(){this。user追梦子;returnundefined;}varanewfn();console。log(a);fn{user:追梦子}例子6虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊functionfn(){this。user追梦子;returnnull;}varanewfn();console。log(a。user);追梦子总结:如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。 2。5setTimeoutsetInterval (1)对于延时函数内部的回调函数的this指向全局对象window; (2)可以通过bind()方法改变内部函数this指向。默认情况下代码functionPerson(){this。age0;setTimeout(function(){console。log(this);},3000);}varpnewPerson();3秒后返回window对象通过bind绑定functionPerson(){this。age0;setTimeout(function(){console。log(this);}。bind(this),3000);}varpnewPerson();3秒后返回构造函数新生成的对象Person{。。。}3、在DOM事件中 3。1作为一个DOM事件处理函数 当函数被用作事件处理函数时,它的this指向触发事件的元素(针对addEventListener事件)。被调用时,将关联的元素变成蓝色functionbluify(e){this指向所点击元素console。log(thise。currentTarget,thise。currentTarget);总是true当currentTarget和target是同一个对象时为trueconsole。log(thise。target,thise。target);this。style。backgroundColorA5D9F3;}获取文档中的所有元素的列表varelementsdocument。getElementsByTagName();将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色for(vari0;ielements。length;i){elements〔i〕。addEventListener(click,bluify,false);} 3。2作为一个内联事件处理函数 (1)当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素; (2)当代码被包括在函数内部执行时,其this指向等同于普通函数直接调用的情况,即在非严格模式指向全局对象window,在严格模式指向undefined:buttononclickconsole。log(this)showmebuttonbuttononclick(function(){console。log(this)})()showinnerthisbuttonbuttononclick(function(){usestrict;console。log(this)})()usestrictbutton控制台打印buttononclickconsole。log(this)showmebuttonWindow{postMessage:,blur:,focus:,close:,parent:Window,}undefined4、箭头函数 4。1全局环境中 在全局代码中,箭头函数被设置为全局对象:varglobalObjectthis;varfoo()this;console。log(foo()globalObject);true 4。2this捕获上下文 箭头函数没有自己的this,而是使用箭头函数所在的作用域的this,即指向箭头函数定义时(而不是运行时)所在的作用域。1、箭头函数在函数内部,以非方法的方法使用functionPerson(){this。age0;setInterval((){this。age;},3000);}varpnewPerson();Person{age:0}普通函数作为内部函数functionPerson(){this。age0;setInterval(function(){console。log(this);this。age;},3000);}varpnewPerson();Window{。。。} 4。2this捕获上下文 箭头函数没有自己的this,而是使用箭头函数所在的作用域的this,即指向箭头函数定义时(而不是运行时)所在的作用域。1、箭头函数在函数内部,以非方法的方法使用functionPerson(){this。age0;setInterval((){console。log(this);this。age;},3000);}varpnewPerson();Person{age:0}普通函数作为内部函数functionPerson(){this。age0;setInterval(function(){console。log(this);this。age;},3000);}varpnewPerson();Window{。。。} 在setTimeout中的this指向了构造函数新生成的对象,而普通函数指向了全局window对象。 4。3箭头函数作为对象的方法使用 箭头函数作为对象的方法使用,指向全局window对象;而普通函数作为对象的方法使用,则指向调用的对象。varobj{i:10,b:()console。log(this。i,this),c:function(){console。log(this。i,this);}};obj。b();undefinedwindow{。。。}obj。c();10Object{。。。} 4。4箭头函数中,call()、apply()、bind()方法无效varadder{base:1,对象的方法内部定义箭头函数,this是箭头函数所在的作用域的this,而方法add的this指向adder对象,所以箭头函数的this也指向adder对象。add:function(a){varfvvthis。base;returnf(a);},普通函数f1的this指向windowadd1:function(){varf1function(){console。log(this);};returnf1();},addThruCall:functioninFun(a){varfvvthis。base;varb{base:2};returnf。call(b,a);}};console。log(adder。add(1));输出2adder。add1();输出全局对象window{。。。}console。log(adder。addThruCall(1));仍然输出2(而不是3,其内部的this并没有因为call()而改变,其this值仍然为函数inFun的this值,指向对象adder 4。5this指向固定化 箭头函数可以让this指向固定化,这种特性很有利于封装回调函数varhandler{id:123456,init:function(){document。addEventListener(click,eventthis。doSomething(event。type),false);},doSomething:function(type){console。log(Handlingtypeforthis。id);}}; 上面代码的init方法中,使用了箭头函数,这导致这个箭头函数里面的this,总是指向handler对象。如果不使用箭头函数则指向全局document对象。 4。6箭头函是不适用场景 (1)箭头函数不适合定义对象的方法(方法内有this),因为此时指向window; (2)需要动态this的时候,也不应使用箭头函数。例1,this指向定义箭头函数所在的作用域,它位于对象cat内,但cat不能构成一个作用域,所以指向全局window,改成普通函数后this指向cat对象。constcat{lives:9,jumps:(){this。lives;}};例2,此时this也是指向window,不能动态监听button,改成普通函数后this指向按钮对象。varbuttondocument。getElementById(press);button。addEventListener(click,(){this。classList。toggle(on);}); 参与互动