[JS]JS中call/apply/bind方法总结
来源:互联网 发布:mysql 重启 编辑:程序博客网 时间:2024/05/20 12:24
JavaScript的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
在JavaScript中,call和apply都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部this的指向。bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。
call,apply,bind这三个方法其实都是继承自Function.prototype中的,属于实例方法。
call方法的一个应用是调用对象的原生方法。也可以用于将类数组对象转换为数组。
对于apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样
3.apply的应用有--将数组的空元素变为undefined
通过apply方法,利用Array构造函数将数组的空元素变成undefined。
bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。
在JavaScript中,call和apply都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部this的指向。bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。
call/apply/bind常常用于继承和回调函数(指定函数的执行作用域)。
在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它。
call/apply/bind方法的来源
首先,在使用call,apply,bind方法时,我们有必要知道这三个方法究竟是来自哪里?为什么可以使用的到这三个方法?call,apply,bind这三个方法其实都是继承自Function.prototype中的,属于实例方法。
console.log(Function.prototype.hasOwnProperty('call')) //trueconsole.log(Function.prototype.hasOwnProperty('apply')) //trueconsole.log(Function.prototype.hasOwnProperty('bind')) //true上面代码中,都返回了true,表明三种方法都是继承自Function.prototype的。当然,普通的对象,函数,数组都继承了Function.prototype对象中的三个方法,所以这三个方法都可以在对象,数组,函数中使用。
Function.prototype.call()
函数实例的call方法,可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。并且会立即执行该函数。call方法的一个应用是调用对象的原生方法。也可以用于将类数组对象转换为数组。
var obj = {};console.log(obj.hasOwnProperty('toString')); //falseobj.hasOwnProperty = function() { return true;}console.log(obj.hasOwnProperty('toString')); //trueconsole.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); //false
上面代码中,hasOwnProperty是obj对象继承的方法,如果这个方法一旦被覆盖,就不会得到正确结果。call方法可以解决这个方法,它将hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。要注意的是,hasOwnProperty是Object.prototype原生对象的方法,而call是继承自Function.prototype的方法。
继承
function Product(name, price) { this.name = name; this.price = price;}function Food(name, price) { Product.call(this, name, price); this.category = 'food';}//等同于function Food(name, price) { this.name = name; this.price = price; this.category = 'food'; }//function Toy 同上function Toy(name, price) { Product.call(this, name, price); this.category = 'toy';}var feta = new Food('feta', 5);var robot = new Toy('robot', 40);console.log(feta);//Food { name: 'feta', price: 5, category: 'food' }console.log(robot);//Toy { name: 'robot', price: 40, category: 'toy' }多重继承
var s1 = function(name){ this.name = name;}var s2 = function(sex){ this.sex = sex;}var s3 = function(age){ this.age = age;}var Student = function(name,sex,age,score){ s1.call(this,name); s2.call(this,sex); s3.call(this,age); this.score = score;}Student.prototype.construction = Student;var s = new Student('jack','male','12','100');console.log(s.name); //输出:jackconsole.log(s.sex); //输出:male console.log(s.age); //输出:12console.log(s.score);//输出:100console.log(s instanceof Student);//输出:true
Function.prototype.apply()
apply方法的作用与call方法类似,也是改变this指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数。同时也会立即执行该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。对于apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样
function keith(a, b) { console.log(a + b);}keith.call(null, 2, 3); //5keith.apply(null, [2, 3]); //51、apply的应用有--数组之间追加
var array1 = [12 , "foo" , {name:"Joe"} , -2458];var array2 = ["Doe" , 555 , 100];Array.prototype.push.apply(array1, array2);console.log(array1) //[ 12, 'foo', { name: 'Joe' }, -2458, 'Doe', 555, 100 ]console.log(array2) //[ 'Doe', 555, 100 ]2、apply的应用有--获取数组中的最大值和最小值
var numbers = [5, 458 , 120 , -215 ];var maxInNumbers = Math.max.apply(Math, numbers); console.log(maxInNumbers) //458maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215);console.log(maxInNumbers) //458Javascript中是没有提供找出数组中最大值的方法的,结合使用继承自Function.prototype的apply和Math.max方法,就可以返回数组的最大值。
3.apply的应用有--将数组的空元素变为undefined
通过apply方法,利用Array构造函数将数组的空元素变成undefined。
console.log(Array.apply(null, [1, , 3])); // [1, undefined, 3]空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined和null。因此,遍历内部元素的时候,会得到不同的结果。
var a = [1, , 3];a.forEach(function(index) { console.log(index); //1,3 ,跳过了空元素。})Array.apply(null,a).forEach(function(index){ console.log(index); ////1,undefined,3 ,将空元素设置为undefined})Function.prototype.bind()
bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。
var keith = { a: 1, count: function() { console.log(this.a++); }};var f = keith.count.bind(keith);f(); //1f(); //2var obj = {a : 5}f.call(obj);//3,说明bind是作用于执行时的上下文,而不是定义是的上下文
var bar = function(){ console.log(this.x);}var foo = { x:3}var sed = { x:4}var func = bar.bind(foo).bind(sed);func(); //? var fiv = { x:5}var func = bar.bind(foo).bind(sed).bind(fiv);func(); //?
答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于在包中再包了第一次 bind() ,故第二次以后的 bind 是无法生效的。
function f(a,b,c){ console.log(a,b,c);}var f_Extend = f.bind(null,"extend_A")f("A","B","C") //--> A B Cf_Extend("A","B","C") //--> extend_A A Bf_Extend("B","C") //--> extend_A B Cf.call(null,"extend_A") //--> extend_A undefined undefined这个区别不是很好理解,call是把第二个及以后的参数作为f方法的实参传进去,而bind虽说也是获取第二个及以后的参数用于之后方法的执行,但是f_Extend中传入的实参则是在bind中传入参数的基础上往后排的。
//这句代码相当于以下的操作var f_Extend = f.bind(null,"extend_A")f_Extend(4,5);//extend_A 4 5//↓↓↓var f_Extend = function(b,c){ return f.call(null,"extend_A",b,c);}f_Extend(4,5);//extend_A 4 5
总结一下call/apply/bind方法
- 第一个参数都是指定函数内部中this的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。
- 都可以在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。
- call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。
0 0
- [JS]JS中call/apply/bind方法总结
- js中bind、call、apply方法详解
- js中call、apply、bind方法
- JS call bind apply
- js中bind、call、apply的方法使用
- 关于js中call、apply、bind方法的区别
- js中call()、apply()、bind()方法的区别
- js function call,apply,bind方法
- JS中的call、apply、bind方法
- JS中的call、apply、bind方法
- JS中的call、apply、bind方法
- JS中的call、apply、bind方法详解
- 理解JS中的call、apply、bind方法
- JS中的call、apply、bind方法
- JS中的call、apply、bind方法
- 理解JS中的call、apply、bind方法
- 理解JS中的call、apply、bind方法
- 理解JS中的call、apply、bind方法
- 【SQL查询】集合查询之INTERSECT
- java web 前端开发框架和流程
- Java switch-case 语句的优点和几点注意事项
- 组合模式(Composite)
- ELM实验思路
- [JS]JS中call/apply/bind方法总结
- Fragment常用操作的生命周期切换展示
- 第十四周项目3折腾二维数组
- 判断母字符串是否含子字符串。
- Unity3D 项目架构基础(一)U3D简单状态机模式
- 欢迎使用CSDN-markdown编辑器
- idea 快捷键
- 安卓开发学习笔记(5):view
- 关于myeclipes打代码时候下面出现黄线的问题