对this指向大致的定义
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
1.普通函数调用,此时 this 指向 window
例一:
function test(){
var name = "微光";
console.log(this.name); //undefined
console.log(this); //Window
}
test();
上面说过this最终指向的是调用它的对象,这里的函数test实际是被Window对象所点出来的
2.对象方法调用, 此时 this 指向 该方法所属的对象
例二:
var o = {
name:"微光",
fn:function(){
console.log(this.name); //微光
}
}
o.fn();
因为我们调用fn这个函数是通过了o.fn()执行,那指向明显就是对象o了
例三:
var o = {
name:"微光",
fn:function(){
console.log(this.user); //微光
}
}
window.o.fn();
这段代码跟例二几乎是一样,我们先来理解下为啥这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,
这里先说个而外话,window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象。
我们先不说为啥会不指向window,接下来再看一段代码。
例四:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
这里同样也是对象o点出来的,但是同样this并没有执行它,可能你会说为啥不是指向对象o?
补充三个知识点:
1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window
2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
例四可以证明,如果不相信,那么接下来我们继续看几个例子。
例5:
var o = {
a:10,
b:{
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。
还有一种比较特殊的情况,例6:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
这里this指向的是window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要。
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,
例6中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子5是不一样的,例子5是直接执行了fn。
构造函数版this:
function Fn(){
this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子
构造函数调用, 此时 this 指向 实例对象,new关键字可以改变this的指向
将这个this指向对象a
为什么我说a是对象,因为用了new关键字就是创建一个对象实例,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a
当this碰到return时:
function fn()
{
this.user = '微光';
return {};
}
var a = new fn;
console.log(a.user); //undefined
function fn()
{
this.user = '微光';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
function fn()
{
this.user = '微光';
return 1;
}
var a = new fn;
console.log(a.user); //微光
function fn()
{
this.user = '微光';
return undefined;
}
var a = new fn;
console.log(a.user); //微光
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
function fn()
{
this.user = '微光';
return null;
}
var a = new fn;
console.log(a.user); //微光
箭头函数中的this:
const o = {
a() {
console.log(this)
},
b: () => {
console.log(this)
}
}
o.a() //o
o.b() //window
const c = o.a //window 复制并没有执行
const d = o.b //window
c()
d()
当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this。
面试题一:
var foo = 1;
function bar() {
foo = 10;
return;
function foo() {}
}
bar();
alert(foo);
输出1,考察了变量提升,可以变为
var foo = 1;
function bar(){
function foo(){}; // 这里在内部定义了 foo 是一个函数
foo = 10; // 因此这里属于局部变量,不影响到外层的foo
return foo;
}
bar();
alert(foo) //1
// 在foo=10的时候,foo是有定义的,属于局部变量,影响不到外层的foo。
1、预解析中,变量的提升,只会在当前的作用域中提升,提前到当前作用域的最前面。
2、函数的变量只会提前到函数作用域的最前面,不会出去影响全局的变量。
面试题二:
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
alert(typeof bar());
输出function,相当于
// 上述代码相当于:
function bar() {
function foo() { }
var foo; //函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被变量赋值后覆盖
return foo;
foo = 10;
foo = 11;
}
alert(typeof bar());
面试题三:
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
var go = foo.baz.bar; //并没有执行所以最终指向的是window
alert(go());
alert(foo.baz.bar()); //只指向上一级
输出3,1,
面试题四:
x = 1;
function bar() {
this.x = 2;
return x;
}
var foo = new bar(); //new 改变了this指向
alert(foo.x);
输出2
面试题五:
var arr = [];
arr[0] = 'a';
arr[1] = 'b';
arr.foo = 'c';
arr.name = "zs"
alert(arr.length); // arr = ["a", "b", foo: "c", name: "zs"]
2,数组的原型是 Object,所以可以像其他类型一样增加属性,但是不影响其固有性质。arr.foo 和 arr.name 不算在 arr.length 中
面试题六:
function foo(){}
delete foo.length;
alert(typeof foo.length);
number,length属性无法被删除
面试题七:
var name="the window";
var object={
name:"my object",
getName: function(){
return this.name;
}
}
object.getName();
(object.getName)();
(object.getName = object.getName)()
输出
my object
my object
the window
备注:
第一行的代码,this指向的就是object,所以毫无疑问;
第二行代码虽然加上括号,就好像只是在引用一个函数,但this的值得到了维持。因为object.getName和(object.getName)的定义相同。
第三行代码,先执行一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值不能得到维持,结果就返回the window.