We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向
call
apply
先看个常用例子
var foo = { value: 1 }; function bar() { console.log(this.value); } bar.call(foo); // 1
试想下,是不是可以先把bar变成foo对象的属性,执行完后再删除它呢?
var foo = { value: 1, bar: function() { console.log(this.value); } }; foo.bar(); // 1 delete foo.bar;
总结一下步骤
Function.prototype.myCall = function(context) { // 取得传入的对象(执行上下文),比如上文的foo对象 // 不传第一个参数,默认是window, var context = context || window; // 给context添加一个属性,这时的this指向调用call的函数,比如上文的bar context.fn = this; // 通过展开运算符和解构赋值取出context后面的参数 var args = [...arguments].slice(1); // 执行函数 var result = context.fn(...args); // 删除函数 delete context.fn; return result; };
思路跟call一样,只是在处理参数的时候有点不一样
Function.prototype.myApply = function(context) { var context = context || window; context.fn = this; var result; // 判断第二个参数是否存在,是一个数组 // 如果存在,则需要展开第二个参数 if (arguments[1]) { result = context.fn(...arguments[1]); } else { result = context.fn(); } delete context.fn; return result; }
思路和作用基本一致,区别在于返回一个函数,并且可以通过bind实现柯里化
bind
Function.prototype.myBind = function(context) { if (typeof this !== 'function') { throw new TypeError('Error'); } var _this = this; var args = [...arguments].slice(1); // 返回函数 return function Fn() { // bind有个特点 一个绑定函数也能使用new操作符创建对象 if (this instanceof Fn) { return new _this(args, ...arguments); } return _this.apply(context, args.concat(arguments)); } }
var arr1 = [1, 2, { id: 1, id: 2 }, [1, 2]]; var arr2 = ['ds', 1, 9, { name: 'jack' }]; // var arr = arr1.concat(arr2); Array.prototype.push.apply(arr1,arr2)
var numbers = [ 5, 458 , 120 , -215 ]; var maxInNumbers = Math .max .apply (Math , numbers), //458 maxInNumbers = Math. max. call( Math, 5, 458 , 120 , -215 ); //458
function isArray(obj) { return Object.prototype.toString.call(obj) == '[object Array]' } isArray([]) //true
var toString = Object.prototype.toString; toString.call(new Date); // [object Date] toString.call(new String); // [object String] toString.call(Math); // [object Math] //Since JavaScript 1.8.5 toString.call(undefined); // [object Undefined] toString.call(null); // [object Null]
首先,何为类数组? 1、拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解) 2、不具有数组所具有的方法
常见类数组 1、arguments 2、DOM 对象列表(比如通过 document.getElementsByTags 得到的列表),jQuery 对象(比如 $("div"))
通过call/apply,使用数组原生方法操作类数组 先定义一个类数组 var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 }; 操作
var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };
var newArray = Array.prototype.slice.call(anArrayLikeObj, 0); console.log(newArray); // ["Martin", 78, 67, Array[3]] // Search for "Martin" in the array-like object console.log(Array.prototype.indexOf.call(anArrayLikeObj, "Martin") === -1 ? false : true); // true // Try using an Array method without the call () or apply () console.log(anArrayLikeObj.indexOf("Martin") === -1 ? false : true); // Error: Object has no method 'indexOf' // Reverse the object: console.log(Array.prototype.reverse.call(anArrayLikeObj)); // {0: Array[3], 1: 67, 2: 78, 3: "Martin", length: 4} // Sweet. We can pop too: console.log(Array.prototype.pop.call(anArrayLikeObj)); console.log(anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, length: 3} // What about push? console.log(Array.prototype.push.call(anArrayLikeObj, "Jackie")); console.log(anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, 3: "Jackie", length: 4}
slice:提取字符串的某个部分,并以新的字符串返回被提取的部分
function transitionTo(name) { var args = Array.prototype.slice.call(arguments, 1, 3); return args; } transitionTo("contact", "Today", "20","hh","ghh"); //["Today", "20"]
感谢您耐心看到这里,希望有所收获!
如果不是很忙的话,麻烦右上角点个star⭐,举手之劳,却是对作者莫大的鼓励。
我在学习过程中喜欢做记录,分享的是自己在前端之路上的一些积累和思考,希望能跟大家一起交流与进步,更多文章请看【amandakelake的Github博客】
The text was updated successfully, but these errors were encountered:
模拟bind那个里面的代码typeof中间多了一个空格
Sorry, something went wrong.
@wangyicong thanks
Function.prototype.myBind = function(context) { if (typeof this !== 'function') { throw new TypeError('Error'); } var _this = this; var args = [...arguments].slice(1); return function Fn() { if (this instanceof Fn) { // 这里 `args` 是不是要解构一下, 否则第一个参数变成数组了 return new _this(args, ...arguments); } // 这里 arguments 是不是也要解构以下,否则会保存 // arguments // 如果 args是, 1,2,3, arguments是 4,5,6,打印如下 // 1 2 3 Arguments(3) [4, 5, 6, callee: ƒ, Symbol(Symbol.iterator): ƒ] return _this.apply(context, args.concat(arguments)); } }
No branches or pull requests
call
和apply
都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向一、模拟思路
先看个常用例子
试想下,是不是可以先把bar变成foo对象的属性,执行完后再删除它呢?
总结一下步骤
二、模拟call
三、模拟apply
思路跟
call
一样,只是在处理参数的时候有点不一样四、模拟bind
思路和作用基本一致,区别在于返回一个函数,并且可以通过
bind
实现柯里化五、三者区别
相同点
不同
六、常见用法
1、合并数组
2、获取最大最小值
3、判断变量类型
4、操作类数组
首先,何为类数组?
1、拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解)
2、不具有数组所具有的方法
常见类数组
1、arguments
2、DOM 对象列表(比如通过 document.getElementsByTags 得到的列表),jQuery 对象(比如 $("div"))
通过call/apply,使用数组原生方法操作类数组
先定义一个类数组
var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };
操作
5、提取arguments参数
slice:提取字符串的某个部分,并以新的字符串返回被提取的部分
后记
感谢您耐心看到这里,希望有所收获!
如果不是很忙的话,麻烦右上角点个star⭐,举手之劳,却是对作者莫大的鼓励。
我在学习过程中喜欢做记录,分享的是自己在前端之路上的一些积累和思考,希望能跟大家一起交流与进步,更多文章请看【amandakelake的Github博客】
The text was updated successfully, but these errors were encountered: