JavaScript Codes

5 篇文章 0 订阅

JavaScript Codes

数列

1 在Javascript中什么是伪(类)数组?如何将伪数组转化为标准数组?

伪数组具有以下特点的对象:

  • 按索引方式存储数据;
  • 具有length属性;
  • 没有数组的push、shift、pop等方法;
    如function的arguments对象,还有getElementsByTagName、ele.childNodes等返回的NodeList对象,或者自定义的某些对象,这些都可以是伪数组。如:
var guiseArr={
    '0':"AAA",
    '1':"BBB",
    '2':"CCC",
    length:3
}

我们可以通过以下几种方式将伪数组转换为标准数组:

//第一种方法,使用slice
Array.prototype.slice.call(arr,0);
//第二种方法,直接使用for循环
var newArr=[];
for(var i=0;i<arr.length;i++){
    newArr=arr[i];
}
//第三种方法,使用ES6的Array.from() 方法用于通过拥有 length 属性的对象或可迭代的对象来返回一个数组。
var newArr=Array.from(arr);
//f附加:Array.from(object, mapFunction, thisValue)
var arr = Array.from([1, 2, 3], x => x * 10);
// arr[0] == 10;
// arr[1] == 20;
// arr[2] == 30;

获取字符串中频率最高的字符

let str = "ahbbccdeddcccddfg";

String.prototype.getMostOften = function () {
  let str = this;
  let obj = {};
  let max = 0;

  for (let i = 0; i < str.length; i++) {//记录各字符串及对应次数
    if (obj[str[i]]) {
      obj[str[i]]++
    } else {
      obj[str[i]] = 1
    }
  };

  for (let key in obj) {//记录最大次数
    max = max < obj[key] ? obj[key] : max
  }

  for (let key in obj) {//输出最大次数及对应字符
    if (obj[key] === max) {
      console.log(`最多的字符是${key},一共出现了${max}次`);
    }
  }
}

str.getMostOften();//最多的字符是c,一共出现了5次  最多的字符是d,一共出现了5次

斐波那契数列

function fib(num) {
  if (num === 0) return 0;
  if (num === 1) return 1;
  return fib(num - 2) + fib(num - 1);//arguments.callee(num-2)+arguments.callee(num-1);
}

fib(6) // 8

取数组的最大值(ES5、ES6)?

答:

//ES5 的写法
    Math.max.apply(null, [14, 3, 77, 30]);
    
    //ES6 的写法
    Math.max(...[14, 3, 77, 30]);
    //reduce
    [14, 3, 77, 30].reduce((accumulator, currentValue) => {
      return accumulator = accumulator > currentValue ? accumulator : currentValue
    });

附注:reduce()

https://www.jianshu.com/p/541b84c9df90

多维数组降维:

	var array = [1, [2], [3, [4, [5]]]];
	array.toString().split(',')//["1", "2", "3", "4", "5"]  注意光是split不够得 会将数字转为字符串 需要处理
	array.toString().split(',').map(e=>+e)//[1, 2, 3, 4, 5]

//reduce()
	function flat(arr){
		return arr.reduce(
		(pre,item) => pre.concat(Array.isArray(item) ? flat(item) : item),
		[]
		)
	}
//redue()
	const flattenDeep = (arr) => Array.isArray(arr)
	  ? arr.reduce( (a, b) => [...a, ...flattenDeep(b)] , [])
	  : [arr]

用js实现随机选取10–100之间的10个数字,存入一个数组,并排序

var arr = [];
function getRandom(start, end) {
  return Math.floor(Math.random() * (end - start + 1) + start)
};
var i = 10;
while (i) {
  arr.push(getRandom(10, 100))
  i--;
};
arr.sort()


ES5

new

作用:

  • 创建一个空对象,继承构造函数原型,并且this引用该对象,
  • 属性与方法被加入到this引用的对象中
  • 新建的对象由this引用,最后隐式返回this

步骤:

使用new命令时,它后面的函数依次执行下面的步骤。

  • 创建一个空对象,作为将要返回的对象实例。
  • 将这个空对象的原型,指向构造函数的prototype属性。
  • 将这个空对象赋值给函数内部的this关键字。
  • 开始执行构造函数内部的代码。

注意事项:

如果构造函数内部有return语句,且return后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。

new命令内部流程

function _new(constructor, params) {
  let args = [].slice.call(arguments, 1);
  let obj = Object.create(constructor.prototype);
  let ctx = constructor.apply(obj, args);
  return (typeof ctx === 'object' && ctx != null) ? ctx : obj
}

代码详解:

function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
  var args = [].slice.call(arguments);// 将 arguments 对象转为数组
  console.log(args); // [ƒ, "张三", 28]

  var constructor = args.shift();// 取出构造函数
  console.log(constructor); //ƒ () {this.price = 1000;return { price: 2000 };}

  console.log(constructor.prototype);//{color: "red", constructor: ƒ}
  var context = Object.create(constructor.prototype); // 创建一个空对象,继承构造函数的 prototype 属性 实现context.__proto__ == constructor.prototype
  console.log(context);//Father {} 见下图
  console.log(context.price);//undefined 

  var result = constructor.apply(context, args);  // 执行构造函数  进行属性添加  并捕捉有可能返回的返回值
  console.log(context);//Father {price: 1000} 见下图
  console.log(context.price);//1000
  console.log(result);//{price: 2000}
  
  return (typeof result === 'object' && result != null) ? result : context;  // 如果返回结果是对象,就直接返回,否则返回 context 对象
}
var Father = function () {
  this.price = 1000;
  return { price: 2000 };
};
Father.prototype.color = 'red'
// 实例
var chid = _new(Father, '张三', 28);
console.log(chid)//{price: 2000}

在这里插入图片描述

JS如何实现继承

步骤:

第一步是在子类的构造函数中,调用父类的构造函数。

第二步,是让子类的原型指向父类的原型,这样子类就可以继承父类原型。

ES5

function Afn(Aname){
  this.name = Aname;
  this.gender = '男'
};
Afn.prototype.sayName = function(){console.log(this.name +''+this.gender)};

function Bfn(Bname,age){
  Afn.apply(this,arguments);
  this.age = age//自定义
};

Bfn.prototype = Object.create(Afn.prototype) //或者  Bfn.prototype = new Afn()
Bfn.prototype.sayAge = ()=>{console.log(this.age)}//自定义  非法

let bfn = new Bfn('henry',12)

bfn.sayName()//henry男 
bfn.sayAge()//undefined this指向了window(箭头函数this为定义时的所在环境对象)
console.log(bfn instanceof Bfn);//true
console.log(bfn instanceof Afn);//true
console.log(Bfn instanceof Afn);//fals

ES6

class Afn{
  constructor(name){
    this.name = name;
    this.gender = '女';
    this.body = '漂亮'
  };
  sayName(){console.log(this.name +''+this.gender)};
  getBody(){return this.body}
}

class Bfn extends Afn{
  constructor(name,age){
    super(name);
    this.age = age;
  };
  getBody(){console.log(this.age + '岁,真'+super.getBody() +'!');
  }
}

let bfn = new Bfn('小黄',17)

bfn.sayName()//小黄女
bfn.getBody()//17岁,真漂亮!
console.log(bfn instanceof Bfn);//true
console.log(bfn instanceof Afn);//true
console.log(Bfn instanceof Afn);//false

单个方法继承

上面代码中,子类是整体继承父类。有时只需要单个方法的继承,这时可以采用下面的写法。

    ClassB.prototype.print = function() {
      ClassA.prototype.print.call(this);
      // some code
    }

上面代码中,子类B的print方法先调用父类A的print方法,再部署自己的代码。这就等于继承了父类A的print方法。

多重继承

JavaScript 不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。

function M1() {
      this.hello = 'hello';
    }
    
    function M2() {
      this.world = 'world';
    }
    
    function S() {
      M1.call(this);
      M2.call(this);
    }
    
    // 继承 M1
    S.prototype = Object.create(M1.prototype);
    // 继承链上加入 M2
    Object.assign(S.prototype, M2.prototype);
    
    // 指定构造函数
    S.prototype.constructor = S;
    
    var s = new S();
    s.hello // 'hello'
    s.world // 'world'

上面代码中,子类S同时继承了父类M1和M2。这种模式又称为 Mixin(混入)。

实现Object.create()

附:Object.create()详解
原理:让newObj的原型对象是oldObj (以前是这个函数的prototype 那么就让一个构造函数的prototype = oldObj 再new 这个函数即可)

if (typeof Object.create !== 'function') {
  Object.create = function (obj) {
    function F() {}
    F.prototype = obj;
    return new F();
  };
}

上面代码表明,Object.create方法的实质是新建一个空的构造函数F,然后让F.prototype属性指向参数对象obj,最后返回一个F的实例,从而实现让该实例继承obj的属性。

JSONP:
https://juejin.im/post/5d2547d36fb9a07ea33c3cfd

深拷贝和浅拷贝

  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,浅拷贝只复制对象的第一层属性;

  • 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。对对象的属性进行递归复制。
    let a = {
    age: 1
    }
    let b = a
    a.age = 2
    console.log(b.age) // 2
    从上述例子中我们可以发现,如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。

通常在开发中我们不希望出现这样的问题,我们可以使用浅拷贝来解决这个问题。

浅拷贝

对象:
Object.assign

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

let a = {
    age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
展开运算符(…)
  let a = {
        age: 1
    }
    let b = {...a}
    a.age = 2
    console.log(b.age) // 1
赋值实现
function simpleClone(initalObj) {    
  var obj = {};    
  for(var i in initalObj) {
    obj[i] = initalObj[i];
  }    
  return obj;
}
数组
slice
var arr = [1,2,3,4];
var arr2 = arr.slice()
concat
var arr = [1,2,3,4];
var arr2 = [].concat(arr)
展开运算符(…)

通常浅拷贝就能解决大部分问题了,但是当我们遇到如下情况就需要使用到深拷贝了

let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = {...a}
a.jobs.first = 'native'
console.log(b.jobs.first) // native

浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到刚开始的话题了,两者享有相同的引用。要解决这个问题,我们需要引入深拷贝。

深拷贝

添加到Object原型上避免考虑是否是基本数据类型
 Object.prototype.clone = function(){
          var o = this.constructor === Array ? [] : {};
          for(var e in this){
                  o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];
          }
          return o;
  }
JSON.parse(JSON.stringify(object))来解决。
let b = JSON.parse(JSON.stringify(a))

但是该方法也是有局限性的:

  • 会忽略 undefined
  • 会忽略 symbol
  • 会忽略函数
  • 会忽略正则与date对象
  • 不能序列化函数
let a = {
    age: undefined,
    sex: Symbol('male'),
    jobs: function() {},
    name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}

你会发现在上述情况中,该方法会忽略掉函数和 undefined 。

五种常见数据类型递归遍历

(可以对 JavaScript 中的五种主要数据类型(Number、string、Object、Array、Boolean)进行复制):

精简版(不考虑性能)
function deepClone(source) {
  if (typeof obj !== 'object' && obj == null) return;

  let target = Array.isArray(source) ? [] : {};
  //let target = obj.constructor === Array ? [] : {}
 
  for (let key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (typeof source === 'object' && source != null) {
        target[key] = deepClone(source[key])
      } else {
        target[key] = source[key]
      }
    }
  };
  return target;

};
考虑数组性能用while来做
function clone(Obj) {  
		 if (null == obj || "object" != typeof obj) return obj;//考虑到null  基本数据类型直接赋值 
         var buf;   
         if (Obj instanceof Array) {   
             buf = [];                    //创建一个空的数组
             var i = Obj.length;   
             while (i--) {   
                 buf[i] = clone(Obj[i]);   
             }   
             return buf;    
         }else (Obj instanceof Object){   
             buf = {};                   //创建一个空对象
             for (var k in Obj) {           //为这个对象添加新的属性
                 buf[k] = clone(Obj[k]);   
             }   
             return buf;   
         }
     }
考虑到data对象且考虑数组性能用for来做
function clone(obj) {
    var copy;
 
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;
 
    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
 
    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }
 
    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }
 
    throw new Error("Unable to copy obj! Its type isn't supported.");
}

定义一个log方法,让它可以代理console.log的方法

log(){
	console.log.apply(console,arguments)
}

如何实现一个 call 函数

Function.prototype.myCall = function (context) {
  var context = context || window
  // 给 context 添加一个属性
  // getValue.call(a, 'yck', '24') => a.fn = getValue
  context.fn = this
  // 将 context 后面的参数取出来
  var args = [...arguments].slice(1)
  // getValue.call(a, 'yck', '24') => a.fn('yck', '24')
  var result = context.fn(...args)
  // 删除 fn
  delete context.fn
  return result
}

如何实现一个bind函数

Function.prototype.myApply = function (context) {
  var context = context || window
  context.fn = this

  var result
  // 需要判断是否存储第二个参数
  // 如果存在,就将第二个参数展开
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }

  delete context.fn
  return result
}

如何实现一个bind函数


ES6

实现call apply bind

bind

简单实现:
Function.prototype.bind = function(ctx){
	var _this = this;
	_this.call(ctx,[].slice.call(arguments,1))
};

功能封装

post & get 流程

var xhr = new XMLHttpRequest();

//get
xhr.open('GET', url + '?' + params, true);
xhr.send(null);

//post
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', '...');
xhr.send(params)//username=huanger&password=123

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4) {//判断异步调用是否完成
    if (status >= 200 && xhr.status < 300) {判断异步调用是否成功
      success(xhr.responseText || xhr.responseXML);//成功回调函数
    } else {
      fail(xhr.status)失败回调函数
    }
  }
}

Ajax简单封装

function Ajax(opts) {
  let url = opts.url;
  let type = (params.type || 'GET').toUpperCase();
  let dataType = opts.dataType || "json";
  let success = opts.success;
  let onerror = opts.onerror;
  let data = opts.data || {};

  let dataStr = [];
  for (let key in data) {
    dataStr.push(key + '=' + data[key])
  };
  dataStr = dataStr.join('&');

  if (type === 'GET') {
    url += '?' + dataStr
  };


  let xhr = new XMLHttpRequest();
  xhr.open(type, url, true);

  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {//判断异步调用是否完成
      if (status >= 200 && xhr.status < 300) {判断异步调用是否成功
        success(xhr.responseText || xhr.responseXML);//成功回调函数
      } else {
        fail(xhr.status)失败回调函数
      }
    }
  }

  if (type == 'GET') {
    xhr.send(null);
  } else {
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    xhr.send(dataStr);
  }

}

原生JS实现Jq的ready方法?

function ready(fn){
      if(document.addEventListener) {        //标准浏览器
          document.addEventListener('DOMContentLoaded', function() {
              //注销事件, 避免反复触发
              document.removeEventListener('DOMContentLoaded',arguments.callee, false);
              fn();            //执行函数
          }, false);
      }else if(document.attachEvent) {        //IE
          document.attachEvent('onreadystatechange', function() {
             if(document.readyState == 'complete') {
                 document.detachEvent('onreadystatechange', arguments.callee);
                 fn();        //函数执行
             }
         });
     }
 };

封装一个函数,参数是定时器的时间,.then执行回调函数

function sleep (time) {
    return new Promise((resolve) => setTimeout(resolve, time));
}

写一段JS程序提取URL中的各个GET参数

有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数
(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:'1', b:'2', c:'', d:'xxx', e:undefined}
function serilizeUrl(url) {
     var result = {};
     url = url.split("?")[1];
     var map = url.split("&");
     for(var i = 0, len = map.length; i < len; i++) {
         result[map[i].split("=")[0]] = map[i].split("=")[1];
     }
     return result;
 }

清除字符串前后的空格

function trim(str) {
    if (str && typeof str === "string") {
        return str.replace(/(^\s*)|(\s*)$/g,""); //去除前后空白符
    }
}

实现一个函数,判断输入是不是回文字符串

function run(input) {
  if (typeof input !== 'string') return false;
  return input.split('').reverse().join('') === input;
}

时间戳转为日期格式

//时间戳转换为自定义年月日时分秒时间格式:
//number :传入时间戳  时间戳为10位需*1000,时间戳为13位的话不需乘1000
//format :返回格式,支持自定义 但参数必须与formatArr里保持一致
function formatTime(number, format) {
  //格式化日期函数,如月、日、时、分、秒保证为2位数
  function formatNumber(n) {
    n = n.toString()
    return n[1] ? n : '0' + n
  }
  let date = new Date(number) //转为时间对象  不带参数的话返回当前日期
  let newArr = []
  let formatArr = ['Y', 'M', 'D', 'h', 'm', 's']

  newArr.push(formatNumber(date.getFullYear()))
  newArr.push(formatNumber(date.getMonth() + 1))
  newArr.push(formatNumber(date.getDate()))

  newArr.push(formatNumber(date.getHours()))
  newArr.push(formatNumber(date.getMinutes()))
  newArr.push(formatNumber(date.getSeconds()))

  for (let i = 0; i < newArr.length; i++) {
    format = format.replace(formatArr[i], newArr[i])  //字符串一一对应替换
  }
  return format
}
var timestamp = 1488481383;//时间戳
console.log(formatTime(timestamp, 'Y/M/D h:m:s'));//转换为日期:2017/03/03 03:03:03
console.log(formatTime(timestamp * 1000, 'h:m'));//转换为日期:03:03

DOM

写一个函数,批量操作 css。

function css(node, styleObj) {
  //补全
}
css(document.body, {
  "color": "red",
  "background-color": "#ccc"
})

答:

function css(node, styleObj) {
  for(key in styleObj) {
    node.style[key] = styleObj[key]
  }
}
css(document.body, {
  "color": "red",
  "background-color": "#ccc"
})

补全代码,要求:当鼠标放置在 li 元素上,会在 img-preview 里展示当前 li 元素的 data-img 对应的图片。

<ul class="ct">
  <li data-img="1.png">鼠标放置查看图片1</li>
  <li data-img="2.png">鼠标放置查看图片2</li>
  <li data-img="3.png">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
//补全
</script>

答:

<script>
  var list = document.querySelector(".ct");
  var preview = document.querySelector(".img-preview");
  var newimg = document.createElement("img");

  list.addEventListener("mouseover", function(e) {
    if(e.target.tagName.toLowerCase() === "li") {
       newimg.src = e.target.getAttribute("data-img");
       preview.appendChild(newimg);
    }
  });

  list.addEventListener("mouseout", function() {
    preview.removeChild(newimg);
  });
</script>

取到页面中所有的checkbox

var domList = document.getElementsByTagName(‘input’)
 var checkBoxList = [];
 var len = domList.length;  //缓存到局部变量
 while (len--) {  //使用while的效率会比for循环更高
   if (domList[len].type == ‘checkbox’) {
       checkBoxList.push(domList[len]);
   }
 }

想实现一个对页面某个节点的拖曳?如何做?(使用原生JS)

  • 给需要拖拽的节点绑定mousedown, mousemove, mouseup事件
  • mousedown事件触发后,开始拖拽
  • mousemove时,需要通过event.clientX和clientY获取拖拽位置,并实时更新位置
  • mouseup时,拖拽结束
  • 需要注意浏览器边界的情况

下面这个ul,如何点击每一列的时候alert其index

考察闭包

 <ul id=”test”>
     <li>这是第一条</li>
     <li>这是第二条</li>
     <li>这是第三条</li>
 </ul>
var lis=document.getElementById('2223').getElementsByTagName('li');
 for(var i=0;i<3;i++)
 {
     lis[i].onclick=(function(a){
         return function() {
             alert(a);
         }
     })(i);
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值