网络异常,图片无法展示
|
前言
在全局上下文中,严格默认 this 为 undefined,非严格模式下,this 为 window。块级作用域的 this 是继承所在上下文中的 this 。在函数的私有上下文中,this 情况多种多样。
注意 this 并不是执行上下文,EC 是执行上下文,this 是执行主体。
1. 元素的事件
给元素的某个事件行为绑定方法,事件触发,方法执行,此时方法中的 this 一般都是当前元素本身。
// DOM0 btn.onclick = function anonymous() { console.log(this); // this指向元素本省 } // DOM2 btn.addEventListener('click', function anonymous() { console.log(this); // this指向元素本省 }, false); // DOM2-ie中 btn.attachEvent('onclick', function anonymous() { // <= IE8 console.log(this); // this -> window 特殊情况 })
2. 普通函数执行
普通函数执行,它里面的 this 取决于执行方法前面是否有“点”,有“点”,“点”前面是谁,this 就是谁,前面没有“点”,非严格模式 this 是 window,严格模式是 undefined。
3. 构造函数执行
构造函数执行,this 执行当前类的实例。
function Func() { this.name = "F"; console.log(this); //=>构造函数体中的THIS在“构造函数执行”的模式下,是当前类的一个实例,并且THIS.XXX=XXX是给当前实例设置的私有属性 } Func.prototype.getNum = function getNum() { // 而原型上的方法中的THIS不一定都是实例,主要看执行的时候,“点”前面的内容 console.log(this); }; let f = new Func; f.getNum(); f.__proto__.getNum(); Func.prototype.getNum();
4. 箭头函数
箭头函数中没自身的this,所用的 this 都是上下文中的 this 。
- 箭头函数没有this
- 箭头函数没有prototype
- 箭头函数没有constructor
- 箭头函数不能被new执行
- 箭头函数没有arguments,如果想用实参集合只能使用...args。
普通函数执行:
- 形成私有上下文 (和AO)
- 初始化作用域链
- 初始化THIS
- 初始化ARGUMENTS
- 形参赋值
- 变量提升
- 代码执行
箭头函数执行:
- 形成私有上下文 (和AO)
- 形参赋值
- 代码执行
- 代码执行的时候遇到 this 直接找上级上下文中的 this。
let obj = { i: 0, // func:function(){} func() { // THIS:OBJ let _this = this; setTimeout(function () { // THIS:WINDOW 回调函数中的THIS一般都是WINDOW(但是有特殊情况) _this.i++; console.log(_this); }, 1000); } }; obj.func();
5. call/apply/bind
call/apply
- 第一个参数就是改变 this 的指向,写谁就是谁,在非严格模式下,null/undefined 指向的是 window。 - call/apply 的唯一区别就是,传递参数不一样,apply 第二个参数是数组,call的参数是一个一个传递。 - call 的性能要比 apply 好一些(尤其是传递给函数的参数超过三个的时候)
bind
- call/apply都是改变this的同时就把函数执行了,但是bind不是立即执行函数,属于预先改变this和传递一些内容,利用的是柯理化的思想。
这里提到这个 call/apply/bind 在面试中也常也会被问到关于如何自己实现这三个方法,其实不难,只要理解这三个方法就可以手写他们了。
apply源码-手写apply源码
~(function(proto){ function apply(content, args) { if (content === undefined || contetn === null) { content = window; } else { content = Object(content); } content.$fn = this; var res = content.$fn(...args); delete content.$fn; return res; } proto.apply = apply; })(Function.prototype)
call源码-手写call源码
~(function(proto){ function call(content, args) { if (content === undefined || contetn === null) { content = window; } else { content = Object(content); } content.$fn = this; var res = content.$fn(...args); delete content.$fn; return res; } proto.call = call; })(Function.prototype)
bind源码-手写bind源码
~(function(proto) { function bind(content) { if(content === undefined || content === null) { content = window; } // 获取实参集合 var args = [].slice.call(arguments, 1); // 最后要执行的函数 var _this = this; return function anonymous() { var amArgs = [].slice.call(arguments, 0); _this.apply(content, args.concat(amArgs)); } } proto.bind = bind; })(Function.prototype); ~(function(proto) { function bind(content = window, ...args) { if (content === null) { content = window; } return (...amArgs) => { // 经测试apply的性能在三个参数以上是没有call好的 this.call(content, ...args.content(amArgs)); } } proto.bind = bind; })(Function.prototype);