JavaScript 原型

/*
 * JavaScript 中,对象分为普通对象和函数对象,Object 和 Function 是JS自带的函数对象。
 * 函数对象的一个属性是原型对象 prototype,普通对象没有prototype。
 * 原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,它没有prototype属性)。
 * 在函数对象创建的时候,创建了一个它的实例对象并赋值给它的prototype,即函数对象的原型对象就是自己的一个实例对象。(凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。Function.prototype = new Function (); 所以Function.prototype是函数对象。
 * 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype,函数对象的原型对象的__proto__属性,它指向创建它的函数对象Object的原型对象prototype。Object.prototype对象也有__proto__属性,但它比较特殊,为null。这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。
 * Object.__proto__ === Function.prototype 
 * Object是函数对象,是通过new Function()创建,所以Object.__proto__指向Function.prototype。
 * Function.__proto__ === Function.prototype
 * Function也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。
 * Function.prototype.__proto__ === Object.prototype
 * 原型对象中都有个预定义的constructor属性,用来引用它的函数对象。
 * Function.prototype.constructor === Function
 * Object.prototype.constructor === Object
 * Object.constructor===Function 本身Object就是Function函数构造出来的。
 */

// 工厂模式创建对象
function createObject(name, age) {
    // 1.创建对象
    var obj = new Object();
    // 2.添加实例属性
    obj.name = name;
    obj.age = age;
    // 3.添加实例方法
    obj.run = function() {
        return this.name + this.age;
    };
    return obj;
}
var myBox = createObject("Lee", 28);
var myBoxBox = createObject("Leeee", 288);
myBox.run(); // "Lee28"
myBoxBox.run(); // "Leeee288"

// 构造函数创建对象
function Box(name, age) {
    this.name = name;
    this.age = age;
    this.run = function() {
        return this.name + this.age;
    };
}
var myBox = new Box("Lee", 28);
myBox.run(); // "Lee28"

// call() 对象冒充 定义对象o冒充Box 对象o便具备Box的属性和方法
var o = new Object();
Box.call(o, "Lee", 28);
o.run(); // "Lee28"

// 把构造函数中的方法通过全局函数来实现引用地址相等 但是破坏了封装性 不推荐
function Box(name, age) {
    this.name = name;
    this.age = age;
    this.run = run;
}
function run() {
    return this.name + this.age;
}
var myBox1 = new Box("Lee", 28);
var myBox2 = new Box("Leeeee", 2888);
myBox1.run(); // "Lee28"
myBox2.run(); // "Leeeee2888"
myBox1.run == myBox2.run; // true

// 原型
// 定义(构造函数)对象 Box
/* 
 * 定义 Box 的默认操作
 * 创建一个临时普通对象 即为 Box 的原型对象 var temp = new Box();
 * 为 Box 定义属性 prototype 指向 Box 的原型对象 Box.prototype = temp;
 * 为 Box.prototype 对象定义 constructor 属性 该属性指向构造函数即 Box 对象 Box.prototype.constructor = Box;
 * 为 Box.prototype 对象定义 __proto__ 属性 该属性指向创建它的 Object 对象的原型对象 Box.prototype.__proto__ = Object.prototype;
 */
function Box(name, age) {
    this.name = name;
    this.age = age;
    this.run = function() {
        return this.name + this.age;
    }
}
typeof Box; // "function"
typeof Box.prototype; // "object"
Box.prototype; // Object {constructor: function Box(name, age), __proto__: Object}
Box.prototype.__proto__ === Object.prototype; // true

// 添加原型属性和方法
Box.prototype.name = "Lee";
Box.prototype.age = 28;
Box.prototype.run = function() {
    return this.name + this.age;
};

// 定义函数对象 Box 的实例对象 myBox1
/*
 * 定义函数对象 Box 的实例对象 myBox1 默认操作
 * 为 myBox1 对象定义属性 __proto__ 该属性指向指向创建它的 Box 对象的原型对象 myBox1.__proto__ = Box.prototype;
 * JavaScript 会通过 __proto__ 属性向上寻找所有的属性和方法 所以为 Box.prototype 定义的属性和方法即为 Box 对象的所有实例对象共有属性和方法
 */
var myBox1 = new Box("Leeeee", 288888);
myBox1.__proto__; // Object {name: "Lee", age: 28, run: function(), constructor: function Box(name, age), __proto__: Object}
myBox1.__proto__ === Box.prototype; // true
myBox1.run(); // "Leeeee288888"
myBox1.__proto__.run(); // "Lee28"
myBox1.constructor; // 见下
/*
function Box(name, age){
    this.name = name;
    this.age = age;
    this.run = function() {
        return this.name + this.age;
    }
}
*/
// 原型对象.isPrototypeOf(实例对象) 判定实例对象是不是指向了原型对象
Box.prototype.isPrototypeOf(myBox1); // true

var  myBox2 = new Object();
Box.prototype.isPrototypeOf(myBox2); // false

// 删除实例属性
myBox1.name; // "Leeeee"
delete myBox1.name; // true
// myBox1.name 属性不存在 通过 __proto__ 属性寻找到 Box.prototype.name 属性
myBox1.name; // "Lee"

// 判断实例属性中是否存在指定属性
myBox1.hasOwnProperty("name"); // false

// 删除原型属性
delete Box.prototype.name; // true
myBox1.name; // undefined
// 判断实例属性或者原型属性中是否存在指定属性
"name" in myBox1; // false

// 重定义或者覆盖属性
Box.prototype.name = "KK";
myBox1.name; // "KK"
"name" in myBox1; // true

// 遍历原型对象所有的属性和方法
var num = 0;
for (o in Box.prototype) {
    console.log(o); // 依次输出见下
    num++;
}
/*
age
run
name
*/

// 遍历实例对象和原型对象所有的属性和方法
var num = 0;
for (o in myBox1) {
    console.log(o + ":" + myBox1[o]); // 依次输出见下
    num++;
}
/*
age:288888
run:function () {
        return this.name + this.age;
    }
name:KK
*/

// 使用字面量的方式创建原型对象
// 字面量创建原型对象 constructor 属性指向 Object
Box.prototype = {
    name: "lucy",
    age: 10,
    run: function() {
        return this.name + this.age;
    }
}
var myBox = new Box("lucy", 12);
myBox1.constructor; // 见下
/*
function Box(name, age){
    this.name = name;
    this.age = age;
    this.run = function() {
        return this.name + this.age;
    }
}
*/
myBox.constructor; // function Object() { [native code] }
myBox.constructor === Box; // false
myBox.constructor === Object; // true

// 使用字面量创建原型对象 并且把 constructor 指向 Box
Box.prototype = {
    constructor: Box,
    name: "Lily",
    age: 10,
    run: function() {
        return this.name + this.age;
    }
};
var myBox = new Box();
myBox.constructor; // 见下
/*
function Box(name, age){
    this.name = name;
    this.age = age;
    this.run = function() {
        return this.name + this.age;
    }
}
*/
// Box.prototype 重写会切断实例与原来原型的关系
myBox1.__proto__.run(); // "KK28"
myBox.__proto__.run(); // "Lily10"

// 查看 Array 原型对象里的方法 sort()
Array.prototype.sort; // function sort() { [native code] }

// 给 String 原型对象添加方法 addString()
String.prototype.addString; // undefined
String.prototype.addString = function() {
    return this + "被添加了!";
}
var box = "Lee";
box.addString(); // "Lee被添加了!"
var box = new String("Lee");
box.addString(); // "Lee被添加了!"

// 组合构造函数和原型模式
// 保持独立用的构造函数
function Box(name, age) {
    this.name = name;
    this.age = age;
    this.family = ['哥哥', '姐姐'];
}
// 保持共享用的原型
Box.prototype = {
    constructor: Box,
    run: function() {
        return this.name + this.age;
    }
}
var box = new Box("pu", 28);
box.run(); // "pu28"

// 动态原型模式,把原型封装到构造函数里
// 保持独立用的构造函数
function Box(name, age) {
    this.name = name;
    this.age = age;
    this.family = ['哥哥', '姐姐'];
    // 原型初始化只有第一次才执行
    if (typeof this.run != 'function') {
        Box.prototype.run = function() {
            return this.name + this.age;
        };
    }
}
var box = new Box("pu", 28);
box.run(); // "pu28"

// 寄生构造函数 = 工厂模式 + 构造函数
function Box(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.run = function() {
        return this.name + this.age;
    };
    return obj;
}
var box = new Box("Lee", 28);
box.run(); // "Lee28"

// 稳妥构造函数 = 工厂模式
function Box(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.run = function() {
        return this.name + this.age;
    };
    return obj;
}
// 不使用new
var box = Box("Lee", 28);
box.run(); // "Lee28

// 继承
// 通过原型链继承
function Box() {
    this.name = "Lee"; // L1
}
Box.prototype.name = "Jack";
function Desk() {
    this.age = 100;
}
Desk.prototype = new Box();
var desk = new Desk();
// 属性寻找采用就近原则,如果L1行没有定义实例属性,打印出原型属性 Jack
desk.name; // "Lee"

// 使用对象冒充,只能继承构造里的实例属性,不能继承原型属性。
function Box(name, age) {
    this.name = name;
    this.age = age;
    this.family = ['哥哥', '姐姐', '妹妹'];
}
Box.prototype.run = function() {
    return this.name + this.age;
}
function Desk(name, age) {
    Box.call(this, name, age)
}
var desk = new Desk('Lee', 28);

desk.name; // "Lee"
desk.family; // ["哥哥", "姐姐", "妹妹"]
// 出错因为继承不到原型里的方法
desk.run(); // desk.run is not a function(…)

// 添加原型链继承 称为组合继承
Desk.prototype = new Box();
var desk = new Desk('Lee', 28);
desk.run(); // "Lee28"

// 原型式继承
// 临时中转函数
function obj(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var box = {
    name: "Lee",
    age: 100,
    family: ['哥哥', '姐姐', '妹妹']
};
var myBox = obj(box);
myBox.name; // "Lee"

// 寄生式继承 = 原型式 + 工厂模式 目的是为了封装函数继承的过程
function obj(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
//寄生函数
function create(o) {
    var f = obj(o);
    f.run = function() {
        return this.name;
    };
    return f;
}
var box = {
    name: "Lee",
    age: 100,
    family: ['哥哥', '姐姐', '妹妹']
};
var myBox = create(box);
myBox.run(); // "Lee"

// 寄生组合函数
// 临时中转函数
function obj(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
//寄生函数
function create(box, desk) {
    var f = obj(box.prototype);
    f.constructor = desk; //调整构造指针
    desk.prototype = f;
}
function Box(name, age) {
    this.name = name;
    this.age = age;
}
Box.prototype.run = function() {
    return this.name + this.age;
}
function Desk(name, age) {
    Box.call(this, name, age); //对象冒充
}

// 通过寄生组合继承来实现继承
create(Box, Desk);
原文地址:https://www.cnblogs.com/pumushan/p/6757070.html