Javascript创建对象的7种模式

html5前端开发是什么|网站前端开发学什么软件|前端开发和java开发工程师

1.)工厂模式 _
这种模式抽象了创建具体对象的过程,考虑到 ECMAScript 中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节~
示例:
javascript 代码

function createPerson(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        console.log(this.name);
    };
    return o;
}
var person1 = createPerson(“Nicholas”, 29, “Software Engineer”);
person1.sayName();
var person2 = createPerson(“Greg”, 27, “Doctor”);
person2.sayName();

函数createPerson()能够根据接受的参数来构建对应的Person对象;这个函数可以被无数次地调用,而他每次都返回一个包含相关属性和方法的Person对象!
(工厂模式解决了创建多个相似对象的问题,但没能解决对象识别的问题,即如何知道一个对象的类型)

2.)构造函数模式
ECMAScript中的构造函数可以创建特定类型的对象 _
javascript 代码

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        console.log(this.name);
    };
}
var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
person1.sayName();
var person2 = new Person(“Greg”, 27, “Doctor”);
person2.sayName();

在上述例子中,Person()函数取代了createPerson()函数。
两者不同之处如下:
(1) 没有显示地创建对象;
(2) 直接将属性和方法赋给了this对象;
(3) 没有return语句;
要创建Person的新实例,必须使用new操作符。
在构造函数的函数中,person1和person2分别保存着Person的一个不同实例。这两个对象都有一个constructor属性,并指向Person;
person1.constructor == Person; // true
person2.constructor == Person; // true

但是,对于检测对象类型,还是 instanceof 操作符更可靠,上个例子中所创建的对象既是Person的实例,也是Object的实例;
person1 instanceof Object; //true
person1 instanceof Person; //true;
person2与person1一致;

构造函数的问题:
使用构造函数的主要问题是每个方法都要在每个函数上重新创建一遍;
即在person1和person2中都有一个名为sayName()的方法,但两个方法不是同一个Function的实例(为什么?如果把上个构造函数改写,大家就会明白);
javascript 代码

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = new Function(“console.log(this.name)”); //注意这里
}

那么如何避免这种情况(方法如下):
javascript 代码

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName() {
    console.log(this.name);
}
var person = new Person(“lemon”, 25, “Frontend Engineer”);
person.sayName();

3.) 原型模式
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以有特定类型的所有实例共享的属性和方法。
prototype属性是通过构造函数而创建的那个对象实例的原型对象,其好处是乐意让所有对象实例共享它所包含的属性和方法, 不用在构造函数中定义对象实例的信息,而是将这些
信息直接添加到原型对象中。
javascript 代码

function Person() {}
Person.prototype.name = “Nicholas”;
Person.prototype.age = 29;
Person.prototype.job = “Software Engineer”;
Person.prototype.sayName = function() {
    console.log(this.name);
};
var person1 = new Person();
person1.sayName();
var person2 = new Person();
person2.sayName();
console.log(person1.sayName == person2.sayName);

(1) 认识hasOwnProperty()方法
这个方法只在给定属性存在与对象实例中时,才返回true;
(2) in操作符
in可以使用在for-in循环中,也可以单独使用,在单独使用时会通过对象能够访问给定属性时返回true,无论该属性是存在于实例中还是原型中。
看下它俩的使用:javascript 代码

function Person() {}
//简洁版
Person.prototype = {
    name: “Nicholas”,
    age: 29,
    job: “Software Engineer”,
    sayName: function() {
        console.log(this.name);
    },
};
var person = new Person();
console.log(person.hasOwnProperty(“name”)); // false
console.log(“name” in Person); // true
person.name = “Greg”;
console.log(person.hasOwnProperty(“name”)); // true

判断一个属性是否存在于原型中:
javascript 代码

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

在上述的(简洁版)代码中,我们将Person.prototype设置为等于一个以对象字面量形式创建的新对象,最终结果相同,但是constructor属性不再指向Person了。
解决方法:javascript 代码

function Person() {}
Person.prototype = {
    constructor: Person, //这种方式重设constructor属性会导致它的[[Enumerable]]特性被设置为true。
    name: “Nicholas”,
    age: 29,
    job: “Software Engineer”,
    sayName: function() {
        console.log(this.name);
    },
};

4.) 原型的动态性
由于在原型中查找值的过程是一次搜索,因此我们对原型的任何修改都能立即从实例中反映出来,即使是先创建实例再修改原型也是如此。
javascript 代码

function Person() {}
var friend = new Person();
Person.prototype.sayHi = function() {
    console.log(“hi~”);
};
friend.sayHi();

但如果我们使用对象字面量的方式修改Person原型,此时的Person.prototype指向的是一个新对象。我们知道,调用构造函数时会为实例添加一个指向最初原型的[[Prototype]]指针,
而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。
实例:
javascript 代码

funciton Person(){}
    var friend = new Person();
    Person.prototype = {
     constructor : Person,
     name : “Nicholas”,
     age : 29,
     job : “Software Engineer”,
     sayName = function(){
         console.log(this.name);
     }
    };
    friend.sayName(); //error

5.) 原生对象的原型
原型模式的重要性不仅体现在创建自定义类型方面,就连原生的引用类型,都是采用这种模式创建的。所有原生引用类型(Javascript内置对象)都是在其构造函数的
原型上定义了方法。
实例:
javascript 代码

console.log(typeof Array.prototype.sort); //function
console.log(typeof String.prototype.substring); //function
console.log(typeof Date.prototype.getDay); //function

通过原生对象的原型,不仅可以取得默认方法的引用,而且可以定义新方法。可以像修改自定义对象的原型一样修改原生对象的原型,因此可以随时添加方法。
javascript 代码

String.prototype.startWith = function(text) {
    return this.indexOf(text) == 0;
};
var msg = “Hello world”;
console.log(msg.startWith(“Hello”)); //true

6.)原型对象的问题
原型模式的缺点: 1是省略了为构造函数传递初始化参数的环节,结果所有实例再默认情况下都将取得相同的属性值;2是最大的问题是由其共享的本性所导致的。
javascript 代码

function Person() {}
Person.prototype = {
    constructor: Person,
    name: “Nicholas”,
    age: 29,
    job: “Software Engineer”,
    friends: [“Shelby”, “Court”],
    sayName: function() {
        console.log(this.name);
    },
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push(“Van”);
console.log(“person1.friends: ” + person1.friends);
console.log(“person2.friends: ” + person2.friends);
console.log(
    “person1.friends == person2.friends –> ” +
        (person1.friends === person2.friends),
);

–> 组合使用构造函数模式和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式和原型模式。
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。
这样,每个实例都会有自己的一份实例属性的副本,但又共享着对方法的引用,最大限度节省了内存。
另外,这种模式还支持向构造函数传参,可谓是集两种模式之长。
javascript 代码

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = [“Shelby”, “Court”];
}
Person.prototype = {
    constructor: Person,
    sayName: function() {
        console.log(this.name);
    },
};
var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
var person2 = new Person(“Greg”, 26, “Doctor”);
person1.friends.push(“Van”);
console.log(“person1.friends: ” + person1.friends);
console.log(“person2.friends: ” + person2.friends);
console.log(
    “person1.friends == person2.friends –> ” +
        (person1.friends === person2.friends),
);
console.log(
    “person1.sayName == person2.sayName –> ” +
        (person1.sayName === person2.sayName),
);

–> 动态原型模式
动态原型模式把所有信息封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要情况下),有保持了同时使用构造函数和原型的优点。javascript 代码

function Person(name, age, job) {
    //属性
    this.name = name;
    this.age = age;
    this.job = job;
    //方法
    if (typeof this.sayName != “function”) {
        Person.prototype.sayName = function() {
            console.log(this.name);
        };
    }
}
var friend = new Person(“Nicholas”, 29, “Software Engineer”);
friend.sayName();

使用动态原型模式时,不能使用对象字面量重写原型。

6.) 寄生构造函数模式
这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像典型的构造函数。
javascript 代码

function Person(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        console.log(this.name);
    };
    return o;
}
var friend = new Person(“Nicholas”, 29, “Software Engineer”);
friend.sayName();

关于寄生构造函数模式:
其返回的对象与构造函数或者与构造函数原型之间没有关系;也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。

7.) 稳妥构造函数模式
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this对象。
稳妥对象最适合在一些安全的环境中(禁用this和new),或者防止数据被其他应用程序改动时使用。
稳妥构造函数与寄生构造函数类似,但有两点不同:
1是新创建对象的实例方法不引用this;
2是不使用new操作符调用构造函数。
javascript 代码

function Person(name, age, job) {
    //创建要返回的对象
    var o = new Object();
    //可以在此定义私有变量和函数
    //添加方法
    o.sayName = function() {
        console.log(name);
    };
    //返回对象
    return o;
}
var friend = Person(“Nicholas”, 29, “Software Engineer”);
friend.sayName();

在这种模式创建的对象中,除了使用sayName()方法外,没有其他办法访问name的值。
与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间没有什么关系。

ide在前端开发中指什么意思|前端开发工程师 知乎|web前端开发工程师工作描述

» 本文来自:前端开发者 » 《Javascript创建对象的7种模式》
» 本文链接地址:https://www.rokub.com/4795.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!