2js考点和面试题
做题的本质:
拿到面试题,第一反应考点(知识点)是什么,而不是题目本身.所以先到知识点再到题目
考点1:js基本数据类型
typeof
可以识别所有的基本数据类型
可以识别函数类型。
不可识别具体的引用类型
总结:除了Functon外的构造函数的new 出来的实例类型都是'object'。面试时候出了typeof function基本就是function
typeof null==='object'// JavaScript 诞生以来便如此 null是空指针对象
console.log(typeof 1); //'number' console.log(typeof 'a'); //'string' console.log(typeof true); //'boolean' console.log(typeof undefined); //'undefined' console.log(typeof { a: 12 }); //'object' console.log(typeof null); //'object'
console.log(typeof [1, 2]); //'object'
console.log(typeof new Date()); //'object'
console.log(typeof function () {}); //'function'
console.log(typeof Math.max); //'function' //除Function外所有构造函数的类型都是'object'
console.log(typeof new String('abc'));
console.log(typeof new Number(123));
console.log(typeof new Function()); //‘function’
null undefined
null表示没有对象,即表示该处不应该有值
用于对象原型链的终点
undefined 表示该处缺少一个值,只不过尚未定义
变量初始化但未赋值,默认值是undefined;函数参数默认undefined;函数默认返回时是undefined;对象不存在的属性,该属性值是undefined
==&===
深拷贝
function deepClone(obj) { // 如果不是引用类型(默认就是一些基本数据类型和函数类型和undefined)直接返回 if (typeof obj !== 'object' || obj === null) { return obj; } let result if (obj instanceof Array) { result = [] } else { result = {} } // for-in循环 array 和object都可以使用 便利key for (let key in obj) { if (!obj.hasOwnProperty(key)) continue // 递归拷贝 result[key] = deepClone(obj[key]); } return result }
两个对象的深度合并:如果属性值冲突,以后面一个合并对象为主
// js 两个对象的深度合并 并且以后面一个为主 function mergeObject(obj1, obj2) { const resObj = { ...obj1, ...obj2 } // 首先把所有的key收集起来 for (const key in resObj) { // 分三种情况 // obj2有的 obj1没有的 那么就直接那obj2 if (obj2.hasOwnProperty(key) && (!obj1.hasOwnProperty(key))) { resObj[key] = obj2[key] } // obj2没有的 obj1有的 直接拿 obj1 else if ((!obj2.hasOwnProperty(key)) && obj1.hasOwnProperty(key)) { resObj[key] = obj1[key] } // obj1和obj2公共的 那么就拿obj2的 如果公共值是对象 需要递归取值 else { if (typeof resObj[key] === 'object') { resObj[key] = mergeObject(obj1[key], obj2[key]) } else { resObj[key] = obj2[key] } } } return resObj } const obj1 = { direction: "horizontal", // 水平切换选项 observer: true, // 修改swiper自己或子元素时,自动初始化swiper observeParents: true, // 修改swiper的父元素时,自动初始化swiper speed: 2000, // 滑动速度 默认300 loop: true, // 循环轮播 autoplay: { // 自动轮播 这个值和loop:true 强烈建议成对出现 delay: 3000, // 3秒切换一次, disableOnInteraction: true }, pagination: { el: '.swiper-pagination', clickable: true } } const obj2 = { speed: 1000, // 滑动速度 默认300 loop: true, // 循环轮播 bbb: 400, autoplay: { delay: 5000 }, pagination: { el: '.swiper-pagination', aaa: 100 } } const resObj = mergeObject(obj1, obj2) console.log(resObj);
考点2:原型和原型链
每个实例对象默认都有__proto__隐式属性,每个类默认自带prototype显示属性。实例.__proto__===类.prototype。上图中Student.prototype本身也是一个对象
手写instanceof
object instanceof constructor
console.log(s instanceof Student);//true
function instance_of(leftObject, rightConstructor) { let rightProto = rightConstructor.prototype let leftValue = leftObject.__proto__ while (true) { if (leftValue === null) return false if (leftValue === rightProto) return true leftValue = leftValue.__proto__ } }
手写 call apply bind
将函数设为对象属性值,执行对象的函数方法,删除该对象的函数属性和属性值(函数)
// call bind apply 作用手动指定函数中的上下文this fn.call(context) 此时 fn函数中的this===context const obj = { name: 'zs', age: 12, gender: 'male', } function fn(a, b) { console.log(this); console.log(a, b); } Function.prototype.call1 = function (context, ...rest) { // call函数中的this是fn context = Object(context) || window context.fn = this context.fn(...rest) //这句话是本质 delete context.fn } fn.call1(obj, 1, 2) Function.prototype.bind1 = function (context, ...rest) { context = Object(context) || window context.fn = this return () => { context.fn(...rest) } } const fn2 = fn.bind1(obj, 1, 2) fn2() function fn1(arr) { console.log(arr); } Function.prototype.apply1 = function (context, arr) { context = Object(context) || window context.fn = this context.fn(arr) }
手写 new
创建一个空对象,这个空对象的__proto__指向构造函数的prototype 这样保证构造出来实例对象可以访问构造函数原型上实例方法 Object.create
执行构造函数,给空对象赋属性值 call|apply,这个时候空对象里面就有属性和属性值。
返回这个空对象。
// Object.create(obj)方法创建一个新空对象{},使用现有的对象obj来提供新创建的对象的__proto__。 // 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象 // 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象 // 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象 function _new(Constructor, ...args) { const obj = Object.create(Constructor.prototype) const res = Constructor.call(obj, ...args) //给空对象赋属性值 return res instanceof Object ? res : obj } const p = _new(Person, 'zs', 10)
手写Object.create
function create(obj) { function Fn() {} Fn.prototype = obj return new Fn() }
考点3:js作用域和闭包
es6转es5
https://www.jianshu.com/p/8a8f7b0f887a
闭包的形式
手写防抖和节流
// 防抖函数 function debounce(fn, delay) { let timer = null //闭包 return function () { timer && clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, arguments) //频繁操作之后最后一次执行代码 注意:箭头函数里面没有this arguments参数。 timer = null }, delay) } }
例子
输入框防抖
const input = document.querySelector('input'); function fn(e) { const value = e.target.value console.log(value); } // 防抖函数 function debounce(fn, delay) { let timer = null //闭包 return function () { timer && clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, arguments) //频繁操作之后最后一次执行代码 timer = null }, delay) } } fn = debounce(fn, 500) input.addEventListener('input', fn, false);