一、作用域
1、写出console.log结果(作用域)
(function(){
var a = b = 2;
})()
console.log(typeof a==='undefined'); //true
console.log(typeof b==='undefined'); //false
考查点:作用域
解析:
var a = b = 2;
相当于
b = 2;//b没有var修饰符,相当于全局变量
var a = b;//a是函数内变量,函数外访问不了,直接访问a,会报引用错误(ReferenceError)
2、写出console.log结果(作用域和变量提升)
var name = 'World!';
(function(){
if(typeof name == 'undefined'){
var name = 'Lucy';
console.log("Goodbye "+name);//Goodbye Lucy
}else{
console.log("Hi "+name);
}
})()
输出结果:Goodbye Lucy
考查点:作用域和变量提升
解析:
Js代码分为两个阶段:预编译阶段(预处理)和执行阶段,在编译阶段找到所有声明(包括var声明和函数声明),将声明提升至作用域的顶部。
(function(){
if(typeof name == 'undefined'){
var name = 'Lucy'; // var变量声明同时赋值
console.log("Goodbye "+name);//Goodbye Lucy
}else{
console.log("Hi "+name);
}
})()
相当于:
(function(){
var name; //var变量提升
if(typeof name == 'undefined'){
name = 'Lucy'; //仅赋值
console.log("Goodbye "+name);//Goodbye Lucy
}else{
console.log("Hi "+name);
}
})()
3、写出console.log结果(变量提升、函数提升,调用顺序)
var a = 1;
function a(a) {
console.log(a);
var a = 3;
}
a(6); //Uncaught TypeError: a is not a function
考查点:
- 变量和函数声明提升:js包含预处理和执行阶段;在预处理期 对变量和函数进行处理,将变量和函数声明提升至作用域的顶部。
- 调用顺序:预处理时,先变量后函数,当变量名和函数名一致时,后者会覆盖前者。
解析:
这里我们详细解析下输出结果:预处理期,先处理var a,然后处理函数a,此时typeof a为function;代码执行阶段,对a进行赋值,此时a=1,则a的类型为number,所以a(6)会报错。
示例:变量提升
var a = 2
function fn() {
console.log(a)
var a = 3
}
fn() //undefined
函数fn内,var a提升在作用域顶部,相当于
function fn(){
var a;
console.log(a);
a = 3;
}
示例:先变量后函数,函数声明覆盖变量声明
function b(){
}
var b;
console.log(typeof b);//function
4、写出输出结果:作用域问题
var arr=[];
for(var i=0;i<10;i++){
arr.push(function(){console.log(i)});
}
//代码1
arr[1]();//10;
//代码2
for(var i=0;i<10;i++){
arr[i](); //0,1,2,3,4,5,6,7,8,9
}
结果解析:
代码1输出解析:代码1输出结果为10,因为此时调用方法,变量i值已经为10;所以调用arr中任何一个元素的方法都会返回10。
代码2输出解析:代码2输出结果为0,1,2,3,4,5,6,7,8,9,当执行for循环时,i变量的值发生了变化,所以在循环中立即调用数组arr中元素的方法时,返回的是当前i变量的值。
5、写出输出结果(考查作用域)
var obj = {
color: "red",
fun: function() {
var self = this;
console.log("out_fun:" + this.color);//"red"
(function() {
console.log("inner_fun:" + this.color);//undefined
console.log("inner_fun:" + self.color);//"red"
}());
}
};
obj.fun();
考查点:考查作用域和闭包问题
结果解析:fun中IIFE(立即调用的函数表达式)有自己的作用域,其中的this指向window,window中没有color属性,所以this.color返回undefined;但是它能访问父层的作用域,所以self.color返回值是red。
6、考查作用域
自由变量跨作用域取值时,要取创建这个函数的作用域取值,而非父作用域。
var m = 10;
var fn = function(n){
if(n > m){
console.log(n); //15
}
};
(function(f){
var m = 100;
f(15);
})(fn)
ps: 所谓自由变量就是变量调用和声明的作用域不同。例在 fn函数中 用到变量 m,但并没有在 fn 中声明,要到别的作用域中找它,这个变量 m就是自由变量
7、考查闭包、作用域
变量取值:首先要在该函数内取值 -》如没有,再去创建这个函数的作用域取值,而非父作用域 -》如创建这个函数的作用域依然没有,继续往上查找,直到全局作用域;如果全局作用域也没找到,那么这个变量就不存在。
二、算法相关
1、找出两个字符串的不同
//利用正在exec方法
function fn(str1,str2){
var re = new RegExp("[^"+str1+"]|[^"+str2+"]","g");
var arr = [],tmp=null;
while((tmp=re.exec(str1+str2))!=null){
arr.push(tmp[0])
}
return arr;
}
fn("Hi,I am Lucy!","Hi,I'm Lily!"); //["a", "u", "c", "'", "l"]
//利用match方法
function fn2(str1,str2){
var re = new RegExp("[^"+str1+"]|[^"+str2+"]","g");
return (str1+str2).match(re);
}
fn2("Hi,I am Lucy!","Hi,I'm Lily!"); //["a", "u", "c", "'", "l"]
考查点:正则表达式
解析:exec可以返回更多的信息:正则匹配结果,匹配结果的索引值(index属性值),原数组(input属性值)
2、给定一个由N个整数组成的数组,数组中有正数也有负数,数组中一个或多个连续元素可以组成一个子数组,请从这些连续元素组成的子数组中找出和最大的子数组,并给出该子数组的起始元素和结尾元素的索引值
var arr1=[1,-2,3,4,6,-10,12];
function getMaxSum(arr){
if(!arr || !arr.length){
return "数组为空";
}
var max = 0;
var sum = 0;
var start = 0;
var oldStart = 0;
var end = 0;
for(var i=0,ln=arr.length;i<ln;i++){
if(sum<=0){
start = i;
sum = 0;
}
sum += arr[i];
if(sum>max){
max = sum;
end = i;
if(end>=start){
oldStart = start;
}
}
}
return {max:max,start:oldStart,end:end};
}
console.log(getMaxSum(arr1));//{"max":15,"start":2,"end":6}
3、给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
例如:字符串"abcabbcbbcca",的不含重复字符的最长子串为"abc",其长度为3.
function maxSubstringLen(str) {
var newStr = "";
var longStr = "";
var strArr = str.split("");
for(var i=0;i<strArr.length;i++){
if(newStr.indexOf(strArr[i])==-1){
newStr += strArr[i];
}else{
if(longStr.length<newStr.length){
longStr = newStr;
}
var index = newStr.indexOf(strArr[i]);
newStr = newStr.substring(index+1)+strArr[i];
}
}
if(longStr.length<newStr.length){
longStr = newStr;
}
return longStr.length;
};
maxSubstringLen("abcabbcbbcca");//3
三、JS基础
1、使用 typeof 判断一个引用类型的值 是不是 对象的弊端,如何正确判断对象?
弊端:用typeof不能准确判断一个引用类型是object、array还是null。
解决方法:用Object.prototype.toString.call(待判断数据类型的元素)。
console.log(typeof [] === 'object' );//true
console.log(typeof null === 'object' );//true
console.log(typeof {} === 'object' );//true
//准备判断对象类型的方法:
Object.prototype.toString.call([]);//"[object Array]"
Object.prototype.toString.call(null);//"[object Null]"
Object.prototype.toString.call({});//"[object Object]"
2、map和parseInt
[1,2,3].map(parseInt); //[1, NaN, NaN]
该题同时考察map和parseInt的用法:
map: array.map(function(value,index,arr), thisParam)
参数 | 描述 |
---|---|
function(value,index,arr) | 必填 |
thisParam | 选填,改变函数中this指向 |
parseInt:parseInt(string, radix)
参数 | 描述 |
---|---|
string | 必填;要被解析的字符串。 |
radix | 选填;要解析的数字的基数,介于 2 ~ 36 之间。 |
3、new 创建实例的过程
实现步骤:
1)创建一个新对象;
2)新对象连接到构造函数原型上;
3)执行构造函数代码(将this指向obj,为这个新对象添加属性);
4)返回新对象。
实现代码:
function create(Fn) {
if (typeof Fn !== 'function') {
throw 'Fn must be a function';
}
// 1、创建一个对象新对象
var obj = new Object()
// 2、给该对象的__proto__赋值为Fn.prototype,即设置原型链
obj.__proto__ = Fn.prototype
// 3、执行Fn,并将obj作为内部this
var ret = Fn.apply(obj, [].slice.call(arguments, 1));
// 4、如果Fn有返回值,则将其作为new操作返回内容,否则返回obj
return ret instanceof Object ? ret : obj;
};
4、内存泄漏
- 意外的全部变量:局部作用域中未生命的变量;
- setTimeout 的第一个参数使用字符串而非函数;
- 闭包;
- Dom引用:Dom元素被删除时,内存中的引用未被正确清空;
- 控制台(console.log)
四、考查点
1、跨域问题
2、js设计模式(单例模式)
3、原型链
4、闭包
5、请求响应过程
6、浏览器垃圾回收机制
7、如何比较两个对象是否相等
8、防抖和节流
9、页面关闭监听
10、跨站脚本攻击(XSS)
11、页面计时中关闭再次打开,如何保证计时有效
12、如何实现浏览器内多个标签页之间的通信
原创内容,转载请标记出处:https://blog.csdn.net/yihanzhi/article/details/79664156