this的指向
this 既不指向函数自身也不指向函数的词法作用域
例1:使用this
call() 方法是预定义的 JavaScript 方法,用来调用所有者对象作为参数
function identify() { return this.name.toUpperCase(); } function speak() { var greeting = "Hello, I'm " + identify.call(this); console.log(greeting); } var me = { name: "Kyle" }; var you = { name: "Reader" }; identify.call(me); // KYLE identify.call(you); // READER speak.call(me); // Hello, 我是 KYLE speak.call(you); // Hello, 我是 READER
例2:显式传入一个上下文对象context
function identify(context) { return context.name.toUpperCase(); } function speak(context) { var greeting = "Hello, I'm " + identify(context); console.log(greeting); } var me = { name: "Kyle" }; var you = { name: "Reader" }; identify(you); // READER speak(me); //hello, 我是 KYLE
对比:
使用this更加简洁
隐式传递一个对象引用
this 提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将 API 设计
得更加简洁并且易于复用。
顾名思义的误解(指向自身)
证明:假设this指向自身,函数的被调用的次数应该等于this语句指向的次数
function foo(num) { console.log("foo: 调用序号" + num); // 记录 foo 被调用的次数 this.count++; } foo.count = 0; var i; for (i = 1; i < 5; i++) { foo(i) } // foo 被调用了多少次? console.log(foo.count); // 0 -- WTF
执行 foo.count = 0 时,的确向函数对象 foo 添加了一个属性 count。但是函数内部代码
this.count 中的 this 并不是指向那个函数对象,所以虽然属性名相同,根对象却并不相
同
无意中创建了一个global全局变量count为NaN
如何从函数内部引用自身
1.具名函数可以通过词法作用域引用自身
function foo() { foo.count = 4; // foo 指向它自身 }
疑问:强制 this 指向 foo 函数对象可行吗
解惑:使用call函数强制绑定,call(…) 可以确保 this 指向函数对象 foo 本身
function foo(num) { console.log('foo: 调用序号', num) console.log('foo.count', foo.count) console.log('this.count', this.count) this.count++ } foo.count = 1 var i; for (i = 1; i < 5; i++) { foo.call(foo, i) }
匿名函数如何引用自身
思考:下面匿名函数如何引用自身
setTimeout( function(){ // 匿名(没有名字的)函数无法指向自身 }, 10 );
词法作用域显然不支持
传统:arguments.callee 来引用当前正在运行的函数对象(es5中使用,es6中已被弃用)
是目前唯一一种可以从匿名函数对象,内部引用自身的方法
总结
this 既不指向函数自身也不指向函数的词法作用域,this 隐式“传递”对象引用;
函数里的this,如果函数不是作为方法运行,this指向顶层对象,但是严格模式下,this返回undefined;
this判断
调用位置
调用位置:就是函数在代码中被调用的位置(不是声明的位置)
调用栈:到达当前执行位置所调用的所有函数
例1:调用位置与调用栈分析
function baz() { // 当前调用栈是:baz // 因此,当前调用位置是全局作用域 console.log("baz"); bar(); // <-- bar 的调用位置 } function bar() { // 当前调用栈是 baz -> bar // 因此,当前调用位置在 baz 中 console.log("bar"); foo(); // <-- foo 的调用位置 } function foo() { // 当前调用栈是 baz -> bar -> foo // 因此,当前调用位置在 bar 中 console.log("foo"); } baz(); // <-- baz 的调用位
this绑定规则
默认绑定
this 的默认绑定指向全局对象
例:在函数中调用this
function demo() { console.log('this\n', this) } demo()
var 声明变量的问题
js文件
function demo() { console.log('this\n', this) console.log('this.name\n', this.name) } var name = 'yma16' demo()
没有提升到全局对象中
web网页中
var会把变量提升至window全局对象
global与window对象(顶层对象)
顶层对象在浏览器环境指的是window,在Node中指的是global对象。
严格模式
如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此 this 会绑定
到 undefined:
function demo() { "use strict" console.log('this\n', this) } demo()
隐式绑定
例:
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); // 2
当 foo() 被调用时,它的落脚点确实指向 obj 对象。当函数引
用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。因为调
用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的
显示绑定
例:
function foo() { console.log( this.a ); } var obj = { a:2 }; foo.call( obj ); //
在调用 foo 时强制把它的 this 绑定到 obj 上
new 绑定
例:
function foo(a) { this.a = a; } var bar = new foo(2); console.log( bar.a ); // 2
用 new 来调用 foo(…) 时,我们会构造一个新对象并把它绑定到 foo(…) 调用中的 this
优先级
显示>隐式
new>隐式
判断
- 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。
var bar = new foo() - 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是
指定的对象。
var bar = foo.call(obj2) - 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上
下文对象。
var bar = obj1.foo() - 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到
全局对象。