js
js中的数据类型
基本类型:number string boolean null undefined symbol bigint
引用数据类型:object (包含,Date,RegExp,Function,Array,Math..)
在 ES6 中新增的 Symbol 类型,代表创建后独一无二且不可变的数据类型,它的出现我认为主要是为了解决可能出现的全局变量冲突的问题。
两种类型的区别是: 存储位置不同
原始数据类型直接存储在栈(stack)中的简单数据段, 占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。
引用数据类型存储在堆(heap) 中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
作用域 变量提升
函数执行时的作用域
解构赋值
ES 6 语法知道哪些,分别怎么用?
ES6、ES7、ES8特性一锅炖(ES6、ES7、ES8学习指南)
class
- 在类中声明方法的时候,千万不要给该方法加上function关键字
- 方法之间不要用逗号分隔,否则会报错
- 类实质上就是一个函数。类自身指向的就是构造函数。所以可以认为ES6中的类其实就是构造函数的另外一种写法! console.log(Person===Person.prototype.constructor);//true
- 类的所有方法都定义在类的prototype属性上
- constructor方法是类的构造函数的默认方法,通过new命令生成对象实例时,自动调用该方法。
- constructor方法如果没有显式定义,会隐式生成一个constructor方法。所以即使你没有添加构造函数,构造函数也是存在的。
constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。 - constructor中定义的属性可以称为实例属性(即定义在this对象上),
constructor外声明的属性都是定义在原型上的,可以称为原型属性(即定义在class上)。
hasOwnProperty()函数用于判断属性是否是实例属性。其结果是一个布尔值, true说明是实例属性,false说明不是实例属性。
in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。 - 通过proto来为类增加方法。使用实例的proto属性改写原型,会改变Class的原始定义,影响到所有实例,所以不推荐使用!
- class不存在变量提升,所以需要先定义再使用。因为ES6不会把类的声明提升到代码头部,但是ES5就不一样,ES5存在变量提升,可以先使用,然后再定义。
箭头函数都有哪些特点?
-
箭头函数是
匿名函数
. -
不能作为
构造函数
,不能使用new
let foo=()=>{} var newFoo=new foo() //foo is not a construcotr
-
箭头函数没有
原型对象
-
不能使用argumetns,取而代之用rest参数...解决
let C = (...c) => { console.log(c); } C(1,2,3,3)
-
不绑定this
会捕获其定义时所在的this指向作为自己的this。由于在vue中自动绑定 this 上下文到实例中,因此不能使用箭头函数来定义一个周期方法。 箭头函数的this永远指向
上下文的this
,call、apply、bind也无法改变
babel ES6 转换 ES5 实现原理
如何判断变量的类型
Array.isArray
typeof
instanceof
constructor:此属性返回对创建此对象的数组函数的引用 console.log(arr.constructor === Array); //true Object.prototype.toSting
一般只有回答了Object.prototype.toSting这个答案,才算完事
this的指向有哪几种?分别说出来
改变this指向有哪几种方式?(call,apply,bind以及他们的区别)
闭包是什么?哪些地方用到了闭包?写出一个闭包
回答完闭包的概念,可以说防抖、节流就用到了闭包,
一般面试官会接着问你,可以把自己准备的防抖、节流说一下,有的让你手写实现
原型是什么? 原型链是什么?
原型是什么? 原型链是什么?
-
所有
引用类型
都有一个__proto__(隐式原型
)属性,属性值是一个普通的对象 -
所有
函数
都有一个prototype(原型)
属性,属性值是一个普通的对象 -
所有
引用类型的__proto__
属性指向它构造函数的prototype
var a = [1,2,3]; a.proto === Array.prototype; // true
原型链
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型
上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__
中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链
。
原型链最顶层Object的prototype的__proto__指向为null
什么是浅拷贝和深拷贝?
Event Loop 机制
很重要啊,必会啊!!!!!
promise 打印面试题
js异步发展史
围绕这几个描述: ajax、promise、generator、async await
async await 怎么用?实现原理是什么 ?
async await 如何捕获异常
回调函数的坏处
数组api背熟(哪几个可以改变原数组,每一个的返回值最好记住)
map forEach filter的区别(知道上面这个题,这个就没啥问题)
every some的区别(知道上上面这个题,这个就没啥问题)
reduce (好好看一下)
内存泄漏
setTimeout模拟setInterval
CommonJS、AMD、CMD和ES6模块化区别
js如何实现继承
创建对象的6种方式总结
js的设计模式
发布订阅
单例、工厂、构造函数、发布订阅
订阅发布、观察者,会的越多越好,回答这种题,最好往自己擅长的地方回答,被动变主动, 比如vue的双向数据绑定就是用的订阅发布,不要只干干的回答问题,要会拓展,会延伸
DOM事件流和事件委托
越来越火的网络请求Fetch和Axios到底有什么区别
ajax,axios,fetch的区别是什么?
axios是什么?axios如何实现原理?
axios 之cancelToken原理以及使用
图片懒加载
讲vue-lazyloader的原理,手写伪代码, 源码以及设计
函数式编程
用JavaScript的异步实现sleep函数
js 控制最大请求数(快手手写题目)
字节跳动面试官:请你实现一个大文件上传和断点续传
广度遍历 & 深度遍历
类型转换
symbol的作用
for in 和 for of的区别
相关文章: blog.csdn.net/margin_0px/…
- 优先迭代数字属性
- 会遍历所有私有的和公有的可枚举属性(性能最差的循环)
- 无法迭代symbol类型的私有属性(告别for in)
let keys = Object.getOwnPropertyNames(obj); keys = keys.concat(Object.getOwnPropertySymbols(obj)); keys.forEach(key =>{console.log(key)})
requestAnimationFrame的优势
相关文章:
手写题汇总
手写new, new操作符都做了些什么
手写 bind
//手写apply
Function.prototype.myApply = function (context, args) {
//这里默认不传就是给window,也可以用es6给参数设置默认参数
context = context || window
args = args ? args : []
//给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol()
context[key] = this
//通过隐式绑定的方式调用函数
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
//手写call
//传递参数从一个数组变成逐个传参了,不用...扩展运算符的也可以用arguments代替
Function.prototype.myCall = function (context, ...args) {
//这里默认不传就是给window,也可以用es6给参数设置默认参数
context = context || window
args = args ? args : []
//给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol()
context[key] = this
//通过隐式绑定的方式调用函数
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
Function.prototype.myBind = function (context, ...args) {
const fn = this
args = args ? args : []
return function newFn(...newFnArgs) {
return fn.apply(context, [...args,...newFnArgs])
}
}
手写promise
手写promise.all、 promise.race
考察promise.all, promise.race的最多,必须会
Promise.all = function(arr) {
let res = [];
return new Promise((resolve, reject) => {
for(let i=0; i< arr.length; i++) {
Promise.resolve(arr[i]).then(data => {
i++;
res[i] = data;
if(i === arr.length) {
return resolve(res);
}
}, err => {
return reject(err);
});
}
})
}
手写防抖、节流
手写防抖、节流(背下来,必会!!!)
手写ajax
手写深拷贝
function deepClone(targetObj) {
let type = Object.prototype.toString.call(targetObj);
let newObj;
if (type === "[object Object]") {
newObj = {};
} else if (type === "[object Array]") {
newObj = [];
} else {
return targetObj;
}
for(key in targetObj) {
let value = targetObj[key];
newObj[key] = deepClone(value);
}
return newObj;
}
// 用map处理循环引用的问题
function cloneDeep(obj, hash = new WeakMap()) {
if(Object.prototype.toString.call(obj) !== '[object Object]') return obj;
if(hash.get(obj)) return hash.get(obj);
let cloneObj = {};
hash.set(obj, cloneObj);
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
cloneObj[key] = cloneDeep(obj[key], hash);
}
}
return cloneObj;
}
let obj = { name: 1, address: { x: 100 } };
obj.o = obj; // 对象存在循环引用的情况
let d = cloneDeep(obj);
obj.address.x = 200;
console.log(d);
手写event bus
手写instanceof实现原理
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
function instance_of(L, R) {
var O = R.prototype;
L = L.__proto__;
while (true) {
if (L === null)
return false;
if (O === L)
return true;
L = L.__proto__;
}
}
代码解释:
①L表示对象实例,R表示构造函数或者父类型实例
②取R的显式原型,取L的隐式原型
③循环遍历,进行判断②中的两个值是否相等,相等返回true,不相等继续查找L的原型链
参考: zhuanlan.zhihu.com/p/105487552
手写axios
手写curry
function curry(fn) {
let judge = (...args) => {
if (args.length == fn.length) return fn(...args)
return (...arg) => judge(...args, ...arg)
}
return judge
}
function add(a, b, c) {
return a + b + c
}
add(1, 2, 3)
let addCurry = curry(add)
addCurry(1)(2)(3)
手动实现parseInt
手动实现一个find, findIndex
手写实现map
Array.prototype.copyMap = function (fn, toThis) {
let arr = this;
const result = [];
const redirectThis = toThis || Object.create(null);
for (let i = 0; i < arr.length; i++) {
const item = fn.call(redirectThis, arr[i], i, arr);
result.push(item);
}
return result;
}