JavaScript--原型与原型链详解

1、概念

对象:一组属性和方法的集合。JavaScript中,一切皆对象,由普通对象(Object)和函数对象(Function)组成。

原型:又称原型对象,在定义函数时被创建,是一组属性和方法的集合,是JavaScript面向对象实现的主要方式。

prototype:每个函数有prototype属性(指针),指向其原型对象;可见,普通对象没有prototype。

constructor:原型对象中的constructor属性(指针),指向其构造函数。

__proto__:用构造函数实例化一个对象,实例对象中含有__proto__属性,其指向原型对象。

原型链:JavaScript通过原型实现对象,在对象的构造函数和实例中都有相关的属性指向其原型对象;而原型对象同样也是对象,也存在同样的属性指向其原型对象,直至追溯到Object.prototype原型对象;按照这规律,形成原型链,当使用对象的某些属性或方法时,就沿着原型链上寻找,直接找到或返回空值(null或undefined)。

下面结合示例代码一起学习:

function Person() {

}

Person.prototype.fisrtName = "Li";
Person.prototype.lastName = "Bill";
Person.prototype.age = 12;

Person.prototype.sayHello = function() {
    console.log("My name is " + this.fisrtName + " " + this.lastName);
}

var person1 = new Person();
var person2 = new Person();
person1.sayHello();
console.log(Person.prototype == person1.__proto__); // true
console.log(Person.prototype.constructor == Person); // true
console.log(Person.prototype.__proto__ == Object.prototype); // true
console.log(Object.prototype.constructor == Object); // true
console.log(Object.prototype.__proto__ == null); // true
console.log(person1.__proto__ == person2.__proto__); // true
console.log(person1.constructor == Person); // true
构造函数--原型--实例 关系图
原型链

2、作用

让同一类型的所有对象实例共享属性和方法。

3、应用

(1) 对象实现

构造函数模式:定义实例属性和方法,根据参数差异化对象。

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.sayHello = function () {
        console.log("My name is " + this.firstName +" "+ this.lastName);
    }
}

var person1 = new Person("Li", "Bill", 18);
var person2 = new Person("Wang", "John", 19);
person1.sayHello();
person2.sayHello();

原型模式:定义对象的共享属性和方法。

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
}

Person.prototype.job = "IT";
Person.prototype.sayHello = function () {
    console.log("My name is " + this.firstName +" "+ this.lastName);
}

var person1 = new Person("Li", "Bill", 18);
var person2 = new Person("Wang", "John", 19);
person1.sayHello();
console.log("My job is = " + person1.job);
person2.sayHello();
console.log("My job is = " + person2.job);

组合构造函数模式和原型模式:同时定义差异和共性

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    if (typeof this.sayHello != "function") {
        Person.prototype.sayHello = function() {
            console.log("My name is " + this.firstName + " " + this.lastName + ", " + this.age + " old.");
        }
    }
}

var person1 = new Person("Li", "Bill", 13);
var person2 = new Person("Wang", "John", 12);
person1.sayHello();
person2.sayHello();

字面量方式创建原型对象:Person原型(实例person)的默认constructor会改变,为Object();可以在字面量赋值上增加constructor的指向为Person,但此时constructor性质变为可枚举;person0为先创建的对象,其构造函数依然为Person(),其原型不带任何属性和方法。

function Person() {

}

var person0 = Person();

Person.prototype = {
    // without constructor point to
    //constructor: Person, // change default [[Enumerable]] true
    firstName: "Wang",
    lastName: "Bill",
    age: 12,
    sayHello: function() {
        console.log("My name is " + this.firstName + " " + this.lastName);
    }
}

console.log(Person.prototype);
console.log(Person.prototype.constructor); // [Function: Object]
var person = new Person();
person.sayHello();
console.log(person.constructor); // [Function: Object]
console.log(person.__proto__); 

也可以用如下方式重新定义constructor:

// reset contructor 
Object.defineProperty(Person.prototype, "constructor", {
    enumerable: false,
    value: Person
});

寄生构造函数模式:这种方式相当于把构造函数的作用变为一般函数,返回了一个Object实例。

function Person(first, last, age) {
    var o = new Object();
    o.firstName = first;
    o.lastName = last;
    o.age = age;
    o.sayHello = function() {
        console.log("My name is " + this.firstName + " " + this.lastName);
    };
    return o;
}

var person1 = new Person("Wu", "Kate", 12);
person1.sayHello();

Object.create( )创建对象方式:用一个对象作为新对象的原型。

function Person() {
    this.sayName = function() {
        console.log("My name is Tom Bruce");
    }
}

var person = new Person();

var person1 = Object.create(person);
person1.sayName();
console.log(person1.__proto__ == person); // true

(2)常用API

确认对象是否为某一构造函数的原型类型:isPrototypeOf( );

获取对象的原型对象:Object.getPrototypeOf( )。

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
}

Person.prototype.name = "Wang Bill"

var person1 = new Person("Wang", "Bill", 18);

console.log(Person.prototype.isPrototypeOf(person1));
console.log(Object.getPrototypeOf(person1).name);
console.log(Person.prototype.name);

判断对象是否含有某个属性:hasOwnProperty( );

判断一个属性是否存在于某个对象或原型:in 操作符;

结合上面的判断,可以判断属性是否存在于某个原型。

function Person() {
    this.firstName = "Li";
}

Person.prototype.firstName = "Wang";
Person.prototype.lastName = "Bill";
Person.prototype.sayName = function() {
    console.log("My name is " + this.firstName + " " + this.lastName);
}

var person1 = new Person();
console.log(person1.hasOwnProperty("firstName")); // true
delete person1.firstName;
console.log(person1.hasOwnProperty("firstName")); // false, instance has deleted
console.log("firstName" in person1); // true, prototype has firstName

function hasPrototypeProperty(object, property) {
    return !object.hasOwnProperty(property) && (property in object);
}

console.log(hasPrototypeProperty(person1, "firstName")); // true

获取对象上所有可枚举的属性:Object.keys( );

获取对象上所有的属性:Object.getOwnPropertyNames()。

function Person() {

}

Person.prototype.firstName = "Wang";
Person.prototype.lastName = "Bill";
Person.prototype.sayHello = function() {
    console.log("My name is " + this.firstName + " " + this.lastName);
}

var keys = Object.keys(Person.prototype); // show enumerable property 
console.log("prototype:");
console.log(keys); 

var person = new Person();
var pkeys0 = Object.keys(person);
console.log("instance 0:");
console.log(pkeys0);

person.name = "Bill";
person.age = 12;
var pkeys1 = Object.keys(person);
console.log("instance 1:");
console.log(pkeys1);

var protoKeys = Object.getOwnPropertyNames(Person.prototype); //show all property
console.log("getOwnPropertyNames Person.prototype:");
console.log(protoKeys);

(3)扩展基本数据类型

String.prototype.data = function(text) {
    return this.indexOf(text) == 0;
}

var msg = "Prototype";
console.log(msg.data("Proto"));

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值