您的位置:首页 > Web前端 > JavaScript

JS关于对象,原型(prototype),构造函数(constructor)的概念,以及创建对象的几种方式讲解

2019-02-25 14:16 417 查看
JS是面向对象的编程语言,对象其实就是属性和方法的集合体。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值,这个值可以是数据或函数。
创建对象一般有两种方法:
(1)创建一个Object实例
var person = new Object();
person.name = "zhangsan";
person.age = 22;
person.sayHi = function(){}
(2)使用对象字面量
var person = {
name: "zhangsan",
age: "22",
sayHi: function(){}
}
虽然上面两种方法都可以创建对象,但如果要创建很多对象,这样做就很不方便了。于是就有了工厂模式,构造函数模式,原型模式,组合使用构造函数模式和原型模式。
工厂模式基本淘汰了,不再赘述。说下构造函数模式:
function Person(name,age){
this.name = name;
this.age = age;
this.sayHi =function(){
console.log(this.name)
}
}
var person1 = new Person("a", 12);
var person2 = new Person("b", 14);
按照惯例,构造函数始终都应该以一个大写字母开头。
要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4

个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。

用构造函数模式创建对象的缺点主要是,每个方法都要在每个实例上重新创建一遍,而这是没有必要的。所以可以把构造函数内部的函数定义移到外面来:
function Person(name,age){
this.name = name;
this.age = age;
this.sayHi = sayHi
}
function sayHi(){
console.log(this.name)
}
var person1 = new Person("a", 12);
var person2 = new Person("b", 14);

这样做的问题在于:如果对象有很多方法,我们就需要定义多个全局函数,也就没有了封装性可言。

基于上面的问题,我们引入了原型模式。
在这里,就不得不说下原型是什么了。
我们创建的每个函数都有一个prototype(原型)属性,其实就是通过调用构造函数而创建的那个对象实例的原型对象。那什么是原型对象呢?
在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向protutype属性所在函数的指针。即Person.prototype.constructor == Person。而通过这个构造函数,我们还可以继续为原型对象添加其他属性和方法。
来总结下原型和实例的关系:
每个构造函数都有一个原型对象prototype,原型对象都包含一个指向构造函数的指针constructor,而实例都包含一个指向原型对象的内部指针_proto_。

原型模式就是不在构造函数中定义对象实例的信息,而是直接添加到原型对象中,像这样:
function Person(){};
Person.prototype.name = "zhangsan";
Person.prototype.age = 12;
Person.prototype.sayHi = function(){
alert(this.name);
}
var person1 = new Person();
var person2 = new Person();

这样写很麻烦,可以用对象字面量来重写整个原型对象,但这样重写后,原型对象里面的constructor就不再指向构造函数了.。也可以自己在字面量里重写以下constructor

function Person(){};
Person.prototype = {
**constructor: Person**
name: "zhangsan",
age: 12,
sayHi: function(){
alert(this.name);
}
}

原型模式省略了构造函数传递初始化参数这一环节,结果所有实例默认情况下都会获得相同的属性值。还有一个问题是,当在某个实例改变属性值时,其他实例的属性值也会随之改变!因为所有实例的属性和方法是相通的。

因为上面的情况,就产生了组合使用构造函数和原型模式的方式,也是目前使用最多的方式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: