javascript类和原型学习笔记

简介:

js中类的所有实例对象都从同一个原型对象上继承属性。我们可以自己写一个对象创建的工厂方法来来“模拟”这种继承行为:

//inherit()返回一个继承自原型对象p的属性的性对象
//这里使用ECMAScript5中的Object.create()函数
//如果不存在该函数,则使用另一种方法
function inherit(p){
    if(p == null) throw TypeError();
    if(Object.create)
        return Object.create(p);
    var t = typeof p;
    if(t !== "object" && t!=="function")
        throw TypeError();
    function f(){};
    f.prototype = p;
    return new f();
}

代码中Object.create方法是在ECMAScript5中定义的,它创建一个新的对象,其中第一个参数是这个对象的原型:

var x = Object.create({x:1,y:2});
var y = Object.create(Object.prototype);//和{}或new Object()类似

下面模拟了一个类的构造函数:

function range(from,to){
    var r = inherit(range.methods);
    r.from = from;
    r.to = to;
    return r;
}

range.methods = {
    includes:function(x){
    return this.from <= x && x <= this.to;
    },
    foreach:function(f){
        for(var x = Math.ceil(this.from);x <= this.to;x++)
            f(x);
    },
    toString:function(){
        return "(" + this.from + "..." + this.to + ")";
    }
}

//我们可以向下面这样创建range对象以及调用它的方法
var r = range(1,3);
r.includes(2);
r.foreach(console.log);
console.log(r);

接下来我们用js的标准的new方法来创建相同的对象:

//类的构造函数约定首字母大写
//注意函数结尾不用return something代码
function Range(from,to){
    this.from = from;
    this.to = to;
}
//方法内容和前面一样,省略
Range.prototype = {
    includes:function(x){...},
    foreach:function(f){...},
    toString:function(){...}
};

//同样给出创建和使用的代码
var r = new Range(1,3);
r.includes(2);
r.foreach(console.log);
console.log(r);

以上代码遵循了一个编程约定:定义构造函数即是定义类,首字母需要大写,普通函数和方法的首字母皆为小写。
还有要注意的是,第一段代码原型是range.methods,这种命名可以是任意的;而第二段代码中原型是Range.prototype,这个名称是必须的。对Range()构造函数的调用会自动使用Range.prototype作为新Range对象的原型。

每个js函数(ECMAScript5中的Function.bind()方法返回的函数除外)都自动拥有一个prototype属性,该属性的值为一个对象,该对象包含唯一一个不可枚举属性constructor,该属性的值味一个函数对象:

var f = function(){};
var p = f.prototype;
var c = p.constructor;
c === f //must true!对于任意函数f,有f.prototype.constructor === f;

以上可以认为constructor是以指回其构造函数的反向”指针”,由于constructor方法在对象的原型对象中,所以可以用任意对象来调用:

var obj = new F();
obj.constructor === F; //must true!

需要注意的是,以上第2个例子中Range类使用了一个新的对象重写了预定义的Range.prototype对象,但是这个新定义的原型对象不含有constructor属性,因此Range类的实例中也不含有constructor属性,我们可以给原型显示添加一个构造函数:

Range.prototype = {
    constructor:Range,
    //same codes...
};

还有一种方法是使用预定义的原型对象,域定义的原型对象包含constructor属性:

Range.prototype.includes = function(x){...};
Range.prototype.foreach = function(f){...};
Range.prototype.toString = function(){...};
相关文章
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
30 0
|
23天前
|
JavaScript
js开发:请解释什么是ES6的类(class),并说明它与传统构造函数的区别。
ES6的类提供了一种更简洁的面向对象编程方式,对比传统的构造函数,具有更好的可读性和可维护性。类使用`class`定义,`constructor`定义构造方法,`extends`实现继承,并可直接定义静态方法。示例展示了如何创建`Person`类、`Student`子类以及它们的方法调用。
20 2
|
25天前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承利用原型链查找属性,节省内存但不支持私有成员。类继承通过ES6的class和extends实现,支持私有成员但占用更多内存。两者各有优势,适用于不同场景。
18 0
|
1月前
uni-app 65egg.js聊天类chat.js封装(二)
uni-app 65egg.js聊天类chat.js封装(二)
22 1
|
1月前
|
JavaScript
JS数组增删方法的原理,使用原型定义
JS数组增删方法的原理,使用原型定义
|
1月前
|
JavaScript
JS原型对象prototype
JS原型对象prototype
|
1月前
|
JavaScript 前端开发
深入理解 JavaScript 对象原型,解密原型链之谜(下)
深入理解 JavaScript 对象原型,解密原型链之谜(下)
|
1月前
|
JavaScript 前端开发
深入理解 JavaScript 对象原型,解密原型链之谜(上)
深入理解 JavaScript 对象原型,解密原型链之谜(上)
|
1月前
uni-app 66聊天类chat.js封装(三)
uni-app 66聊天类chat.js封装(三)
26 6
|
1月前
uni-app 64聊天类chat.js封装(一)
uni-app 64聊天类chat.js封装(一)
22 2