在js中实例化对象之前的'this'是什么?

mk.*_*mk. 4 javascript scope this

我不明白以下几点:

var x = function() {
    this.foo="foo";
    return function() {
        this.bar = "bar";
        return foo+bar;
    };
}(); // returns inner

alert(x()); // 'foobar', so both 'this' variables are set
alert(x.bar); // undefined - but wasn't it used correctly?
alert(new x().bar); // ok, works
Run Code Online (Sandbox Code Playgroud)

我的假设是第一次生成并使用默认的'this'范围/变量映射,然后当调用'new'时,通过并返回带有新'this'的新对象(function?).或者,也许x不是一个合适的对象?但是,那么'这个'怎么会被设置并用来制作'foobar'?

了解这一点我需要知道什么?

Eug*_*kin 9

首先让我们来看看JavaScript的一些优点,然后我们可以处理你的例子.

功能的上下文

误解的一个方面是背景.每个函数都在上下文中调用,可以使用关键字来获取this.让我们编写一个可用于检查上下文的函数:

var probe = function(){
  // if the context doesn't have a name, let's name it
  if(!this.name){
    this.name = "lumberjack";
  }
  // print the name of my context
  console.log(this.name);
};
Run Code Online (Sandbox Code Playgroud)

开始了:

name = "global!";

// when we call a function normally it still have a context:
// the global context
probe(); // prints: global!

var ctx = {name: "ctx"};

// we can set a context explicitly using call()
probe.call(ctx); // prints: ctx

// we can set a context explicitly using apply()
probe.apply(ctx); // prints: ctx

// it is set implicitly, if we call a function as a member
ctx.fun = probe;
ctx.fun(); // prints: ctx

// or we can create a brand new object and set it as a context:
// that's what "new" does
var t = new probe(); // prints: lumberjack

// let's sum it up:
console.log(name);     // prints: global!
console.log(ctx.name); // prints: ctx
console.log(t.name);   // prints: lumberjack
Run Code Online (Sandbox Code Playgroud)

这就是为什么它很容易陷入困境并无意中陷入全球环境.

在构造函数中返回值

许多人在看到构造函数返回值时感到困惑.这是合法的.构造函数可以返回对象,函数或数组.该值将用作实例.旧实例将被丢弃.

var myClass = function(){
  // if it is called as a constructor, "this" will be a new instance
  // let's fill it up:
  this.a = 42;
  this.b = "Ford";
  this.c = function(){ return "Perfect"; };
  // done? let's discard it completely!
  // and now for something completely different...
  return {
    owner: "Monty Python",
    establishment: "Flying Circus"
  };
};
var t = new myClass();
alert(t.owner + "'s " + t.establishment);
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,它展示了"Monty Python的飞行马戏团".

如果构造函数返回其他内容(例如,数字,字符串,null,未定义),则返回的结果将被丢弃,并且将使用旧实例.

这个例子

你的例子很难理解,主要是因为它的编写方式.让我们通过重写来简化它.

首先让我们来处理x:

var x = function() {
  this.foo = "foo";
  return function() {
    this.bar = "bar";
    return foo + bar;
  };
}(); // returns inner
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的匿名函数(1 function)是立即执行的,所以我们可以内嵌它:

// next assignment can be simplified because
// top "this" is window or the global scope
//this.foo = "foo"; =>
foo = "foo";
x = function() {
  this.bar = "bar"; // this line depends on its context, or "this"
  return foo + bar; // this line uses global "foo" and "bar"
};
Run Code Online (Sandbox Code Playgroud)

所以最后我们有两个全局变量:( foo一个字符串)和x一个(一个函数).

现在,让我们在1 警告:

alert(x()); // 'foobar', so both 'this' variables are set
Run Code Online (Sandbox Code Playgroud)

再次,让我们内联x():

// next assignment can be simplified because
// top "this" is window or the global scope
//this.bar = "bar"; =>
bar = "bar";
// at this moment both global "foo" and "bar" are set
alert(foo + bar); // => "foo" + "bar" => "foobar"
Run Code Online (Sandbox Code Playgroud)

在2 警报也同样简单:

alert(x.bar); // undefined - but wasn't it used correctly?
Run Code Online (Sandbox Code Playgroud)

它不需要太多的重写.x是一个函数,我们没有添加任何属性,所以x.bar是未定义的.如果添加它,您可以看到结果:

x.bar = "bar2";
alert(x.bar); // bar2
Run Code Online (Sandbox Code Playgroud)

3 警报演示JavaScript的OOP在行动:

alert(new x().bar); // ok, works
Run Code Online (Sandbox Code Playgroud)

(旁注:它的作用只是因为你先跑x(),否则会因为bar未定义而爆炸).

让我们改写它:

var t = new x();
alert(t.bar); // bar
Run Code Online (Sandbox Code Playgroud)

现在让我们分析构造函数.它有两个语句:赋值和返回.后者被忽略,因为它返回一个字符串.所以我们可以像这样重写它:

x = function(){
  this.bar = "bar";
};
var t = new x();
alert(t.bar); // bar
Run Code Online (Sandbox Code Playgroud)

我希望现在看起来都很简单.