JS常见问题总结

发布于 2021-02-01  4,715 次阅读


1. 什么是 JavaScript ?

JavaScript 是一种具有面向对象的、解释型的、基于对象和事件驱动的、跨平台的、弱类型的程序设计语言

2. JavaScript 与 ECMAScript 的关系?

ECMAScript 是规则,JavaScript 是对规则的体现

3. 变量的命名规则?

严格区分大小写,由英文、数字、下划线、$组成,推荐使用驼峰命名法,不能使用保留字和关键字,见名知意,名字不能重复

4. window.onload 的作用?

当页面加载完成后再执行

5. js 数据类型?

基本数据类型有:Number、String、Boolean、Undefined、Null;

复合数据类型有:Object(object、array、function)

6. null 和 undefined 的区别?

null 表示值为空,但是为 object 类型

undefined 表示变量没有初始化

7. 运算符的种类?

算术运算符 + - * / % ++ --

赋值运算符 = += -= *= /=

比较运算符 > >= < <= == != === !==

逻辑运算符是与 &&,或 ||, 非 !

三目运算符 // 条件 ? 语句一 : 语句二 如果条件成立,执行 ? 后面语句,不成立执行:后面的语句

8. var a = 10;var b = a++; a、b 最后的结果是?

a=11,b=10

9. “==”与“===”的区别?

==值一样,类型可以不一样

===值一样,类型一样

10. console.log(0.1+0.2 == 0.3)

false ,因为小数相加会有一点偏差

11. NaN 会在什么样的情况下出现呢?列举出现这种情况的代码

typeof Number(undefined));//NaN
typeof Number([1,2]));//NaN
typeof Number({}));//NaN
typeof Number(10abc));//NaN

12. 列举三种强制类型转换和 2 种隐式类型转换

Number() String() parseInt()
console.log(1+‘2’);
console.log(2-true);

13. document.write() 与 innerHTML 的区别?

  • document.write()可以识别标签。
  • document.write()会覆盖标签中已有的内容, 但是不会覆盖 document.write()添加的内容。
  • document.write()只能操作 body 的内容。
  • document.write() == document.body.innerHTML。

14. this 对象的理解?

  • 在事件处理函数中,this 指向触发事件的元素
  • 在全局中(普通函数)中,this 指向 window
  • 谁调用指向谁

15. 写一个获取非行间样式的函数

function getStyle(obj, attr) {  //obj 表示元素 attr 表示属性
    if (obj.currentStyle) {
        return obj.currentStyle[attr]// ie 浏览器
    } else {
        return getComputedStyle(obj)[attr]// 标准浏览器
    }
}

16. 说说你对作用域链的理解?

作用域链是 JS 的查找机制,从当前作用域查找,若没有则向上一级作用域查找,一直到最外层,如果都查找不到则返回 is not define

17.写出下列函数的运行结果

var x = 1, y = z = 0;
function add(n) {
    n = n + 1;
};
y = add(x);
function add(n) {
    n = n + 3;
};
z = add(x);
console.log(x, y, z);

结果: undefined undefined

18. 请解释变量提升?

  • 变量提升(预解析)找 var 的时候,如果存在 var 关键字,则会将这个变量先存储下来,存储的形式为:var a = undefined,预解析的时候变量中存的都是 undefined,

  • 等到逐行解析遇到表达式即 + - * / % ++ -- = 等操作才会改变变量的值。找 function 的时候,会将整个函数都保存下来。找参数的时候,即执行函数时,函数内部可以看作是一个小的区域,有自己的预解析,参数就跟变量 var 一样。

19. 函数声明和函数表达式声明的区别?

  • 函数声明 function 函数名(){}
  • 函数表达式声明 var f =function (){console.log(函数表达式);} f();
  • 区别:解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问),函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。

20. JavaScript 两种变量范围有什么不同?

  • 全局变量: 直接在 script 标签下声明的变量,任何地方都能访问,任何地方都能对其值进行改变。
  • 局部变量: 函数内部定义的变量,函数内能访问,出了函数的括号就不能访问(垃圾回收)。

21. 定时器的分类?他们的区别及用法是什么?

  • setInterval( 函数 ,间隔时间(单位毫秒))
  • setTimeout(函数,间隔时间(单位毫秒))

22. js 有哪些内置对象?

  • 时间对象 date, 字符串对象 string,数学对象 Math,数值对象 Number,
  • 数组对象 Array,函数对象 function, 函数参数集合 arguments,
  • 布尔对象 Boolean,基础对象 Object

23. 把下面的字符串去重,并去除掉特殊字符按数字在前字母在后的顺序排序字符串

如下:“1233fddfd&3434fdsaff&454545&4545444rfdsfds&545gdsgs”

var str = '1233fddfd&3434fdsaff&454545&4545444rfdsfds&545gdsgs';

// 去重
var newstr = ;
for (var i = 0; i < str.length; i++) {
    var s = str[i];
    if (newstr.indexOf(s) == -1) {
        newstr += (str[i])
    }
}
console.log(newstr);

// 去除特殊字符
var strs = newstr.replace(&, )
console.log(strs);  //123fd4sa5rg

// 排序
var str1 = '';
var str2 = '';
for (var i = 0; i < strs.length; i++) {
    if (strs.charCodeAt(i) < 65) {
        str1 += strs[i]
    } else {
        str2 += strs[i]
    }
}
console.log(str1 + str2);  // 12345fdsarg

24. 截取字符串“abcdefg”中的 def

var str=“abcdefg”
str.substring(3,6)//包括 3 不包括 6

25. 提取url中的参数并返回

有这样一个url:http://item.taobo.com/item.html?a=1&b=2&c=&d=xxx&e, 请写一段 js 程序提取 url 中各个 get 参数 ( 参数名和参数个数不确定 ),将其 key-value形式返回到一个 json 结构中,如 {a:“1”,b:“2”,c:“”,d:“xxx”,e:undefined}

var str = url:http://item.taobo.com/item.html?a=1&b=2&c=&d=xxx&e;
var arr1 = str.split(?)[1]
var arr2 = arr1.split(&)
var obj = {};
for (var i = 0; i < arr2.length; i++) {
    var arr = arr2[i]
    var pro = arr[0]
    var len = arr.substring(1)
    if (len == =) {
        len =  
    } if (len == ) {
        len = undefined
    }
    len = len.replace(/[=]/, )
    obj[pro] = len;
}
console.log(obj)
// {a: 1, b: 2, c:  , d: xxx, e: undefined}

26. 判断一个字符串中出现次数最多的字符,并且统计次数

var str = '1233fddfd&3434fdsaff&454545&4545444rfdsfds&545gdsgs';
// 1、去重
var newstr = ;
for (var i = 0; i < str.length; i++) {
    var s = str[i];
    if (newstr.indexOf(s) == -1) {
        // indexOf(str[,index]) 该方法返回某个指定的字符串值在字符串中首次出现的位置。index 是可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1
        newstr += (str[i])
    }
}
console.log(newstr);

// 2.去除特殊字符
var w = newstr.replace(&, )
console.log(w);//123fd4sa5rg

//3.排序
var str1 = '';
var str2 = '';
for (var i = 0; i < w.length; i++) {
    if (w.charCodeAt(i) < 65) {
        str1 += w[i]
    } else {
        str2 += w[i]
    }
}
console.log(str1 + str2);
// console.log(str2);

var str = asddfssssaasswef;
var obj = {};
//遍历字符串,将出现的字符存入到数组中
for (var i = 0; i < str.length; i++) {
    if (!obj[str.charAt(i)]) {
        obj[str.charAt(i)] = 1;
    } else {
        obj[str.charAt(i)]++;
    }
}
console.log(obj);
var max = 0;
var charmax;
//遍历数组,找出出现最多的字母出现的次数
for (var key in obj) {
    if (obj[key] > max) {
        max = obj[key];
        charmax = key;
    }
}
console.log(出现最多的字符是 + charmax + ,出现了 + max + 次);

27. 数组方法 pop() push() unshift() shift()

  • push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度
  • pop()方法则从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项.
  • shift()能够移除数组中的第一个项并返回该项,同时将数组长度减 1
  • unshift()能在数组前端添加任意个项并返回新数组的长度

28. split() join() 的区别?

  • splice()集删除、添加、替换于一身
  • arr.splice(1) //从当前位置开始删除,删除到末尾
  • arr1.splice(1,1,1) //从 1 的位置开始删除,删除一个,用 1 代替
  • arr.splice(1,0,4) //添加
  • join()方法只接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的字符串

29. 编写一个数组去重的方法

var arr = [1, 3, 5, 2, 3, 3, 5, 6, 2, 3, 4, 6, 3, 3, 5, 2];
//原理: 先找相邻的两个元素 做相等比较 如果有相等的值,保留前者,删除后者,下标调整
//数组的第一个元素
for (var i = 0; i < arr.length; i++) { // 控制所有的循环遍数
    //在循环一遍
    for (var j = i + 1; j < arr.length; j++) {
        //相等比较
        if (arr[i] == arr[j]) {
            //删除 splice 一个一个删除
            arr.splice(j, 1);
            //下标减少
            j--;
        }
    }
}
console.log(arr);

30. [“1”, “2”, “3”].map(parseInt) 运行结果是?

原例子相当于[parseInt(1,0),parseInt(2,1),parseInt(3,2)]//即 10 进制 1 转为 10 进制,(1 进制 2 转为 10 进制,2 进制 3 转为 10 进制)不存在

因此输出:[1, NaN, NaN]

31. 冒泡算法排序

var arr = [8, 23, 1, 43, 12, 56, 13, 66]
for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < arr.length - i; j++) {
        if (arr[j] > arr[j + 1]) {
            var temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
}
console.log(arr);

32. DOM 怎样添加、移除、移动、复制、创建和查找节点?

  • 创建新节点
    createDocumentFragment() //创建一个 DOM 片段
    createElement() //创建一个具体的元素
    createTextNode() //创建一个文本节点
  • 添加、移除、替换、插入
    appendChild()
    removeChild()
    replaceChild()
    insertBefore()
  • 查找
    getElementsByTagName() //通过标签名称
    getElementsByName() //通过元素的 Name 属性的值
    getElementById() //通过元素 Id,唯一性

33. 什么是 window 对象 ? 什么是 document 对象 ?

Window 对象表示浏览器中打开的窗口。
document 对象表示给定浏览器窗口中的 HTML 文档

34. offsetWidth、clientWidth、scrollTop 的区别?

  • clientHeight 可视区域高度 包括 padding,不包括 border、margin、滚动条
  • offsetHeight 元素本身高度 包括 padding,border,滚动条
  • scrollHeight 元素内容整体高度 包括 padding,不包括 border、margin
  • scrollTop 滚动的高度
  • offsetTop 相对于最近的 position 不为 static 的父元素的上偏移距离,没有则指向 body

35. 如何获取 url 地址中搜索内容?

用?分割 search ?q=javascript 返回 URL 的查询字符串

36. 事件、IE 与火狐的事件机制有什么区别?

IE 的是冒泡流,而火狐同时支持冒泡流和捕获流

37. 如何阻止冒泡?

  • jQuery:
    ev.stopPropagation(); //阻止冒泡的操作
    return false; //阻止默认事件 + 阻止冒泡的操作

  • JavaScript标准浏览器:
    ev.stopPropagation(); // 只会阻止事件冒泡,不会阻止默认行为
    ev.preventDefault(); // 只会阻止默认行为,不会阻止事件冒泡

  • JavaScript ie 浏览器:
    ev.cancelBubble = true; // 阻止事件冒泡
    ev.returnValue = false; // 阻止默认行为

38. 事件绑定和普通事件有什么区别?

普通添加事件的方法不支持添加多个事件,最下面的事件会覆盖上面的,而事件绑定(addEventListener)方式添加事件可以添加多个。

39. 如何用原生 js 给元素绑定两个 click 事件?

btn.addEventListener(click,hello1); fuction hello1(){}
btn.addEventListener(click,hello2); fuction hello2(){}

40. 解释一下事件流?

  • 事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即 DOM 事件流。
  • 事件捕获阶段:事件的传播是从最不特定的事件目标到最特定的事件目标。。
  • 确定目标阶段:通过捕获确定具体触发事件的元素
  • 事件冒泡阶段:事件的传播是从最特定的事件目标到最不特定的事件目标。
  • 事件传播的顺序对应浏览器的两种事件流模型:捕获型事件流和冒泡型事件流。
  • 在绑定事件 addEventListener(事件类型,处理函数,是否捕获)中有 3 个参数,最后一个参数默认是 false:表示冒泡,true:表示捕获。

41. 事件委托是什么?

  • 利用事件冒泡的原理,子元素的事件会冒泡到父元素,可以只给父元素添加事件,通过事件目标判断元素。
    优点:节省内存,动态添加的子元素也包含事件

42. 给 10000 个 li 添加点击事件?

var ul = document.getElementsByTagName('ul')[0]
for (var i = 0; i < 10000; i++) {
    var li = document.createElement('li');
    li.innerHTML = i;
    ul.appendChild(li);
}

ul.onclick = function (ev) {
    var objevent = window.event || ev
    var target = objevent.target || objevent.srcElement;
    target.style.background = red;
}

43. 拖拽效果中有几种事件?

  • onmousedown
    onmousemove
    onmouseup

44. 什么是回调函数?

  • 回调函数是某个操作或某个动作做完以后调用的函数

45. 使用正则表达式验证邮箱

let reg = /^[0-9a-z]\w+@[a-z0-9]+\.(com|cn|edu|net|org|gov)$/i  // \w 匹配字母和数字及_
let str = "123ase@qq.com"
console.log(reg.test(str))

46. 请用 js 去除字符串空格

var str =  fdf er re545 6565 2fdfd 
// 去除字符串内所有的空格
str = str.replace(/\s*/g,);// *匹配 0 个或任意多个

47. 判断字符串是否是这样组成的。第一个字符必须是字母,后面可以是字母、数字、下划线,总长度 5-20

let reg = /^[a-zA-Z]\w{4,19}$/
let str = "121asas12ASD"
console.log(reg.test(str))

48. cookie 的利弊?

  • 优点:极高的扩展性和可用性
  • 缺点:
    1)Cookie 的数量和长度的限制
    2)安全性问题
    3)有些状态不可能保存在客户端

49. 封装一个获取 cookie 的函数

function getcookie(key) {
    var arr = document.cookie.split(';');
    for (var i = 0; i < arr.length; i++) {
        var str = arr[i].split('=');
        if (str[0] == key || str[0] == ' ' + key) {
            return str[1];
        }
    }
    return -1;
}

50. new 操作符具体干了什么呢 ?

  • 1)创建一个空对象
    2)由 this 变量引用该对象
    3)该对象继承该函数的原型
    4)把属性和方法加入到 this 引用的对象中
    5)新创建的对象由 this 引用,最后隐式地返回 this。

51. 用过哪些设计模式?

  • 工厂模式
    单体模式
    代理模式
    迭代器模式

52. call() 和 apply() 的区别和作用?

  • 区别:apply 函数名(方法名) function.call(this 的指向,[参数 1,参数 2...])
  • 作用:是改变 this 的指向

53. JavaScript 对象的几种创建方式?

具体见对象进阶

  • 字面量创建
    实例方式创建
    工厂方式创建
    构造函数创
    原型创建
    构造原型混合创建

54. JavaScript 对象的几种继承方式?

具体见对象进阶

  • 分为原型链继承、对象冒充继承和组合继承

55. JavaScript 原型,原型链 ?

  • 原型: 在 JavaScript 中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个 prototype 属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
  • 原型链:在 JavaScript 中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在 JavaScript 中是通过 prototype 对象指向父类对象,直到指向 Object 对象为止,这样就形成了 一个原型指向的链条,专业术语称之为原型链。

56. 如何判断一个对象是否属于某个类?

具体见对象进阶

  • typeof()
    instanceof 方法可以判断变量是否是数组类型 //true/false
    对象,可以使用 constructor 属性来判断其类型
    Object.prototype.toString.call()

57. 小贤有一条可爱的狗 (Dog), 它的叫声很好听 (wow), 每次看到主人的时候就会乖乖叫一声 (yelp), 从这段描述可以得到以下对象:

function Dog() {
 this.wow = function () {
    alert(\'wow\');
 }
 this.yelp = function () {
    this.wow();
 }
}

小芒和小贤一样原来也有一条可爱的狗,可是突然有一点疯了 (MadDog), 一看到人就会每隔半秒叫一声 (wow) 地不停叫唤 (yelp)。请根据描述,按示例形式用代码来实现。( 继承,原型,setInterval);

function MadDog() {
  this.yelp = function() {
    var self = this;
    setInterval(function() {
      self.wow();
    }, 500);
  };
}

MadDog.prototype = new Dog();
//for test
var dog = new Dog();
dog.yelp();
var madDog = new MadDog();
madDog.yelp();

58. 什么是闭包?闭包有什么作用?说说你对闭包的理解

  • 闭包就是能够读取其他函数内部变量的函数
    闭包的作用:创建一个安全的环境,保证内部的代码不收到外部的干涉,如果过多使用闭包,容易导致内存泄露

59. 用闭包方式完成下面代码的修改,使得属性 user,id 外界不可见

User = function () { }
User.prototype = {
 id: ””,
 name: ””,
 getId: function () { return this.id },
 setId: function (id) { this.id = id },
 getName: function () { return this.name },
 setName: function (name) { this.name = name }
}
var User = function() {
    var id = id;
    var name = name;
    this.__proto__ = {
        getId: function() {
            return id;
        },
        setId: function(newid) {
            id = newid;
        },
        getName: function() {
            return name;
        },
        setName: function(newname) {
            name = newname;
        }
    }
}
var admin = new User();
admin.setId(1);
admin.setName(liming);
console.log(admin.name, admin.getName()); //undefined,liming

60. 写一个 mul 函数,使用方法如下

console.log(mul(2)(3)(4)) //24
console.log(mul(4)(3)(4)) //48
function mul (x) {
    return function (y) {
        return function (z) {
            return x * y * z;
        };
    };
}

61. 创建 ajax 的过程

function ajax(url, data, method, success) {
    // 异步对象
    var ajax = new XMLHttpRequest();
    // get 跟 post 需要分别写不同的代码
    if (method == 'get') {
        if (data) {// 如果有值
            url += '?' + data;
        }
        ajax.open(method, url);// 设置 方法 以及 url
        ajax.send(); // send 即可
    } else {
        ajax.open(method, url);
        // 需要设置请求报文
        ajax.setRequestHeader(Content-type,
            application/x-www-form-urlencoded)
        // 判断 data send 发送数据
        if (data) {
            ajax.send(data); // 如果有值 从 send 发送
        } else {
            ajax.send();// 没有值 直接发送即可
        }
    }

    // 注册事件
    ajax.onreadystatechange = function () {
        // 在事件中 获取数据 并修改界面显示
        if (ajax.readyState == 4 && ajax.status == 200) {
            success(ajax.responseText);
        }
    }
}
// 获取本地数据
ajax('bendi.txt', , get, function (res) {
    console.log(res);
})

62. ajax 请求的时候 get 和 post 方式的区别,什么时候用 post?

post 方式需要设置请求报文
ajax.open(method,url);
ajax.setRequestHeader(Content-type,application/x-www-form-urlencoded)

63. ajax 请求时,如何解释 json 数据?

var json = eval( \'(\' + date + \')\' );
var json2 = JSON.parse( date )

64. 同步和异步的区别 ?

  • 异步:不按顺序执行,同一时刻只能执行一个事件
    同步:按顺序执行,同一时刻只能执行一个事件

65. 常见的 http 状态码?

  • 1)1XX 系列:指定客户端应响应的某些动作,代表请求已被接受,需要继续处理
    2)2XX 系列:代表请求已成功被服务器接收、理解、并接受。最常见的有 200、201 状态码。
    3)3XX 系列:代表需要客户端采取进一步的操作才能完成请求,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的 location 域中指明。最常见的有 301、302 状态码
    4)4XX 系列:表示请求错误。代表了客户端看起来可能发生了错误,妨碍了服务器的处理。常见有:401、404 状态码。
    5)5XX 系列:代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。常见有 500、503 状态码。

66. eval 的作用是?

  • eval()方法将字符串数组转换成真正的数组

67. js 哪些操作会造成内存泄露?

  • 1). 全局变量引起的内存泄露
    2). 闭包引起的内存泄露:慎用闭包
    3). dom 清空或删除时,事件未清除导致的内存泄漏
    4). 循环引用带来的内存泄露

68. $(document).ready() 方法和 window.onload 有什么区别?

  • 1)、执行时机不同,window.onload 必须等待网页中所有的内容加载完毕后才能执行,而$(document).ready()是网页中所有 DOM 结构绘制完毕就执行,可能 DOM 元素关联的东西并没有加载完
    2)、window.onload 只能写一个,多个时后面的会覆盖前面的,$(document).ready()可以写多个且不会覆盖。
    3)、window.onload 没有简写形式,而$(document).ready()可以简写成$(function(){})。

69. jQuery 的属性拷贝 (extend) 的实现原理是什么,如何实现深拷贝?

  • 在默认情况下,通过$.extend()合并操作不是递归的(浅拷贝);如果第一个对象的属性本身是一个对象或数组,那么它将完全用第二个对象相同的 key 重写一个属性。这些值不会被合并。然而,如果将true 作为该函数的第一个参数,那么会在对象上进行递归的合并(深拷贝)。
  • 浅拷贝(false 默认):如果第二个参数对象有的属性第一个参数对象也有,那么不会进行相同参数内部的比较,直接将第一个对象的相同参数覆盖。
  • 深拷贝(true):如果第二个参数对象有的属性第一个参数对象也有,还要继续在这个相同的参数向下一层找,比较相同参数的对象中是否还有不一样的属性,如果有,将其继承到第一个对象,如果没 有,则覆盖。

70. $().attr 与 $().prop() 的区别 ?

  • prop 方法一般用于操作 input 的 checked,其它情况应该用 attr 方法

71. Jquery 如何给新添加的元素绑定事件?

  • 采用事件委托的方法,不能使用 on 方法

72. 怎么解决跨域问题?

  • 1)通过 jsop 解决跨域
    2)通过修改 document.domain 来跨子域
    3)使用 window.name 来进行跨域
    4)使用 HTML5 中新引进的 window.postMessage 方法来跨域

73. ajax 的缺点?

  • 1)浏览器对 XMLHttpRequest 对象的支持度不足
    2)破坏浏览器前进,“”后退“”按钮的正常功能
    3)对搜索引擎的支持度不足
    4)开发和调试工具的缺乏

74. 页面编码和被请求的资源编码如果不一致如何处理?

  • 若引入的 js 是 gbk 编码,则 js 后加上 charset=utf-8,反之亦然

75. jquery 中 $.get() 提交和 $.post() 提交有区别吗?

  • 相同点:都是异步请求的方式来获取服务端的数据;
  • 异同点:
    1)请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。
    2)参数传递方式不同:get 请求会将参数跟在 URL 后进行传递,而 POST 请求则是作为 HTTP消息的实体内容发送给 Web 服务器的,这种传递是对用户不可见的。
    3)数据传输大小不同:get 方式传输的数据大小不能超过 2KB 而 POST 要大的多安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。

76. jquery.extend 与 jquery.fn.extend 的区别?

  • 类级别的插件:$.extend() 扩展工具方法下的插件形式 $.trim()
  • 对象级别的插件:$.fn.extend() 扩展到 jq 对象下的插件形式 $().css()

活的像诗一样