一:call、apply、bind
call是一个方法,函数的方法,可以调用函数,可以改变函数的指向
function.call(thisArg, arg1, arg2, ...)
dog.eat.call(cat,'鱼','肉') dog.eat.apply(cat,['鱼','肉']) // 参数不同,带数组的 dog.eat.bind(cat,'鱼','肉')() // call会执行,bind不会执行,需要调用一下
call() 方法接受的是一个参数列表,
apply() 方法接受的是一个包含多个参数的数组。
bind()方法需要调用才会执行
call、apply、bind 应用
继承 子类继承父类的方法,可以实现多重继承
function Animal(name, price) {
this.eat = function () {
console.log('eating')
}
}
function Bird(){
fly()
}
function Cat(name, price) {
Animal.call(this)
Bird.call(this)
}
let c = new Cat
c.eat()
c.fly() // 多重继承
手写实现
思考,call从哪里来的
js函数其实都是Function对象,Function对象是构造函数,构造函数是有原型对象的Function.prototype,里面有call属性,同时也是一个方法,其实就是个函数而已,
模仿自己写的话,就业再原型对象里面新加newCall属性
function person(a,b,c){
// console.log(this.name)
// console.log(a,b,c)
return {
name:this.name,
a:a,
b:b,
c:c
}
}
let egg = {name :"xixixi"}
Function.prototype.newCall = function(obj){
console.log('obj',obj) //{name :"xixixi"}
var obj = obj||window // 如果第一个参数没有传,或者是null的话,就指向window,要不然会报错
console.log(this) // 这里的this指向的是函数person,谁调用就指向谁
obj.p = this //Obj是第一个参数 所以这块改变this
let newArguments = [];
for(let i=1;i<arguments.length;i++){ //i=1 从索引是1开始,因为索引=0的第一个参数是this
// newArguments.push(arguments[i])
newArguments.push('arguments['+i+']') // 用eval实现,需要字符串拼接
}
console.log('newArguments',newArguments)
// obj.p(newArguments)
//这里数组相当于第一个参数了,所以 console.log(a,b,c)输出的值是
//['aaa', 'bbb', 'cccc'] undefined undefined
//不要for循环,因为不确定argument的长度,会重复调用,
//导致其他的比如console.log(this.name)重复输出
// 想用eval的来实现obj.p(newArguments)
//要改成eval('obj.p('newArguments[0]','newArguments[1]','[newArguments[2]]')')
//所以push的时候要字符串拼接;
let res = eval('obj.p('+newArguments+')')
delete obj.p //是因为不能改变原有的数据,所以加了之后 还得删掉
return res
}
var xili = person.newCall(egg,'aaa','bbb','cccc')
console.log('xili--',xili)
这个是按照上面修改的apply,差别就是参数的处理,这个没有加返回值,加上之后就是上面那种,带return的
Function.prototype.newApply = function(obj,arr){
var obj = obj||window
obj.p = this
if(!arr){
obj.p()
} else {
let newArguments = [];
for(let i=0;i<arr.length;i++){ //i=0 从索引是0开始,因为是全部元素
newArguments.push('arr['+i+']') // 用eval实现,需要字符串拼接
}
eval('obj.p('+newArguments+')')
}
delete obj.p
}
person.newApply(egg,['aaa','bbb','cccc'])
Bind
// bind
function person(a,b,c){
console.log('name==',this.name)
console.log('a====',a)
console.log('b====',b)
console.log('c====',c)
}
let egg = {name :"xixixi"}
Function.prototype.newBind = function(obj){
let that = this
arr = Array.prototype.slice.call(arguments,1) //切割第一个参数
console.log('arr==',arr) // ['aaa', 'bbb', 'cccc']
console.log('arguments111',arguments) //[ {name :"xixixi"},['aaa','bbb','cccc']] 是newBind第一个括号的参数
return function(){
console.log('arguments222',arguments) // "ddd" 是newBind第二个括号的参数
let arr2 = Array.prototype.slice.call(arguments)
console.log('arr2===',arr2)// ['ddd']
arrSum = arr.concat(arr2)
console.log('arrSum===',arrSum) // ['aaa', 'bbb', 'cccc', 'ddd']
that.apply(obj, arrSum)
}
}
person.newBind(egg,'aaa','bbb','cccc')('ddd')
Bind进阶 配合new使用
参考学习视频 技术蛋老师15:00 实在听不懂,等进步了,再回来
// bind 进阶 new
function person(a,b,c){
console.log('name==',this.name)
console.log('a====',a)
console.log('b====',b)
console.log('c====',c)
}
person.prototype.pppp = 'pppp'
let egg = {name :"xixixi"}
Function.prototype.newBind = function(obj){
let that = this
arr = Array.prototype.slice.call(arguments,1) //切割第一个参数
return function(){
let arr2 = Array.prototype.slice.call(arguments)
arrSum = arr.concat(arr2)
that.apply(obj, arrSum)
}
}
let cici = person.newBind(egg,'aaa','bbb','cccc')
let ci = new cici('ci');
console.log('ci.pppp',ci.pppp)