我经历了很多有描述的 Stack Overflow 问题,但我发现它们非常令人困惑。我想要的是一个简单的解释,请不要引用链接。
我完全糊涂了,完全混为一谈:
原型,
对象,
构造函数
我做了很多研究,但我发现它们非常复杂。
有什么简单的解释吗??
我经历了很多有描述的 Stack Overflow 问题,但我发现它们非常令人困惑。我想要的是一个简单的解释,请不要引用链接。
我完全糊涂了,完全混为一谈:
原型,
对象,
构造函数
我做了很多研究,但我发现它们非常复杂。
有什么简单的解释吗??
好的,旋风之旅:
对象是具有属性的事物。属性具有名称和值。名称始终是字符串(尽管大多数情况下我们可以不带引号来编写它们),并且值可以是 JavaScript 支持的任何内容:数字、字符串、布尔值、null、未定义或对对象的引用。
所以:
var a = {
propertyName: "property value"
};
a
是一个引用对象的变量,该对象有一个名为 的属性propertyName
,其值为字符串"property value"
。
一个对象(比如)可以在它“后面”obj
有另一个对象(比如),除非有自己的具有给定名称的属性,否则它会借用它的属性。是 的原型对象。举个例子最容易理解:p
p
obj
obj
p
obj
// 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
属性,则每次我们要求obj
它y
时都会询问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 会更进一步。
函数是做事的代码单元。函数也是对象,因此它们可以具有属性,尽管实际上很少在函数上使用属性(除了call
and 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 非常灵活,您可以做到这一点。
我在我的博客上写了关于 JavaScript 的文章:Nifty Snippets - javascript
label
Mozilla 开发网络拥有出色的JavaScript 信息
当然,还有规范——它是实际细节的最佳来源,但很难阅读 :-)
你很幸运。有一个非常简单的解释:
第一步:创建一个对象
假设您要圈出:
var circle = {};
第二步:给它一些属性
可以画一个圆,所以让我们创建一个名为 的属性draw
:
circle.draw = function () {
// drawing logic
};
因此,我们有一个称为draw
属于对象的方法circle
。
第三步:扩展对象
现在我想要一个球,一个球有点像一个圆圈。所以让我们扩展circle
创建一个球:
var ball = Object.create(circle);
circle
并使用它来创建一个名为 的新对象ball
。ball
现在具有 的所有属性circle
。所以我们可以调用ball.draw
.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
的函数。paint
garden
paint
所以这里有两个构造函数:
Grass
Garden
这是两个原型:
Grass.prototype
Garden.prototype
在init
函数内部,我们创建了一个Garden
(即一个对象)的实例:
var garden= new Garden();
在我们创建多个实例的initialize
方法内部:garden
Grass
var g= new Grass();
就是这样。
我想我为时已晚,但这是我的 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
同样,您在任何函数中编写的代码都会进入这个函数。
JavaScript 是 Web 应用程序中用于使网页动态化的脚本语言。这种语言允许通过处理页面上显示的元素上的事件来处理用户操作......它还用于根据条件修改网页上的内容......
方法(或)函数是 javascript 中用于指定逻辑的编程结构。您将把所需的逻辑放入一个方法中,并在发生任何事件时从网页调用它...
javascript中没有构造函数...
javascript中会有隐式和用户定义的对象...隐式对象包括日期、数组等...
这只是一个基本的摘要.. 您需要关注网站(或)书籍以了解更多关于 javascript 的信息