1. js实现防抖,节流简单代码
防抖就是在动作停止以后一段时间内再触发,节流就是一段时间内只能触发一次。
防抖
function debounce(callback, time) {
let timer=null;
return function(){
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(callback,time);
}
}
节流
function throttle(name,time) {
return new Promise((resolve,reject)=>{
if(this[name]) {
return false;
}
this[name] = true;
setTimeout(()=>{
this[name] = false;
console.log('点击成功')
},time);
resolve(this[name]);
})
}
3. 实现对象的拷贝
Object.assign可以实现对象的拷贝,现在我们来手动实现以下:Object.keys不会遍历原型链身上的属性,所以下面使用Object.keys(src[i])
Object.myassign = function(target, ...src) {
let length = src.length;
for (let i = 0; i < length; i++) {
if (src[i] !== null && src[i] !== undefined) {
for (let key of Object.keys(src[i])) {
target[key] = src[i][key];
}
}
}
return target;
}
4.对url地址'?username=xll&age=23&grades=90' 进行解析
使用URLSearchParams构造函数
let str = '?username=xll&age=23&grades=90';
let searchParams = new URLSearchParams(str);
let res = [];
for (let item of searchParams) {
res[item[0]] = item[1];
}
searchParams.set('page', 2);
console.log(searchParams.toString());//username=xll&age=23&grades=90&page=2
console.log(res);//[ username: 'xll', age: '23', grades: '90' ]
使用split+map
let str = '?username=xll&age=23&grades=90';
//通过location.search可以得到上面的字符串str
str = str.slice(1);
let res = [];
// console.log(str);
for (let item of str.split('&').map(x => x.split('='))) {
//[[username=xll],[age=23],[grades=90]]
//map之后得到[[username,xll],[age,23],[grades,90]] item循坏这个数组
res[item[0]] = item[1];
}
console.log(res);
5. 拍平数组
使用递归去判断数组里面是否有数组;使用函数收集参数的方式...arr可以实现多个数组连接
let arr = [1, 2, [2, [3, 4, [5, 6, [7]]]]];
const concatArray = function(...arr) {
let newArray = [];
const concatarray = function(arr) {
arr.forEach((item, index, array) => {
if (!Array.isArray(item)) {
newArray.push(item);
} else {
return arguments.callee(item);
}
});
}
concatarray(arr);
return newArray;
}
console.log(concatArray(arr, [8, 9])); //[1,2,2,3,4,5,6,7]
6. CORS跨域资源共享字段
Access-Control-Allow-Origin:'*'
Access-Control-Allow-Methods:POST ,GET
Access-Control-Allow-Headers:
Access-Control-Allow-Credential:true
CORS中的预检请求 使用options方法发送并包含以下头部
Origin:
Access-Control-Request-Method:POST
Access-Control-Request-Headers:
简单请求非简单请求
7. JS数据类型以及栈、堆
JS是动态语言,JS变量没有数据类型是值有数据类型,JS数据类型Boolean、Undefined、Null、Number、String、Symbol、Object,JS内存空间分为栈空间和堆空间、代码空间。栈是线性结构,在内存中是一片连续的存储空间,先进后出,堆的数据结构是一种树状结构,存储数据的方式是只要知道地址就可以得到值,然后这个地址又存放在变量中,变量存放在栈中,就这样通过变量引用来使用这个引用数据类型。基本数据类型存放在栈中,大小固定通过按值访问,使用频繁,所以放在栈中。而引用类型大小不固定,但内存的地址大小固定,所以可以把地址保存在变量中变量放到栈中保存,来通过地址访问堆内的数据,提高效率。参考
8. 创建对象的几种方式?
1. 工厂模式创建对象
function Person(name, age, job) {
let o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
console.log(this.name);
}
return o;
}
const person1 = new Person('xll', 23, 'student')
console.log(person1); //{ name: 'xll', age: 23, job: 'student', sayName: [Function] }
2. 构造函数模式
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
console.log(this.name);
}
}
const person1 = new Person('xll', 23, 'student')
console.log(person1);//Person { name: 'xll', age: 23, job: 'student', sayName: [Function] }
构造函数相比于共厂函数:没有显示的创建对象,属性和方法赋值给了this,没有return ;如果不适用new 关键字就会被当作普通函数使用,而class类没有使用关键字new就会报错;
new的过程:1)在内存中创建一个新的对象;2)新对象的__proto__指向构造函数的prototype;3)构造函数内部 的this被赋值这个新对象;4)执行构造函数内部代码,给新对象属性赋值,如果构造函数返回非空对象那就返回该对象,否则返回新创建的对象; 3. 原型模式
function Person() {}
Person.prototype.name = 'xll';
Person.prototype.age = 23;
Person.prototype.job = 'student';
Person.prototype.sayName = function() {
console.log(this.name);
}
const person1 = new Person();
9. 怎么判断属性是在实例上还是原型上
hasPrototypeProperty判断属性是否在实例上面,in对象原型,实例上的属性都会被遍历到;
function hasPrototypeProperty(object, name) {
return !object.hasOwnProperty(name) && (name in Object)
}
10. 继承方式有哪几种?
1.组合继承=原型+盗用构造函数
function Father(name) {
this.name = name;
this.colors = ['pink', 'red', 'blue'];
}
Father.prototype.sayName = function() {
console.log(this.name);
}
function Son(name, age) {
Father.call(this, name);
this.age = age;
}
Son.prototype = new Father();
Son.prototype.sayAge = function() {
console.log(this.age);
}
const son1 = new Son('son', 34);
2. Object.creat()
const person1 = {
name: 'xll',
age: 23,
}
const person2 = Object.create(person1)
console.log(person2.name);//xll
3. 寄生式组合继承
function object(o) {
function F() {};
F.prototype = o;
return new F();
}
function inheritPrototype(son, father) {
let prototype = object(father.prototype)
prototype.consturctor = son;
son.prototype = prototype;
}
function Father(name) {
this.name = name;
}
Father.prototype.sayName = function() {
console.log(this.name);
}
function Son(name, age) {
Father.call(this, name);
this.age = age;
}
inheritPrototype(Son, Father);
Son.prototype.sayAge = function() {
console.log(this.age);
}
const person = new Son('son', 23);
4.类继承
class Father {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Son extends Father {
constructor(name, age) {
super(name);
this.age = age;
}
sayAge() {
console.log(this.age);
}
}
const person = new Son('xll', 23);
11. js对象实现一个虚拟DOM?
12. 字符串String有哪些方法,各自有什么区别,是否改变原字符串?
13. 数组Array有哪些方法,各自有什么区别,是否改变原数组?
14.实现instance_of
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__;
}
}
15. 闭包会带来什么问题,什么地方使用?
16. js判断一个变量是否为数组?
1.typeof 判断变量的身份,判断字符串string, 数字和NaN得到number,函数得到function。
2. instanceof判断
let arr = [1, 3, 4];
console.log(arr instanceof Array); //true
console.log(arr instanceof Object); //true
3. constructor判断
let arr = [1, 3, 4];
console.log(arr.constructor === Array); //true
4. Object.prototype.toString.call()判断
let arr = [1, 3, 4];
let arr1 = Object.prototype.toString.call(arr);
console.log(arr1); //[object Array]
17. 实现js对象的深拷贝
1. JSON.parse JSON.stringify快速克隆
此方法克隆会有以下几个问题: 忽略undefined symbol 不能序列化函数 不能解决循坏引用的对象
// 1. JSON.parse/stringify 快速克隆 但是存在数据丢失问题
const a = {
string: 'string',
number: 123,
bool: false,
nul: null,
date: new Date(),
undef: undefined,
inf: Infinity,
re: /.*/,
symbol: Symbol,
}
console.log(a);
console.log(typeof a.date); //object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone); //会丢失undefined symbol re
console.log(typeof clone.date);
2. ES6提供的Object.assign()实现浅拷贝
这里需要注意一点: Object.assign()拷贝的是属性值,当原对象的属性值是对一个对象的引用那么它只是指向那个引用。即当原对象的属性值是简单类型像string number 的时候可以把Object.assign()当作深拷贝,而原对象的属性值为对象或者其他引用类型的时候当做浅拷贝。
const obj1 = {
a: 'a',
b: 'b'
}
let obj2 = Object.assign({}, obj1, { c: 'c' });
let obj3 = {...obj1 };
console.log(obj1); //{ a: 'a', b: 'b' }
obj1.d = 'd';
console.log(obj1); //{ a: 'a', b: 'b', d: 'd' }
console.log(obj2); //{ a: 'a', b: 'b', c: 'c' }
console.log(obj3); //{ a: 'a', b: 'b' }
3. 原生实现js对象的深拷贝
- 判断入参obj是否为兑现或者函数且不能为null;2. 判断obj具体是数组还是对象。
// 3. 原生实现深拷贝
function copyFn(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null;
}
if (!isObject(obj)) {
throw new Error('Input is not Object');
}
let newObj = Array.isArray(obj) ? [] : {};
for (let key of Object.keys(obj)) {
if (typeof obj[key] === 'object') {
newObj[key] = copyFn(obj[key]);
} else {
newObj[key] = obj[key];
}
}
return newObj;
}
let obj1 = {
name: 'lisi',
age: '23',
sing: function() {
console.log('sing');
},
obj2: { name: 'obj2' },
}
let obj2 = copyFn(obj1);
18. 如何判断一个url是否只包含qq.com?
使用正则:参考
let url1 = 'http://www.qq.com';
let url2 = 'http://www.qq.com.cn';
let url3 = 'http://www.qq.com/a/b';
let url4 = 'http://wwww.qq.com?a=1';
let url5 = 'http://www.123qq.com?a=1';
let url6 = 'http://www.baidu.com?redirect=http://www.qq.com/a';
function check(url) {
let res = /^https?:\/\/w{3,3}\.qq\.com[^.]*$/;
if (res.test(url)) {
return true;
} else {
return false;
}
}
console.log(check(url1)); //true
console.log(check(url2)); //false
console.log(check(url3)); //true
console.log(check(url4)); //false
console.log(check(url5)); //false
console.log(check(url6)); //false
判断输入字符串是否为数字、字母、下划线组成:
let str = '1234ab_';
function isValid(str) {
let regExp = /^\w+$/;
return regExp.test(str);
}
console.log(isValid(str)); //true
19. 实现数组的forEach方法
Array.prototype.myForEach = function(callback, thisArg) {
var _this;
if (typeof callback !== 'function') {
throw 'callback must be a function'
}
if (arguments.length > 1) {
_this = thisArg;
}
if (!Array.isArray(arr)) {
throw 'this function is work for array'
}
for (let index = 0; index < this.length; index++) {
callback.call(_this, this[index], index, this)
}
}
let obj = { name: 'lise', age: 21 }
//没有指定thisArg
arr.myForEach(function(item) {
console.log(item + '===>' + this);
console.log('-------------------------');
})
//指定thisArg
arr.myForEach(function(item, index, array) {
console.log(item + '=====>' + this.name);
console.log(index + '====>' + this.age);
console.log(array + '====>' + this.name);
console.log('************************************');
}, obj)
执行结果:
- 没有指定回调函数this的情况:
2. 指定回调函数this的情况:
20. 数组的reduce方法实现
Array.prototype.myReduce = function(callback, initValue) {
if (!callback) {
throw new TypeError('undefined is not a function');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + "is not a function");
}
var res, index = 0;
if (initValue) {
res = initValue;
} else {
//没有初始值就拿数组第一个当作初始值
if (this.length === 0) {
throw new TypeError('Reduce of empty array with no inital value');
} else {
res = this[0];
index = 1;
}
}
for (let i = index; i < this.length; i++) {
res = callback(res, this[i], i, this);
}
return res;
}
使用reduce: 去除数组重复数据
let arr = [1, 2, 3];
let res = arr.myReduce((a, b) => a + b);
console.log(res);
let arr1 = ['a', 'b', 'c', 'b', 'a'];
let res2 = arr1.myReduce(function(pre, cur, index, array) {
if (pre.indexOf(cur) == -1) {
pre.push(cur);
}
return pre;
}, []);
console.log(res2);
打印结果:
21. call、apply、bind用法以及区别
var name = 'ang'
console.log(name)
let obj = {
name: 'xll',
age: '13'
}
function testMyCall(a,b,c) {
console.log(a+b+c+`${this.name}`);
}
testMyCall.call(obj,1,2,3);
Function.prototype.myCall = function (obj) {
if (!obj) {
obj = window;
}
let args = [];
obj.func = this;//使用了myCall方法的函数
for (let i = 1; i < arguments.length; i++) {
args.push("arguments["+i+"]");
}
eval("obj.func("+args+")");
// let arr = Array.prototype.slice.call(arguments,1);
// obj.func(...arr);
delete obj.func;
}
testMyCall.myCall(obj,1,1,1)