【js常见面试题】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、js本地对象/内置对象/宿主对象

  • 本地对象指的是可以用new实例化的
  • 内置对象指的是Math、global这些
  • 宿主对象指的是浏览器自带的 document、window等

二、js深拷贝和浅拷贝

1.浅拷贝方法:

  1. Object.assign
  2. 解构赋值

2.深拷贝方法:

  1. JSON.stringify(xx)
    缺点:值为undefined/Symbol的会被忽略;值为function的也会被忽略
  2. 递归实现
    var obj1 = [{
        name: '臧三',
        childs: ['小明', '小芳'],
        fn: function() {},
        age: undefined
    }]
    var obj2 = extend(obj1)
    obj2[0].childs = []
    console.log(obj1, obj2)
    
    function extend(data) {
    	if (typeof data === 'object' && data) {
    		var value = data.length ? [] : {}
    		for(let i in data) {
    			value[i] = extend(data[i])
    		}
    		return value
    	} else {
    		return data
    	}
    }
    

二、常见继承方式

  1. 扩展原型对象
  2. call/apply借用构造函数实现继承
  3. 组合继承:原型链继承方法+借用构造函数继承属性

三、如何进行代码优化

  1. 代码重用
  2. 函数单一职责原则
  3. 变量、闭包的内存释放

四、前端优化

  1. 减少http请求次数
  2. 减少操作dom次数,避免回流与重绘,少用全局变量
  3. gzip压缩,cdn加速,文件服务器

五、js实现冒泡排序

function sort(arr) {
	for(let i = 0; i < arr.length; i++) {
		for(let j = 0; j < arr.length -i; j++) {
			let temp = arr[j]
			if (arr[j] > arr[j+1]) {
				arr[j] = arr[j+1]
				arr[j+1] = temp
			}
		}
	}
	
	return arr
}

六、isNaN和Number.isNaN

  1. Number.isNaN只有对于NaN才返回true,非NaN一律返回false。首先会判断传入的值是否是数字类型,如果不是,直接返回false,是判断一个值是否严格等于NaN
  2. isNaN: 通过Number将参数转为数字类型,如果转换成功,则返回false,反之返回true。它只是判断参数是否能转换为数字,不能判断是否严格等于NaN

七、isFinite和Number.isFinite

  1. Number.isFinite 先检测一个值是不是数值,如果不是,直接返回false. 如果是一个数值,再建查其是不是有效的
  2. isFinite 调用Number将值转换为数值类型,再检测

八、Array.prototype.flat/flagMap

flat: 数组拍平
flatMap:先map再flat

九、Object.is

相等运算符:自动转换数据类型
严格相等运算符:

NaN === NaN => false
+0 === -0 => true

Object.is 在所有环境中,只要两个值是一样的, 他们就应该相等

Object.is(+0, -0) => false
Object.is(NaN, NaN) => true

十、common.js循环加载

commonjs模块的重要特性是加载时执行,一旦某个模块被循环加载,就只输出已经执行的部分,还未执行的部分不会输出

十一、es6模块循环加载

es6模块动态引用,被import的变量不会被缓存,会成为一个指向被加载模块的一个引用,需要开发者自己保证,在取值的时候取到值

十二、js中哪些数据类型是false

0 undefined NaN ‘’ null -0

十三、js对象如何转换为原始类型

  1. toString: 返回对象的字符串表示
  2. valueOf:返回对象的字符串,数值或者布尔值表示
  3. Symbol.toPrimitive: 这个符号作为一个属性表示一个方法,该方法将用自定义的规则转换为相应的原始值(优先级高于valueOf)
    Symbol.toPrimitive
  4. 预期转换为字符串类型:字符串拼接、字符串模板、String()
  5. 预期抓换为number类型:除法、减法、Number()、正负号(不是加减运算)
  6. 预期转换为default类型:数字加法、布尔运算(Boolean a && 11)
    == 也是default 但不一定是true,要看具体的类型
    注意:布尔运算所有的对象类型都被转换为true

    三种方法触发的顺序
  7. 首先判断对象是否有Symbol.toPrimitive方法,若有则执行该方法,没有则执行下面的步骤
  8. 如果预期被转换为字符串类型时,则优先执行toString方法
  9. 如果预期被转换为默认类型或者数字类型时,则优先执行valueOf方法
    若没有valueOf方法,但是定义了toString方法,则会执行toString方法

十四、实现call/apply

Function.prototype.myCall = function(obj) {
	let object = obj || window
	object.fn = this
	// let arg = Array.prototype.slice.apply(arguments, [1])
	let [,...arg] = arguments
	arg = typeof arg !== undefined ? arg : []
	let result = object.fn(...arg)
	delete object.fn
	return result
}
Function.prototype.myApply = function(obj) {
	let object = obj || window
	object.fn = this
	let [, arg] = arguments
	arg =  arg instanceof Array  ? arg : []
	let result = object.fn(...arg)
	delete object.fn
	return result
}

十五、实现bind

  1. 绑定this, 返回一个新函数
  2. 可以传入参数,参数会叠加
var foo={
   value:1
};
function bar(){
  console.log(this.value)
}
Function.prototype.myBind = function(context){
	let self = this
	// let arg = Array.prototype.slice.call(arguments, 1)
	let [,...arg] = arguments
	return function() {
		// let arg1 = Array.prototype.slice.call(arguments)
		let [...arg1] = arguments
		self.apply(context, arg.concat(arg1))
	}
}
bar.myBind(foo)()
  1. 一个绑定函数也可以使用new操作符创建对象,这种情况就像把原函数当作构造器,同时调用时的参数被提供给模拟函数
var foo={
   value:1
};
function bar(name, age){
  this.name = name
  this.age = age
  console.log(this.value)
}
Function.prototype.myBind = function(context){
	let self = this
	// let arg = Array.prototype.slice.call(arguments, 1)
	let [,...arg] = arguments
	let returnFn = function() {
		// let arg1 = Array.prototype.slice.call(arguments)
		let [...arg1] = arguments
		// this指的是空对象,这个对象是有具体类型的
	    // self是指foo构造函数
		self.apply(this instanceof self ? this : context, arg.concat(arg1))
	}
	returnFn.prototype = self.prototype
	return returnFn
}
bar.myBind(foo, 'dhl')(28)

十六、instanceOf

只要右边变量的prototype再左边变量的原型链上就返回true

十七、移动端1px

transform: scale(0.5) 很灵活,缩小线的大小

十八、浏览器垃圾回收机制

标记清理(常用)和引用计数
再变量存在上下文,浏览器添加存在上下文的标记
当变量不存在于上下文时,浏览器添加离开上下文标记,等待浏览器清除
引用计数再代码存在循环引用的时候会出现问题

十九、防抖

function debounce(fn, delay) {
	let timer
	return function(){
		clearTimeout(timer)
		timer = setTimeout(() =>{
			fn.call(this)
		},delay)
	}
}

二十、节流

function throttle(fn,delay) {
	let startTime = +new Date()
	let timer 

	return function() {
		let now = +new Date()
		clearTimeout(timer)
		if (now - startTime > delay){
			fn.call(this)
		} else {
			timer = setTimeout(() => {
				fn.call(this)
				startTime = +new Date()
			}, now - startTime)
		} 
	}
}

二十一、正向代理与反向代理

  1. 正向代理隐藏客户端:浏览国外网站
  2. 反向代理隐藏服务器:起到一个负载均衡的作用,比如从外网访问企业内网

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值