JavaScript - 面试题

一. 普通函数和箭头函数的区别

1. 箭头函数没有 functioin 关键字
2. 箭头函数作为匿名函数,是不能作为构造函数的,不能使用new操作符进行实例
3. 箭头函数不能绑定arguments,取而代之的是rest,例如:
	es5:
		function a() {
			console.log(arguments)
		}
		a(1,2,3,4)
	es6:
		let a = (...b) => {
		    console.log(b)
		}
		a(1,2,3,4)
4. 普通函数的this指向调用它的那个对象
	var length = 10
	function fn() {
	    console.log(this.length)
	}
	var t = {
	    length: 5,
	    methid: function(fn) {
	        fn() // 此时调用,方法内部this指向的是window,所以第一次打印的是10
	        arguments[0]() // 此时调用,方法内部this指向的是arguments对象,所以打印的是arguments的长度
	    }
	}
	t.methid(fn, 1) // 结果是0和1
6. 箭头函数没有原型属性
7. 箭头函数的 this 永远指向其上下文的  this ,任何方法都改变不了其指向,如 call() ,  bind() ,  apply() 
	

二.经典this面试题

var x = 3;
var y = 4;
var obj = {
    x: 1,
    y: 6,
    getX: function() {
        var x =5;
        return function() {
            return this.x;
        }();
    },
    getY: function() {
        var y =7;
         return this.y;
    }
}
console.log(obj.getX())
console.log(obj.getY())
var name="the window";

 var object={
    name:"My Object", 
    getName:function(){ 
       return this.name;
   } 
 }
object.getName(); 
(object.getName)();
(object.getName=object.getName)();   //"the window",函数赋值会改变内部this的指向,这也是为什么需要在 React 类组件中为事件处理程序绑定this的原因;


var a=10; 
 var obt={ 
   a:20, 
   fn:function(){ 
     var a=30; 
     console.log(this.a)
   } 
 }
 obt.fn(); 
 obt.fn.call(); 
 (obt.fn)();
 (obt.fn,obt.fn)(); // 和赋值操作差不多,this不能维持,所以返回全局作用域的a
 new obt.fn();
 function a(xx){
    this.x = xx;
    return this
  };
  var x = a(5);
  var y = a(6);
  
  console.log(x.x) 
  console.log(y.x)

三. apply、call、bind

1.共同点:
		1-1: call 、apply 和bind都是为了改变函数体内部 this 的指向
2.区别:接受参数的方式不太一样
		2-1:func.call(this, arg1, arg2); func.bind(this, arg1, arg2);
		2-2:func.apply(this, [arg1, arg2])
		2-3:bind返回的是函数,call和apply会立即执行
3. 实例
		3-1:数组追加
				var array1 = [12 , "foo" , {name:"Joe"} , -2458]; 
				var array2 = ["Doe" , 555 , 100]; 
				Array.prototype.push.apply(array1, array2); 
				console.log(array1)
		3-2:获取数组中的最大值和最小值
				var  numbers = [5, 458 , 120 , -215 ];
				var maxNum = Math.max.apply(Math, numbers)
				var minNum = Math.min.apply(Math, numbers)
		3-3:验证是否是数组(前提是toString()方法没有被重写过)
				var obj = [1,2,3,4]
				Object.prototype.toString.call(obj)
		3-4:类(伪)数组使用数组方法
				Array.prototype.slice.call(document.getlementByTagName('div'))
4.面试题
		4-1:定义一个 log 方法,让它可以代理 console.log 方法
				function log() {
						console.log.apply(console, arguments)
				}
		4-2:接下来的要求是给每一个 log 消息添加一个"(app)"的前辍,比如:
				function log() {
					var args = Array.prototype.slice.call(arguments)
					args.unshift('1------>')
					console.log.appyl(console, args)

bind

var altwrite = document.write;
altwrite("hello"); // 会报错,因为altwrite() 改变了this指向,指给了window
修改如下:
	altwrite.bind(document)('hello')  // 利用bind改变this指向到docment
	或者
	altwrite.call(document, 'hello')
题目:
	this.num = 9; 
	var mymodule = {
	  num: 81,
	  getNum: function() { 
	    console.log(this.num);
	  }
	};
	mymodule.getNum(); // 81
	var getNum = mymodule.getNum;
	getNum(); // 9, 因为在这个例子中,"this"指向全局对象
	var boundGetNum = getNum.bind(mymodule);
	boundGetNum(); // 81

四.高阶函数

1.概念:英文叫Higher-order function。JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
2.例如map、reduce、filter
	2-1:map()作为高阶函数,事实上它把运算规则抽象了
			var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 
		 	arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
	2-2:reduce
			var arr = [1, 3, 5, 7, 9];
			arr.reduce(function (x, y) {
			    return x + y;
			});
	2-3:filter
			var arr = [1, 2, 4, 5, 6, 9, 10, 15];
			var r = arr.filter(function (x) {
			    return x % 2 !== 0;
			});

五.变量提升

1. 函数提升在变量提升上面
		console.log(fn)
		var fn = 10
		console.log(fn)
		function fn() {
			console.log(10)
		}
		console.log(fn)
		依次输出结果是:
		function() {console.log(10)}  ----  10 ----  10

六. 同步任务和异步任务的优先顺序

1. js在一个时间只能干一件事 -- 单线程
2. js遇见异步任务先放入异步队列中,等同步任务执行完成再去执行异步任务

七. 异步任务的放入时间和执行时间

	for (var i = 0; i < 3; i++) {
        setTimeout(function() {
            console.log(i)  //  3 3 3
        },10)
    }
	1. 输出四个3的理由
    	1-1:js 执行的时候会先执行同步任务,setTimeout是异步任务
    	1-2:根据js运行机制,setTimeout 10毫秒之后会放到异步任务中
    	1-3:10毫秒for早就执行完了,最终的i已经是3了
   	2. 作用域解决 var 改为 let
   		2-1:let为块级作用域, 变量 i 只存活到每次for循环大括号结束,var的i是不收for循环限制的
	3.  闭包解决
		3-1:这个是通过自执行函数返回一个函数,然后在调用返回的函数去获取自执行函数内部的变量,此为闭包
		3-2:闭包会导致内存占用过高,因为变量都没有释放内存
			for (var i = 0; i < 4; i++) {
			  setTimeout(
			    (function(i) {
			      return function() {
			        console.log(i);
			      };
			    })(i),
			    300
			  );
			}

八.promise 的发展史

1. jq-deferred 
		1-1:在1.5版本之前的ajax,所有的成功都在success方法里面
		1-2:在1.5版本之后的ajax,就可以存在多个.done  .file 在到后来的.then就和promise非常像了

九. 堆和栈的区别

1. 栈:
	1-1:栈内存一般储存基础数据类型;按值访问;存储的值大小固定;由系统自动分配内存空间;空间小,运行效率高;先进后出,后进先出;栈中的DOM,ajax,setTimeout会依次进入到队列中,当栈中代码执行完毕后,再将队列中的事件放到执行栈中依次执行。
2. 堆:
	2-1:堆内存一般储存引用数据类型;按引用访问;存储的值大小不定,可动态调整;主要用来存放对象;空间大,但是运行效率相对较低
例如:
var a1 = 0;   // 栈 
var a2 = 'this is string'; // 栈
var a3 = null; // 栈

var b = { m: 20 }; // 变量b存在于栈中,{m: 20} 作为对象存在于堆内存中
var c = [1, 2, 3]; // 变量c存在于栈中,[1, 2, 3] 作为对象存在于堆内存中

[图解](https://juejin.im/post/5b1deac06fb9a01e643e2a95)

十. es6笔试题

var obj = [
    { id:3, parent:2 },
    { id:1, parent:null },
    { id:2, parent:1 },
 ]
 转换为: 
 var obj = {
     id: 1,
        parent: null,
        child: {
            id: 2,
            parent: 1,
            child: {
                id: 3,
                parent: 2
            }
        }
    }
前者转换后者
	var newarr = obj.sort((a, b) => b.parent - a.parent).reduce((acc, cur) => {
		return acc ? { ...cur, child: acc } : cur
	}, {})
后者转前者
	fn(o) {
       const { child, ...other } = o
       return child ? [other, ...this.fn(child)] : [other]
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值