影视网站设计论文,重庆永川网站建设报价,wordpress头像存储,东莞快速建站平台在第一部分中#xff0c;主要总结了函数作为一个对象的常见属性#xff08;name/length#xff09;、如何自定义属性以及如何使用函数构造器#xff08;Function#xff09;。
这里总结函数作为对象的常见方法#xff08;apply/call/bind/toString#xff09;。 使用 c…在第一部分中主要总结了函数作为一个对象的常见属性name/length、如何自定义属性以及如何使用函数构造器Function。
这里总结函数作为对象的常见方法apply/call/bind/toString。 使用 call 绑定 this
call 方法指定 this 并且逐个提供参数。
基本语法
thisArg调用 f 时指定的 this 值 非严格模式下null/undefined 将被替换为全局对象原始值String/Number/...将被转换为对象 arg1, arg2, /* …, */ argN 函数的参数逐个传入。
f.call(thisArg)
f.call(thisArg, arg1)
f.call(thisArg, arg1, arg2)
f.call(thisArg, arg1, arg2, /* …, */ argN)简单案例
下面一个案例普通调用时this 指向全局call 调用时this 指向具体对象。
function log() {console.log(this.xxx);console.log(this);
}
let o { xxx: 100, yyy: 200 }log(); // undefined或其他globalThis.xxx - globalThis/Window
log.call(o) // 100 - { xxx: 100, yyy: 200 }
log.call() // undefined或其他globalThis.xxx - globalThis/Window
log.call(null) // undefined或其他globalThis.xxx - globalThis/Window上面的例子中undefined/null 将转换成全局对象但在严格模式下
use strict
function log() {console.log(this);
}log.call() // undefined
log.call(null) // null借用方法
一个对象的方法给另外一个对象使用。达到目的方案如下
直接通过对象调用并且通过 call 指定其他的对象先将方法赋值成为一个函数在通过 call 的调用指定其他的对象先将方法赋值成为一个函数并对 call 进行自绑定。
const cat {name: Kitty,showName () { console.log(this.name); }
}
const dog {name: 阿旺
}cat.showName.call(dog) // 阿旺let showName cat.showName
showName.call(dog) // 阿旺let boundedShowName showName.call.bind(showName)
boundedShowName(dog) // 阿旺对象原型链上的方法也可以借用。下面一个例子中借用数组原型链上的切片方法。
let arr [1, 2, 3, 4];
const slice Array.prototype.slice;
const boundedSlice slice.call.bind(slice);slice.call(arr, 1) // [2, 3, 4]
boundedSlice(arr, 1) // [2, 3, 4]apply 方法
apply 和 call 方法能够达到几乎等效目的。
基本语法
thisArg调用 f 时指定的 this 值 非严格模式下null/undefined 将被替换为全局对象原始值String/Number/...将被转换为对象 argsArray类数组对象调用 f 时的参数或者如果不需要向函数提供参数则为 null/undefined。
f.apply(thisArg)
f.apply(thisArg, argsArray)apply VS call
大多数情况下使用 call 或 apply 均可apply 可能会更快因为大多数 JS 引擎在内部对其进行了优化。下面一个等效表达中
arr 期望是一个类数组对象itor 期望是一个可迭代对象。
f.apply(thisArg, arr)
f.call(thisArg, ...itor)可以看出apply/call 两者几乎相同不同的是参数方式参数在 call() 中逐个作为列表传递而在 apply() 中它们会组合在一个类数组对象中。
Math.max.apply(null, [1, 3, 5]) // 5
Math.max.call(null, 1, 3, 2) // 3简单案例
下面一个例子中在一个数组后添加若干元素。
let arr [a, b];
arr.push.apply(arr, [0, 1, 2]);
arr // [a, b, 0, 1, 2]arr.push.call(arr, 3, 4)
arr // [a, b, 0, 1, 2, 3, 4]arr.push(arr, ...[5, 6])
arr // [a, b, 0, 1, 2, 3, 4, 5, 6]呼叫转移
将所有参数、上下文一起传递给另一个函数被称为“呼叫转移”。下面是一种最简单的表达在外部看来 f() 和 w() 没有声明区别。
function f() { console.log(arguments[0]) }
function w() { f.apply(this, arguments) }f() // 1
w() // 1使用 bind 创建一个 Bounded Function - 绑定函数
bind 方法创建一个新函数当调用该新函数时它会调用原始函数目标函数-Target Function
将其 this 上下文绑定为指定值同时还可以绑定一系列参数会插到新函数传入参数的前面。
基本语法
thisArg调用绑定函数给原始函数 f 时指定的 this 值 非严格模式下null/undefined 将被替换为全局对象原始值String/Number/...将被转换为对象如果使用 new 创建绑定函数忽略该值 arg1, arg2, /* …, */ argN在调用原始函数 f 时逐个插入到传入绑定函数的参数前的参数。。
f.bind(thisArg)
f.bind(thisArg, arg1)
f.bind(thisArg, arg1, arg2)
f.bind(thisArg, arg1, arg2, /* …, */ argN)bind 参数的绑定顺序
给函数指定 this 值并不复杂。下面一个案例具体讲述 bind 参数的绑定顺序问题。
boundedFn1 成功地绑定了 this 对象 为一个字符串 xy并且将两个其余参数绑定在调用时 目标函数 fn 的 this 指定为 xy通过 bind 绑定的其他参数插入在目标函数参数列表的前面相当于 fn(a, b, 1, 2)。 boundedFn2 失败地绑定了 this 对象 为一个字符串 xxyy并且将两个其余参数绑定在调用时 目标函数 fn 的 this 指定仍然为 xy因为 boundedFn1 已经是一个绑定函数this 的指定不会被覆盖通过 bind 绑定的其他参数插入在目标函数参数列表的前面以及第一次绑定参数的后面相当于 fn(a, b, c, d, 1, 2)。
function fn(...args) {console.log(this, args.join());
}let boundedFn1 fn.bind(xy, a, b)
boundedFn1(1, 2) // String {xy} ab12let boundedFn2 boundedFn1.bind(xxyy, c, d)
boundedFn2(1, 2) // String {xy} abcd12一般的对于多层绑定函数this 指定是第一层其他参数按照层数依次插入在目标函数的参数列表前面fn(...argsFloor1, /* ... */, argsFloorX, ...args)。
使用 toString 方法获取函数源码字符串
函数作为对象重写了从 Object 继承来的 toString() 方法。toString 方法返回一个包含用于定义函数的源文本段的字符串。对于内置函数、由 bind 创建的绑定函数、非 JavaScript 函数调用 toString()返回一个看起来像原函数的字符串。
function f() {console.log(111)
}f.toString() // function g() { \n console.log(111) \n}
g.bind(null).toString() // function () { [native code] }
Math.max.toString() // function max() { [native code] }实际源代码与 toString() 结果比较
注意toString 方法可以修改。
function f() { }
class A {a() { }
}
function* g() { }f.toString() // function f() { } 普通函数
A.toString() // class A { a() { } } 类
g.toString() // function* g() { } 生成器
((a) a).toString() // (a) a 箭头函数
({ a() {} }.a).toString() // a() {} 方法
({ *a() {} }.a).toString() // *a() {} 生成器方法
({ [x]() {} }[x]).toString()// [x]() {} 计算方法
Function.prototype.toString.toString() // function toString() { [native code] }
f.bind(null).toString() // function () { [native code] }
(Function(a, b)).toString() // function anonymous(a\n) {\nb\n}
(Object.getOwnPropertyDescriptor({ get a() {} }, a).get).toString() // get a() {}
(Object.getOwnPropertyDescriptor({ set a(x) {} }, a).set).toString() // set a(x) {}关于什么的计算方法/属性计算变量不能点式读取。
let [x, y, z] [ad, cc, gg]
let o { [x]: 11, [y]: function() {}, [z] (){} }o.ad // 11
o.cc // f () {}
o.gg // ƒ [z](){}
o[x] // 11
o[y] // f () {}
o[z] // ƒ [z](){}
o.x // undefined
o.y // undefined
o.z // undefined