將類數組/含有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; }