前端JS面试题

37 篇文章 0 订阅
6 篇文章 0 订阅

前端JS面试题

call 和 apply 的区别 是什么,哪一个性能更好一些?

  • 传参的区别
    • call 是一个个传递
    • apply是传递一个数组
    • bind 是预先处理,但是不会立即执行
    • 但是 call 在基于ES6的展开运算符也可以将数组中的每一项传递给函数
  • call apply 都是 Function 原型上面的方法,而每个函数作为 Function 的实例,可以调取其方法
  • 在参数过多的时候,call 的性能会好一些
  • console.time 可以测试一段程序执行的时间 console.timeEnd

实现 (5).add(3).minus(2) 使其输出结果为 6

假设 arr 是一个数组,它之所以可以调用 arr.push()这个方法式因为 它是Array的实例,可以继续调用Array原型上面的  push 方法
~function(){
//每一个方法执行完,都要返回Number这个类的实例,这样才可以继续调取Number类原型中的方法(链式写法)
	function check(n){
		n = Number(n)
	 	return  isNaN(n) ? 0 : n
	}
	
	function add(n){
		n = check(n)
		//this 不能赋值
		return  this + n
	}
	
	function minus(n){
		n = check(n)
		return this - n
	}
	
	['add','minus'].forEach(item=>{
		Number.prototype[item] = eval(item)
	})
}()
console.log((5).add(3).minus(2))

箭头函数与普通函数(function)的区别是什么?构造函数(function) 可以使用new 生成实例,那么箭头函数可以么?为什么

箭头函数与普通函数区别
  • 箭头函数语法上比普通函数更加简洁(ES6中每一种函数都可以使用形参默认值和剩余运算符)

  • 箭头函数中没有自己的this,他里面的this 从属于函数所处的上下文(使用call/apply等任何方式都无法改变this的指向)

    document.body.onclick = function(){
    	//this:boby
    	arr.sort(function(){
    		//this:window
    		/***********回调函数中的this一般都是window***************/
    		return a -b
    	})
    }
    /*回调函数:把一个函数b作为实参传递给另外一个函数A ,函数A在执行的时候,可以把传递进来的函数B去执行*/
    
  • 箭头函数没有arguments(类数组),只能基于…arg获取传递得参数集合(数组)

  • 箭头函数不能被 new 执行(因为:箭头函数没有this 也没有prototype)

如何把一个字符串中得大小写取反(大写变小写,小写变大写)l

let str = 'sdsdsdSDSAD哈哈哈sdjsHJJkj';
str = str.replace(/[a-zA-Z]/g,content=>{
    //俩种思路
    //先将其转换然后在比较 如果相同代表之前也为大写
    //2.根据AScLL值进行比较
    return content.toUpperCase() ===content ? content.toLowerCase : content.toUpperCase()
})
实现一个字符串匹配算法,从字符串 S 中,查找是否存在字符串 T ,若存在返回所在位置,不存在返回 -1! (如果不能基于 indexof / includes等内置得方法,你会怎么处理)
//使用正则
~function(){
	function myIndexof(T){
		let reg = new RegExp(T),
			res = reg.exec(this);
		return res===null?res=-1:res.index
	}
	String.prototype.myIndexof = myIndexof
}()

//常规解法
~function(){
	function myIndexof(T){
		let lenT = T.length,
			lenS = this.length,
			res = -1;
			if (lenT >lenS) return res;
		for (var i = 0; i <= lenS - lenT; i++) {
			if(this.substr(i,lenT)=== T){
				res = i
				break;
			}
		}
		return res
	}
	String.prototype.myIndexof = myIndexof
}()

输出下面代码运行结果

var a = {}, b = '123',c =123;
a[b] = 'b'
a[c] = 'c'
console.log(a[b])
a = {100 : '哈哈','100' :'嘻嘻'} //输出{100: "嘻嘻"}
//因为后面得会替换前面得  对象属性key 可以为字符串也可以数字 a['123'] <=>a[123]

var a = {}, b = Symbol('123'),c =Symbol(123);
a[b] = 'b'
a[c] = 'c'
console.log(a[b])
//Symbol 是ES6中新增得数据类型,  Symbol(123) === Symbol(123) false 它创建出来得值是唯一值

var a = {}, b = {key:'123'},c ={key:'456'};
a[b] = 'b'
a[c] = 'c'
console.log(a[b])
//({key:'123'}).toString()==>>>"[object Object]"\
//obj ={}  arr = [12,23] obj[arr] = 'xzt'  obj => {'12,23':'xzt'}

在输入框中如何判断输入的是一个正确的网址,例如:用户输入一个字符串,验证是否符合URL网址的格式

let str = 'http://www.baidu.com/index.html?lx=1&from=wx#video'
let reg = /^((http|https|ftp):\/\/)?(([\w-]+\.)+[a-z0-9]+)((\/[^/]*)+)?(\?[^#]+)?(#.+)?$/i
console.log(reg.exec(str))

判断输出题

function Foo(){
	Foo.a = function(){
		console.log(1)
	}
    this.a = function(){
		console.log(2)
	}
}
//把Foo当做类,在原型上设置实例共有的属性方法=》实例.a()
Foo.prototype.a = function(){//原型上面加属性和方法
    console.log(3)
}
//把Foo当做普通对象设置私有的属性方法 =》Foo.a()
Foo.a = function(){//在Foo上加了私有属性
    console.log(4)
}
Foo.a()//输出4
let obj = new Foo() //生成 Foo 实例 obj 可以调取原型上的方法  Foo.a : f=>1 obj.a:f=>2
obj.a()//输出2  私有属性中有a
Foo.a()//在私有属性上面找 所以输出1

编写代码实现图片懒加载

  • 前端性能优化的重要方案
    • 通过图片或者数据的延迟加载,我们可以加快页面渲染的速度,让第一次打开页面的速度变快
    • 只有滑动到某个区域,我们才加载真是的图片,这样也可以节省加载的流量
  • 处理方案
    • 把所有需要延迟加载的图片用一个盒子包起来,设置宽搞和默认站位图
    • 开始让所有的img src 为空,把真实图片的地址放到IMG的自定义属性上,让IMG隐藏
    • 等到所有其他资源都加载完成后,我们再开始加载图片
    • 对于很多图片,需要当页面滚动的时候,当前图片区域完全显示出来后再加载真实图片

实现一个$attr(name,value)遍历,属性为 name 值为 value 的元素集合

function $attr(props,value){
	let el = document.getElementsByTagName('*'),
		arr = []; 
	// [].forEach.call(el,item=>{})
	el = Array.from(el)//把非数组转换成数组
	el.forEach(item=>{
		//存储的是当前元素props 对应的属性值
		let itemVale = item.getAttribute(prop)
		if (prop === 'class') {
			//样式类属性名要特殊处理
			new RegExp("\\b" + value + "\\b").test(itemVale)?arr.push(item):null;
			return;
		}
		if (itemVale===value) {
			//获取的值 和传递的值校验成功:当前就是我们想要的
			arr.push(item)
		}
	})
	return arr
}

英文字母汉字组成的字符串,用正则给英文单词前后加空格

let reg = \\b[a-z]+\b\ig;
str = str.replace(reg,value=>{
	return " " + value + " "
}).trim()//首尾去除空格

编写一个程序,将数组扁平化,并去除其中重复部分数据,最终得到一个升序而且不重复的数组


自己实现new

function myNew(Fn,...arg){
	//创建一个空对象
	// let obj = {}
	// //让他的原型链之指向 Fn.prototype(作为Fn 的一个实例)
	// obj.__proto__ = Fn.prototype
	let obj = Object.create(Fn.prototype)
	//Object.create(AA对象):创建一个空对象,并且让空对象obj作为AA对象所属构造函数的实例
	//(obj.__proto__ = AA)
	Fn.call(obj,...arg)
	return obj
}

合并数组

let ary1 = ['A1','A2','B2','C1','C2','C3','D','D1']
let ary2 = [A','B2','C1]

let n= 0
for(var i = 0;i<ary2.length;i++){
	let item2 = ary2[i]
	for(var j=0;j<ary1.length;j++){
		let item1 = ary2[j]
		if(item1.includes(item2)){
			n = j
		}
	}
	ary1.splice(n+1,0,item2)
}

判断输出值

var b = 10;
(function b(){
	b= 20;
	console.log(b) //输出 b 这个函数
})()
console.log(b)//输出10

let fn = function AAA(){
	AAA = 100
	console.log(AAA)//当前函数
}
AAA()==》 报错

1、本应匿名的函数如果设置了函数名,在外面还是无法调用,但是在函数里面是可以使用的
2、而且类似于创建常亮一样,这个名字存储的值不能再被修改(非严格模式下不报错,但是不会有任何效果,严格模式下直接报错,我们可以把AAA理解为是用const 创建出来的)

赋值比较

  • == 进行比较的时候,如果俩边数据类型不一样,则先转换为相同的数据类型,然后在进行比较

    • {} == {} 俩个对象进行比较,比较的是堆内存的地址
    • null == undefined 相等 的 / null === undefined 不相等
    • NaN == NaN 不相等,NaN 和谁都不相等
    • [12] == ‘12’ 对象和字符串比较,是把对象 toString()转换为字符串后再进行比较的
    • 剩余所有情况在进行比较的时候,都是转换为数字(前提数据类型不一样)
      • 对象转数字:先转换为字符串,然后在转换为数字
      • 字符串转数字:只要出现一个非数字字符,结果就是NaN
      • 布尔转数字 :true => 1 false =>0
      • null 转数字 0
      • undefined 转数字 NaN
  • 实现 a1 && a2 && a==3

    if (a==1 && a==2 && a==3){
    	console.log('OK')
    }
    //方法一:
    var a = {
    	n = 0;
    	toString :function (){
    		return ++this.n;
    	}
    }
    
    //方法二:
    //shift :删除第一项,把删除的内容返回,原有数组改变
    let a = [1,2,3]
    a.toString = a.shift
    
    //方法三:
    letn = 0
    Object.definProperty(window,'a',{
    	get :function(){
    		return ++n
    	}
    })
    

判断输出

let obj = {
	2:3,
	3:4,
	length:2,
	push : Array.prototype.push
} 
obj.push(1)
//this : obj  obj[obj.length] = 1 ==> obj[2] = 1 ==> obj.length = 3
obj.push(2)
//this : obj  obj[obj.length] = 2 ==> obj[3] = 1 ==> obj.length = 4
console.log(obj)

Array.prototype.push = function AA(){
	this[this.length] = val
	//=>this.length 在原来的基础上加一
	return this.length
}

冒泡排序

let ary = [1,5,4,2,8,9]

let ary = [1,5,4,2,8,9]

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

插入排序

function insert(ary){
	let handel = []
	handel.push(ary[0])
	for (var i = 1; i < ary.length; i++) {
		let itemA = ary[i]
		for (var j=handel.length-1;j>=0; j--) {
			let itemB = handel[j]
			if (itemA>itemB) {
				handel.splice(j+1,0,itemA)
				break;
			}
			if (j===0) {
				handel.unshift(itemA)
			}
		}
	}
	
	return handel
}

函数柯理化:预先处理的思想(利用闭包的机制)

请实现一个add 函数,满足以下功能

add(1)
add(1)(2)
add(1)(2)(3)
add(1)(2)(3)(4)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值