JavaScript中的this陷阱的最全收集并整理(没有之一(4)

function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { var self = this; function doIt() { console.log(self.foo); } doIt(); } function doItIndirectly(method) { method(); } var thing = new Thing(); thing.logFoo(); //logs "bar" doItIndirectly(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

你可以用bind来代替任何一个函数或者方法的this,即便它没有赋值给实例的初始prototype。

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"

你应该避免在构造函数里面返回任何东西,因为这可能代替本来应该返回的实例。

function Thing() { return {}; } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = new Thing(); thing.logFoo(); //Uncaught TypeError: undefined is not a function

奇怪的是,如果你在构造函数里面返回了一个原始值,上面所述的情况并不会发生并且返回语句被忽略了。最好不要在你将通过new调用的构造函数里面返回任何类型的数据,即便你知道自己正在做什么。如果你想创建一个工厂模式,通过一个函数来创建一个实例,这个时候不要使用new来调用函数。当然这个建议是可选的。

你可以通过使用Object.create来避免使用new,这样同样能够创建一个实例。

function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = Object.create(Thing.prototype); thing.logFoo(); //logs "bar"

在这种情况下并不会调用构造函数

function Thing() { this.foo = "foo"; } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = Object.create(Thing.prototype); thing.logFoo(); //logs "bar"

因为Object.create不会调用构造函数的特性在你继承模式下你想通过原型链重写构造函数的时候非常有用。

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

object this
在一个对象的一个函数里,你可以通过this来引用这个对象的其他属性。这个用new来新建一个实例是不一样的。

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

注意,没有使用new,没有使用Object.create,也没有使用函数调用创建一个对象。你也可以将对象当作一个实例将函数绑定到上面。

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

当你用这种方式使用this的时候,并不会越出当前的对象。只有有相同直接父元素的属性才能通过this共享变量

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

你可以直接通过对象引用你需要的属性

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

DOM event this
在一个HTML DOM事件处理程序里面,this始终指向这个处理程序被所绑定到的HTML DOM节点

function Listener() { document.getElementById("foo").addEventListener("click", this.handleClick); } Listener.prototype.handleClick = function (event) { console.log(this); //logs "<div></div>" } var listener = new Listener(); document.getElementById("foo").click();

除非你自己通过bind切换了上下文

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwzsgz.html