视频教程-call&&applyhtml
call、apply、bind三者均来自Function.prototype,被设计用来用于改变函数体内this的指向。前端
举个例子node
// 有只猫叫小黑,小黑会吃鱼 const cat = { name: '小黑', eatFish(...args) { console.log('this指向=>', this); console.log('...args', args); console.log(this.name + '吃鱼'); }, } // 有只狗叫大毛,大毛会吃骨头 const dog = { name: '大毛', eatBone(...args) { console.log('this指向=>', this); console.log('...args', args); console.log(this.name + '吃骨头'); }, } console.log('=================== call ========================='); // 有一天大毛想吃鱼了,但是它不知道怎么吃。怎么办?小黑说我吃的时候喂你吃 cat.eatFish.call(dog, '汪汪汪', 'call') // 大毛为了表示感谢,决定下次吃骨头的时候也喂小黑吃 dog.eatBone.call(cat, '喵喵喵', 'call') console.log('=================== apply ========================='); cat.eatFish.apply(dog, ['汪汪汪', 'apply']) dog.eatBone.apply(cat, ['喵喵喵', 'apply']) console.log('=================== bind ========================='); // 有一天他们以为每次吃的时候再喂太麻烦了。干脆直接教对方怎么吃 const test1 = cat.eatFish.bind(dog, '汪汪汪', 'bind') const test2 = dog.eatBone.bind(cat, '喵喵喵', 'bind') test1() test2()
apply() 方法调用一个具备给定this值的函数,以及做为一个数组(或相似数组对象)提供的参数。func.apply(thisArg, [argsArray])
thisArg 可选的参数。在 func 函数运行时使用的 this 值。注意,不必定是该函数执行时真正的 this 值:若是这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),当值为原始值(1,‘string’,true)时 this 会指向该原始值的自动包装对象(Number,String,Boole)。
argsArray 可选的参数。一个数组或者类数组对象(NodeList),其中的数组元素的每一项将做为单独的参数传给 func 函数。若是该参数的值为 null 或 undefined,则表示不须要传入任何参数。从ECMAScript 5 开始可使用类数组对象。segmentfault
妙用一:数组拼接数组
var array = ['a', 'b']; var elements = [0, 1, 2]; array.push.apply(array, elements); console.info(array); // ["a", "b", 0, 1, 2]
解决了想修改原数组,不想用循环,还想传递一个数组的问题浏览器
妙用二:数组求最值app
/* 找出数组中最大/小的数字 */ var numbers = [5, 6, 2, 3, 7]; /* 应用(apply) Math.min/Math.max 内置函数完成 */ var max = Math.max.apply(null, numbers); /* 基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */ var min = Math.min.apply(null, numbers); console.log(max,min)
妙用三:伪数组转换ide
var arrayLike = { 0: 'xiaobai', 1: 'xiaohei', 2: 'xiaohong', length: 3 } var arr = Array.prototype.slice.call(arrayLike); console.log(arr)
妙用四:变量类型判断函数
function isArray(obj) { return Object.prototype.toString.call(obj) == '[object Array]'; } console.log(isArray([])) console.log(isArray('qianduan'))
妙用五:构造继承this
function Animal(name, age) { this.name = name; this.age = age; } function Dog() { Animal.apply(this,['cat','5']); // Animal.call(this, 'cat', '5'); this.say = function() { console.log(this.name + ":" + this.age); } } var dog = new Dog(); dog.say(); //cat:5
new的过程Dog中的this指向了建立的dog对象,而后执行构造函数中的代码,执行了关键的apply,apply将当前环境的this(dog对象)指定给Animal,因此Animal中的this指向的就是dog对象,Animal中定义了name和age属性,就至关于在dog中定义了这些属性,所以dog对象便拥有了Animal中定义的属性,从而达到了继承的目的
call() 方法调用一个函数, 其具备一个指定的this值和分别地提供的参数(参数的列表)。apply的语法糖。fun.call(thisArg, arg1, arg2, ...)
妙用一:调用匿名函数
妙用一:调用匿名函数
兼容严格模式,严格模式下,匿名函数里this会报错。也实现了匿名函数针对不一样的this,作不一样的处理。
妙用二:字符串分隔链接
var temp = Array.prototype.join.call('hellow!', ','); console.log(temp)
字符串没有join方法,借用Array
妙用三:字符串取每一项
Array.prototype.map.call('foo', (item) => { console.log(item) }).join('');
字符串没有join方法,借用Array
bind()方法建立一个新的函数,在调用时设置this关键字为提供的值。并在调用新函数时,将给定参数列表做为原函数的参数序列的前若干项。
function.bind(thisArg[, arg1[, arg2[, ...]]])
解释一下:
ES6新增的方法,这个方法会返回一个新的函数(函数调用的方式),调用新的函数,会将原始函数的方法当作传入对象的方法使用,传入新函数的任何参数也会一并传入原始函数。
基本
function f(x) { console.log(this.a + x); //原始函数 } var obj = { a: 1 //传入对象 } var newFn = f.bind(obj) //会将原始函数的方法当作传入对象的方法使用 newFn(2) //调用新的函数 setTimeout(function() { console.log(this.name + ": Got it!") }.bind(this), 30) daily() { this.enjoy(function() { this.eat() this.drink() this.sleep() }.bind(this)) }
若是使用new运算符构造生成的绑定函数,则忽略绑定的this。
返回函数用做构造函数
function f(x) { this.a = 1; this.b = function() { return this.a + x } } var obj = { a: 10 } var newObj = new(f.bind(obj, 2)) //传入了一个实参2 console.log(newObj.a) //输出 1, 说明返回的函数用做构造函数时obj(this的值)被忽略了 console.log(newObj.b()) //输出3 ,说明传入的实参2传入了原函数original
不传值
window.color = 'red'; function sayColor(){ console.log(this.color); } var func2 = sayColor.bind();//this同理 // 输出 "red", 由于传的是'',全局做用域中this表明window。等于传的是window。 func2();
屡次bind会发生什么?
在Javascript中,屡次 bind() 是无效的。更深层次的缘由, bind() 的实现,至关于使用函数在内部包了一个 call / apply ,第二次 bind() 至关于再包住第一次 bind() ,故第二次之后的 bind 是没法生效的。
屡次绑定
function say() { console.log(this.x); }; var a = say.bind({x: 1}); var b = a.bind({x: 2}); b() var a = function() { return say.apply({x: 1}); //改变say的this }; var b = function() { return a.apply({x: 2}); //改变了a的this };
妙用一:偏函数(使一个函数拥有预设的初始参数)
//在绑定this的同事传入几个值做为默认参数,以后执行时再传入的参数排在默认参数后面。 const obj = {} function f(...args) {console.log(args)} const newFn = f.bind(obj, '1', '2') newFn('3', '4') function add(arg1, arg2) { return arg1 + arg2 } // 建立一个函数,它拥有预设的第一个参数 var addThirtySeven = add.bind(null, 37); var result3 = addThirtySeven(5, 10); console.log(result3) // 37 + 5 = 42 ,第二个参数被忽略
妙用二:快捷调用
<div class="test">hello</div> <div class="test">hello</div> <div class="test">hello</div> <div class="test">hello</div> <script> function log() { console.log("hello") } //const forEach = Array.prototype.forEach //forEach.call(document.querySelectorAll(".test"), (test) => test.addEventListener("click", log)) const unbindForEach = Array.prototype.forEach, forEach = Function.prototype.call.bind(unbindForEach) forEach(document.querySelectorAll(".test"), (test) => test.addEventListener("click", log)) </script>
何时是用什么方法
原始高清视频下载
QQ答疑交流群:
600633658
咱们的连接: