刷题-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, …}复制代码