javascript对象定义-Javascript 中的对象查找

2023-08-26 0 5,132 百度已收录

最近经常有人在群里问一些简单的问题,比如贴出一段代码乱七八糟的代码,然后说上面的某个变量是什么。 例如,这是一个很好的例子:

function fn(arg) {
alert(
this.arg);
alert(
this);
}
fn(
123);
var o = { fn: fn };
o.fn(
123);

那么可能会有这样的疑问:

为什么 this.arg 未定义? 为什么两次调用 fn 的 this 不同?

为此,我认为作为一个看似不成熟的后端,我还是应该教导和解释我能做的事情。 因此,在本文中,我计划从非常肤浅的层面解释 javascript 中的对象搜索是如何工作的。

注意,本文只是从一个幻觉中介绍了对象查找的过程。 文章中的观点并不都是正确的,甚至还存在一些谬误,但这也是为了初学者更好地理解对象查找的过程。 我认为如果太具体、太深入的话,会造成一些负面影响。 如果三天后,你回来发现这篇文章不是那么正确,那么恭喜你,那时你已经可以找到正确的前进方向,并且这篇文章中的错误将不再对你产生任何影响。

物体分类

所谓对象搜索,就是在一段可执行代码的范围内找到当前需要的对象。 在javascript中,需要搜索的对象大致可以分为三类:

区分这3种类型的对象查找是首要任务,您可以根据以下原则进行区分:

看一下这段代码:

var foo = this;
foo.bar();

这两行代码演示了 3 种类型的对象查找,即:

找到 this 对象并给 foo 变量一个形式参数。 查看 foo 变量。 找到 foo 变量下的 bar 属性并将其作为 function.variable 查找调用

当某个对象的搜索被确定为变量搜索后,就可以按照变量搜索的规则进行查看。

变量查找,即作用域链上的查找。 作用域链是 javascript 中两个著名的链之一。 以下代码显示了标准作用域链:

var foo = 1;
function a() {
var bar = 2;
function b() {
foo
= 3;
function c() {
alert(foo
+ ',' + bar); // 注意这一行
}
c();
}
b();
}
a();

在c函数中,一共查找了2个变量,分别是foo和bar。

变量查找可以简单地遵循“自下而下”的原则,即:

在函数 c 的范围内搜索 foo 和 bar。 显然,c上没有foo和bar的声明,搜索失败。 在包含c的函数(即函数b)范围内搜索foo和bar。 可以看到b上只有foo的形参,没有声明,所以查找失败。 在包含b的函数范围内,即函数a,搜索foo和bar,可以找到bar的声明,因此判断bar为2。由于a没有被任何函数包含,那么寻找在全局作用域中查看foo,发现有foo的声明,所以判断foo的值是1。但是因为在函数b中,这个tgcode foo有一个形参,所以foo的值就变成了3完全确定foo的tgcode值为3,bar的值为2,所以输出“3,2”。

综上所述,变量的搜索是沿着作用域链进行的。 作用域链可以简单地看成是函数之间的包含关系。 当变量在包含的函数中不存在时,将在包含该变量的函数中搜索该变量,直到全局范围。

属性查找

当确定对象的查找为属性查找时,可以根据属性查找的规则进行检查。

属性查找,即原型链上的查找,这是javascript双链的另一种,一个原型链可以表示如下:

var a = function() {};
var b = function() {};
var c = function() {};
b.prototype
= new a();
c.prototype
= new b();
a.prototype.foo
= 1;
b.prototype.bar
= 2;
c.prototype.foo
= 3;
var o = new c();
alert(o.foo
+ ',' + o.bar); // 这一行进行查找

属性查找是一个不断寻找原型的过程,即:

检查c.prototype中是否定义了foo和bar,发现定义了foo,其值为3。发现c.prototype是new b()得到的对象,然后搜索b.prototype可以看到如果定义了bar,发现定义了,其值为2,因此判断foo的值为3,bar的值为2,输出“3,2”。

综上所述,属性搜索是沿着原型链进行的。 原型链的具体知识这里就不详细讲解了,可以找另一篇文章参考。 对于所有对象来说,原型链最终都会是Object.prototype。

这次查找

搜索这个是很多人的苦恼点,很多人可能会有这个不稳定的想法javascript对象定义,这实在是让人无语。 this的查找可以说是三个对象查找中最简单的一个,因为虽然这个对象的判断根本没有“查找”的过程。

首先,this 对象只需要在一个函数中确定。 如果是在全局域中,这将始终是全局对象,通常是浏览器中的窗口对象。 在javascript中,函数调用有四种形式:

函数调用模式

诸如 foo() 之类的调用方法称为函数调用模式,这是最直接的使用函数的方式。 请注意,此处 foo 显示为单独的变量,而不是属性。

在这些模式下,foo函数体中的this始终是Global对象,即浏览器中的window对象。

方法调用模式

诸如“foo.bar()”之类的调用方法称为方法调用模式。 注意,它的特点是被调用的函数作为对象的属性出现,并且必须有“.”等关键符号。 或者 ”[]”。

在这些模式下,bar函数体中的this始终是“.”之前的对象。 或“[”,如上例,它必须是 foo 对象。

构造函数模式

new foo() 的调用被称为构造函数模式,它的关键字 new 可以很好地说明问题,并且非常容易识别。

在这些模式下javascript对象定义,foo 函数内的 this 始终是 new foo() 返回的对象。

应用图案

`foo.call(thisObject)` 和 `foo.apply(thisObject)` 方法称为Apply Pattern,它使用外部`call` 和`apply` 函数。

在这些模式下,`call` 和 `apply` 的第一个参数是 foo 函数体中的 this,如果 thisObject 为 `null` 或 `undefined`,那么它将被做成一个 Global 对象。

应用上面四种方法来判断一个函数是用什么样的Pattern来调用的,就可以很容易地判断出这是什么。

另外,这永远不会为“搜索”过程扩展作用域链或原型链,并且只有在调用函数时才会得到完全确认。

总结

对于对象的查找:

确定它是变量查找、属性查找还是此查找。 如果是变量查找,则扩展作用域链来查找它。 如果找不到,就会出现ReferenceError。 如果是属性搜索,就会沿着原型链去搜索,如果找到了,那就是未定义的。 如果是this搜索,找到调用该函数的代码,根据调用方式判断是哪个this。

注意拆分一个查找过程,比如this.foo.bar.yahoo(),可以拆分成这样的代码,这样更清晰:

var o = this; // this查找
var foo = o.this; // 属性查找
var bar = foo.bar; // 属性查找
bar.yahoo(); // 属性查找,加Method Invocation Pattern

最后,如果你能花三天时间理解这种东西,这篇文章对你的用户来说就不会很重要:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 javascript javascript对象定义-Javascript 中的对象查找 https://www.wkzy.net/game/154913.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务