刷题-5 bind 相关问题
题目1
function f() {
console.log(this);
}
let f1 = f.bind(1).bind(2)
f1()
解析:
- bind 基本实现(不完整)
Function.prototype.bind = function (thisArg) {
var _this = this
return function () {
_this.apply(thisArg)
}
}
-
bind 原理:
bind的原理, bind的作用是永久改变一个函数执行过程中的this,它的基本实现 bind的执行不会立即执行需要改变this指向的函数 bind执行后返回一个新函数 新函数调用会间接调用源函数来实现源函数的执行 函数执行过程中通过apply(apply、call)把this指向thisArg 闭包: 内层函数可以访问外层数据 内层:return 后面的函数 外层:bind函数阻止垃圾回收, 所以即使bind已经执行完成了,但是因为return的函数被外部引用, 所以bind中的thisArg并没有被回收, 这样后续无论什么时候调用return出去的函数都能访问到thisArg -
所以:
function f() {
console.log(this);
}
let f1 = f.bind(1).bind(2);
f1();
// 其实可以看成下面的调用
let temp = f.bind(1);
let f1 = temp.bind(2);
f1();
首先 temp 是 f.bind(1) 的结果
temp = function(1) {
// 这里的 thisArg = 1
function() {
f.apply(1);
}
}
//也就是temp调用的时候接收了一个1的参数,然后间接的调用了f,并把f的this指向了temp的参数1
//然后 let f1 = temp.bind(2) 执行以后 f1 代码
f1 = function(2) {
// 这里的 thisArg = 2
function() {
temp.apply(2);
}
}
// f1调用的时候接收了一个2的参数,然后间接的调用了temp,并把temp的this指向了2
- 重点:
其实这里特别注意的是其实f1调用了temp并确实改了temp的this为2,但是这里是没有调用最开始的f的,而是temp.apply(2)的时候再去调用的f.apply(2),所以无论中间有多少层bind,最后那个f调用永远都是最开始的1
let temp = f.bind(1);
let f1 = temp.bind(2);
let f2 = f1.bind(3);
let f3 = f2.bind(4);
let f4 = f3.bind(5);
f4();
f4() => f3.apply(5) => f2.apply(4) => f1.apply(3) => temp.apply(2)=>f.apply(1)
就是bind一次包一层函数,每一次都有自己的this指向,最后一次执行的也就是最开始bind的才会执行初始绑定的函数,改变它的this.
题目 2
function f() {
console.log(typeof this);
}
let f1 = f.bind(1).bind(2)
let val = f1() // object
- 重点:
this 永远必须是个 对象,不能是其他类型,虽然不能直接赋值,但是可以通过call、apply、bind 内部改变 this,但是为了确保 this 为对象类型,如果赋给他的值是非对象的,则会转成对象
-
解析:
- Number、String、Boolean 是 javascript 内置的三个基本类型包装对象
- null 和 undefined 没有对象包装对象(类) this 指向将不会改变,等同于 f() 直接调用
function f() {
console.log(typeof this, this);
}
f.call(0)
// object Number {0} 其实是: new Number(0)
f.call('hello world')
// object String {"hello world"} 其实是: new String('hello world')
f.call(true)
// object String {"hello world"} 其实是: new Boolean(true)
f.call(null)
// object Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
f.call(undefined)
// object Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}