【问题标题】:What 's the prototype used when a function is declared in javaScript在 javaScript 中声明函数时使用的原型是什么
【发布时间】:2013-11-22 06:07:45
【问题描述】:

我有一个关于 javaScript 函数的问题。考虑以下两个函数定义:

    // run time definition 
    var foo_1 = function () {
        console.log("I ma foo 1"); 
    }
    // parse time definition 
    function foo_2 ()  {
        console.log("I ma foo 2"); 
    }

既然在 javaScript 中每件事都是一个对象,那么在前面的代码中是否创建了两个名为 foo_1foo_2 的新对象?如果有,它们的原型对象是什么?这些对象是什么时候创建的?

我也在努力理解 var obj={} 和 var foo=function(){} 之间的真正区别,它们都是对象,但第一个具有“类型”Object,而第二个具有类型 function。它是否正确?

根据我的书“JavaScript 的优点”,每个新的文字对象都链接到Object.prototype,默认情况下是一个空对象。为了验证这种行为,我尝试运行以下脚本:

Object.prototype
//Object {}
Object.prototype = { name: "This is an experiment"}; 
//Object {name: "This is an experiment"}
function test() { conosle.log("Test"); }
test.prototype;
//Object {}

为什么test.prototype 的结果是一个空对象?

最后,我想知道这些函数定义是否等同于以下代码:

   this.foo =  function() {
         console.log("I ma foo");
    }

如果有,this 是什么?

【问题讨论】:

标签: javascript function


【解决方案1】:

为什么 test.prototype 的结果是一个空对象?

所有函数都有一个prototype属性,最初引用一个空对象。

定义:(重新签名)

整个 JavaScript 都使用原型作为一种方便的方式 定义将自动执行的属性和功能 应用于对象的实例

您设置了 Objectprototype 值,而不是 test 函数。

在 JS 中 - 每个对象 - 继承 Object.prototype

如果您已将函数附加到 Object.prototype - 如您所愿:

Object.prototype.name = function (){alert(1);}; 
function test() { console.log("Test"); }
var a = new test();
a.name();

它会提醒1

编辑

关于您的评论:

我们真正想要实现的是一个原型链,以便一个 Player 可以是人,人可以是哺乳动物,哺乳动物可以是 Animal 等等,一直到 Object。最好的技术 创建这样一个原型链就是使用一个对象的实例作为 另一个对象的原型:

SubClass.prototype = new SuperClass();

考虑这段代码:

function Person(){}

   Person.prototype.dance = function(){};

function Player(){}

   Player.prototype = new Person();     <------

var player = new Player();

assert(player instanceof Player,"player receives functionality from the Player prototype");
assert(player instanceof Person, "... and the Person prototype");
assert(player instanceof Object, "... and the Object prototype");
assert(typeof player.dance == "function", "... and can play!")

指出的那一行是使你能够从人中创建玩家的原因(你会看到玩家是人的一个实例!):

http://jsbin.com/oNixIMo/8/edit

【讨论】:

  • You set the prototype value of Object and not for the test function. 是的,但这应该在创建函数时从 Object 继承,不是吗? Object.prototype.name =...Object.prototype= ... 有什么区别?
  • test.prototype 也是一个对象,所以 is 将继承Object.prototype 中定义的属性。
  • @RoyiNamir 正如我所说,这不是真的:jsbin.com/oNixIMo/5/edit testprototype 本身就是一个对象,所以它当然也会继承自 Object.prototype;除非你像我在回答中解释的那样破坏链,否则设置为 test.prototype 一个根本没有原型链的新对象。
  • @ZER0 我明白你的意思了。你是对的。删除了那部分。它将使用它,因为所有对象都这样做 - 继承 Object.prototype。 tnx 指出这一点..
【解决方案2】:

我觉得你对函数和对象的原型有些困惑,希望我能澄清一下。

首先:

function foo_2 ()  {
    console.log("I ma foo 2"); 
}

这称为“函数声明”,其中:

var foo_1 = function () {
    console.log("I ma foo 1"); 
}

称为“函数表达式”。您可以在此处获得详细信息:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression,以及 Function 构造函数示例。

既然在 javaScript 中每件事都是一个对象,那么在前面的代码中是否创建了两个名为 foo_1 和 foo_2 的新对象?

是的,它们是对象,如果您修改 prototype 链,您将影响它们:

Object.prototype.testName = "this is an experiment";

function test() {}

console.log(test.testName) // "this is an experiment"

但是test.prototype 也是一个对象,所以如果你这样做:

console.log(test.prototype.testName) // "this is an experiment"

你没有正确获取属性的原因可能是因为是继承的,你使用的控制台(节点,浏览器)只显示对象自己的属性(如Object.keys),没有抓取整个原型链。

这是主要原因,因为您不应该更改 Object.prototype:您将影响几乎所有事情,并且您无法预测后果。

我说“大部分”是因为您可以创建实际上不继承自 Object 原型的对象。您可以使用 Object.create 或支持的非标准 _proto_

var foo = {};
console.log(foo.testName) // "this is an experiment"

var bar = Object.create(null);
console.log(bar.testName) // undefined

最后,我想知道这些函数定义是否等同于以下代码:

this.foo =  function() {
  console.log("I ma foo");
 }

这取决于您执行此代码时this 是什么。如果您在全局范围内执行代码,它们基本上是等价的,因此 this 将是全局对象(在浏览器中是 window)。但是,有区别。使用此语法,您将能够删除 foo 属性,在声明时您不能这样做。所以:

this.foo = function() {};
var bar = function() {};

delete foo // can be deleted;
delete bar // shouldn't be deleted;

见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

【讨论】:

    【解决方案3】:

    是的var fn = function(){}; 是函数类型

    为什么 test.porototype 是空的:因为它是 Function.prototype,而不是 Object.prototype

    这是什么:在最后贴的链接中回答

    您可以使用函数作为构造函数来创建对象:

    var Person = function(name){
      this.name = name;
    };
    Person.prototype.walk=function(){
      this.step().step().step();
    };
    

    在示例中,Person 被称为构造函数,因为它是一个对象,您可以为其赋予属性,例如:Person.static="somthing" 这对于与 Person 相关的静态成员很有用,例如:

     Person.HOMETOWN=22;
     var ben = new Person("Ben");
     ben.set(Person.HOMETOWN,"NY");
     ben.get(Person.HOMETOWN);//generic get function what do you thing it'll get for ben?
     ben.get(22);//maybe gets the same thing but difficult to guess
    

    当您使用 Person 创建实例时,您必须使用 new 关键字:

    var bob = new Person("Bob");console.log(bob.name);//=Bob
    var ben = new Person("Ben");console.log(bob.name);//=Ben
    

    属性/成员name 是特定于实例的,对于 bob 和 ben 来说是不同的

    成员 walk 可用于所有实例(bob 和 ben 是 Person 的实例)

    bob.walk();ben.walk();
    

    因为在 bob(以及后来的 ben)上找不到 walk(),JavaScript 将在 Person.prototype 中查找它。 bob 和 ben 都只有一个 walk 函数,但该函数的行为会有所不同,因为在 walk 函数中它使用 this

    如果 ben 正在等待红灯并且您将调用 walk 并且 bob 处于绿灯状态,那么显然即使 walk 对 bob 和 ben 执行相同的操作但 @987654331 也会发生不同的事情@ 将引用当前对象(bob 为 bob,ben 为 ben)。

    当我执行ben.walk=22 之类的操作时,会出现阴影成员,即使 bob 和 ben 共享 walk 将 22 分配给 ben.walk 不会影响 bob.walk。这是因为该语句将在 ben 上创建一个名为 walk 的成员并为其分配值 22。当请求 bob.walk 时,您将获得 Person.prototype.walk 函数,因为在 bob 上找不到 walk .然而,请求 ben.walk 会得到 22 的值,因为成员 walk 是在 ben 上创建的,并且由于 JavaScript 发现 walk on ben 它不会在 Person.prototype 中查找。

    因此,当在实例上找不到成员时,JavaScript 引擎将查找构造函数的原型。那么 ben.hasOwnProperty 是从哪里形成的呢?实例 ben 没有它, Person.prototype 没有它。答案是有一个原型链,Person 的构造函数是 Function,所以当在 ben 或 Person.prototype 上找不到 hasOwnProperty 时,它会查找 Person 构造函数的原型(即 Funcition)。如果它在那里找不到 hasOwnProperty(但它可以),那么它会在 Function 的构造函数的原型(是 Object)中查找。

    一切都应该从 Object.prototype 继承,除非你这样做 Object.create(null,{}) 在我看来这是一个坏主意。您可以在 Object.prototype 上添加东西(这也不是一个好主意),JS 中的任何对象都将“继承”:

    Object.prototype.yipee=function(){
      console.log("yipeee");
    };
    
    22..yipee();//logs yipeee
    "hello".yipee();//logs yipee
    

    现在您已经了解了它的基础知识,您可以查看以下内容:

    https://stackoverflow.com/a/16063711/1641941(以“this变量”结尾)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-23
      • 2011-08-07
      • 2011-06-01
      • 2011-02-16
      • 2012-07-15
      • 2021-03-17
      • 1970-01-01
      • 2018-10-26
      相关资源
      最近更新 更多