JavaScript Prototype基础

The prototype Property
引用
prototype property that refers to a predefined prototype object


Prototype属性是指一个早已确定的原型对象

Classes, Constructors, and Prototypes
引用
JavaScript does not support true classes the way that languages like Java, C++, and C# do.


JavaScript不支持真正的类继承,事实上是它是一个基于原型继承的,这和传统语言很不一样。

在JavaScript the Good Parts一书中,Douglas Crockford这样描述:
引用
It is Lisp in C's Clothing


在JS中,新建一个对象可以用对象的直接量{},或者通过构造函数

var array = new Array(10);
var today = new Date( );


定义我们自己的对象
// Define the constructor.
// Note how it initializes the object referred to by "this".
function Rectangle(w, h) {
    this.width = w;
    this.height = h;
    // Note: no return statement here
}

// Invoke the constructor to create two Rectangle objects.
// We pass the width and height to the constructor
// so that it can initialize each new object appropriately.
var rect1 = new Rectangle(2, 4);    // rect1 = { width:2, height:4 };
var rect2 = new Rectangle(8.5, 11); // rect2 = { width:8.5, height:11 };


在构造函数中始终要用this来引用当前对象,以来添加对象的属性

如果要添加方法:
// Create a Rectangle object
var r = new Rectangle(8.5, 11);
// Add a method to it
r.area = function( ) { return this.width * this.height; }
// Now invoke the method to compute the area
var a = r.area( );


当创建了对象之后再添加方法显得有些麻烦,我们可以这样:
function Rectangle(w, h) {
    this.width = w;
    this.height = h;
    this.area = function( ) { return this.width * this.height; }
}


引用
It is inefficient to use regular properties for methods that are intended to be shared by all objects of the same class (that is, all objects created with the same constructor).

这样问题就来了。以这种常规属性来存储对象方法是很没有效率的,这种方法本该是没个这样的对象实例所“共享”的,而不要每次新建一个对象都要新建一个这个方法的拷贝。

这时我们的原型对象就上场了

引用
a JavaScript object inherits properties from its prototype.

After creating the empty object, new sets the prototype of that object.
The prototype of an object is the value of the prototype property of its constructor function.

All functions have a prototype property that is automatically created and initialized when the function is defined.
The initial value of the prototype property is an object with a single property. This property is named constructor and refers back to the constructor function with which the prototype is associated.

JS的对象都会从它的原型那里继承属性。
我们在new一个对象的时候,new关键字就会设定对象的prototype属性,其值就是该对象的prototype对象的引用

函数也是对象,所以它也不例外有一个在定义时就有的prototype属性

Prototype属性初始时所指向的Prototype对象只有一个constructor属性,这个属性又指向了与这个prototype对象相关的构造函数

// The constructor function initializes those properties that
// will be different for each instance.
function Rectangle(w, h) {
    this.width = w;
    this.height = h;
}

// The prototype object holds methods and other properties that
// should be shared by each instance.
Rectangle.prototype.area = function( ) { return this.width * this.height; }


上面这个例子中,在构造函数里定义了每个实例都会有不同值的属性,而在其Prototype中定义共享的属性,这里是一个方法。

引用
The prototype object is associated with the constructor, and each object initialized by the constructor inherits exactly the same set of properties from the prototype. This means that the prototype object is an ideal place for methods and other constant properties.


在新建一个对象时,构造函数和Prototype对象共同作用。每个对象都会从Prototype中继承属性。我们可以将对象的常量和方法放在对象的Prototype里面。

引用

Inherited properties behave just like regular properties of an object. They are enumerated by the for/in loop and can be tested with the in operator.


继承过来的属性和普通属性一样,同样可以被for/in的循环中枚举出来。你只能通过对象的hasOwnProperty()方法来辨别:

var r = new Rectangle(2, 3);
r.hasOwnProperty("width");   // true: width is a direct property of r
r.hasOwnProperty("area");    // false: area is an inherited property of r
"area" in r;                 // true: "area" is a property of r


Therefore, property inheritance occurs only when you read property values, not when you write them. If you set the property p in an object o that inherits that property from its prototype, what happens is that you create a new property p directly in o. Now that o has its own property named p, it no longer inherits the value of p from its prototype. 


这种继承是可读的,但不可写。如果你试图修改对象中某个通过Prototype继承过来的属性,操作是可以完成的,结果是这个对象自己拥有了一个赋有新值的属性,它再也不继承自Prototype。

Extending Built-in Types
扩展内置的数据类型

// Returns true if the last character is c
String.prototype.endsWith = function(c) {
    return (c == this.charAt(this.length-1))
}

var message = "hello world";
message.endsWith('h')  // Returns false
message.endsWith('d')  // Returns true

引用

There is a strong argument against extending built-in types with your own methods; if you do so, you are essentially creating your own custom version of the core JavaScript API. Any other programmers who have to read or maintain your code will likely find it confusing if your code includes methods they have never heard of.

Note that you must never add properties to Object.prototype.

The technique shown here for extending built-in object types is guaranteed to work only for core JavaScript "native objects
."

There is one case in which it is safe and useful to extend the prototype of a built-in native class: to add standard methods to a prototype when an old or incompatible JavaScript implementation lacks them.


扩展JS内核的数据类型是十分具有争议的行为。例如上例中,我们扩展类String的内置方法,可是这样就相当于自定了JS的API,其他程序员不可能知道你的制定的这些特性。除非你想开发JS的大型框架。

另外,不要试图去扩展Object,这太危险了。JS的每个对象都从Object继承。如果你真的修改了Object的Prototype,那么用{}字面量新建的对象也是默认包含那些属性的,而不是我们预期中的“空”。

扩展核心API当然也可以来弥补兼容性的不足。
例如,IE4&5都不支持Function.apply()方法,那么我们可以定义它:
// IE 4 & 5 don't implement Function.apply( ).
// This workaround is based on code by Aaron Boodman.
if (!Function.prototype.apply) {
    // Invoke this function as a method of the specified object,
    // passing the specified parameters.  We have to use eval( ) to do this
    Function.prototype.apply = function(object, parameters) {
        var f = this;                // The function to invoke
        var o = object || window;    // The object to invoke it on
        var args = parameters || []; // The arguments to pass

        // Temporarily make the function into a method of o
        // To do this we use a property name that is unlikely to exist
        o._$_apply_$_ = f;

        // We will use eval( ) to invoke the method. To do this we've got
        // to write the invocation as a string. First build the argument list.
        var stringArgs = [];
        for(var i = 0; i < args.length; i++)
            stringArgs[i] = "args[" + i + "]";

        // Concatenate the argument strings into a comma-separated list.
        var arglist = stringArgs.join(",");

        // Now build the entire method call string
        var methodcall = "o._$_apply_$_(" + arglist + ");";

        // Use the eval( ) function to make the methodcall
        var result = eval(methodcall);

        // Unbind the function from the object
        delete o._$_apply_$_;

        // And return the result
        return result;
    };
}

你可能感兴趣的:(JavaScript,prototype,chrome,C#,lisp)