3

我经历了很多有描述的 Stack Overflow 问题,但我发现它们非常令人困惑。我想要的是一个简单的解释,请不要引用链接。

我完全糊涂了,完全混为一谈:

  • 原型,

  • 对象,

  • 构造函数

我做了很多研究,但我发现它们非常复杂。

有什么简单的解释吗??

4

4 回答 4

11

好的,旋风之旅:

对象

对象是具有属性的事物。属性具有名称和值。名称始终是字符串(尽管大多数情况下我们可以不带引号来编写它们),并且值可以是 JavaScript 支持的任何内容:数字、字符串、布尔值、null、未定义或对对象的引用。

所以:

var a = {
    propertyName: "property value"
};

a是一个引用对象的变量,该对象有一个名为 的属性propertyName,其值为字符串"property value"

原型

一个对象(比如)可以在它“后面”obj有另一个对象(比如),除非有自己的具有给定名称的属性,否则它会借用它的属性。是 的原型对象。举个例子最容易理解:ppobjobjpobj

// Let's create an object `p` with a couple of properties, `x` and `y`
// This syntax is called an "object initializer" (aka "object literal")
var p = {
    x: "x on p",
    y: "y on p"
};

// Now, we'll create a new object, `obj`, using `p` as its prototype
var obj = Object.create(p);

// And that means if we ask `obj` for a property called `x`, since it doesn't
// have its **own** `x`, it asks `p` for it. (And the same with `y`)
console.log(obj.x); // "x on p"
console.log(obj.y); // "y on p"

// But we can give `obj` its *own* `x` instead if we want
obj.x = "x on obj";
console.log(obj.x); // "x on obj"
console.log(obj.y); // "y on p"

// Doing that to `obj` had no effect on `p`
console.log(p.x); // "x on p"
console.log(p.y); // "y on p"

原型的一个非常非常重要的方面是对象之间的连接是实时的。因此,如果obj没有y属性,则每次我们要求objy时都会询问p。因此,如果我们更改p的值y,如果我们要求更改,就会显示该更改obj

var p = {
    x: "x on p",
    y: "y on p"
};

var obj = Object.create(p);

console.log(obj.y); // "y on p"

p.y = "updated y on p";

console.log(obj.y); // "updated y on p"

这种实时连接是至关重要的。再一次,这样想:我们 obj财产y,然后obj说“我没有自己的,所以我会去要p它,然后给你。”

注意:Object.create我用来创建的函数obj是 ECMAScript5 的新函数(几年前的规范更新)。我们将回到另一种为对象提供原型的方法。

对象的原型当前始终在创建对象时设置,并且无法更改(我无法在创建后交换 aq而不是p上面的obj)。上面是我Object.create用来做的(下面我们将讨论构造函数)。在 ECMAScript5 (ES5) 之前,没有标准的方法来获取对象的原型。ES5 现在为我们提供了一种方法,称为Object.getPrototypeOf,但仍然没有提供改变它的方法。下一个版本 ES6 会更进一步。

职能

函数是做事的代码单元。函数也是对象,因此它们可以具有属性,尽管实际上很少在函数上使用属性(除了calland apply,我们不需要在这里讨论)。

您可以声明一个函数:

function foo() {
}

...或者您可以使用表达式创建一个:

// An anonymous -- unnamed -- function assigned to variable `foo`
var foo = function() {
};

// A function named `f` assigned to variable `foo`
var foo = function f() {
};

声明和表达式是不同的。在执行同一范围内的任何分步代码之前,对函数声明进行评估。与所有其他表达式一样,函数表达式在分步代码中遇到时进行评估。(人们有时称其为“提升”,因为这意味着实际上,即使函数声明位于范围的底部,它也会发生,就好像它已被提升 - 提升 - 到顶部。)

函数可以有参数:

// `a` and `b` are arguments
function sum(a, b) {
    console.log(a + b);
}

他们可以有返回值:

function sum(a, b) {
    return a + b;
}
console.log(sum(1, 2)); // "3"

如果一个函数没有返回其他值,则调用该函数的结果就是 value undefined

方法

JavaScript 没有方法。它只有功能——但这就是它真正需要的。但是,如果您有一个分配给对象属性的函数,并且您将该函数作为从对象中检索属性的表达式的一部分调用,那么就会发生一些事情,使 JavaScript看起来有方法:this关键字在函数调用中引用该对象. 再一次,一个例子创造了奇迹:

// A blank object
var obj = {};

// Lets put a function on it as a property
obj.foo = function() {
    console.log("this is obj? " + this === obj);
};

// Let's call that function
obj.foo(); // "this is obj? true"

更多关于我的博客:

构造函数

构造函数与new关键字一起使用,它们是您为对象提供原型的方式之一。当您通过 调用函数时new,会创建一个新对象,并从函数的prototype属性中分配一个原型:

function Foo() {
}
Foo.prototype.x = "x on Foo.prototype";

var obj = new Foo();
console.log(obj.x); // "x on Foo.prototype"

每个函数都会自动拥有一个prototype属性,尽管我们当然不会将绝大多数函数用作构造函数。

这里需要注意的重要一点:prototype函数的属性只是一个无聊的旧属性。它不是任何对象的原型,直到/除非通过new运算符调用该函数。当你通过 调用函数时,new操作符使用函数的prototype属性来设置新对象的原型,仅此new而已。

值得一提的是,在 ES5 之前,像上面这样的构造函数是您可以使用给定原型创建对象的唯一方法。但是有了 ES5,我们得到了Object.create,它为如何使用 JavaScript 开辟了更多的模式。(通过使用临时函数总是可以创建自己的Object.create,事实上这正是某些人所做的。)有些人不喜欢使用new关键字和prototype属性,他们更喜欢使用“builder”模式你只需调用一个函数并取回一个对象。JavaScript 非常灵活,您可以做到这一点。


更多探索

于 2013-05-30T12:18:26.740 回答
4

你很幸运。有一个非常简单的解释:

第一步:创建一个对象

假设您要圈出:

var circle = {};

第二步:给它一些属性

可以画一个圆,所以让我们创建一个名为 的属性draw

circle.draw = function () {
    // drawing logic
};
  1. 属性只是属于对象的变量。变量本身不是属性。
  2. 属性和变量可以保存任何类型的数据。JavaScript 中的函数是数据。
  3. 当一个属性包含一个函数时,它被称为一个方法。

因此,我们有一个称为draw属于对象的方法circle

第三步:扩展对象

现在我想要一个球,一个球有点像一个圆圈。所以让我们扩展circle创建一个球:

var ball = Object.create(circle);
  1. 在这里,我们获取对象circle并使用它来创建一个名为 的新对象ball
  2. 该对象ball现在具有 的所有属性circle。所以我们可以调用ball.draw.
  3. 该对象circle是 的原型ball

第四步:给它一些属性

每个球都有一个radius,所以让我们给我们一个:

ball.radius = 5;

第五步:创建构造函数

这里有问题。每次我想创建一个新球时,我都会扩展circle并手动定义radius球的。相反,我想要一个函数来创建球并给它一个半径。此函数称为构造函数:

function createBall(radius) {
    var ball = Object.create(circle);
    ball.radius = radius;
    return ball;
}

var baseball = createBall(5);
var basketball = createBall(10);

baseball.draw();
basketball.draw();

这几乎就是您需要了解的有关原型、对象和构造函数的全部内容。

当然还有更多解释,但对于一个 StackOverflow 答案来说太多了。我写了一篇关于它的博客文章,我不打算在这里重写同样的东西。你应该阅读我的博客。这是值得的: http: //aaditmshah.github.io/why-prototypal-inheritance-matters


编辑:当然,我将解释该代码中发生的事情:http: //cssdeck.com/labs/4ksohwya

首先,向下滚动到最后:

window.addEventListener(
    'load',
    init(null),
    false);

当页面加载它执行init

function init(images) {

    canvas= document.getElementById('s');
    ctx= canvas.getContext('2d');
    canvas.width= window.innerWidth;
    canvas.height=window.innerHeight;

    garden= new Garden();
    garden.initialize(canvas.width, canvas.height, 300);

    lerp(0,2000);

    time= new Date().getTime();
    interval = setInterval(_doit, 30);
}

init函数创建Garden( garden = new Garden();) 的实例并执行 的initialize方法garden。它还_doit以 30 毫秒的间隔调用该函数。

initialize : function(width, height, size)  {
  this.width= width;
  this.height= height;
  this.grass= [];

  for(var i=0; i<size; i++ ) {
    var g= new Grass();
    g.initialize(
        width,
        height,
        50,      // min grass height 
        height*2/3, // max grass height
        20,     // grass max initial random angle 
        40      // max random angle for animation 
        );
    this.grass.push(g);
  }

  this.stars= [];
  for( i=0; i<this.num_stars; i++ )  {
    this.stars.push( Math.floor( Math.random()*(width-10)+5  ) );
    this.stars.push( Math.floor( Math.random()*(height-10)+5 ) );
  }
},

然后 的initialize方法garden创建 的一些实例Grass,调用它们的initialize方法并将它们存储在一个数组中。

function _doit()    {

  ctx.fillStyle= gradient;
  ctx.fillRect(0,0,canvas.width,canvas.height);
  var ntime= new Date().getTime();
  var elapsed= ntime-time;
  garden.paint( ctx, elapsed );

  // lerp.
  if ( elapsed>nextLerpTime ) {
    lerpindex= Math.floor((elapsed-nextLerpTime)/nextLerpTime);
    if ( (elapsed-nextLerpTime)%nextLerpTime<lerpTime ) {
      lerp( (elapsed-nextLerpTime)%nextLerpTime, lerpTime );
    }
  }

}

_doit函数调用 的paint函数,函数调用每个草garden的函数。paintgardenpaint


所以这里有两个构造函数:

  1. Grass
  2. Garden

这是两个原型:

  1. Grass.prototype
  2. Garden.prototype

init函数内部,我们创建了一个Garden(即一个对象)的实例:

var garden= new Garden();

在我们创建多个实例的initialize方法内部:gardenGrass

var g= new Grass();

就是这样。

于 2013-05-30T12:19:37.257 回答
0

我想我为时已晚,但这是我的 2 美分:

原型:

String.prototype.x = "yahoo"

现在String的每个实例都将具有属性x

所以无论是它(new String()).x还是"".x两者都具有等于雅虎的价值

因此,它就像扩展一个预定义的类。


对象

JavaScript 中的所有东西,除了其他原始类型,都是一个对象。

对象是名称-值对的集合,仅此而已。

{"a": 0, "b" : 1}

甚至Array也是 JS 中的一个对象,具有一些额外的属性和方法。


函数和方法

这是一个功能:

function a() { };

现在让我们给它一个Array方法的状态:

Array.prototype.a = a;

构造函数:

new String()

从以下位置获取 String 的实现:String.constructor

同样,您在任何函数中编写的代码都会进入这个函数。

于 2013-05-30T12:29:29.927 回答
-4

JavaScript 是 Web 应用程序中用于使网页动态化的脚本语言。这种语言允许通过处理页面上显示的元素上的事件来处理用户操作......它还用于根据条件修改网页上的内容......

方法(或)函数是 javascript 中用于指定逻辑的编程结构。您将把所需的逻辑放入一个方法中,并在发生任何事件时从网页调用它...

javascript中没有构造函数...

javascript中会有隐式和用户定义的对象...隐式对象包括日期、数组等...

这只是一个基本的摘要.. 您需要关注网站(或)书籍以了解更多关于 javascript 的信息

于 2013-05-30T12:06:17.623 回答