将类数组/含有length属性的对象转化为数组javascript
类数组:(例如经过document.getElementsByTagName获取的元素、含有length属性的对象)具备length属性,而且能够经过0、一、2…下标来访问其中的元素,可是没有Array中的push、pop等方法。java
注意:可是这个不适用于IE6~8,会报错,只能使用循环来解决es6
// 类数组 let trueArr = Array.prototype.slice.call(arrayLike) // 含有length属性的对象 let obj4 = { 0: 1, 1: 'thomas', 2: 13, length: 3 // 必定要有length属性 }; console.log(Array.prototype.slice.call(obj4)); // [1, "thomas", 13]
求数组中的最大和最小值数组
注意:边界问题,临界值大概在 [ 参数个数限制在65536]app
let arr = [1,2,3,89,46] let max = Math.max.apply(null,arr)//89 let min = Math.min.apply(null,arr)//1
数组追加函数
数组方法contact比较:contact返回新数组,不修改原数组测试
let arr1 = [1,2,3] let arr2 = [4,5,6] let total = [].push.apply(arr1, arr2) //6
利用call和apply作继承this
function Person(name,age){ // 这里的this都指向实例 this.name = name this.age = age this.sayAge = function(){ console.log(this.age) } } function Female(){ Person.apply(this,arguments)//将父元素全部方法在这里执行一遍就继承了 } let dot = new Female('Dot',2)
判断变量类型prototype
function isArray(obj){ return Object.prototype.toString.call(obj) == '[object Array]' } isArray([]) // true isArray('dot') // false
其余:使用 log 代理 console.log代理
function log(){ console.log.apply(console, arguments); } // 固然也有更方便的 let log = console.log()
特色:
当 bind 返回的函数做为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效
var bindFoo = bar.bind(foo, 'daisy'); var obj = new bindFoo('18');
// 使用apply和call来实现this指向问题 Function.prototype.bind2 = function (context) { if (typeof this !== "function") { throw new Error("what is trying to be bound is not callable"); } var self = this; // 得到bind的参数从第二个参数到最后一个参数 var args = Array.prototype.slice.call(arguments, 1); var fNOP = function () {}; var fBound = function () { // 指bind返回的函数传入的参数 var bindArgs = Array.prototype.slice.call(arguments); // 看成为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可让实例得到来自绑定函数的值 // 以上面的是 demo 为例,若是改为 `this instanceof fBound ? null : context`,实例只是一个空对象,将 null 改为 this ,实例会具备 habit 属性 // 看成为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context // new bind返回的函数,this失效,但传入的参数生效 return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs)); } // fBound.prototype = this.prototype; // 保证继承,原型链,让 fBound 构造的实例可以继承绑定函数的原型中的值,下面两行代码等同于Object.creater() fbound.prototype = Object.create(this.prototype); // 咱们直接修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype。这个时候,咱们能够经过一个空函数来进行中转 fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; } // es6实现 Function.prototype.bind = function(context) { if(typeof this !== "function"){ throw new TypeError("not a function"); } let self = this; let args = [...arguments].slice(1); function Fn() {}; Fn.prototype = this.prototype; let bound = function() { let res = [...args, ...arguments]; //bind传递的参数和函数调用时传递的参数拼接 context = this instanceof Fn ? this : context || this; return self.apply(context, res); } //原型链 bound.prototype = new Fn(); return bound; }
实现思路
注意的点
难点解析 - 接受不定长参数
var args = []; // 为了拼出一个参数字符串,arguments类数组,不能使用 for(var i = 1, len = arguments.length; i < len; i++) { // args: ["arguments[1]", "arguments[2]", .....] args.push('arguments[' + i + ']'); } // 1. context.fn(args.join(',')) es6语法实现es3的call方法不合适 // 2. 这里 args 会自动调用 Array.toString() 这个方法 // 3. eval做用:当作是<script>标签,只接受原始字符串做为参数,用JavaScript的解析引擎来解析这一堆字符串里面的内容 var result = eval('context.fn(' + args +')');
call总体实现
Function.prototype.call2 = function (context) { // 首先要获取调用call的函数,用this能够获取 var context = context || window; context.fn = this; var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); } var result = eval('context.fn(' + args +')'); delete context.fn return result; } // 测试 bar.call2(null); // 2 console.log(bar.call2(obj, 'kevin', 18)); // es6 Function.prototype.call = function (context) { if (!context) { context = typeof window === 'undefined' ? global : window; } context.fn = this; let rest = [...arguments].slice(1);// 空数组slice后返回的仍然是空数组 let result = context.fn(...rest); delete context.fn; return result; }
Function.prototype.apply = function (context, arr) { var context = Object(context) || window; context.fn = this; var result; if (!arr) { result = context.fn(); } else { var args = []; for (var i = 0, len = arr.length; i < len; i++) { args.push('arr[' + i + ']'); } result = eval('context.fn(' + args + ')') } delete context.fn return result; } // es6: Function.prototype.apply = function (context, rest) { if (!context) { //context为null或者是undefined时,设置默认值 context = typeof window === 'undefined' ? global : window; } context.fn = this; let result; if(rest === undefined || rest === null) { //undefined 或者 是 null 不是 Iterator 对象,不能被 ... result = context.fn(rest); }else if(typeof rest === 'object') { result = context.fn(...rest); } delete context.fn; return result; }