面试题 js
1 数据类型
基本数据类型有
Number | String | Boolean | Null | Undefined | Symbol(ES6新增数据类型) | bigInt
引用数据类型统称为Object类型,细分的话有
Object | Array | Date | Function | RegExp
*区别*
基本数据类型的数据直接存储在栈中;
引用数据类型的数据存储在堆中,在栈中保存数据的引用地址,这个引用地址指向的是对应的数据,以便快速查找到堆内存中的对象。
顺便提一句,栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗
2 判断数据类型有几种方法
- 1 typeof 缺点:无法分辨是
null
,Array
还是Object
typeof | null | [] | {} | 11 | NaN | undefined | Object |
---|---|---|---|---|---|---|---|
值 | 'Object' | 'Object' | 'Object' | 'Number' | 'Number' | 'undefined' | 'function' |
- 2 instanceof (instance: 例子)
相当于.__proto__.constructor===
function Foo() { }
var f1 = new Foo();
var d = new Number(1)
console.log(f1 instanceof Foo);// true f1.__proto__.constructor===Foo
console.log(d instanceof Number); //true
console.log(123 instanceof Number); //false -->不能判断字面量的基本数据类型
判断[]
var arr =[]
console.log(arr instanceof Array)
- 3 Object.prototype.toString.call() 相当于Undefined.prototype.toString(伪代码)
//.call()
var person = {fullName:function(){return this.firstName + " " this.lastName;}}
var person1 = { firstName:"Bill", lastName: "Gates", }
person.fullName.call(person1); // 将返回 "Bill Gates"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(123)); // "[object Number]"
console.log(Object.prototype.toString.call("abc")); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
2 Foo.getName()的故事
function Foo() {
//相当于window.getName
getName = function () { console.log(1); };
console.log('this is' + this)
return this;
}
//为Foo添加this.getName一个方法
Foo.getName = function () { console.log(2); };
Foo.prototype.getName = function () { console.log('baidu' && 'google'); };
//变量赋值
var getName = function () { console.log(4); };
//变量声明
function getName() { console.log(5); }
// 请写出一下的输出结果
Foo.getName(); //2
getName(); //4
Foo().getName(); //Foo(): getName赋值 | this is window | windows 1
getName(); //1
//运算符的优先级
//【 obj.X = new X() = X() > new X】
//结合性 obj.X = new X() = X()从左往右 new X从右往左
new Foo.getName(); //2 new (Foo.getName)();
new Foo().getName(); //(new Foo()).getName()
//this is [object Object] (因为没在里面this.getName 去找原型) google
new new Foo().getName(); // new ( (new Foo()).getName ) ()
//this is [object Object] (将getName作为构造函数再次new) google
&& 和 ||
1 && x 运行x 0 && x 运行0
1 || x 运行1 0 || x 运行x
3 数组去重
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
//es5
function unique(arr) {
for (var i = 0; i < arr.length; i++) { // 首次遍历数组
for (var j = i + 1; j < arr.length; j++) { // 再次遍历数组
if (arr[i] == arr[j]) { // 判断连个值是否相等
arr.splice(j, 1); // 相等删除后者
// array.splice(index, howmany, item1, ....., itemX)
// index指定位置添加/删除,使用负值指定从数组末尾开始的位置。
// howmany要删除的项目数。如果设置为 0,则不会删除任何项目。
j--;
}
}
}
return arr
}
//es6
function unique (arr) { return Array.from(new Set(arr)) }
//es5其他方法
创建新[], 新arr.indexOf() 新arr.includes()
不新[]
function unlink(arr) {
return arr.filter(function (item, index, arr) {
//当前元素,在原始数组中的第一个索引===当前索引值,否则返回当前元素
return arr.indexOf(item) === index;
});
}
4 深浅拷贝
//浅拷贝 对象只有一层
// 方式1
function shallowClone1(o) {
let obj = {}
for (let i in o) {
obj[i] = o[i]
}
return obj
}
// 方式2
var shallowClone2 = { ...obj1 }
// 方式3
var shallowClone3 = Object.assign({}, obj1)
// 深拷贝,对象里还有对象
// 简易版
function deepClone(o) {
let obj = {}
for (var i in o) {
// if(o.hasOwnProperty(i)){
if (typeof o[i] === "object") {
obj[i] = deepClone(o[i])
} else {
obj[i] = o[i]
}
// }
}
return obj
}
// 简易版存在的问题:参数没有做检验,传入的可能是 Array、null、regExp、Date
// 有可能碰到循环引用问题 var a = {}; a.a = a; clone(a);//会造成一个死循环
// 循环检测
// 继续升级
function deepClone4(o, hash = new map()) {
if (!isObject(o)) return o//检测是否为对象或者数组
if (hash.has(o)) return hash.get(o)
let obj = Array.isArray(o) ? [] : {}
hash.set(o, obj)
for (let i in o) {
if (isObject(o[i])) {
obj[i] = deepClone4(o[i], hash)
} else {
obj[i] = o[i]
}
}
return obj
}
5 身份证正则
RegExp 对象定义
var reg = /^\d{17}[X\d]$/
[] 匹配[]中的任何一位字符
^和$ 同时使用 严格匹配-必须跟书写的正则内容完全相同, 不能长或短
{X} 匹配X个 n的组合
RegExp 对象方法
test() 检索字符串中的指定值。返回值是 true 或 false。
exec() 检索字符串中的指定值。返回值是被找到的值或null。
console.log(reg.test("146284378426327953")) //true
5 i++
var i=0
console.log(i++) //0
console.log(i) //1
6 concat
var arr1 = [1, 2, 12]
var arr2 = [3, 5]
arr1.concat(arr2) //不改变arr1
arr1.sort() //1 12 2
alert(arr1.join(";")) //1;12;2
7 new()到底做了什么?
function Person () {
this.name = name;
this.age = age;
this.sex = sex
this.sayName = function () {
return this.name;
};
}
Person.prototype.sayAge = function(){eturn this.age;}
var obj = new Person("tom", 21, "famle");
使用关键字new创建新实例对象经过了以下几步:
1 创建一个空对象{}
2 继承原型, 将新对象的_proto_指向构造函数的prototype对象
3 继承属性方法, Person.call(obj) (this指向新对象 Person的this 指向-> obj)
4 返回新的对象
8 "use strict"是什么,优缺点
严格模式
优点: 代码更严谨,安全
缺点: 项目中打包压缩js时, 会将严格模式与非严格模式js代码混合, 导致非严格模式js代码出错
9 将url转化为对象
var url = 'https://www.so.com/s?q=es6&src=srp&fr=hao_360'
var str = url.split('?')[1]
var temp = str.split('&')
var obj = {}
for(var i=0; i<temp.length;i++){
var t = temp[i].split('=')
obj[t[0]]=t[1]
}
console.log(obj) //结果{ q:'es6',src:'srp',fr:'hao_360'}
10 字符串中出现最多的字符
var str = 'aaaabbbbbbccccccc'
var obj = {}
for (var i = 0; i < str.length; i++) {
var char = str.charAt(i)
if (obj[char]) obj[char]++
else obj[char] = 1
}
console.log(obj) //{a: 4, b: 6, c: 7}
var sum = 0 , name = null
for (var i in obj) {
if (obj[i] > sum) {
name = i
sum = obj[i]
}
}
console.log(name+":"+sum) //c:7
11 创建对象的方式
1 {}与new Object()
2 new 构造函数()
3 Object.create(原型)
//父类
function Person(name,age){}
//子类
function Student(name){}
//继承
Student.prototype = Object.create(Person.prototype) //=new Person();
不能直接Student.prototype = Person.prototype(引用类型赋值)
等价于 Student.prototype = new Person();
12 判断图片加载完成
1 onload事件
<img id="img1"src="http://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpg">
<script type="text/javascript">
img1.onload =function() {}
</script>
2 onreadystatechange//在xmlhttp用过, readystate准备状态,readystatechange准备状态变化
img1.onreadystatechange =function() {
if(img1.readyState=="complete"||img1.readyState=="loaded"){}
}
3 轮询节点属性complete
var timer = setInterval(function() {
if(img.complete) { clearInterval(timer) }
}, 50)
13 对象作为key值
var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456;
console.log(a[b]);//为什么是456?
因为键名称只能是字符串,b/c单做键会调用toString得到的都是[object Object],a[b],a[c]都等价于a["[object Object]"],那不就是更新[object Object]这个键的值了
14 事件委托(代理)
1 事件委托是利用事件的冒泡原理来实现的,
2 大致可以分为三个步骤:
(1) 确定要添加事件元素的父级元素;
(2) 给父元素定义事件,监听子元素的冒泡事件;
(3) 使用 event.target 来定位触发事件冒泡的子元素。
3 当子元素是动态的必须用事件委托
4 优点
(1)节约内存 (事件处理程序都是对象,对象越多越会占用内存)
(2)动态绑定事件
15 隐式转换
=>数字
console.log(true+1) //2
console.log(undefined+1) //NaN
=>字符串
console.log("12"+true) //12true
console.log(typeOfnull) //Object
16 websocket 与 ajax
websocket 长连接 全双工,可以从服务器推送更新信息到客户端
ajax 短链接 只能客户端发起请求,若想获得服务器信息更新只能轮询
17 cookie session localStorage sessionStorage区别
1 大小不同
cookie 4k session 无限制 localStorage和sessionStorage 5M
2 有效期不同
cookie document.cookie="url=http:...; max-age=" + 30*24*60*60;
//max-age默认为-1,即关闭浏览器后失效, 为0时,删除cookie
session 永久
localStorage 永久
sessionStorage 页面关闭
3 存储位置
cookie localStorage sessionStorage 客户端
session 服务器
HTML4的cookie有很多缺点(小,随HTTP发送占用带宽),
HTML5不再使用它,转而使用改良后的Web Storage(localStorage和sessionStorage)
18 将函数的arguments转化为数组
1 arguments是对象 => Array.from(arguments)
2 [...arr] 是将伪数组转化为数组
19 获取某元素下所有节点
document.getElementById('box').getElementByTagName("*")
20 显示到2023年的剩余时间
<script>
var newyear = new Date("1/1/2023");
function fn() {
var now = new Date();
var time = new Date(newyear.getTime() - now.getTime());
document.getElementsByTagName("timer")[0].innerHTML =
time.getMonth()+1+"月"+time.getDay()+"日"+time.getHours()+"小时"
+time.getMinutes()+"分"+time.getSeconds()+"秒";
}
setInterval(fn, 500);
</script>
<body>
<timer></timer>
</body>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)