1

我之前问过为什么backbone.js 的_.isArray(arr)函数仍然返回true,即使我做了类似的事情,

var a = [];
    a.something = "test";

因为我有点期望它会变成一个[object Object](不确定这是否是引用你这样做时生成的对象的正确方法var o = {},但我说的是你可以使用 key: value 对的对象类型。任何有关如何引用该对象的见解都非常受欢迎。

我收到的答案是它不会改变数据类型a,只是将属性添加something到它。我可以在控制台中看到我得到了 a.something = "test",但是它存储在哪里?它在数组的原型中吗?(我很确定不是)。但是,简单的“添加属性”是什么意思?

var a = "";
a.asdf = "test";
a.zxcv = "test1";

不会以类似的方式返回属性,因为字符串不是对象,但函数应该是对象,然而

var a = function(){};

    a.asdf = "test";
    a.zxcv = "test1";

    console.log(a);

只返回

function (){

} 

(它看起来像一个字符串......)我不知道为什么我不能这样做var a = new Function()(即使我以前从未见过它);它返回与上面相同的内容。jslint 也说它是 eval。为什么..?

我只是想弄清楚“向对象添加属性”的含义以及这些属性“去向”的位置,以及为什么它们在不同类型的对象中的行为不同

4

2 回答 2

3

在 JavaScript 中,有几种基本类型,包括undefinednumberstring. 还有objects。所有对象都有属性。

每个小写-o 对象都是从构造函数创建的。在对象字面量表示法的情况下,构造函数是一个隐含的Object. 数组也是对象,但不是使用Object构造函数创建的,而是使用构造函数创建的Array。函数也是具有Function构造函数的对象。

数组

当您看到一个数组时,您可能会认为它具有编号的元素;0, 1, 2 等等。实际上,数组只是另一个对象,只是它不是使用字母属性名称,而是使用数字属性名称,并且您不使用它.来访问元素。

实际上,浏览器对数组进行了一些优化,以使其比使用不同类型的对象时更快,但这种优化仍将保留此处描述的语义。

拳击

字符串的奇怪行为是因为字符串不是对象,但是有一些古怪的装箱行为someString.property = value不会出错。只有对象本身才能具有属性和方法;但我们都知道这someNumber.toString()不是错误。那里怎么了?

事实证明,在某些情况下,当您尝试像使用对象一样使用原语时,它会将原语装箱成对象。例如,当我调用 时someNumber.toString(),它将使用Number构造函数创建一个与原始编号不同的对象。然后它以正常方式查找,并设置为对象toString执行它。this

当您在字符串上设置属性时,出于该操作的目的,它被隐式转换为String-constructor 对象。String它很好地设置了对象的属性;只是拳击是暂时的;装箱不会保留在保存原始字符串的变量中。

函数对象

的确,我们很少使用new Function,但如果你确实使用它,它的作用与听起来完全一样:它创建了一个新函数。你可以给它传递一个字符串,这将是函数的主体。eval如果您创建一个带有字符串主体的新函数然后调用它,那离ing 代码不远了。这就是 JSLint 将其标记为eval.

当您将对象记录到控制台时,开发人员工具通常会向您显示属性,因为这通常是对象最重要的部分。函数通常不会被分配自定义属性,因此开发人员工具只使用纯字符串表示,它通常只显示函数参数和主体。函数的字符串表示在不显示属性方面并不少见——toString普通的Object只会 return [object Object]

原型链

当然,这些信息澄清了很多事情,但它仍然没有解释这一点:

console.log(new Array() instanceof Object);  // => true

世界卫生大会?数组的构造函数是Array,不是Object!这是因为原型链。它是控制继承的东西。

每个对象都有一个名为 的内部属性[[Prototype]]。没有标准的方法来访问它,尽管许多浏览器有一个非标准的__proto__属性来访问它。用于new创建对象时,[[Prototype]]设置为prototype用于创建对象的函数的属性。

假设我们有一个对象foo,它的构造函数为Foo. 当我们访问一个属性时,它首先在自己的属性中foo.bar查找。如果在那里找不到或未定义,它将在'自己的属性中查找。如果在那里找不到,它将在's中查找,然后一直查找,直到找到。这是允许继承的功能。barfoobarfoo[[Prototype]]barfoo[[Prototype]][[Prototype]]null [[Prototype]]

为了确定一个对象是否是一个实例,isinstance通过原型链查看是否有任何[[Prototype]]s 匹配prototype函数的。原来,如果你遍历一个数组的原型链,你会碰到Array'prototype,Object'prototype,然后是null。因此,将isinstance屈服于truenew Array() instanceof Object

进一步阅读

您可能对带注释的 ECMAScript 5 规范感兴趣,该规范定义了语言,当然还详细介绍了一些使用的特定算法。它不会为您安排好一切;一些非常有见地的东西没有明确描述,但需要你自己拼凑一些。出于这个原因,除非您尝试自己实现它,否则您可能不想直接通读它,而是在您对某些行为感到好奇时参考它的部分内容。

于 2013-07-25T05:40:20.943 回答
0

在 javascript 中,数组只是一个对象,它具有从 0 到 n 个您提供的值的预分配键。

var x = ['a','b','c','d',234];就像

var x = {0:'a',1:'b',2:'c',3:'d',4:234,length:5}; 并且所有数组函数都可以使用这样的数组调用来处理它Array.prototype.sort.push(x,'sdfsd');

Main Object 的所有方法/属性都由所有数组继承。

因此,当您将非数值分配给数组时,假设有 2 个元素。它是这样添加的...

var x =['a','Stack','flow',0];
--added value x.a = 'something';
it really looks like this now
var x = {
    0:'a',
    1:'Stack',
    2:'flow',
    3:'0',
    a:'something'
    }

但是,对于 js,x仍然是一个数组,当您在x上运行任何函数时,a不会出现。直到您像x.a.

x.hasOwnProperty('a'); //true

Object.keys(x); //listing all keys in object(array x)
// ["0", "1", "2", "3", "a"] !!!keys function returns an array consisting of all keys in an object.

功能对象是不同的,它们不仅仅是带有键的对象。

您仍然可以为它们分配东西,但它们只会返回函数。您可以访问 xa 等属性。但不要这样做。

概括

一切都继承自Object对象,因此可以具有属性和方法。

数组是专门的对象,被称为Array从 继承方法/道具Object,将值存储在名为 0-n 形式的索引键中。但是由于继承,仍然可以有额外的属性和方法,尽管不会出现在数组方法或属性中。

函数是继承自function object其继承的对象,Object因此函数(functionObjects)具有两者的属性。函数也有额外的属性,比如原型和参数。

当你写这个:...

var x = new function anonymous/named (){} 发生 3 件事: 1. x = {}; 2. 函数执行...如果它有 this.p = etcc...然后 x 得到它并且 x 变成 x= {p:'etc'} 3. x. proto = function.prototype

那么如果你在 x 中查找一个属性或方法但没有找到,那么 js 会查看 proto 中是否有一些东西,那么它指的是函数的原型对象,它会去那里并在那里搜索。这就是你在Javascript中拥有类的方式。

于 2013-07-25T05:42:03.497 回答