一個 前端知識點彙總綜合了學習過程當中的知識點,好比this、閉包、BFC、ES6等,若是大佬們以爲還能夠的話,求個star啦!html
call()
方法調用一個函數,其具備一個指定的this值和分別提供的參數:前端
fun.call(thisArg, arg1, arg2, ...)
apply()
方法調用一個函數,其具備一個指定的this值,以及做爲一個數組(或相似數組的對象)提供的參數:git
fun.apply(thisArg, [argsArray])
舉個栗子???:es6
var one = { name: 'one', sayName: function(age) { console.log(`Hello, I'm ${this.name}, and I'm ${age} years old`) } } var day = { name: 'day' } one.sayName.call(day, 20) // Hello, I'm day, and I'm 20 years old one.sayName.apply(day, [20]) // Hello, I'm day, and I'm 20 years old
fn.call(o)
的原理就是先經過o.m = fn
將fn做爲o的某個臨時屬性m存儲,而後執行m,執行完畢後將m屬性刪除。數組
大體就是這樣:緩存
day.fn = one.sayName day.fn() delete day.fn
因此能夠模擬實現apply和call。閉包
首先來看apply的模擬:app
Function.prototype.applyOne = function() { var context = arguments[0] var args = arguments[1] context.fn = this eval(context.fn(args.join(','))) // args.join(',')返回的是string,因此須要進行一下特殊處理) delete context.fn } one.sayName.applyOne(day, [20]) // Hello, I'm day, and I'm 20 years old
要注意到的是,若this傳入的是null,或者不傳入,則會默認是全局環境,而且apply是有返回值的。dom
Function.prototype.applyTwo = function() { var context = arguments[0] || window var args = arguments[1] context.fn = this if (args == void 0) { return context.fn() } var result = eval(context.fn(args.join(','))) // args.join(',')返回的是string,因此須要進行一下特殊處理 delete context.fn return result } var name = "oneday" var one = { name: 'one', sayName: function(age) { console.log(`Hello, I'm ${this.name}, and I'm ${age} years old`) } } var day = { name: 'day' } one.sayName.applyTwo(null, [20]) // Hello, I'm oneday, and I'm 20 years old
emmmm...有一個問題就是萬一context裏面原本就有fn屬性怎麼辦呢...對於es6而言,能夠將fn設置爲一個獨特的Symbol值,以下:函數
var fn1 = Symbol('aaa') var fn2 = Symbol('aaa') fn1 == fn2 // false
可是畢竟symbol是es6的特性啊,因此在es5中可使用產生隨機數的方法,例如:
var fn1 = 'o' + Math.random() var fn2 = 'o' + Math.random()
接下來就是apply:
Function.prototype.callOne = function() { var context = [].shift.applyTwo(arguments) var args = [].slice.applyTwo(arguments) // 將剩下的參數做爲數組傳入啊 return this.applyTwo(context, args) }
emmmm...第一個參數就是arguments的第一個(通常是this,或者沒有),後面的參數就做爲數組形式傳入。
bind方法建立一個新的函數,當被調用時,this值是傳遞給bind的第一個參數,它的參數是bind其餘的參數和其本來的參數,返回的是由指定的this值和初始化參數改造的原函數拷貝。
fun.bind(thisArg[, arg1[, arg2[, ...]]])
實例:
var name = '2333' function Person(name) { this.name = name this.sayName = function() { setTimeout(function() { console.log(`Hello, I'm ${this.name}`) }, 1000) } } var oneday = new Person('1111') oneday.sayName() // Hello, I'm 2333
可是下面這樣就是1111~
this.sayName = function() { setTimeout(function() { console.log(`Hello, I'm ${this.name}`) }.bind(this), 1000) } var oneday = new Person('1111') oneday.sayName() // Hello, I'm 1111
並且還有偏函數(Partial Functions),在mdn中是這麼說的:
bind()
的另外一個最簡單的用法是使一個函數擁有預設的初始參數。這些參數做爲bind()
的第二個參數跟在this後面,以後它們會被插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們的後面。
emmmm...對呀沒看懂,因而就看例子啊...
function list() { return Array.prototype.slice.call(arguments) } var list1 = list(1, 2, 3) // [1, 2, 3] // 因此listFun是擁有預設參數(5, 6)的,做爲預設參數跟在第一個參數this後面 var listFun = list.bind(undefined, 5, 6) // 後面傳入的參數會跟在預設參數的後面 var list2 = listFun(7) // [5, 6, 7] var list3 = listFun(8, 9) // [5, 6, 8, 9]
bind的模擬實現:
Function.prototype.bindOne = function() { var me = this // 緩存this var argArray = Array.prototype.slice.call(arguments, 1) return function() { return me.apply(arguments[0], argArray) } }
可是上述的沒有實現繼續傳參能夠添加到原參數後的功能...因此有了第二版
Function.prototype.bindTwo = function() { var context = arguments[0] var me = this var argArray = Array.prototype.slice.call(arguments, 1) return function() { var innerArgs = Array.prototype.slice.call(arguments) var finalArgs = argArray.concat(innerArgs) return me.apply(context, finalArgs) } }
bind返回的函數若是做爲構造函數,這個構造函數搭配new關鍵字出現的話,bind綁定的this須要被忽略,可是參數還要繼續傳入。意思就是bind的綁定比new的優先級要低。並且要在函數體內判斷調用bind方法的必定要是一個函數。
複習一下new的做用:
var obj = {} obj.__proto__ = Base.prototype Base.call(obj)
Function.prototype.bindThree = function() { if (typeof this !== 'function') { throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable') } // context指要把this綁定到的目標函數 var context = arguments[0] // 這裏的this指向調用bind的函數 var me = this var argArray = Array.prototype.slice.call(arguments, 1) var F = function() {} F.prototype = this.prototype var bound = function() { var innerArgs = Array.prototype.slice.call(arguments) var finalArgs = argArray.concat(innerArgs) // 若是調用bind的函數是F的實例,那麼this就仍是指向調用bind的函數,若是不是F的實例,那麼this就進行改變 return me.apply(this instanceof F ? this : context, finalArgs) } bound.prototype = new F() return bound }