细说JavaScript中的this指向与绑定规则
this的指向
通常在浏览器中,在全局中使用this,该this指向的是window对象,无论是否开启了严格模式。但我们一般使用this,也是在函数中进行使用。所有的函数在被调用的时候,会产生一个函数执行上下文,该上下文中记录这函数的作用域链、AO对象以及当前这个函数的this指向。我们看下面代码:
function foo() { console.log(this) } foo()//window var obj = { name: 'why', foo: foo } obj.foo()//obj foo.apply("abc")//String{'abc'}
上面代码中,我们定义了一个函数foo来输出调用它的时候this的指向,从上往下分别指向的是window、obj、String{'abc'},所以我们可以知道:
- 函数在调用时,JavaScript会默认给this绑定一个值;
- this的绑定和定义的位置(编写的位置)没有关系;
- this的绑定和调用方式以及调用的位置有关系;
- this是在运行时被动态绑定的,而不是编译时固定下来的
判断this绑定的4条规则
规则1:默认绑定
独立函数调用的时候,this永远绑定的是window对象,如下示例:
function foo() { console.log(this) } function foo2() { foo() } var obj = { name: "xiaomin", foo: function() { console.log(this) } } foo()//window foo2()//window var bar = obj.foo bar()//window
规则2:隐式绑定
通过某个对象发起调用的函数,哪个对象发起调用的函数,那么该调用函数的this就隐式绑定在了这个对象:
var obj1 = { name: "obj1", foo: function () { console.log(this); }, }; var obj2 = { name: "obj2", bar: obj1.foo, obj1: obj1, }; obj1.foo();//obj1 obj2.obj1.foo();//obj1 obj2.bar();//obj2
规则3:显示绑定
通过函数的方法call、apply、bind将this显示绑定了某个对象上,那么该函数的this就指向到这个对象上:
function foo() { console.log(this) } var obj = { name: "obj" } foo.call(obj) foo()//obj foo.apply(obj) foo()//obj var newfoo = foo.bind(obj) newfoo()//obj
规则4:new绑定
我们有如下代码:
function Person(name, age) { this.name = name this.age = age console.log(this)//p } var p = new Person("kobe",12);
在这里我们有一个构造函数Person,并用它创建了一个对象,这里简单说明一下通过new调用构造函数创建对象时的5个步骤:
- 在内存中创建一个空对象
- 将该对象的[[prototype]]指向构造函数的prototype属性
- 构造函数里的this指向这个空对象
- 开始执行构造函数的函数体代码
- 如果构造函数未返回内容,将该对象作为返回值返回出去
从上面我们可以看到,在使用new创建对象的时候,在第三个步骤会将构造函数内部的this绑定到创建的这个对象上,也就是上面代码中,Person函数中打印的this就是会是通过new关键字创建的对象p。
this绑定的优先级
当同时出现上列规则的多种规则绑定的时候,这时候this的指向就会根据上面绑定规则的优先级进行绑定:
- 默认绑定优先级最低
- 显示绑定优先于隐式绑定,如下列代码打印的this就不是obj而是String {'aaa'}
function foo() { console.log(this);//String {'aaa'} } var obj = { name: "obj", foo: foo.bind("aaa"), }; obj.foo();
- new绑定优先于隐式绑定,如下列代码打印出来的就不是obj,而是创建出来的对象f
var obj = { name: "obj", foo: function () { this.name = "kkk"; console.log("this:", this);//foo {name: 'kkk'} }, }; var f = new obj.foo();
- new绑定优先bind绑定(new绑定不能同时与call、apply同时使用),如下代码this打印出来的就是obj的对象而不是String{'aaa'}
function foo() { console.log(this); } var bar = foo.bind("aaa"); var obj = new bar(); //var obj2 = new foo.apply("123");//这样写会报错
除了四个this绑定规则外的特殊情况
1、在显示绑定中我们绑定了null或者undefined,this会绑定到window上
function foo() { console.log(this) } foo.call({})//{} foo.call(null)//window foo.call(undefined)//window
2、函数的间距引用,在下列代码中,赋值表达式 p.foo = o.foo 的返回值是目标函数的引用,因此调用位置是 foo(),不是o.foo()。所以打印出来的this是window而不是o或者p
function foo() { console.log(this); } var o = { foo: foo }; var p = {}; o.foo(); // o (p.foo = o.foo)(); // window
3、箭头函数。箭头函数是不会有自己的this的,在调用箭头函数的时候,在它的函数执行上下文中并不会生成它this的记录,而如果在箭头函数的函数体中使用到了this,那么它将会在它的上层作用域里面去找this,看下面代码
var obj = { data: [], changeData: function () { console.log("普通函数this:", this); (() => { console.log("箭头函数this:", this); })(); setTimeout(() => { this.data = ["1", "2", "3"]; console.log("this:", this); }, 1000); }, }; obj.changeData();
打印结果:
可以看出,上面打印的this其实都是指向的obj。在箭头函数内它自身没有this,那么它就向外层寻找,找到了changeData这个函数,而这时由于隐式绑定规则,changeData由obj调用的,那么changeData的this就指向的obj,所以箭头函数的this指向的就是obj。
以上就是细说JavaScript中的this指向与绑定规则的详细内容,更多关于JavaScript this的资料请关注脚本之家其它相关文章!
相关文章
使用ImageMagick进行图片缩放、合成与裁剪(js+python)
由于需要在服务器端处理,使用就研究使用imagemagick来进行。同时准备封装了一个Node.js和Python的方法,主要还是讲一下然后使用imagemagick来对图片进行缩放、合成后进行裁剪吧2013-09-09Bootstrap treeview实现动态加载数据并添加快捷搜索功能
本文实现了运用bootstrap treeview实现动态加载数据,并且添加快捷搜索功能,需要的朋友参考下2018-01-01
最新评论