JS手撕代码

JS设计模式

JavaScript设计模式

apply、call、bind

call、apply、bind 模拟实现

async await generator

async 、await、Generator 原理实现

Promise 实现

Promise 学习笔记

类的创建与继承 new实现

JS 类的创建继承 与 new原理实现

防抖、节流 和 预加载、懒加载

防抖、节流 和 预加载、懒加载

深浅拷贝

1. 数据类型

基本数据类型

number、boolean、string、null、undefined、symbol
基本数据类型是以名值得形式存储在栈内存中的。

进行赋值操作时会新开辟一片栈内存存储新的名值。

引用数据类型

数组、对象、函数等
以上的类型会在栈内存和堆内存中分别开辟一片空间进行存储。

当直接赋值时其实是将a的堆地址赋值给了b,两者最终指向了同一个堆内存。这就是浅拷贝,带来的后果就是你在对b的元素进行操作时,同时改变了a对应的值。

2. 深拷贝方法

方法一

第一种方法简单粗暴,使用JSON.stringify和JSON.parse进行两次转换。

  let a = [1,3,5,7];
  let b = JSON.parse(JSON.stringify(a));

  b[0] = 99;
  console.log("a", a); // [1,3,5,7]
  console.log("b", b); // [99,3,5,7]

这种方法存在一种很大的缺点,转换时会自动忽略undefined,Symbol、function

方法二

用递归的方法去遍历复制所有的层级

function deepClone(obj){
    // 判断数据形式
    let clone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj === "object"){
      for(let key in obj){
        if(obj.hasOwnProperty(key)){
          // 属性是对象则进行递归
          if(obj[key] && typeof obj[key] === "object"){
            clone[key] = deepClone(obj[key]);
          }else{
            clone[key] = obj[key];
          }
        }
      }
    }
    return clone;
  }
  
  let a = [1,3,5,7],
  b = deepClone(a);
  a[0] = 999;
  console.log(a); // [1,3,5,7]
  console.log(b); // [999,3,5,7]

数组去重

var arr = [1, 1, "true", "true", true, 15, false]
//利用ES6去重
function unique(arr) {
	return Array.from(new Set(arr))
}
//利用indexOf方法(该方法用于返回指定数组元素首次出现的地方,若没有则返回-1)
function unique(arr) {
	if(!Array.isArray(arr)) {
		console.log("error");
		return ;
	}
	let result = [];
	for (let i = 0; i < arr.length; i ++) {
		if (result.indexOf(arr[i]) == -1) {
			result.push(arr[i])
		}
	}
	return result;
}
//利用对象属性不能相等
function unique(arr) {
	if (! Array.isArray(arr)) {
		return
	}
	let result = [];
	let obj = {};
	for (let i = 0; i < arr.length; i ++) {
		if (!obj[arr[i]]) {
			result.push(arr[i])
			obj[arr[i]] = 1;
		} else {
			obj[arr[i]] ++
		}
	}
	return array;
}

实现sleep的效果

//使用Promise   先输出111,延迟500ms后输出222
function sleep(ms) {
	return new Promise((resolve) => {
		console.log("111");
		setTimeout(resolve,ms)
	})
}
sleep(500).then(function(){
	console.log("222")
})

//使用async/await  过了500ms后才输出111
function sleep(ms) {
	return new Promise((resolve) => {
		setTimeout(resolve,ms)
	})
}
async function test() {
	let temp = await sleep(500);
	console.log("111");
	return temp;
}
//写一个函数
for (let i = 0; i < 5; i++) {
	setTimeout(function() {
		console.log(i)
	},1000*i)
}

for(var i = 0; i < 5; i ++) {
	(function(i){
		setTimeout(function(){
			console.log(i);
		},1000*i)
	})(i)
}

用promise和async实现每间隔1s,2s,3s…打印i

function sleep(interval){
    return new Promise((resolve)=>	
        setTimeout(resolve);
        }, interval);
}
async function stepPrint(n){
    for(let i=0;i<=n;i++){
         console.log(i);
        await  sleep(i*1000);
         }
}
stepPrint(5)

链表

class Node{
	constructor(data) {
		this.data = data;
		this.next = null;
	}
}

class LinkList{
	constructor() {
		this.head = new Node('head');
	}
	findByValue = (value) => {
		let currentNode = this.head;
		while (currentNode !== null && currentNode.data !== value) {
			currentNode = currentNode.next;
		}
		return currentNode === null ? -1 : currentNode;
	}
	findByIndex = (index) => {
		let pos = 0;
		let currentNode = this.head;
		while (currentNode !== null && pos !== index) {
			pos ++;
			currentNode = currentNode.next;
		}
		return currentNode === null ? -1 : currentNode;
	}
	insert = (value, element) => {
		let currentNode = this.findByValue(element);
		if (currentNode == -1) {
			console.log('error');
			return;
		}
		let newNode = new Node(value);
		newNode.next = currentNode.next;
		currentNode.next = newNode;

	}
	delete = (value) {
		let currentNode = this.head;
		preNode = null;
		while (currentNode !== null && currentNode.data !== value) {
			preNode = currentNode;
			currentNode = currentNode.next;
		}
		if (currentNode == null) {
			return -1
		}
		preNode.next = currentNode.next;


	}

	print = () => {
		let currentNode = this.head
		while (currentNode !== null) {
			console.log(currentNode.data)
			currentNode = currentNode.next;
		}
	}

}

基于promise实现jsonp

function p(url){
    let json;
    let s = document.createElement('script');
    s.src = url + '?callback=fn';
    window.fn = function(data){
        json = data;
    }
    //当script被插入文档中时,src中的资源就会开始加载
    document.body.appendChild(s);
    
    return new Promise((resolve,reject)=>{
        /* throw('err in promise'); */
        s.onload = function(e){
            resolve(json);
        }
        s.onerror = function(){
            reject(json);
        }
    });
}
p('http://localhost:8082').then(data=>{
    console.log(data);
    throw('err before then');
}).catch(err => {
    //可以捕捉到then里的err befor then也可以捕捉到new Promise里的err in promise。
    console.log(err)

将原生的ajax封装成promise

var  myNewAjax=function(url) {
    return new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest();
	  	xhr.open('get',url);
        xhr.send(data);
        xhr.onreadystatechange=function(){
            if(xhr.status==200&&readyState==4){
            var json=JSON.parse(xhr.responseText);
            resolve(json)
        }else if(xhr.readyState==4 &&xhr.status!= 200){
            reject('error'); 
        }
                                         }
    })
}

如何判断一个对象是不是空对象?

//for...in...遍历属性
function judgeObj(obj) {
	for (var attr in obj) {
	return alert("非空对象")
	}
    return alert("空对象")
}
//JSON自带的stringify()方法
if(JSON.stringify(obj) == "{}") {
    console.log("空对象")
}
//ES6新增的方法Object.keys()
if(Object.keys(obj).length > 0) {//会转化为一个数组
    console.log("非空对象")
}

如何实现一个私有变量,用getName方法可以访问,不能直接访问

function People(){
 25       var name='张三'; // 私有变量; 外部无法访问
 27       function say(){  // 私有函数;
 28         return '我是......';
 29       }
 31       this.getName=function(){ // 对外公共的特权方法; 外部可以访问
 32         return name;
 33       }
 38   }
 39   var p=new People()
 40   alert(p.getname())

获得对象上的属性

  • 对象内置属性方法:Object.keys();该方法返回一个数组,数组内包括对象内可枚举属性以及方法名称
var keys= Object.keys(testObj);
console.log(keys); // 输出 keys ["name", "age", "action"]

  • Object.getOwnPropertyNames():方法返回一个指定对象所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组.不可枚举: 比如属性是一个js方法
 var keys = Object.getOwnPropertyNames(testObj);
console.log(keys);  // 输出 keys ["name", "age", "action"]

  • 最原始的 for…in 循环。
var keys =[];
	for(var i in testObj){
	keys.push(i);
}
console.log(keys);   // keys ["name", "age", "action"]

定义一个log方法

function log(){
  console.log.apply(console, arguments);
};
log(1);    //1
log(1,2);    //1 2

JavaScript中实现轮播

<!DOCTYPE html>
<html>
<head>
	<title>Test</title>
</head>
<body>
	<div class="imgBox">
		<img class="img-slide img1" src="images/1.png" alt="1">
		<img class="img-slice img2" src="images/2.png" alt="2">
		<img class="img-slice img3" src="images/3.png" alt="3">
	</div>

<style>
	.img1{
		display:block;
	}
	.img2{
		display: none;
	}
	.img3{
		display: none;
	}
</style>

<script type="text/javascript">
	var index = 0;
	function changeImg() {
		index ++;
		var a = document.getElementsByClassName("img-slice");
		if (index >= a.length) {
			index = 0;
		}
		for (let i = 0; i < a.length; i ++) {
			a[i].style.display = "none";
		}
		a[index].style.display = "block";
	}
	setInterval(changeImg, 2000)
</script>
</body>
</html>

https://www.jianshu.com/p/366e374e108d

实现一个tab组件

https://blog.csdn.net/qq_23244029/article/details/93517575


<html>
 
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>实现Tab组件title>
  <link rel="stylesheet" type="text/css" href="tab.css">
head>
 
<body>
  <div id="container1">
    <ul class="tab-list">
      <li class="tab-item" href="panel-1">tab1li>
      <li class="tab-item" href="panel-2">tab2li>
      <li class="tab-item" href="panel-3">tab3li>
    ul>
    <div class="panel active" id="panel-1">content1div>
    <div class="panel" id="panel-2">content2div>
    <div class="panel" id="panel-3">content3div>
  div>
  <script>
 
 
    /**
     * Tab 组件
     * @param {String} containerId 容器Id
     */
    function Tab(containerId) 
    {
      var cont1 = document.getElementById(containerId);
      var tab_items = cont1.getElementsByClassName('tab-item');
      var pls = cont1.getElementsByClassName('panel');
       
      for(let i = 0;i < tab_items.length;i++){
        tab_items[i].onclick = function(e){
          console.log(e);
          for(let j = 0;j<tab_items.length;j++){
            if(i == j){
              pls[i].style.display = "block";
            }else{
              pls[j].style.display = "none";
            } 
          }
          
        }
      }
      
    }
 
    /**
     * active 方法,可以控制第几个 Tab 组件显示
     * @param {Number} index 要显示的 tab 的序号,从0开始
     */
    Tab.prototype.active = function (index) 
    {
 
    }
 
    var tab = new Tab('container1');
 
  script>
body>
 
html>

js拖拽功能的实现

js拖拽功能的实现

(三)JS控制一次加载一张图片, 加载完后再加载下一张

https://blog.csdn.net/weixin_44462907/article/details/88756890

let loadImg = (src) => {
        return new Promise((resolve, reject) => {
            let img = document.createElement('img')
            img.src = src
            document.body.append(img)
            setTimeout(() => {
                resolve(true)
            }, 1000)
        })
    }
    const imgs = ['../src/img/1.PNG', '../src/img/1.PNG', '../src/img/1.PNG'];
    // 依次加载图片
    async function fSync(imgs) {
        for (let i of imgs) {
            await loadImg(i)
        }
    }
    fSync(imgs);

你可能感兴趣的:(前端面试,javascript,前端)