JavaScript的this学习笔记

1 浏览器宿主的全局环境中,this指的是window对象
2 浏览器中在全局环境下,使用var声明变量其实就是赋值给this或window
3 任何情况下,创建变量时没有使用var或者let(ECMAScript 6),也是在操作全局this

    foo = "bar";
    function testThis() {
      foo = "foo";
    }
    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"

4 除了DOM的事件回调或者提供了执行上下文的情况,函数正常被调用(不带new)时,里面的this指向的是全局作用域

    foo = "bar";
    function testThis() {
      this.foo = "foo";
    }
    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"

5 当用调用函数时使用了new关键字,此刻this指代一个新的上下文,不再指向全局this

    foo = "bar";
    function testThis() {
      this.foo = "foo";
    }
    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"
    console.log(new testThis().foo); //logs "foo"

6 当通过new的方式创建了多个实例后,他们会共用一个原型,直到this.xxx被重写

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    console.log(this.foo);
}
Thing.prototype.setFoo = function (newFoo) {
    this.foo = newFoo;
}
var thing1 = new Thing();
var thing2 = new Thing();

thing1.logFoo(); //logs "bar"
thing2.logFoo(); //logs "bar"
thing1.setFoo("foo");
thing1.logFoo(); //logs "foo";
thing2.logFoo(); //logs "bar";
thing2.foo = "foobar";
thing1.logFoo(); //logs "foo";
thing2.logFoo(); //logs "foobar";

7 在实例中,this是个特殊的对象,而this自身其实只是个关键字。可以把this想象成在实例中获取原型值的一种途径,同时对this赋值又会覆盖原型上的值。完全可以将新增的值从原型中删除从而将原型还原为初始状态

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    console.log(this.foo);
}
Thing.prototype.setFoo = function (newFoo) {
    this.foo = newFoo;
}
Thing.prototype.deleteFoo = function () {
    delete this.foo;
}
var thing = new Thing();
thing.setFoo("foo");
thing.logFoo(); //logs "foo";
thing.deleteFoo();
thing.logFoo(); //logs "bar";

8 不通过实例,直接操作函数的原型

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    console.log(this.foo, Thing.prototype.foo);
}
var thing = new Thing();
thing.foo = "foo";
thing.logFoo(); //logs "foo bar";  this是获取原型值的一个途径 改变的是值的指向而没有直接改变了值

9 同一函数创建的所有实例均共享一个原型。如果给原型赋值了一个数组,那么所有实例都能获取到这个数组。除非你在某个实例中对其进行了重写,实际上是进行了覆盖

function Thing() {
}
Thing.prototype.things = [];
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing2.things); //logs ["foo"]

通常上面的做法是不正确的(改变thing1的同时也影响了thing2)。如果想每个实例互不影响,那么在函数里创建这些值,而不是在原型上。

function Thing() {
    this.things = [];
}
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []

10 多个函数可以形成原型链,这样this便会在原型链上逐步往上找直到找到想引用的值

function Thing1() {
}
Thing1.prototype.foo = "bar";
function Thing2() {
}
Thing2.prototype = new Thing1();
var thing = new Thing2();
console.log(thing.foo); //logs "bar"

注意原型链底层函数中对this的操作会覆盖上层的值

function Thing1() {
}
Thing1.prototype.foo = "bar";
function Thing2() {
    this.foo = "foo";
}
Thing2.prototype = new Thing1();
function Thing3() {
}
Thing3.prototype = new Thing2();
var thing = new Thing3();
console.log(thing.foo); //logs "foo"

11 原型链方法中的this是从实例中的this开始住上查找整个原型链的。也就是说,如果原型链中某个地方直接对this进行赋值覆盖了某个变量,那么我们拿到 的是覆盖后的值。

function Thing1() {
}
Thing1.prototype.foo = "bar";
Thing1.prototype.logFoo = function () {
    console.log(this.foo);
}
function Thing2() {
    this.foo = "foo";
}
Thing2.prototype = new Thing1();
var thing = new Thing2();
thing.logFoo(); //logs "foo";

12 在JavaScript中,函数可以嵌套函数,也就是可以在函数里面继续定义函数。但内层函数是通过闭包获取外层函数里定义的变量值的,而不是直接继承this

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    var info = "attempting to log this.foo:";
    function doIt() {
        console.log(info, this.foo);
    }
    doIt();
}
var thing = new Thing();
thing.logFoo();  //logs "attempting to log this.foo: undefined"
//将this缓存起来,用个叫self或者其他什么的变量来保存,以将外层与内层的this区分开来
function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    var self = this;
    var info = "attempting to log this.foo:";
    function doIt() {
        console.log(info, self.foo);
    }
    doIt();
}
var thing = new Thing();
thing.logFoo();  //logs "attempting to log this.foo: bar"

13 但把实例的方法作为参数传递时,实例是不会跟着过去的。也就是说,此时方法中的this在调用时指向的是全局this

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {  
    console.log(this.foo);   
}
function doIt(method) {
    method();
}
var thing = new Thing();
thing.logFoo(); //logs "bar"
doIt(thing.logFoo); //logs undefined

解决方法就是传递的时候使用bind方法显示指明上下文,bind方法是所有函数或方法都具有的

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () { 
    console.log(this.foo);
}
function doIt(method) {
    method();
}
var thing = new Thing();
doIt(thing.logFoo.bind(thing)); //logs bar

同时也可以使用apply或call 来调用该方法或函数,让它在一个新的上下文中执行。

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () { 
    function doIt() {
        console.log(this.foo);
    }
    doIt.apply(this);
}
function doItIndirectly(method) {
    method();
}
var thing = new Thing();
doItIndirectly(thing.logFoo.bind(thing)); //logs bar

14 使用bind可以任意改变函数或方法的执行上下文,即使它没有被绑定到一个实例的原型上

function Thing() {
}
Thing.prototype.foo = "bar";
function logFoo(aStr) {
    console.log(aStr, this.foo);
}
var thing = new Thing();
logFoo.bind(thing)("using bind"); //logs "using bind bar"
logFoo.apply(thing, ["using apply"]); //logs "using apply bar"
logFoo.call(thing, "using call"); //logs "using call bar"
logFoo("using nothing"); //logs "using nothing undefined"

15 对象中的this
可以在对象的任何方法中使用this来访问该对象的属性。这与用new得到的实例是不一样的

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};
obj.logFoo(); //logs "bar"

通过this所拿到的只是该对象身上的属性而已

var obj = {
    foo: "bar",
    deeper: {
        logFoo: function () {
            console.log(this.foo);
        }
    }
};
obj.deeper.logFoo(); //logs undefined

也可以不通过this,直接访问对象的属性

var obj = {
    foo: "bar",
    deeper: {
        logFoo: function () {
            console.log(obj.foo);
        }
    }
};
obj.deeper.logFoo(); //logs "bar"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值