JS中的this原理详解
来源:互联网 发布:nginx http host 编辑:程序博客网 时间:2024/06/08 10:10
this的用法
- this的用法
- JS中的This
- 独立调用
- 隐式调用使用对象的属性调用
- 显式绑定
- new绑定
- 绑定例外
- 总结一
- 总结代码示例
- JS中的This
JS中的This
- 注意:需要关注的是,调用位置上的调用形式;
独立调用
- 默认绑定规则:this绑定给window;
在严格模式下,默认绑定规则会把this绑定undefined上;
function foo() {console.log( this.a );}var a = 2;(function(){"use strict";foo(); //2})();
这里有一个微妙但是非常重要的细节,虽然 this 的绑定规则完全取决于调用位置,但是只有 foo()运行在非 strict mode 下时,默认绑定才能绑定到全局对象; 严格模式下调用foo()不会影响默认绑定规则;
function foo() {"use strict";console.log( this.a );}var a = 2;foo(); //undefined
无论函数是在哪个作用域中被调用,只要是独立调用则就会按默认绑定规则被绑定到全局对象或者undefined上
隐式调用:(使用对象的属性调用)
- 隐式绑定的规则:this给离函数最近的对象;是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含;
// 隐式绑定的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含// 当函数引用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象function foo() { console.log( this.a );//2}var obj = { a: 2, foo: foo};obj.foo();
- 当函数引用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象;
- 对象属性引用链中只有最顶层或者说最后一层会影响调用位置;
//对象属性引用链中只有最顶层或者说最后一层会影响调用位置function foo() { console.log( this.a );}var obj2 = { a: 42, foo: foo};var obj1 = { a: 2, obj2: obj2};obj1.obj2.foo(); //42
隐式丢失
- 将函数通过隐式调用的形式赋值给一个变量;
function foo() { console.log( this.a );//oops, global}var a = "oops, global"; var obj = { a: 2, foo: foo};var bar = obj.foo; //把obj.foo赋予别名bar,造成了隐式丢失,因为只是把foo()函数赋给了bar,而bar与obj对象则毫无关系bar(); //等价于var a = "oops, global"; var bar = function foo(){ console.log( this.a );}bar();//oops, global
- 将函数通过隐式调用的形式赋值给一个变量;
将函数通过隐式调用的形式进行传参;
var a = 0;function foo(){ console.log(this.a);};function bar(fn){ fn();}var obj = { a : 2, foo:foo}//把obj.foo当作参数传递给bar函数时,有隐式的函数赋值fn=obj.foo。与上例类似,只是把foo函数赋给了fn,而fn与obj对象则毫无关系。bar(obj.foo);//0//等价于var a = 0;function bar(fn){ fn();}bar(function foo(){ console.log(this.a);});
- 内置函数:内置函数与上例类似,也会造成隐式丢失
var a = 0;function foo(){ console.log(this.a);};var obj = { a : 2, foo:foo}setTimeout(obj.foo,100);//0//等价于var a = 0;setTimeout(function foo(){ console.log(this.a);},100);//0
显式绑定
- 通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
//普通对象的属性查找 function foo(a,b) { console.log( this.a,a,b );}var obj = { a:2};foo.call( obj,"a","b"); //2 a bfoo.apply(obj,["a","b"])//2 a b
- 显式绑定规则:
- 硬绑定:硬绑定是显式绑定的一个变种,使this不能再被修改。
// 我们来看看这个显式绑定变种到底是怎样工作的。我们创建了函数 bar() ,并在它的内部手动调用了 foo.call(obj) ,因此强制把 foo 的 this 绑定到了 obj 。无论之后如何调用函数 bar ,它总会手动在 obj 上调用 foo 。这种绑定是一种显式的强制绑定,因此我们称之为硬绑定。function foo() { console.log( this.a );/}var a =1;var obj = {a:2};var obj_test = {a:"test"};var bar = function() { console.log( this.a ); foo.call( obj );};bar(); // 1 2setTimeout( bar, 1000 ); // 1 2bar.call( obj_test ); //test 2 //硬绑定的bar不可能再修改它的this(指的是foo中的this)// 硬绑定的典型应用场景就是创建一个包裹函数,传入所有的参数并返回接收到的所有值 function foo(arg1,arg2) { console.log( this.a,arg1,arg2); return this.a + arg1; } var obj = {a:2}; var bar = function() { return foo.apply( obj, arguments); }; var b = bar(3,2); // 2 3 2 console.log( b ); // 5
new绑定
//3. 这个新对象会绑定到函数调用的 this 。function foo(a) { this.a = a;}var bar = new foo(2);console.log( bar.a ); // 2 //使用 new 来调用 foo(..) 时,我们会构造一个新对象并把它绑定到 foo(..) 调用中的 this 上。 new 是最//后一种可以影响函数调用时 this 绑定行为的方法,我们称之为 new 绑定。
绑定例外
- 箭头函数:this的绑定和作用域有关。如果在当前的箭头函数作用域中找不到变量,就像上一级作用域里去找。
function foo() { setTimeout(() => { console.log('id:', this.id); //id: 42 }, 100);}var id = 21;foo.call({ id: 42 })
- 被忽略的this:当被绑定的是null,则使用的是默认绑定规则;
// 如果你把 null 或者 undefined 作为 this 的绑定对象传入 call 、 apply 或者 bind ,这些值在调用时会被忽略,实际应用的是默认绑定规则;function foo() { console.log( this.a );}var a = 2222;foo.call( null ); // 2
- 柯里化
function foo(a,b) { console.log( "a:" + a + ", b:" + b );}// 把数组“展开”成参数foo.apply( null, [2, 3] ); // a:2, b:3// 使用 bind(..) 进行柯里化var bar = foo.bind( null, [2] );bar( 3 ); // a:2, b:3//升级版:不会污染全局 function foo(a,b) { this console.log( "a:" + a + ", b:" + b ); } // 我们的DMZ空对象,“DMZ”(demilitarized zone,非军事区) var ø = Object.create( null );//{} // 把数组展开成参数 foo.apply( ø, [2, 3] ); // a:2, b:3 // 使用bind(..)进行柯里化 var bar = foo.bind( ø, 2 ); bar( 3 ); // a:2, b:3
总结一
this,this是函数执行的上下文对象;
- 根据函数的调用方式不同,this的值也不同;
- 1、以函数的形式调用的,this是window;
- 2、以方法的形式调用时,this是调用方法的对象;
- 3、以构造函数的形式调用时,this是新创建的对象;
- 4、以call()和apply()调用时,this是方法中第一个参数。
根据函数调用的方式不同this的值也不同:
- 1.以函数的形式调用,this是window
- 2.以方法的形式调用,this是调用方法的对象
- 3.以构造函数的形式调用,this是新创建的那个对象
- 4.使用call和apply调用的函数,第一个参数就是this
- 5.在全局作用域中,this是window
- 6.在响应函数中,给谁绑定的事件this就是谁。
在事件处理函数中:获取触发当前事件的元素;
- 在普通函数中(直接调用):获取的是window对象;
- 作为对象的方法中:获取的是当前对象。
- 在全局作用域中:this指代window对象。
- 构造函数中的this:指代创建的对象。
- 注意:
- 当调用方式不同时,this指代的含义不同,得到的结果也不同。
- this本身不具备任何含义。
总结代码示例
<script> // TODO 一、以全局&调用普通的函数的形式调用,this是window. function fn(){ console.log(this); } fn(); //二、构造函数 //如果函数作为构造函数使用,那么其中的this就代表即将new出来的对象 function Objfn(){ this.a = 10; console.log(this);//此时输出的是对象 Objfn {a: 10} } var objfn = new Objfn(); console.log('objfn.a='+objfn.a);//objfn.a=10 //但是如果直接调用Objfn1()函数,而不是new Objfn1(),那么情况就变成了Objfn()是普通函数 function Objfn1(){ this.a = 10; console.log(this);//此时输出的是对象 Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} } var objfn1 = Objfn1(); //console.log('objfn.a='+objfn1.a);//错误,Cannot read property 'a' of undefined //三、对象方法 //如果函数作为对象的方法,方法中的this指向该对象 var obj={ a:10, foo:function () { console.log(this);//Object {a: 10, foo: function} console.log(this.a);//10 } } obj.foo(); //注意,要是此时在对象方法中定义函数,那么情况就不同了 //此时的函数fn虽然是在 obj1.foo1内部定义的,但它仍然属于一个普通的函数,this仍然指向window. var obj1={ a1:10, foo1:function () { function fn(){ console.log(this);//Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} console.log(this.a1);//undefined } fn(); } } obj1.foo1(); //另外,如果此时foo2不作为对象方法被调用,则 var obj2 = { x: 10, foo2: function () { console.log(this); //Window console.log(this.x); //undefined } }; var fn2 = obj2.foo2; //等价于fn2 = function () { //console.log(this); //Window //console.log(this.x); //undefined //} fn2();//此时又是在全局里执行的普通函数。 //四、构造函数的prototype属性 //在 Foof.prototype.getX函数中,this 指向的 Foof对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前Foof对象的值。 function Foof(){ this.x = 10; } Foof.prototype.getX = function () { console.log(this); //Foof {x: 10} console.log(this.x); //10 } var foof = new Foof(); foof.getX(); //五、函数用call、apply或者bind调用 var obja = { x: 10 } function fooa(){ console.log(this); //Object {x: 10} console.log(this.x); //10 } fooa.call(obja); fooa.apply(obja); fooa.bind(obja)();</script>
阅读全文
0 0
- JS中的this原理详解
- js中的this详解
- js中的this详解
- js中的this详解
- JS中的this用法详解
- js中的this关键字详解
- 详解js中的this用法
- js中的this关键字详解
- js中的this关键字详解
- js中的this关键字详解
- JS中的this指针详解
- JS中的this对象详解
- js中的this关键字详解
- JS中的this对象详解
- js中的this关键字详解
- JS中的this对象详解
- JS中的this对象详解
- js中的this关键字详解
- (一)Angular4 英雄征途HeroConquest-Angular4的安装
- 实现快速排序的非递归
- 2017.07.31工作日记
- plsql 打开之后弹出logon窗口(connection) 解决方法
- Linux学习之shell基础
- JS中的this原理详解
- 递归函数
- centos7 NetworkManager
- 提问的艺术
- C\C++中的多维数组
- arcgis for javascript 选中要素、删除要素和编辑节点
- Java集合框架-LinkedList和HashSet
- Codeforces Round #428 (Div. 2)比赛总结
- 大数据框架对比:Hadoop、Storm、Samza、Spark和Flink