一个 前端知识点汇总综合了学习过程当中的知识点,好比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 }