二叉树非递归前、中、后序遍历
function TreeNode(x) {
this.val = x ;
this.left = null;
this.right = null;
}
function preOrder(root){
var arr = [],res = [];
arr.push(root);
while (arr.length!=0) {
var temp = arr.pop(); //弹出最后一个;
res.push(temp.val);
//将当前节点的左右子树存入
if(temp.right) {
arr.push(temp.right);
}
if(temp.left){
arr.push(temp.left)
}
}
return res;
}
//中序排序,两层遍历
function midOrder(root) {
var res = [],arr= [];
while (true) {
while (root != null) {
arr.push(root);
root = root.left;
}
if(arr.length==0){
break;
}
var temp = arr.pop();
res.push(temp.val);
root = temp.right;
}
}
//后序遍历
function lastOrder(root) {
var arr = [],res = [];
arr.push(root);
while (arr.length != 0) {
var temp = arr.pop();
res.push(temp.val);
if(temp.left) {
arr.push(temp.left)
}
if(temp.right){
arr.push(temp.right)
}
}
return res.reverse();
}
//层次遍历
function levelOrder(root) {
var stack = [root];
var level = [];
var res = [];
var size = stack.length;
while (stack.length > 0) {
while (size-- > 0) {
var temp = stack.shift();
level.push(temp.val);
temp.left && stack.push(temp.left);
temp.right && stack.push(temp.right);
}
res.push(level);
level = [];
size = stack.length;
}
return res;
}
手写ajax
<srcipt>
var xhr = new XMLHttpRequest();
xhr.open('post',url,true); //建立连接
xhr.onreadstateChange = function(){
if(xhr.readstate === 4){ //当该状态为4的时候,此时则表示响应数据已经成功接收并解析完成
if(xhr.status === 200){ //服务器成功响应数据,饭想
//to doing
}
}
}
</srcipt>
手写防抖、节流
// 防抖
function debounce(fuc, wait = 1000, immediate = false){
let timer = null;
return function debounced(...args){
//如果当前计时器不为空
if(timer)clearTimeout(timer);
//首次立即执行
if(immediate && !timer){
timer = setTimeout(()=>{
fuc.apply(this, ..args); // 调用回调函数
timer = null;
},wait)
}
timer = setTimeout(()=>{
fuc.apply(this, ..args); // 调用回调函数
timer = null;
},wait)
//提供撤回函数
debounced.cancel = ()=>{
clearTimeout(timer)
timer = null
}
return;
}
}
//节流,在固定时间内一定会执行某个操作
function throttle(fn, wait = 1000 ){
let timer = null;
let previous = 0;
// <!--const {leading, trailing} = options;-->
//利用闭包实现
const throttled = function(...args){
const now = new Date().getTime();
if(now - previous > wait){
previous = now;
fn(...args);
}
}
return throttled
}
手写js的继承方式
//js的寄生组合继承方式
function A (name) {
this.name = name
}
A.prototype.sayName = function () {
console.log(this.name)
}
//原型式继承
function B (name,age) {
this.age = age
A.call(this,name) //将this指向需要继承的A对象,则我们在new对象的时候,可以根据this的指向复制属性
}
(function () {
//创建一个没有实例方法的类
var Super = function () {}
Super.prototype = A.prototype // 将空类的原型对象执行父类原型对象
B.prototype = new Super(); // 将子类的原型对象指向空实例方法的类
})
B.prototype.constructor = B // 将原型对象中的
- 创建没有实例方法的类
- 类的原型对象指向父类的原型对象
- 子类的原型对象指向无实例方法类的实例
手写core、jsonp的实现原理
// 手写jsonp
function addScriptTag(url) {
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
script.src = url
}
function callerHandler(params) {
//todo somehting ...
}
window.onload = function () {
addScriptTag("http://www.baidu.com?callback=callerHandler")
}
//手写cores
function _myCore() {
var xhr = new XMLHttpRequest();
xhr.open('post',url,true);
xhr.onreadystateChange = function () {
if(xhr.readyState == 4){
if(xhr.status==200){
//todo something
}
}
}
}
正则表达式的应用
将url查询参数解析成字典对象
- 先截取请求参数字符串
- 使用
decodeURLComponent函数进行解码 - 正则匹配出参数对象
function getUrlObject(url){
url = url==null?window.loaction.href:url;
var search = url.substring(url.indexOf("?") + 1);
var obj = {};
var reg = /([^?&=]+)=([^?&=]*)/g; // /g实现全局匹配
search.replace(reg,function(rs,key,value){
var name = decodeURLComponent(key);
var val = decodeURLComponent(value);
obj[name] = val;
})
}
手写实现给定url,将url的参数以对象形式输出
截取字符串、切割字符串、转换参数即可实现
function getUrlParma(url) {
var pamrma = url.substr(url.indexOf('?'));
if(!pamrma) return undefined;
let preArr = pamrma.split('&');
let res = {};
for(var key in preArr){
var item = key.split('=');
res[item[0]] = decodeURIComponent(item[1])
}
return res
}
手写通用拷贝函数
function deepCopy(obj){
var newobj
if(obj && typeof obj !='object'){
newobj = obj;
}else{
for(var i in obj){
if(obj.hasOwnProperty(obj[i]){
if(obj && typeof obj != 'object'){
newobj[i] = obj[i]
}else{
newobj[i] = deepCopy(obj[i])
}
}
}
}
return newobj
}
排序方式中 冒泡、排列、堆、快排、直接排序
//快排
function qucikSort(arr){
if(arr.length <= 1) return arr;
var baseIndex = Math.floor(arr.lenght/2) //向上取整
var base = arr.splice(baseIndex,1)[0] // 截取完返回需要截取的内容
var left = [],right = [];
for(var i = 0 ;i < arr.length;i++){
if(arr[i]<base){
left.push(arr[i])
}else{
right.push(arr[i])
}
}
return quickSort(left).concat([base],quickSort(right));
}
// 直接插入排序,其思路是,当前元素和前面排序完成的子序列进行比较,直到找到比自己小的元素
function insertSort(arr){
var temp = arr[0];
for(var i = 1 ;i < arr.lenght; i++){
if(arr[i-1] > arr[i]){ //前提是当前值要小于前一位
temp = arr[i];
for(var j = i; arr[j-1] > temp ;j--){
arr[j] = arr[j-1]; // 满足条件向后移动一位
}
}
}
}
// 冒泡排序
function bubbleSort(arr){
for(var i = 0 ; i < arr.length - 1 ; i++){
for(var j = 0 ;j < arr.length - 1 - i ; j++){
if( arr[j] > arr[j+1] ){
var t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
}
}
//堆排序,最大堆排序:任意节点的值总不小于其子节点的值
//1、给定的数组经过变换得到一个最大推
//2、将最大堆和末尾的树交互,然后除了最后一个节点以外的新的二叉树进行维护形成新的最大堆
快速排序、选择排序、希尔排序、堆排序是不稳定的排序方式
bind和apply、call的区别 以及手写实现
答案解析:
三个函数都是作用都是可以在特定的作用域中调用函数,相当于设置函数体内this的值,用于扩充函数赖以运行的作用域。
- apply接收两个参数一个this的指向对象、第二个是传递的参数
var func = function(a,b,c){
console.log(a,b,c);
}
var obj = {a: 2} // 定义一个对象用来绑定
Function.prototype.myApply = function(base,args){
base = base || windows; //考虑base为null或者undefined的情况
base.fn = this; // 在base对象新增一个函数对象,在该函数中this指向的是运行时的对象
var result = base.fn(...args); //引用指向 调用该apply函数的this对象,并且传递参数
delete base.fn; //删除多余的属性
return result;
}
func.myApply(obj,[1,2,3])
- call接收的参数时不定的,第一个参数是需要指向的对象,其他则为形参
var func = function(a,b,c){
console.log(a,b,c);
}
var obj = {a: 2} // 定义一个对象用来绑定
Function.prototype.myCall = function(base,...args){
base = base || windows; //考虑base为null或者undefined的情况
base.fn = this; // 在base对象新增一个函数对象,在该函数中this指向的是运行时的对象
var result = base.fn(...args); //引用指向 调用该apply函数的this对象,并且传递参数
delete base.fn; //删除多余的属性
return result;
}
func.myCall(obj,1,2,3)
- bind的区别是,它返回的是一个箭头函数,而apply,call返回的处理结果;bind传参形式与call是一致的。
var func = function(a,b,c){
console.log(a,b,c);
}
var obj = {a: 2} // 定义一个对象用来绑定
Function.prototype.myBind(base,..args1){
return (...args2)=>{ // 用来接收执行bind函数时所带的参数,箭头函数没有arguement对象,但是可以使用...展开符来接收
// 箭头函数不会生成自身作用域的this对象,会引用箭头函数声明时的父级上下文的this
base = base || window;
base.fn = this;
var result = base.fn(...args1,...args2);
}
}
var _bind = func.myBind();
_bind();
js/ES实现发布订阅模式
简单的发布-订阅模式
class Publish{
constructor(this){
this.handlers = []; //初始化事件容器
}
//事件添加方法,参数是事件类型,事件处理方式
addEventLister(type, handler){
if(!this.handlers[type]){
this.handlers[type] = [];
}
this.handlers[type].push(handler); // 添加事件
}
//触发事件两个参数(事件名,参数)
dispatchEvent(type,...args){
if(!this.handlers[type]){
return new Error("未注册该类型事件")
}
//触发全部的类型的事件
this.handlers[type].forEach(fn => {
fn.apply(this,args);
});
}
}
防抖与节流
答案解析:
// 防抖
function debounce(fuc, wait = 1000, immediate = false){
let timer = null;
return function debounced(...args){
//如果当前计时器不为空
if(timer)clearTimeout(timer);
//首次立即执行
if(immediate && !timer){
timer = setTimeout(()=>{
fuc.apply(this, ..args); // 调用回调函数
timer = null;
},wait)
}
timer = setTimeout(()=>{
fuc.apply(this, ..args); // 调用回调函数
timer = null;
},wait)
//提供撤回函数
debounced.cancel = ()=>{
clearTimeout(timer)
timer = null
}
return;
}
}
//节流,在固定时间内一定会执行某个操作
function throttle(fn, wait = 1000 ){
let timer = null;
let previous = 0;
// <!--const {leading, trailing} = options;-->
//利用闭包实现
const throttled = function(...args){
const now = new Date().getTime();
if(now - previous > wait){
previous = now;
fn(...args);
}
}
return throttled
}
生成N个不重复的[min,max]的随机数
方法一:
//存储一个顺序数组,每次随机生成一个下标树之后再删除掉
function rand_1(n , min , max){
var arr = [];
// 是min到max区间的值
for(var i = 0; i < max - min + 1; i++ ){
arr[i] = i+1;
}
for(var k = arr.length - 1; k >=0 ; k--){
var index = parseInt(Math.random()*k) // 生成0到k直接的随机数
var temp = arr[k];
arr[k] = arr[index];
arr[index] = temp;
}
return arr;
}
二叉搜索树
基本性质:
- 在任意结点的左子树不为空,则左子树上所有结点的值均小于它的根节点的值
- 若任意结点的右子树不为空,则右子树的所有结点的值均大于它的根节点的值
- 任意节点的左、右子树分别也是二叉搜索树
手写new的手撕代码
使用new来调用函数会自动执行一下步骤:
- 创建一个新的对象
- 这个新对象会执行[[prototype]] 连接
- 这个新的对象会绑定到函数调用的this
- 如果函数没有返回其他对象,则new表达式中的函数会自动返回这个新的对象
function _new(){
let obj = new Object(); //创建新的对象obj
let fn = Array.prototype.shift().call(arguments); //取参数的第一项作为构造函数
//将创建的对象的原型链指向构造函数的原型对象
obj.__proto__ = fn.prototype;
// result接收构造函数执行后返回的结果
let result = fn.apply(obj, arguments);
return typeof result === 'object' ? result : obj;
}
手写实现reduce、filter、find等函数
//必须使用function,不能使用箭头函数
Array.prototype.myReduce = function(fn , val){
if(typeof fn != 'function'){
throw new TypeError('Not function')
}
//this是调用函数的数组的
for(let i = 0 ;i < this.length;i++){
val = fn(val, this[i]) // val为上一个值,this[i]当前传值
}
return val;
}
promise实现原理
promise可以认为是一个异步函数状态机,利用观察者模式的编程思想,通过特定书写方式去注册对应状态的事件处理函数,然后更新状态,调用注册过的处理函数即可。
实现promise原理主要是去实现定义一下变量以及方法:
/*
* status:pending(进行中)、resolved(成功)、rejected(失败)
* doneList:成功处理函数列表
* failList:失败处理函数列表
* done:注册成功处理函数
* fail:注册失败处理函数
* resolve:更新state为:resolved,并且执行成功处理队列
* reject: 更新state为:rejected,并且执行失败处理队列
*/
1、在构造函数中初始化promise实例对象的初始化状态、调用构造函数传参的function,参数是resolve和reject函数。
2、依次完成注册成功、失败处理函数,将事件添加到对应的队列中
3、声明resolve、reject函数,一旦触发,改变该promise对象的当前状态,并且执行对应处理队列的事件。
promise的all()的实现
Promise.all = function (promiseList) {
return new Promise((resolve, reject) => {
let count = 0;
let res = [];
if(promiseList.length == 0){
resolve(res); // 如果数组中没有相关的promise对象,则直接成功返回
}else{
function storeValue(index, data) {
res[index] = data; // index保证返回的结果可以按顺序返回
if(++count == promiseList.length){
resolve(res) // 改变promise对象的状态
}
}
for(let i = 0; i < promiseList.length; i++){
Promise.resolve(promiseList[i]).then((data) =>{
storeValue(i,data);
}, (err) =>{
reject(err);
return;
})
}
}
})
}
事件委托的应用
利用事件冒泡原理,从目标元素到父元素层层向上,所以如果是多个重复的子元素,我们可以在父类添加点击事件,并且利用Event对象提供的属性target属性,也就是事件源,去操作返回事件的目标节点.
<body>
<ul id='ull'>
<li>11</li>
<li>22</li>
</ul>
</body>
<script>
window.onload = function () {
var list = document.getElementsByTagName('li');
for(let i = 0 ; i < list.length; i++){
//一定要采用闭包形式
list[i].onclick = (function (n) {
return function () {
//to do something
alert(n)
}
}
)(i)
}
}
</script>
css实现三角形
<div class='san'></div>
<style>
.san{
width:100px;
height:100px;
border-left:100px solid transparent;
border-right:100px soild transparent;
border-bottom:100px soild transparent;
}
</style>