javascript 常规的JS函数是否是对象的一部分?

nbysray5  于 2023-02-21  发布在  Java
关注(0)|答案(2)|浏览(166)

当我打印对象时,我没有得到常规样式函数,而只得到了箭头样式函数。常规函数是隐藏在创建的对象中还是不属于类对象?

class Person {
    pName = "Hasnain";
    pAge = 22;

    displayNormalFunc1()
    {
        return this;
    }
    displayNormalFunc2()
    {
        return this;

    }
    displayArrowFunc1 = ()=>
    {
        return this;
    }
    displayArrowFunc2 = ()=>
    {
        return this;
    }
}

objp = new Person();
console.log(objp)
nhhxz33t

nhhxz33t1#

displayArrowFunc1displayArrowFunc2类似于变量,它将在每次初始化Person时被初始化displayNormalFunc1displayNormalFunc2是属于prototype的方法,prototype是原型编程语言的设计原则 它们仅在声明Person时创建一次,并直接写入Person.prototype。可以通过某些javscript API访问它们,但不在此问题中
更多信息:

参见示例:

const p1 = new Person()
const p2 = new Person()

console.log(p1.displayNormalFunc1 === p2.displayNormalFunc1) // true
consele.log(p1.displayArrowFunc1 === p2.displayArrowFunc1) // false

以及

class Foo {
  pLog() {
    console.log('p a')
  }
  log = () => console.log('a')
}

const bar = new Foo()

bar.pLog() // 'p a'
Foo.prototype.pLog = () => console.log('p b')
bar.pLog() // 'p b'

bar.log() // 'a'
Foo.prototype.log = () => console.log('b')
bar.log() // 'a'
fnatzsnv

fnatzsnv2#

这实际上与函数是否为箭头函数无关,我可以用同样的方式定义displayArrowFunc属性,但将其定义为“正则”函数表达式来重写示例,结果是相同的:

class Person {
    pName = "Hasnain";
    pAge = 22;

    displayNormalFunc1()
    {
        return this;
    }
    displayNormalFunc2()
    {
        return this;

    }
    displayArrowFunc1 = function()
    {
        return this;
    }
    displayArrowFunc2 = function()
    {
        return this;
    }
}

objp = new Person();
console.log(objp)

// see comments on answer
console.log(Person.prototype);
console.log(Person.__proto__);
console.log(Person.__proto__ === Function.prototype);

结果实际上归结为关于Javascript对象和“类”的一些不同的东西。我将尽量不太深入,而是给予一个关键事实的快速总结,并附有链接。
Javascript有a version of "inheritance" for objects--直接用于对象,* 而不是 *“类”--这与Java和C#等语言中的a version of "inheritance" for objects大不相同。基本上,每个对象都链接到一个“原型对象”,用于查找原始对象上不存在的属性(包括函数属性或“方法”)。
当你console.log一个对象时,你只会看到“直接存在”于该对象上的属性--而不是那些存在于其原型或其原型的原型等等上的属性,尽管访问原型链中的属性仍然有效。
这就是您所观察到的根本原因-原来原始示例中的“箭头样式函数”(以及我修改后的示例中的非箭头函数)是类示例objp的直接属性,但其他函数不是。
“普通函数”并不是因为这就是Javascript“类”的工作方式。正如我试图通过使用引号来暗示的那样,JS实际上并没有“类”--它们是普通Javascript函数的语法糖。JS的特点是可以使用new operator调用任何函数,然后new operator将构造一个新对象。无论函数体本身实际上做什么。在ES6引入class关键字之前(大约在2014/5年),这曾经是人们在JS中使用“类”的方式。
而向这样的“类”添加“方法”的方法应该是这样的:

function SomeClass(a) {
  this.a = a;
}

SomeClass.prototype.someMethod = function() {
  // do something here
}

注意这个方法实际上是对象SomeClass.prototype的一个属性--然后(由于JS内部的工作方式)它就变成了你通过const someInstance = new SomeClass(2);构造的任何示例的“原型对象”(在上面提到的意义上)。
这就是你的“类”代码被转换成的东西--它只是一个语法糖,这就是为什么displayNormalFunc等不被记录的原因--它们不在实际的示例对象上,而是在它的原型上。
至于为什么displayArrowFunc1和朋友会被记录,那是因为你在类中用不同的方式定义了它们--这种方式是比“类”本身更新的JS特性。你把someProperty = something放在类体中的地方,它们被称为class fields。注意我链接到的文档中的这句话:
公共示例字段存在于类的每个创建的示例上。
简而言之,这就是为什么要记录它们--因为它们在示例上,而不是在其proortype上。这不仅适用于像pNamepAge这样的“常规”值,还有你用这种方式定义的函数/方法--函数在Javascript中只是和其他值一样的值。这与您是否将这些函数表达式定义为箭头函数无关,而是您用来将它们添加到类中的语法。
简而言之,类体中的someProperty = someValue将属性直接放在每个构造的示例上,包括someValue是函数时。而“标准”方法定义是一种特殊的语法,它们最终被添加到所有此类示例的原型中-因此,当示例被记录时,它们不会出现。

相关问题