this
Q:是什么?
- A:JavaScript 语言的一个关键字。
Q:什么时候产生?
- A:函数运行时,在函数体内部自动生成的一个对象。
Q:使用范围?
- A:只能在函数体内部使用。
Q:值是什么?
- A:函数的不同使用场合,
this有不同的值。总的来说,this就是函数运行时所在的环境对象。
Q:this的用法有哪些?
A:
纯粹的函数调用
- 全局性调用,因此
this就代表全局对象
javascriptvar x = 1; function test() { console.log(this.x); } test(); // 1- 全局性调用,因此
作为对象方法的调用
- 这时
this就指这个上级对象
javascriptfunction test() { //上级对象为obj console.log(this.x); } var obj = {}; obj.x = 1; obj.m = test; //作为对象方法调用 obj.m(); // 1- 这时
作为构造函数调用
this指这个构造函数生成的新对象javascriptfunction test() { //this为构造函数生成的对象 this.x = 1; } //构造函数 var obj = new test(); obj.x // 1
apply调用
javascriptvar x = 0; function test() { console.log(this.x); } var obj = {}; obj.x = 1; //此时this为obj对象 obj.m = test; //通过apply调用后,由于没有参数,默认this指向全局对象 obj.m.apply() // 0
Q:为什么this很重要?
- A:
this允许复用函数时使用不同的上下文。(即:“this” 关键字允许在调用函数或方法时决定哪个对象应该是焦点。)
Q:绑定this方法有哪些?
A:
显式绑定:apply、call、bind
隐式绑定:
链式调用方法
obj.fun()new 实例化一个对象
使用ES6的箭头函数
箭头函数中的this:
- 箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined
在函数内部使用
_this = this
Q:this的指向是什么?
- A:this 永远指向最后调用它的那个对象
apply
Q:是什么?
- A:是函数的一个方法,作用是改变函数的调用对象。
Q:怎么用?
- A:它的第一个参数就表示改变后的调用这个函数的对象。
参数为空时,默认调用全局对象。
以用数组传参而且
.apply会在函数中为你自动展开javascriptconst languages = ['JavaScript', 'Ruby', 'Python'] // greet.call(user, languages[0], languages[1], languages[2]) greet.apply(user, languages)
Q:如何实现?
A:
javascriptFunction.prototype.bind = function (context,...innerArgs) { var me = this return function (...finnalyArgs) { return me.call(context,...innerArgs,...finnalyArgs) } }
call
Q:是什么?
- A:是每个函数都有的一个方法,它允许你在调用函数时为函数指定上下文。
Q:能干什么?
- A:通过call方法,可以改变函数执行时的this指向。第一个参数会作为函数被调用时的上下文。(即:
this将会指向传递给call的第一个参数。)其余参数为函数的参数。
Q:怎么用?
A:
javascriptfun.call(thisArg[, arg1[, arg2[, ...]]])- thisArg:
- [, arg1[, arg2[, ...]]:若干个参数列表
Q:执行全局函数时发生了什么?
A:
javascriptfunction say(word) { console.log(world); } say("Hello world"); //js执行函数时会默认完成以下的步骤 say.call(window, "Hello world");- 把第二个到最后一个参数作为函数执行时要传入的参数
- 把函数执行时的this指向第一个参数
- 在上面这个特殊的上下文中执行函数
Q:如何学会用cell替代法分析函数中的this?
A:
全局调用,相当于
cell(window,args);【示例一】
javascriptfunction hello(thing) { console.log(this + " says hello " + thing); } person = { name: "caibirdme" } person.hello = hello; person.hello("world") // 相当于执行 person.hello.call(person, "world") //{name:"caibirdme"} says hello world hello("world") // 相当于执行 hello.call(window, "world")【示例二】
javascriptvar x = 10; var obj = { x: 20, f: function(){ console.log(this.x); //this equals obj // ==> 20 var foo = function(){ console.log(this.x); } foo(); // foo.call(window) //foo中this被指定为window,所以==> 10 } }; obj.f(); // obj.f.call(obj) // ==> 20 10【示例三】
javascript(function(name) { // })("aa"); //等价于 (function(name) { // }).call(window, "aa");
链式调用,向函数上一层找。
Q:如何实现call?
A:
javascriptFunction.prototype.newCall = function(context, ...parameter) { if (context === null || context === undefined) { context = window; } else { //处理当call传入的对象是null的时候,或者其他一些类型的时候 context = Object.create(null) } //用Symbol原因是key可以不被随意改变 let fn = Symbol() //通过this获取函数 context[fn] = this //调用 context[fn](...parameter); //为了保持对象一至,在执行完之后再把这个对象给删除了 delete context[fn] }
bind
Q:是什么?
- A:
.bind和.call完全相同,除了不会立刻调用函数,而是返回一个能以后调用的新函数。
Q:怎么用?
A:与call用法一致。bind 是创建一个新的函数,必须要手动去调用。这个新函数的
this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。javascriptfunction.bind(thisArg[, arg1[, arg2[, ...]]]);thisArg:调用绑定函数时作为
this参数传递给目标函数的值。注意:关于thisArg
- 使用
new运算符构造绑定函数,则忽略该值 - 使用
bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都转换为object bind函数的参数列表为空,或者thisArg是null或者undefined,执行作用域的this将被视为新函数的`thisArg
- 使用
arg1, arg2, ...:当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
返回值:返回一个原函数的拷贝,并拥有指定的
this值和初始参数。
Q:为什么使用new运算符构造绑定函数,该this被忽略?
- A:new的作用: 将
this的值设置为新创建的空对象,而bind将new 中的this(即空对象)设置为传递给它的第一个参数也就是thisArgs。
Q:使用场景?
A:
保存函数参数
【示例】处理异步输出
javascriptfor (var i = 1; i <= 5; i++) { // 缓存参数 setTimeout(function (i) { console.log('bind', i) // 依次输出:1 2 3 4 5 }.bind(null, i), i * 1000); }回调函数this丢失问题