1. 手写instanceof
出题目的
- 考察原型链的理解
知识点
instanceof
- instanceof运算符用于检测结构函数的prototype属性是否出现在某个实例对象的原型链上
- 可以判断继承关系,只要是在同一条原型链上,就可以返回true
演示代码
class Person {
constructor(name){
this.name = name;
}
}
class Student extends Person {
constructor(name,age){
super(name);
this.age =age;
}
}
const zhangsan = new Student;
console.log(myInstance(zhangsan,Student));
console.log(myInstance(zhangsan,Person));
console.log(myInstance(zhangsan,Object));
console.log(myInstance(zhangsan,Array));
function myInstance(obj1,obj2){
let objPrototype = obj1.__proto__
while(true){
if(objPrototype == null){
return false;
}
if(objPrototype === obj2.prototype) {
return true;
}
objPrototype = objPrototype.__proto__
}
}
2. this不同场景,如何取值?
this易混场景
- 普通函数下的this
- call apply bind的this
- 定时器中的this
- 箭头函数中的this
演示代码
//1.普通函数下的this
// 严格模式:this——>undefined
"use strict"
// 普通模式:this——>window
function a(){
console.log(this);
}
a()
//2.call apply bind的this
function a(){
console.log(this);
}
// 情况1:什么都不传,this——>window
// call
// a.call()
// a.call(undefined)
// a.call(null)
// 情况2:传什么,this就是什么
// apply
// a.apply(123)
// a.apply(undefined)
// a.apply(null)
// bind:bind需要一个函数接收
const fn = a.bind({x:1902})
fn()
/*
3.定时器中的this
情况一:定时器+funtion this——>window
情况二:定时器+箭头函数 this——>上层作用域的this
*/
//情况一:this——>window
/*例一
setTimeout(function () {
console.log(this);
}, 100);
*/
/*例二
function fn() {
setTimeout(function () {
console.log(this);
}, 100);
}
fn.call({x:100});
*/
/*例三
const a = {
fn(){
setTimeout(function(){
console.log(this);
},100);
}
}
a.fn();
*/
// 情况二
/* 例一
class Obj{
fn(){
setTimeout(() => {
console.log(this);
}, 100);
}
}
const o = new Obj()
o.fn()
*/
/*例二
function fn(){
setTimeout(() => {
console.log(this);
}, 100);
}
fn.call({x:100})
*/
HTML部分
<button id="btn">
test
</button>
JS部分
/*
4.箭头函数中的 this
情况1:有function作用域的,this是上层作用域的this
情况2:没有function作用域的,this是window
*/
/*
class Obj{
say=()=>{
console.log(this); // this——> Obj{say:f}
}
}
const obj1 = new Obj;
obj1.say();
const obj2 ={
say:()=>{
console.log(this);// this ——>window
}
}
obj2.say()
*/
const oBtn = document.getElementById("btn");
// oBtn.onclick = function(){
// console.log(this);
// }
oBtn.onclick = ()=>{
console.log(this);
}
3. 手写bind函数
知识点
- Function.prototype.myBind
- Array.prototype.clice.call()
- array.shift()
演示代码
function fn(a, b, c, d) {
console.log(this);
console.log(a, b, c, d);
return "this is return"
}
// bind会返回一个函数要用一个变量接收bind返回到函数
// const dp = fn.bind({x:23},1,2,3,4);
// console.log(dp()) ;
//手写bind
Function.prototype.myBind = function () {
const fn = this;
// arguments是一个类数组:[{ x: 10 }, 1, 2, 3]
// const _this = arguments[0];
// 将arguments变成数组,用一个变量接收数组[1, 2, 3, 5, 6]
const arr = Array.prototype.slice.call(arguments);
// 用shift方法获取[{ x: 140 },1, 2, 3, 5, 6]中的{ x: 140 }
const _this = arr.shift();
return function(){
return fn.apply(_this, arr)
}
}
const dp = fn.myBind({ x: 23 }, 1, 2, 3, 4);
console.log(dp());
4. 谈谈闭包和闭包使用场景
什么是闭包
概念:闭包是作用域的一种特殊应用
触发闭包的情况
- 函数当作返回值被返回
- 函数当作参数被传递
- 自执行匿名函数
必报的应用
- 隐藏变量
- 解决for in的问题
作用域
全局作用域、局部作用域
自由变量
不在自己作用域里的变量,就是自由变量 自由变量的值:在函数定义的地方向上层作用域查找。与函数调用位置无关
演示代码
//情况一:函数当作返回值被返回
// function fn(){
// const a = 1;
// return function(){
// console.log(a); // 1
// }
// }
// const a = 5;
// const cb = fn();
// cb()
// 情况二:函数当作参数传覅
function fn(cb){
const a = 100
cb()
}
const a = 500;
fn(function(){
console.log(a); // 500
});
//情况三:自执行匿名函数
(function(index){
console.log(index); // 10
})(10)
HTML部分
<button>0</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
JS部分
const btn = document.querySelectorAll("button");
// 方法一
// for(var i = 0;i<btn.length;i++){
// (function(index){
// btn[i].onclick = function(){
// console.log(index);
// }
// })(i)
// }
// 方法二
for(let i = 0;i<btn.length;i++){
btn[i].onclick = function(){
console.log(i);
}
}
//隐藏变量
function fn(){
const data = {};
return {
set : function(key,val){
data[key] = val;
},
get : function(val){
return data[val]
},
};
}
const json = fn();
json.set("age",18);
console.log(json.get("age"));
5. 请描述event loop的机制
JavaScript是如何执行的?
- 自上而下,从左到右一行一行执行
- 如果有一行报错,后面的代码不执行
- 先执行同步代码,再执行异步代码(setTimeout、Ajax)
Event Loop过程
- 同步代码,一行一行放在Call Stack中执行
- 遇到异步,会先“记录”下代码,等待执行时机(setTimeout、Ajax)。时机到了,将之前“记录”的代码放入Callback Queue
- 当Call Stack为空(同步代码执行完),EventLoop开始工作
- EventLoop轮询查找Callback Queue中是否可执行的代码。如果有,将代码移动到Call Stack中执行
- Event Loop如果没有找到可以执行的代码,则会继续轮询查找
演示代码
console.log("start");
setTimeout(()=>{
console.log("setTimeout");
},2000);
console.log("end");
//输出结果:start,emd,setTimeout