Javascript:如何访问构造函数的'this'成员? [英] Javascript: how to visit the 'this' member of a construction function?
问题描述
在控制台中,我创建了一个构造函数'Car',如下所示,
和new-ed一个名为'mycar'的对象,它发生如下:
> var Car = function(){
... this.make =Ford;
...}
undefined
> var mycar = new Car()
undefined
> mycar.make //当我访问mycar.make时,它有效
'Ford'
> Car.make //当我访问Car.make时,它没有工作
undefined
所以我想问:
如何访问'Car.make',就像我访问'mycar.make'一样?
澄清:通过名称
Car
访问make
但不是通过mycar
字段在哪里。 make =Ford
go?
我还尝试扩展其 __ proto __
in Chrome开发者控制台,但没有找到它。
谢谢!
在之前
让我们仔细看看下面这段代码:
Car = function(brand){
this.brand = brand;
}
Car.prototype.getBrand = function(){
return this.brand;
};
福特=新车(福特);
菲亚特=新车(菲亚特);
ford.getBrand(); //Ford
fiat.getBrand(); //菲亚特
乍一看,你可能认为 getBrand
归 ford
和 fiat
所有,但这是错误的。当你想知道事物在内存中的组织方式时,你不应该单独依赖代码,这可能会产生误导。这是一个正确的快照:
/ $ b $b├──Car
│└──原型$ b $b│└──getBrand$ b $b├──ford$ b $b│├──品牌$ b $b│└──__proto__ - > /汽车/原型$ b $b└──fatat$ b $b├──品牌$ b $b└──__proto__ - > / car / prototype
将其视为文件夹结构,其中目录是对象,文件是属性或方法,和链接是对其他对象的引用。正如我所说, / ford / getBrand
不存在。自己检查, ford.hasOwnProperty(getBrand)
给出 false
。所以,您可能会问,为什么 ford.getBrand()
不会崩溃?这就是名为 __ proto __
的奇怪东西。
__ proto __
是一个可以在每个对象中找到的属性。在我们的代码中, / ford / __ proto __
可以看作是 / Car / prototype
的链接。它也可以被视为一个隐藏文件,因为如果您编写 console.log(ford)
,您将看不到它。事实是你不应该玩它,使用 __ proto __
是有争议的,并且已经气馁了。 (详情请参阅 MDN )。
但超出 __ proto __
争议, ford.getBrand()
有效,因为JavaScript实现了所谓的查找机制。当它无法在对象中找到某些东西时,它将继续搜索该对象的原型。碰巧,由于 / ford / getBrand
不存在,JavaScript将查看 / ford / __ proto __
。
我想告诉你的是,场景背后发生了很多事情,但没有什么神奇之处。该语言执行一些你必须找到和解除的技巧: - )
关于这个
此
是一个上下文关键字,换句话说,它的值取决于上下文。上下文(=范围)是一组值。例如,全局上下文( /
)包含 Car
, ford
和 fiat
,但它还包含这个
,它指的是......全局上下文本身!更有趣的是,JavaScript允许您创建新的上下文。据我所知,调用函数是唯一的方法:
function f(v){
//上下文出生
// ... ...
//上下文死亡
}
f(); //新的本地上下文
f(); //新的本地上下文
在如上所述的本地上下文中, this
默认情况下指的是全局上下文。你可能想要覆盖默认行为,遗憾的是你不能写 this = anything
。没关系,你仍然可以使用 new
关键字,上下文调用或者......暴力破解这个
。
默认情况下:
Car(Ford);
console.log(品牌);
//打印Ford:-\告诉你,
//在'Car`
/`this`的上下文中指的是全局
//上下文默认为
使用 new
关键字:
audi = new Car(Audi);
//在'Car`
//'this`的上下文中指的是`audi`
通过上下文调用:
ford.getBrand(); //Ford
//在`getBrand`
/`this`的上下文中指的是`ford`
使用暴力:
ford.getBrand.call(fiat); //Fiat
//在`getBrand`
/`this`的上下文中指的是`fiat`!
然而,正如您所见,此
永远不会引用 Car
,这就是为什么缺少 / Car / brand
的原因。从构造函数内部向此
添加属性会修改实例( ford
, fiat
或 audi
),而不是班级( Car
)。
之后
跟踪 ford =新车(福特)
:
1。 /车存在吗?是
2.创建一个新对象
3.使用this调用Car =新对象
3.1。将__proto__添加到此
3.2。将此.__ proto__设置为/ Car / prototype
3.1。将品牌添加到
3.2。将this.brand设为Ford
3.3。返回此(新对象)
4.将福特设置为新对象
追踪 ford.getBrand.call(fiat)
:
1。 /福特存在?是
2. / ford / getBrand存在?没有
3. / ford / __ proto __ / getBrand存在吗?是
4. call / ford / __ proto __ / getBrand with this = fiat
4.1。 /菲特存在?是
4.2。 / fiat /品牌存在?是
4.3。返回/菲亚特/品牌
一个简短的演示:
Car = function(brand){console.log(this === Car =,this === Car); this.brand = brand;} Car.prototype.getBrand = function(){console.log(this === ford =,this === ford); return this.brand;}; ford = new Car(Ford); ford.getBrand(); console.log(ford.hasOwnProperty(\getBrand \)=,ford.hasOwnProperty(getBrand) )); console.log(Car.prototype === ford .__ proto__ =,Car.prototype === ford .__ proto __); console.log(Car =,Car); console.log(ford = ,ford); console.log(Car.prototype =,Car.prototype); console.log(ford .__ proto__ =,ford .__ proto __);
In console, I created a construction function 'Car' like below, and new-ed a object named 'mycar', and it happend like this:
> var Car = function() {
... this.make = "Ford";
... }
undefined
> var mycar = new Car()
undefined
> mycar.make // when I visit mycar.make, it worked
'Ford'
> Car.make // when I visit Car.make, it didn't work
undefined
So I want to ask:
how to visit the 'Car.make' like I visit the 'mycar.make'?
clarify: to visit
make
via the nameCar
but not viamycar
where did the field this.make="Ford"
go?
I also tried to expand its __proto__
in Chrome dev console, but didn't found it.
Thanks!
Before this
Let's take a close look at the following piece of code :
Car = function (brand) {
this.brand = brand;
}
Car.prototype.getBrand = function () {
return this.brand;
};
ford = new Car("Ford");
fiat = new Car("Fiat");
ford.getBrand(); // "Ford"
fiat.getBrand(); // "Fiat"
At first glance you may think that getBrand
is owned by ford
and fiat
, but it's wrong. When you want to know how things are organized in memory you should not rely on the code alone, it can be misleading. Here is a proper snapshot :
/
├── Car
│ └── prototype
│ └── getBrand
├── ford
│ ├── brand
│ └── __proto__ -> /Car/prototype
└── fiat
├── brand
└── __proto__ -> /Car/prototype
Think of it as a folder structure where directories are objects, files are attributes or methods, and links are references to other objects. As I said, /ford/getBrand
doesn't exist. Check by yourself, ford.hasOwnProperty("getBrand")
gives false
. So, you may ask, why ford.getBrand()
doesn't crashes ? This is where this weird stuff called __proto__
comes in.
__proto__
is a property that you can find in every object. In our code, /ford/__proto__
could be seen as a link to /Car/prototype
. It could also be seen as a hidden file since you won't see it if you write console.log(ford)
. The fact is that you are not supposed to play with it, "The use of __proto__
is controversial, and has been discouraged." (read more on this at MDN).
But beyond the __proto__
controversy, ford.getBrand()
works because JavaScript implements what's called a lookup mechanism. When it fails to find something into an object, it will keep searching into the prototype of this object. As it happens, since /ford/getBrand
does not exist, JavaScript will look into /ford/__proto__
.
What I want to show you is that there is a lot of things that happen behind the scene, but there is nothing magical. The language performs some tricks that you have to find and demistify :-)
About this
this
is a contextual keyword, in other words, its value depends on a context. A context (= a scope) is a set of values. For example, the global context (/
) contains Car
, ford
and fiat
, but it also contains this
, which refers to... the global context itself ! More interesting, JavaScript allows you to create new contexts. As far as I know, calling a function is the only way to do it :
function f (v) {
// context birth
// ...
// context death
}
f(); // new local context
f(); // new local context
In a local context like the one above, this
refers to the global context by default. You may want to overwrite the default behaviour, unfortunately you can't write this = anything
. Nevermind, you can still take control over this
using the new
keyword, a contextual call or... brute force !
By default :
Car("Ford");
console.log(brand);
// prints "Ford" :-\ told you,
// in the context of `Car`
// `this` refers to the global
// context by default
With the new
keyword :
audi = new Car("Audi");
// in the context of `Car`
// `this` refers to `audi`
With a contextual call :
ford.getBrand(); // "Ford"
// in the context of `getBrand`
// `this` refers to `ford`
Using "brute force" :
ford.getBrand.call(fiat); // "Fiat"
// in the context of `getBrand`
// `this` refers to `fiat` !
However, as you can see, this
never refers to Car
, that's why /Car/brand
is missing. Adding properties to this
from the inside of the constructor modifies the instance (ford
, fiat
or audi
), not the class (Car
).
After this
Trace of ford = new Car("Ford")
:
1. /Car exists ? yes
2. create a new object
3. call Car with this = the new object
3.1. add __proto__ to this
3.2. set this.__proto__ to /Car/prototype
3.1. add brand to this
3.2. set this.brand to "Ford"
3.3. return this (the new object)
4. set ford to the new object
Trace of ford.getBrand.call(fiat)
:
1. /ford exists ? yes
2. /ford/getBrand exists ? no
3. /ford/__proto__/getBrand exists ? yes
4. call /ford/__proto__/getBrand with this = fiat
4.1. /fiat exists ? yes
4.2. /fiat/brand exists ? yes
4.3. return /fiat/brand
A short demo :
Car = function (brand) {
console.log("this === Car =", this === Car);
this.brand = brand;
}
Car.prototype.getBrand = function () {
console.log("this === ford =", this === ford);
return this.brand;
};
ford = new Car("Ford");
ford.getBrand();
console.log("ford.hasOwnProperty(\"getBrand\") =", ford.hasOwnProperty("getBrand"));
console.log("Car.prototype === ford.__proto__ =", Car.prototype === ford.__proto__);
console.log("Car =", Car);
console.log("ford =", ford);
console.log("Car.prototype =", Car.prototype);
console.log("ford.__proto__ =", ford.__proto__);
这篇关于Javascript:如何访问构造函数的'this'成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!