写本文的目的是巩固一下前端的一些基础,互相交流一下,做一个综合的归纳
Javascript
面试Javascript方面的一些问题,或者介绍,持续更新
1.JS的数据类型
String
Number
Boolean
Undefined
BigInt
Symbol
null
Object
Function
2.作用域
ECMAScript 变量可以包含两种不同类型的数据:原始值和引用值。
原始值(primitive value)就是最简单的数据
引用值(reference value)则是由多个值构成的对象。在把一个值赋给变量时,JavaScript 引擎必须确定这个值是原始值还是引用值。引用值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用(reference)而非 实际的对象本身。为此,保存引用值的变量是按引用(by reference)访问的。
JavaScript采用的是词法作用域,函数的作用域基于函数创建的位置。
3.原型、原型链
关于原型链,我就不重复了,有很多总结的文章
Function.prototype.xxx
创建的function通过原型链,就能获取到原型上的方法
Object.prototype.xxx
创建的object通过原型链,就能获取到原型上的方法
xxx.__proto__ == Xxx.prototype
xxx.prototype.__proto__ == Object.prototype.xxx
4.变量声明和函数声明
函数提升优先级高于变量提升,当函数声明与变量名相同时,在变量赋值前,函数声明依旧是函数声明,不会被覆盖;当变量赋值后,函数声明被同变量覆盖。
1.第一个示例
console.log(typeof a);
a();
var a = 3;
function a() {
console.log(typeof a);
}
console.log(typeof a);
a = 6;
a();
答案
"function"
"function"
"number"
"a is not a function"
2.第二个示例
console.log(a);
console.log(typeof f);
var flag = true;
if (!flag) {
var a = 1;
};
if (flag) {
function f(a) {
f = a;
console.log("1");
};
}
console.log(typeof f);
"undefined"
"undefined"
"function"
在非严格模式下,代码块中,只有使用 var 声明的变量和函数声明是可以提升的,但是函数声明只能将函数的名字提升出去
3.第三个示例
function f() {
console.log(typeof f); //function
// var f = 3;
f = 3;
console.log(typeof f); //number
};
f();
var s = function s() {
console.log(typeof s); //function
// var s = 3;
s = 3;
console.log(typeof s); //function
};
s();
上述代码中,函数f是具名函数,函数s是函数表达式。具名函数中,可以在函数内部改变函数名,而函数表达式,如果有函数名,则它的函数名只能作用在其自身作用域中,且不可改变改变函数名。
以上的代码是copy自浅谈JS变量提升
5.Promise实现
9k字 | Promise/async/Generator实现原理解析
6.js - 设计模式
7.虚拟DOM
8.手写 call、apply、bind 原理基础版
1.call
Function.prototype.myCall = function (ctx, ...arg) {
ctx.fn = this
const result = ctx.fn(...arg)
delete ctx.fn
return result
}
var obj = {
a: 5,
b: 1
}
function abc(c, d) {
console.log(this.a - this.b - c - d)
return this.a - this.b - c - d
}
console.log('abc.myCall(obj, 1, 5)', abc.myCall(obj, 1, 5)) // - 2
2.apply
apply和call类似的,只不过传参不一样, apply这里自己初学js时留过一个坑,自己没看清api介绍,以为被apply后的函数,接受也必须是一个数组,后来意识到自己当时有多粗心
apply第二个参数可以为arguments
Function.prototype.myApply = function (ctx, arg) {
ctx.fn = this
const result = ctx.fn(...arg)
delete ctx.fn
return result
}
var obj = {
a: 5,
b: 1
}
function abc(c, d) {
console.log(this.a - this.b - c - d)
return this.a - this.b - c - d
}
console.log('abc.myApply(obj, 1, 5)', abc.myApply(obj, [1, 5])) // - 2
3.bind
bind和call接受参数是一样的,只不过会返回一个函数,通过返回函数执行call或者apply
Function.prototype.myBind = function (ctx, ...arg) {
const that = this
return function () {
// 结合上面的apply方法
return that.myApply(ctx, arg)
}
}
console.log('abc.myBind(obj, 1, 5)', abc.myBind(obj, 1, 5)()) // - 2
9. 手写简版 new
function myNew() {
var obj = new Object()
var Fn = [].shift.call(arguments);
obj._proto_ = Fn.prototype
var res = Fn.call(obj, arguments)
return typeof res === 'object' ? res : obj;//确保构造器总是返回一个对象
}
10.节流和防抖
1.防抖
function debounce(fb, wait) {
var timeout
return function () {
var that = this;
var args = arguments;
clearTimeout(timeout)
setTimeout(function () {
fb.apply(that, args)
}, wait)
}
}
2.节流
function throttle(fn) {
var timeout
return function () {
var that = this;
var args = arguments;
if (timeout) return
setTimeout(function () {
fn.apply(that, args)
timeout = null
}, wait)
}
}
function throttle(fn, wait) {
var previous = 0;
return function () {
var that = this;
var args = arguments;
var now = +new Date();
if (now - previous > wait) {
fn.apply(that, args)
previous = now
}
}
}
11.浅拷贝和深拷贝
浅拷贝和深拷贝主要是对引用的考察
1.浅拷贝
- Object.assign()
- Array.prototype.concat()
- ...展开弗
2.深拷贝
JSON.parse(JSON.stringify());
这个是最简单的,但是弊端
拷贝其他引用类型、拷贝函数、循环引用等一些缺陷
function deepClone(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
12.实现JSON.parse
function parse(jsonStr){
return eval("(" + jsonStr + ")");
}
13.数组排序、去重
1.排序
2.去重
1. [...new Set(arr)]
2. 类似indexof判断是否有,无就添加
14.数组扁平化
递归的方法
function flat(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
newArr = newArr.concat(flat(arr[i]))
}
else {
newArr.push(arr[i])
}
}
return newArr;
}
toString
toString().split(',')
es6
flat(Infinity)
15.instanceof的实现
function instance_of(L, R) {
let O = L.__proto__
const P = R.prototype
while (O) {
if (O === P) return true
O = O.__proto__
}
return false
}
16.JsonP的原理
17.事件机制/Event Loop
从event loop规范探究javaScript异步及浏览器更新渲染时机
后续再慢慢补充下