其他分享
首页 > 其他分享> > js面试题汇总

js面试题汇总

作者:互联网

能实现一个new吗

要实现new操作符,就要知道new + 构造函数都做了什么?

  1. 创建一个空的对象
  2. 将空对象的__proto__属性指向构造函数的原型
  3. 将this指向这个对象
  4. 返回这个对象
function newFun(context) {
	// 创建一个空的对象
	var obj = {}
	// 将空对象的__proto__属性指向构造函数的原型
	obj.__proto__ = context.prototype;
	// 将this指向这个对象  将传入的实参分割出来指向obj上
	context.apply(obj, [].slice.call(arguments, 1))
	return obj;
}
function Person(name, age) {
	this.name = name;
	this.age = age
}
var t = newFun(Person, '小张', 20)

数组扁平化

通过不断递归+跳出条件

function newFlat(arr) {
	let res = new Array()
	arr.forEach((item) => {
		if (Array.isArray(item)) {
			res.push(...newFlat(item))
		} else {
			res.push(item)
		}
	})
	return res
}

用过instanceof吗,什么用法,如何手写?

首先要知道是怎么用的?
instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
实例 instanceof 构造函数存在返回true不存在false

例子
function Person(name, age, city) {
	this.name = name;
	this.age = age;
	this.city = city
}
const a = new Person('小王', 20, '上海')
console.log(a instanceof Person) // true

知道了instanceof的用法之后手动实现instanceof

function instanceOf(instance, constructor) {
	let prototype = constructor.prototype
	while(true) {
		if (instance == null) {
			return false
		}
		if (instance.__proto__ == constructor.prototype) {
			return true
		}
		instance = instance.__proto__
	}
}
// 测试
function Person(name, age) {
    this.name = name;
    this.age = age;
}
let a = new Person('小明', 20);
console.log(instance_of(a, Person)) // true

防抖节流

防抖: 事件被调用后,在执行之前无论被调用多少次都会从头开始计时
节流: 不管事件被调用多少次,总是按照规定时间间隔执行

防抖
function debounce(fn, delay) {
	let timer = null;
	return (...args) => {
		clearTimeout(timer)
		timer = setTimeout(() => {
			fn.apply(this, args)
		}, delay)
	}
}
// 第二种
function debounce(fn, wait) {    
    var timeout = null;    
    return function() {        
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
节流

通过一个控制阀+定时器

function throttle(fn, delay) {
	let valid = true
	return function() {
		if(!vlaid) {
			return false
		}
		valid = false
		setTimeout(() => {
			fn()
			valid = true
		}, delay)
	}
}

call和apply和bind的区别

call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象
第二个参数是
call是按照顺序放进去
apply以数组的形式放进去
bind按照顺序放进去并且返回一个新的函数
call apply和bind每一个函数身上都会用这个方法,我们可以理解为是在Function的原型上面的方法

arguments
其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数都会有一个Arguments对象实例arguments,它引用着函数的实参,可以用数组下标的方式"[]"引用arguments的元素。arguments.length为函数实参个数,arguments.callee引用函数自身。
arguments他的特性和使用方法
特性:
1.arguments对象和Function是分不开的。
2.因为arguments这个对象不能显式创建。
3.arguments对象只有函数开始时才可用。
实现
Function.prototype.myCall = function(context) {
	// context存在取context不存在取window
	const cxt = context || window;
	// 现在cxt上面添加一个函数指向this
	cxt.func = this;
	// 拿到传递的参数列表
	const args = Array.from(arguments).slice(1)
	const res = arguments.length > 1 ? cxt.func(...args) : cxt.func()
	delete cxt.func;
	return res;
}
Function.prototype.myApply = function(context) {
    const cxt = context || window;
    cxt.func = this;
    const res = arguments[1] ? cxt.func(...arguments[1]) : cxt.func();
    delete cxt.func;
    return res;
}
Function.prototype.myBind = function(context) {
     const cxt = JSON.parse(JSON.stringify(context) || window);
     cxt.func = this;
     const args = Array.from(arguments).slice(1)
     return function() {
         const allArgs = args.concat(Array.from(arguments))
         return allArgs.length > 0 ? cxt.func(...allArgs) : cxt.func()
     }
 }

es5和es6继承

继承的区别:
在ES5中: 通过原型链实现继承,实质上是先创造子类的实例对象this,然后再将父类的方法添加到this上面,常见的继承方法是组合继承和寄生组合继承,
在ES6中,通过class进行继承,实质上是先将父类实例对象的属性和方法加到this上面,(所以必须先调用super),然后再用子类的构造函数修改this指向

function Human(name) {
	this.name = name;
}
Human.prototype.run = function() {
	console.log('走你')
}
function Man() {
	this.sex = '男'
}
Man.prototype.habit = function() {
	console.log('喜欢女人')
}
var object = new Man()
object // 

prototype
当前这个Man有性别,但是还没有名字,还没有一些行为,如何让他有行为,让Man继承Human的属性和方法,进一步的写就是

function Human(name) {
	this.name = name;
}
Human.prototype.run = function() {
	console.log('走你')
}
function Man(name) {
	this.sex = '男'
	// 我们希望这里面把Human自己的属性和方法加到Man上面
	// 并且让this指向Man的实例对象
	// 所以我们就需要在这里调用Human并且把Man里面的this传给他
	Human.call(this, name)
}
Man.prototype.habit = function() {
	console.log('喜欢女人')
}
var object = new Man()
object // 

es6继承

class Human{
    constructor(name){
        this.name = name
    }
    run(){
        console.log('走你')
    }
}
class Man extends Human{
    constructor(name){
        super(name)
        this.sex='男'
    }
    habit(){
        console.log('喜欢女人')
    }
}
es6类的写法: 自身的属性写在constructor里面,方法写在constructor同级,相当于写在prototype上面

Man extends Human == Man.prototype.proto = Human.prototype

标签:function,面试题,cxt,name,汇总,js,arguments,prototype,Man
来源: https://blog.csdn.net/qq_43586840/article/details/114764150