this的指向
Posted boses
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了this的指向相关的知识,希望对你有一定的参考价值。
这篇文章酝酿了许久,this的指向一直是让初学者痛苦的事情,但也是有迹可循的在学习中绝对不能秉承猜测的想法来进行,这里参考了阮一峰的博客与《你所不知道的javascript》一书,以及自己的理解。
这篇文章分为三大部分,第一部分是ES5,第二部分是ES6,因为ES6新增了箭头函数,它有些特殊,第三这里暂时指其他。
如果不特殊说明,全局环境默认为浏览器(window)。
首先要明确一点,this总是返回一个对象,他的返回值与运行环境有关,其次我们思考一下为什么要使用this?
这里我参考了阮一峰的this原理,首先JavaScript中的类型分为基本类型和引用类型,对于引用类型存储在内存中,当变量引用时,赋值给变量他的内存地址,
这也是为什么修改一个变量,另外指向相同内存地址变量也会随之更改的原因。
首先看一个例子
var x = 1; function foo() { console.log(x); } var a = { x : 5, foo: foo }; a.foo(); //1
这里返回的是1,因为函数的定义时作用域指向全局,但是函数体内允许引用当前环境的变量,函数也可以在不同环境下运行,这就是引用this的原因。
一:ES5
1.全局环境
全局环境下会返回window对象,怎么样调用才算是全局呢?在全局作用域下调用就是全局环境。
function foo() { console.log(this.x === x); } var x = 5; foo(); //true
这条规则比较简单,不过需要注意的是,在严格模式下(‘use strict’)this会返回undefined。
function foo() { ‘use strict‘ console.log(this === undefined); } var x = 5; foo(); //true 2.
2.对象方法使用
作为对象方法this返回调用方法的对象,下面是一个例子
var a = { x : 5, foo: function() { console.log(this === a); } }; a.foo(); //true
这里是由foo方法的对象是a,所以this是a;
在看一个例子,
var a = { x: 5, fn: { text: ‘es5‘, foo: function () { console.log(this === a.fn); } } }; a.fn.foo(); //true
这里foo方法是由a.fn来调用的,所以this指向a.fn,不过需要注意,在使用的时候需要注意避免嵌套,比如下面这个例子。
var a = { x: 5, fn: { text: [1, 2, 3], foo: function () { this.text.forEach(function() { console.log(this === window); }); } } }; a.fn.foo(); //true
这里foo内部定义了一个函数,这个函数指向的是全局作用域,可以这样来理解,ES5只有全局作用域和函数作用域,因为变量提升的原因,这个函数提升到了头部。
function obj() { console.log(this === window); } var a = { x: 5, fn: { text: [1, 2, 3], foo: function () { this.text.forEach(obj); } } }; a.fn.foo(); //true
3.构造函数使用
作为构造函数使用时,默认指向构造函数的实例。
new命令会执行下面四个步骤:
- 创建一个对象,作为要返回的实例对象;
- 将新建对象的原型对象指向构造函数的prototype属性;
- 将新建对象作为this;
- 开始执行代码;
下面是一个例子
function Foo() { this.a = 10; } var a = new Foo(); console.log(a.a === 10); //true
有一种情况需要注意,就是在构造函数内部使用了return命令,并且返回的是对象。
function Foo() { this.a = 10; return {obj: 123}; } var a = new Foo(); console.log(a.a); //undefined
这里new Foo()返回的就是return的对象,内部的this会被忽略掉。
4.绑定对象
可以分为三种情况 call,apply,bind,
他们三个第一个参数都是要绑定的对象,如果忽略或者传入undefined和null会默认为全局对象,不过严格模式下全局对象默认为undefined。
call和apply只是第二个参数接收不同,call“”,“”的形式传递参数,比如
a.call(null, 1, 2, 3);
而apply是以数组的形式传递参数
a.call(null, [1, 2, 3]);
bind与call方法很像,不过他返回的是一个函数,函数的this指向就是传递bind的第一个参数,多余参数会作为调用对象的初始值储存。
var x = 10; function foo(x, y) { console.log(x + y); } var fn = foo.bind(null, 10); fn(x); //20
可以看到,bind不会像call和apply方法调用就立刻执行函数。
二:ES6
ES6新增了箭头函数,简单来说,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
我们把之前在上面举的几个例子重试一下。
全局环境:
var a = () => this; console.log(a() === window); //true
没有区别,定义时所在的对象是window。
对象方法:
var i = 10 var a = { i : 5, fn: () => this.i };
这里返回有所不同,之所以这样是因为在a.fn这个函数内的this根本没有,所以指向window上。
这样说可能有所难理解,实际上箭头函数内部没有this。
在看一个例子,
function foo() { return () => { return () => { return () => { console.log(‘id:‘, this.id); }; }; }; } var i = foo.call({id: ‘box‘}); i.call({ id: ‘1‘})()(); //id: box i().call({id: ‘2‘})(); //id: box i()().call({id: ‘3‘}); //id: box
这里可以看到返回结果全部是id: box也就是foo函数内部的this,
箭头函数没有自己的this,那么绑定方法自然也是无效的了。
构造函数:
箭头函数内部不能使用new命令,否则会报错!
var Foo = () => this = 10; new Foo(); //Invalid left-hand side in assignment
作为绑定方法:
因为箭头函数没有自己的this,因为作为绑定方法this会失效,下面是一个例子,
var foo = () => this.id; var a = { id: ‘hello ES6‘ }; var id = ‘box‘; console.log(foo.call(a)); //box
这里会报错。 不过需要注意,虽然箭头函数没有自己的this,但是可以给箭头函数外部的函数绑定this指向。
var id = ‘box‘; function foo() { let f = () => { console.log(this.id); }; f(); } foo.call({id: ‘es6‘}); //es6
三:其他
1.作为数组方法调用:
function f1() { console.log(this === arr); } var arr = [f1, 1, 2, 3]; arr[0](); //true
这里可以简单理解为arr数组方法“0”调用了函数,this返回arr数组。
2.作为定时器使用
var id = ‘es6‘; var a = { id: ‘box‘, foo: function() { setTimeout(function() { console.log(this.id === ‘es6‘); }); } }; a.foo(); //true
这是因为定时器是异步操作,当foo运行后,他将指向全局环境,这个例子如果用箭头函数写就会绑定在a上,因为箭头函数的this是定义时所在的对象。
var id = ‘es6‘; var a = { id: ‘box‘, foo: function() { setTimeout(() => {console.log(this.id === ‘box‘)}); } }; a.foo(); //true
可以看到。
3.作为DOM节点
作为节点时,this指向定义节点事件所在的节点。
<div>hello word</div> <body> <script> var div = document.querySelector(‘div‘); div.addEventListener(‘click‘, function() { console.log(this === div); }); </script>
这里会返回true,不过注意,如果用箭头函数写会返回全局,因为这里没有this本身没有this会返回全局环境。
以上是关于this的指向的主要内容,如果未能解决你的问题,请参考以下文章
ngx-translate实现国际化:this.translate.use()this.translate.get()this.translate.instant()onLangChange(代码片段
在 webview_flutter 中启用捏合和缩放,在哪里添加代码片段 [this.webView.getSettings().setBuiltInZoomControls(true);]