在这里纪录著天天自身碰到的一道印象深入的前端题目,以及一道生涯中随处可见的小题目。
强制自身构成积聚的习气,鞭笞自身不停前行,配合进修。
2019/04/15 – 2019/04/21
1. 写一个乱序函数 ?
遍历数组元素,然后将当前元素与今后随机位置的元素举行交流。
function shuffle(a) {
for (let i = a.length; i; i--) {
let j = Math.floor(Math.random() * i);
// es6语法
[a[i - 1], a[j]] = [a[j], a[i - 1]];
}
return a;
}
2. 什么是惰性函数?
惰性函数就是返回一个重写函数。For example:
var foo = function() {
var t = new Date();
foo = function() {
return t;
};
return foo();
};
foo();
3. 静态作用域与动态作用域 ?
静态作用域 —— 函数的作用域基于函数建立的位置。
动态作用域 —— 函数的作用域基于函数的运用位置。
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar(); // 输出 1 。JavaScript 采纳的是词法作用域,也称为静态作用域。雷同的,动态作用域此代码应当输出 2
4. 手写一个 function call()函数 ?
Function.prototype.call2 = function(context, ...args) {
// 由于传进来的 context 有多是 null
context = context || window;
// Function.prototype this 为当前运转的函数
// 让 fn 的上下文为 context
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
};
5. Vue 组件中的 name 属性的作用 ?
组件在全局用 Vue.component()
注册时,全局 ID 自动作为组件的 name。
指定 name 选项的另一个优点是便于调试。有名字的组件有更友爱的正告信息。别的,当在有 vue-devtools,未命名组件将显现成 <AnonymousComponent>
,这很没有语义。经由历程供应 name 选项,可以取得更有语义信息的组件树。
6. Hash 路由和 History 路由的区分 ?
- hash 路由
hash 路由一个显著的标志是带有#,我们主假如经由历程监听 url 中的 hash 变化来举行路由跳转。(
window.addEventListener('hashchange', this.refresh, false);
)hash 的上风就是兼容性更好,在老版 IE 中都有运转,题目在于 url 中一向存在#不够雅观,而且 hash 路由更像是 Hack 而非规范,置信跟着生长越发规范化的 History API 会逐渐蚕食掉 hash 路由的市场。
history 路由
history 路由运用 History API 来完成,详细有:
window.history.back(); // 退却 window.history.forward(); // 行进 window.history.go(-3); // 退却三个页面
history.pushState
用于在阅读汗青中增添汗青纪录,history.replaceState
要领的参数与pushState
要领如出一辙,区分是它修正阅读汗青中当前记载,而非增添纪录,一样不触发跳转。
7. Vue 的相应式道理中 Object.defineProperty
有什么缺点?为何在 Vue3.0 采纳了 Proxy
,扬弃了 Object.defineProperty
?
- Object.defineProperty 没法监控到数组下标的变化,致使经由历程数组下标增添元素,不能及时相应;
- Object.defineProperty 只能挟制对象的属性,从而需要对每一个对象,每一个属性举行遍历,假如,属性值是对象,还需要深度遍历。Proxy 可以挟制全部对象,并返回一个新的对象。
- Proxy 不仅可以代办对象,还可以代办数组。还可以代办动态增添的属性。
2019/04/08 – 2019/04/14
4. 写一个“最终范例”推断函数?
function type(obj) {
var toString = Object.prototype.toString;
var toType = {};
var typeArr = [
"Undefined",
"Null",
"Boolean",
"Number",
"String",
"Object",
"Array",
"Function",
"Date",
"RegExp",
"Error",
"Arguments"
];
// 这里利用了object 对象toString() 后 值为 '[object Array]' 等状况举行推断
typeArr.map(function(item, index) {
toType["[object " + item + "]"] = item.toLowerCase();
});
return typeof obj !== "object" ? typeof obj : toType[toString.call(obj)];
}
2. 写一个函数,推断各种范例的差别变量是不是相称,即“最终即是”函数?
const equals = (a, b) => {
if (a === b) return true;
// 时刻的推断
if (a instanceof Date && b instanceof Date)
return a.getTime() === b.getTime();
// 非 object 范例的推断
if (!a || !b || (typeof a !== "object" && typeof b !== "object"))
return a === b;
if (a.prototype !== b.prototype) return false;
if (Array.isArray(a) && Array.isArray(b)) a.sort(), b.sort();
let keys = Object.keys(a);
if (keys.length !== Object.keys(b).length) return false;
return keys.every(k => equals(a[k], b[k]));
};
3. mouseover 和 mouseenter 的区分 ?
mouseover:当鼠标移入元素或其子元素都邑触发事宜,所以有一个反复触发,冒泡的历程。对应的移除事宜是 mouseout
mouseenter:当鼠标移除元素自身(不包括元素的子元素)会触发事宜,也就是不会冒泡,对应的移除事宜是 mouseleave
4. 一句话描述闭包?
闭包就是可以读取其他函数内部变量的函数,或许子函数在外挪用,子函数地点的父函数的作用域不会被开释。
一个闭包小栗子:
function f1(){
n = 999;
function f2(){
console.log(n);
}
return f2;
}
var result = f1(); //返回的是f2函数
result(); //999,读取内部变量
5. js 的 new 操作符做了哪些事变 ?
new 操作符新建了一个空对象,这个对象原型指向组织函数的 prototype,实行组织函数后返回这个对象。
6. 完成一个深拷贝 ?
//所谓深度克隆,就是当对象的某个属性值为object或array的时刻,要取得一份copy,而不是直接拿到援用值
function deepClone1(origin, target) {
//origin是被克隆对象,target是我们取得copy
var target = target || {}; //定义target
for (var key in origin) {
//遍历原对象
if (origin.hasOwnProperty(key)) {
if (Array.isArray(origin[key])) {
//假如是数组
target[key] = [];
deepClone1(origin[key], target[key]); //递归
} else if (typeof origin[key] === "object" && origin[key] !== null) {
target[key] = {};
deepClone1(origin[key], target[key]); //递归
} else {
target[key] = origin[key];
}
}
}
return target;
}
// 第二个function
function deepClone2(data) {
if (!data || !(data instanceof Object) || typeof data === "function") {
return data;
}
var constructor = data.constructor;
var result = new constructor();
for (var key in data) {
if (data.hasOwnProperty(key)) {
result[key] = deepClone2(data[key]);
}
}
return result;
}
// 第三个fuction
function deepClone3(origin, target) {
var target = target || {},
toStr = Object.prototype.toString;
for (var prop in origin) {
if (origin.hasOwnProperty(prop)) {
//不能把原型链上的一同拷贝了
//推断是元素范例照样援用范例
if (typeof origin[prop] == "object" && typeof origin[prop] !== "null") {
target[prop] = toStr.call(prop) == "[object Array]" ? [] : {};
arguments.callee(origin[prop], target[prop]); //递归挪用
} else {
target[prop] = origin[prop]; //原始范例直接复制
}
}
}
return target;
}
// 第四个function
function deepClone4(obj) {
//推断是不是是简朴数据范例,
if (typeof obj == "object") {
//庞杂数据范例
var result = obj.constructor == Array ? [] : {};
for (let i in obj) {
result[i] =
typeof obj[i] == "object" && obj[i] !== null
? deepClone4(obj[i])
: obj[i];
}
} else {
//简朴数据范例 直接 == 赋值
var result = obj;
}
return result;
}
引荐运用 deepClone2()
7. 函数的防抖与撙节 ?
防抖
所谓防抖,就是指触发事宜后在 n 秒内函数只能实行一次,假如在 n 秒内又触发了事宜,则会从新盘算函数实行时刻。(防误触)
// 延缓实行
function debounce(func, wait) {
var timeout;
return function() {
var context = this;
var args = arguments;
console.log(args);
console.log(func);
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
// 马上实行
function debounce(func, wait) {
var timeout;
return function() {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
var callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) func.apply(context, args);
};
}
撙节
所谓撙节,就是指一连触发事宜但是在 n 秒中只实行一次函数。(限定流量)
// 时刻戳
function throttle(func, wait) {
var previous = 0;
return function() {
var now = Date.now();
var context = this;
var args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
};
}
// 定时器
function throttle(func, wait) {
var timeout;
return function() {
var context = this;
var args = arguments;
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
func.apply(context, args);
}, wait);
}
};
}