返回信息流如图。
这是一条镜像帖。来源:北邮人论坛 / www-technology / #35295同步于 2016/4/7
该镜像源已超过 30 天没有更新,可能在源站已被删除。
WWWTechnology机器人发帖
啥叫做js解绑定包装器?有啥用?
ztinpn
2016/4/7镜像同步11 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
这个好像是用来函数之间传递参数的,然后call和apply这种是用来调用别的方法,动态改变某个类的某个方法的运行环境,apply还有一个妙用是用来将数组变成一个一个参数。解绑定?解arguments类数组?还是解这个方法的运行环境?不懂帮顶
发自「贵邮」
看背景颜色就看出来是 js garden, 哈哈
我觉得是翻译有些问题吧,至少和原版不一样,而且用例也改了. 给你贴一下这部分的原文, 主要是译者注上边的那段
Another trick is to use both `call` and `apply` together to turn methods - functions that use the
value of `this` as well as their arguments - into normal functions which only use their arguments.
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullname = function(joiner, options) {
options = options || { order: "western" };
var first = options.order === "western" ? this.first : this.last;
var last = options.order === "western" ? this.last : this.first;
return first + (joiner || " ") + last;
};
// Create an unbound version of "fullname", usable on any object with 'first'
// and 'last' properties passed as the first argument. This wrapper will
// not need to change if fullname changes in number or order of arguments.
Person.fullname = function() {
// Result: Person.prototype.fullname.call(this, joiner, ..., argN);
return Function.call.apply(Person.prototype.fullname, arguments);
};
var grace = new Person("Grace", "Hopper");
// 'Grace Hopper'
grace.fullname();
// 'Turing, Alan'
Person.fullname({ first: "Alan", last: "Turing" }, ", ", { order: "eastern" });
我也不是完全的理解这段代码, 大概的意思就是实现了最后两行的功能. 在最后一行调用方式里,第一个参数传进去后,最后被 .call.apply 那句执行, 调用后 somehow 就在那个 prototype.fullname 里能读出来是 this
"解绑定包装器" 的意思我的理解就是把本来用 this 的函数实现不使用 this. 也就是上边我贴的原文的开头那两行的说法.
我觉得我好想明白了.
grace.fullname() 没有什么特别,用 prototype 里边的 fullname(), 里边使用 this 来指代
Person.fullname(...) 想做的事情就是, 利用 apply/call 能传 context 的特性, 把 this 传进去. 但是这个例子的特别之处是在于不是传进去一个已有的某个 context(this), 而是传进去一个自己写的 object ({first: Alan, last: Turing}). (因为this 本身也是 object, 所以参数自己写个 object 也没啥问题)
这样当这个自己写的 object 用 apply 传进去以后, 执行了本来的 prototype.fullname(), 正常从这个传进来的 this (就是 alan turing)里读出来 this.first 和 this.last ,加上其他的内容返回全名.
整个代码最复杂的觉得是这句
return Function.call.apply(Person.prototype.fullname, arguments);
这句的神奇之处就是"译者注"的部分. 不过我查了 MDN, 没有查到 Function constructor 上可以用 call, 也没有查到 call.apply 的文档,希望有人能给出来. 暂且就相信译者说的了.
从这个代码的实现和译者注,这句代码的作用就是分解了 arguments.
整个Person.fullname 执行的时候,参数是3个, 也就是上边的这个 arguments 是包含了我们的 object, 以及后边两个控制名字格式的参数.
Function.call.apply(Person.prototype.fullname, arguments); 做到的是 Person.prototype.fullname.apply(arguments里的第一个参数- object, 其他参数) 也就是译者注说的.
译者注那里的第一行 Array.prototype.slice.call(arguments); 是因为 arguments 不是真的是一个 array. (arguments这个章节开头有详细说明)
我感觉我写的乱七八糟的...
感谢!今天我再研究下。欢迎加群:
【 在 AlstonLYG (AlstonLYG) 的大作中提到: 】
: 我觉得我好想明白了.
: grace.fullname() 没有什么特别,用 prototype 里边的 fullname(), 里边使用 this 来指代
: ...................
Function.call.apply(Person.prototype.fullname, arguments)这句我的理解是:
将函数的call方法用apply方法指定到Person.prototype.fullname环境里执行。
apply方法会将arguments数组当做参数传给call方法,而call方法的第一个参数就是调用call方法的函数的执行环境,即this,在这里就是arguments[0]。
解绑定?包装器?这俩啥意思啊
【 在 yunbiquan (SICE敢死队||有理想敢担当勇创新) 的大作中提到: 】
: Function.call.apply(Person.prototype.fullname, arguments)这句我的理解是:
: 将函数的call方法用apply方法指定到Person.prototype.fullname环境里执行。
: apply方法会将arguments数组当做参数传给call方法,而call方法的第一个参数就是调用call方法的函数的执行环境,即this,在这里就是arguments[0]。
我觉得你可以试一下你的猜想。。。
比如:Function.prototype.call==Function.call
这两个方法是一个指向。。。
类似这两个也是。。Function.prototype.call.__proto__==Function.prototype
所以call和apply就能按照你的想法理解了。。。
我还有一点见解是 one.prototype.method.call(o,args)==o.method(args)的话,
前提是o是one的一个实例。
或者o的原型链上有method方法?
类似 [].push.call(arr1,arr2)==arr1.push(...arr2)
不知道这个结论是否正确。
【 在 AlstonLYG 的大作中提到: 】
: 我觉得我好想明白了.
: grace.fullname() 没有什么特别,用 prototype 里边的 fullname(), 里边使用 this 来指代
: Person.fullname(...) 想做的事情就是, 利用 apply/call 能传 context 的特性, 把 this 传进去. 但是这个例子的特别之处是在于不是传进去一个已有的某个 context(this), 而是传进去一个自己写的 object ({first: Alan, last: Turing}). (因为this 本身也是 object, 所以参数自己写个 object 也没啥问题)
: ...................
我说下我的理解哈,举个例子吧
Array.prototype.get2nd = function () {
return this[1]
}
在Array的prototype上添加一个函数get2nd,获取数组的第二个元素,正常情况下我可以这么用:
var a = [1,2,3,4,5]
console.log( a.get2nd() ) // 2
要是我想把这个函数用在arguments上,就得这样:
var func = function () {
return Array.prototype.get2nd.call(arguments)
}
console.log( func(1,2,3) ) // 2
代码里的那一长串很不好看,我想把它封装一层,可以这样做:
Array.get2nd = function () {
var args = Array.prototype.slice.call(arguments);
return Array.prototype.get2nd.apply(args[0], args.slice(1));
}
然后使用的时候就是这样的:
var func = function () {
return Array.get2nd(arguments)
}
console.log( func(1,2,3) ) // 2
上面代码里的Array.get2nd就是《JavaScript秘密花园》里所说的 解绑定包装器,本来Array.prototype.get2nd正常使用是用在Array对象上的,即this绑定的是Array对象,而包装后的Array.get2nd可以用在任何 类数组 的元素上,就比如上面提到的arguments,即this可以为我想指定的任何变量
以上是我自己的理解,有什么地方不妥,一起讨论哈~~
【 在 ztinpn 的大作中提到: 】
: 如图。