**this**是 this 那条语句所在的执行上下文,在非严格模式下,全局指向**window**,在函数中则取决于函数的调用位置(即函数被谁调用了)
浏览器(runtime)
非严格模式
- this的四种绑定规则
/**
- 就是function a,挂载在window上
- 所以当执行a(),可以理解成window.a()
*/
console.log(window.a);
```javascript // 案例三 let obj = {} function a() { function b() { function c() { console.log(this) } c() } b.apply(obj) } a(); // window /**```javascript// 案例二function a() {function b() {function c() { console.log(this) }c()}b()}a(); // window
- 这说明c的this并不受所在函数b的影响
- 仅仅是因为直接c(),这样调用c函数,即使用了默认绑定的方式
*/
```
隐式绑定
```javascript // 案例一 let obj = { a: function() {
} } obj.a(); // obj /**console.log(this)
- 很明显,a被obj调用,所以函数a里面的this指向obj
*/
javascript // 案例二 // 本来是隐式绑定,但实际上 隐式丢失 了,变成了默认绑定 let obj = { a: function() { console.log(this) } }
let fn = obj.a fn(); // window /**
- obj.a赋给了fn。调用fn的时候,前面没有xxx.fn,而是直接fn(),所以采用了默认绑定
*/
javascript // 案例三 // 同理,另一个隐式丢失的情况 let obj = { a: function() { return function() {
} } }console.log(this)
let fn = obj.a(); fn(); // window
<a name="j3MHy"></a>### 显示绑定- call、apply、bind的区别- `fn.call( <this> ,p1,p2...)`- `fn.apply( <this> ,[p1,p2...])`- `fn.bind( <this> )(p1,p2...)`- 注意:如果把`null`或者`undefined`作为 this 的绑定对象传入`call`、`apply`或者`bind`,这些值在调用时会被忽略,实际应用的是默认绑定规则。- 注意:如果传入的是 `值类型` 而不是 `引用类型` 的话,那么将会把`值类型`隐式转换为对应的 `对象形式`(也就是 `new String()`、`new Number()`之类的)```javascript// 案例一let obj = {name: 'kons'}function a() {console.log(this.name);}a.call(obj); // konsa.apply(obj); // konsa.bind(obj)(); // kons
// 案例二// 理解bind的实现,简陋版Function.prototype.mybind = function (obj) {let __this = this; // 获取函数实例return function (...rest) {__this.apply(obj, rest); // 硬绑定}}// 知道了这个之后,就知道下面这个,为什么是window,而不是objlet obj = {a: function () {console.log(this)}}let fn = obj.afn.bind(null).call(obj); // window
// 手写bind函数Function.prototype.mybind = function (objThis, ...params) {const thisFn = this; // 保存当前调用的函数let funcForBind = function (...otherParams) {// 如果是new出来的,this会指向新new出来的对象。如果不是,this是指向window,改为指向objThisconst isNew = this instanceof funcForBind;const thisArg = isNew ? this : objThis;return thisFn.call(thisArg, ...params, ...otherParams);}// 克隆一下funcForBind.prototype = Object.create(thisFn.prototype);return funcForBind;}
new绑定
- 定义JS的“构造函数”:在JS中,构造函数只是一些使用
new操作符时被调用的函数。它们只是被new操作符调用的普通函数而已。- 包括内置对象函数,Number、String等等,也只是普通函数
- 实际上并不存在所谓的“构造函数”,只有对函数的“构造调用”
new来调用函数、或者说发生构造函数调用时,会自动执行下面的五步- 1.创建一个新的空对象
{} - 2.将构造函数的
prototype属性赋值给新对象的__proto__ - 3.将构造函数的this指向新对象
- 4.执行构造函数的代码
- 5.如果函数没有返回其他
引用类型,那么new表达式中的函数调用会自动返回这个新对象 ```javascript // 案例一 //在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法 function CreateCat(name){ this.name = name; }
- 1.创建一个新的空对象
CreateCat.prototype.eat = function(something){ console.log(this.name + ‘ eat ‘ + something); } /**
- CreateCat.prototype = new Object() —> {
- proto: Object.prototype,
- constructor: CreateCat(){…},
- eat: function(something){…}
- } */
var catA = new CreateCat(‘xiaoA’); /**
- catA = {
- proto: CreateCat.prototype,
- name: ‘xiaoA’
- }
*/
javascript // 案例二 function Test() { this.name = ‘Test’; this.count = 2; return 456 }
const one = new Test();
console.log(one); // {name: ‘Test’, count: 2}
```javascript// 案例三function Test() {this.name = 'Test';this.count = 2;return [456]; // 换成其他引用类型就会改变,如{go:4}、function(){}、new Number(456)}const one = new Test();console.log(one); // [456]
四种绑定的优先级
- new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
绑定的例外
软绑定
- 作用:解决由于硬绑定,无法使用 隐式绑定 或者 显示绑定 来修改this
// 软绑定的实现Function.prototype.softBind = function(objThis,...params) {let thisFn = this;let bound = function(...otherParams){let context = (!this || this === (window || global)) ? objThis: this;return thisFn.call(context, ...params, ...otherParams);}bound.prototype = Object.create(thisFn.prototype);return bound;}// 使用方法let obj = {};function a() {console.log(this);}a.bind(null).apply(obj); // windowa.softBind(null).apply(obj); // obj
- 作用:解决由于硬绑定,无法使用 隐式绑定 或者 显示绑定 来修改this
箭头函数
- 函数体内的this对象,继承的是外层代码块的this
- 函数没有prototype原型
- 不可以作为构造函数。new了会报错
- 没有
arguments - 箭头函数没有自己的this,所以不能用call()、apply()、bind()这些方法去改变this的指向
