js中创建对象有那些方法

除了使用Object构造函数或者字面量都可以创建对象,但是也有缺点就是使用同一个接口创建很多对象,会产生大量的重复代码。

1. 工厂模式

简单来说就是把Object创建对象使用函数进行封装,然后再返回创建的对象,就可以创建多个相同对象。

js 复制代码
function createPerson(name, age) {
	var o = new Object();
	o.name = name;
	o.age = age;
	o.sayName = function () {
		alert(this.name);
	}
	return o;
}
var person1 = createPerson('张三', 18);

函数createPerson根据参数创建了一个包含所有必要信息的Person对象,可以多次调用这个函数,每次调用都能返回一个对象。

工厂模式缺点: 没有解决对象识别问题,就是怎样知道一个对象的类型。

2. 构造函数模式

js 复制代码
function Person(name, age, job) {
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = function () {
		alert(this.name);
	}
}
var person1 = new Person('张三', 18, '前端工程师');

1. 什么是构造函数

构造函数本身跟普通函数一样,也不存在定义构造函数的特殊语法。唯一区别在于调用的方式不同,任何函数只要通过new 操作符来调用,都可以叫做构造函数。默认情况下构造函数的首字母大写,不大写也没有问题,主要是为了与普通函数区分。

2. 为什么有构造函数

为了创建对象而已,本身就是一个函数。

3. 创建一个新实例经历的过程

创建实例,必须使用new操作符调用。

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(也就是修改this,将this指向这个新对象)
  • 执行构造函数中的代码(给对象新增属性方法)
  • 返回新对象

3. 构造函数比其他函数区别

通过new操作符调用就叫做构造函数,如果不通过new操作符调用就是普通函数。一般构造函数默认首字母大写,不大写也没事,主要是为了区分是构造函数还是普通函数。

4. 构造函数比工厂模式的优点

自定义的构造函数将来可以将它的实例标识为一种特定的类型。

5. 构造函数比工厂模式的不同之处

  • 没有显式创建对象,也就是new Object
  • 直接将属性和方法赋给了this对象
  • 没有return语句

6. 构造函数的问题

每个方法都要在每个实例上重新创建一遍

3. 原型模式

js 复制代码
function Person() {}
Person.prototype.name = '张三';
Person.prototype.age = 18;
Person.prototype.job = '前端工程师';
Person.prototype.sayName = function () {
	alert(this.name);
}
var person1 = new Person();
person1.sayName(); // '前端工程师'

1. 原型对象

创建一个新函数都会有一个prototype(原型)属性,这个属性指向函数的原型对象。

在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针(也就是构造函数)。创建一个自定义构造函数之后,其原型对象默认只会取得constructor属性,其他方法,则会从Object继承而来的。

当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。这个指针(内部属性)叫做[[Prototype]],可以通过_proto_进行或者。用它来连接实例与构造函数的原型对象。

1. 原型对象的好处

可以让所有对象实例共享它所包含的属性和方法,换句话说,不必在构造函数中定义对象实例的信息,而是直接将这些信息添加到原型对象中。

2. isPrototypeOf()

用来检测实例是否指向某个原型对象,返回布尔类型

js 复制代码
Person.prototype.isPrototypeOf(person1); // true

3. Object.getPrototypeOf()

返回原型对象

js 复制代码
Object.getPrototypeOf(person1) == Person.prototype; // true
Object.getPrototypeOf(person1.name); // '张三'

4. 如何读取属性值

当对象某个对象属性时,首先先从对象实例本身开始读取,如果存在就返回,不存在就开始向原型对象查找属性。

5. 对象实例保存访问属性注意点

虽然实例对象可以对属性进行添加、编辑等操作,但是不能重写原型中的值。如果在实例中添加一个与原型中属性同名的属性,只是会把原型中对应的属性屏蔽掉。访问值时,会访问实例新创建的这个属性值,如果将实例对象中的这个属性删除,则会访问到原型中该属性的值。

hasOwnProperty()用来检测一个属性是否存在实例中还是原型中,返回布尔类型,若在实例中返回true。

js 复制代码
person1.hasOwnProperty('name'); // false
person1.name = '李四';
person1.hasOwnProperty('name'); // true

2. 原型与in操作符

in操作符可以单独使用,也可以在for...in中使用。

**单独使用时:**判断能否访问到某个属性,不管这个属性在实例上还是原型中,返回布尔类型。

js 复制代码
'name' is person1; // true

可以与hasOwnProperty()一起使用,来判断某个属性存在对象还是原型中。

js 复制代码
function hasPrototypeProperty(object, name) {
	return !object.hasOwnProperty(name) && (name in object);
}

hasOwnProperty只有在实例时才回返回true,in只要任意存在都返回true。

若hasOwnProperty为true,则结果返回false,代表在实例中。

若hasOwnProperty为false,in为true, 则结果返回true,代表在原型中。

若都为false,则结果返回false,代表不存在

**for...in: **返回的是所有可枚举的属性,包括实例、原型中存在的。

3. 更简单的原型语法

前面的例子每添加一个属性或方法都要敲一遍Person.prototype。可以用一个包含所有属性和方法的对象字面量来重写整个原型对象。

js 复制代码
function Person(){}
Person.prototype = {
	name: '张三',
	age: 18,
	job: '前端工程师',
	sayName: function() {
		alert(this.name);
	}
}

这样看着是简单了,但是其实是用对象字面量又重新创建了一个新对象,这时的constructor属性将不再执向Person了。因为每创建一个函数,都会创建它的prototype对象,这个对象也会自动获得constructor属性。

这里本质重写了默认的prototype对象,因此constructor属性也变成了新对象的constructor属性(也就是Object构造函数), 不再执行Person函数。

解决方法

可以通过修改constructor属性值进行解决。

js 复制代码
Person.prototype.constructor = Person;

但是这样修改会使其属性的描述特性[[Enumerable]]被设置成true,默认原生的属性是不可枚举的,所以可以使用Object.defineProperty()进行设置属性值。

js 复制代码
Object.defineProperty(Person.prototype, 'constructor', {
	enumerable: false,
	value: Person
})

4. 原型的动态性

动态性指的是不管创建实例在设置原型前后,都能获取到原型中的属性和方法。

但是有一种情况则不行,那就是重写了对象原型,重写也是用字面量重写设置了一个新对象(上一个标题3)。

为什么重写了对象原型就不能获取属性和方法了呢?

因为在调用构造函数时就为实例添加了一个指针,指向最初的原型对象,所以说修改原型对象就等于切断了构造函数和最初原型之间的联系。

实例中的指针指向原型,而不指向构造函数。

5. 原生对象的原型

原型模式不仅仅体现在创建自定义类型,就连原生的引用类型也是采用这种模式,都是在其构造函数的原型上定义的方法。

通过原生对象的原型,不仅可以取得所有默认方法的引用,也能定义新方法,也可以修改原生对象的原型就像修改自定义对象的原型。

6. 原型对象的问题

  • 它省略了为构造函数传递初始化参数的这一环节,造成所有实例在默认情况下都将取得相同的属性值。
  • 最大问题是其共享的本质导致的

不懂,以后编写

4. 组合使用构造函数模式和原型模式

**用法:**构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。

**结果: **每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省内存,并且还支持向构造函数传递参数。

javascript 复制代码
function Person(name, age, job) {
	this.name = name;
	this.age = age;
	this.job = job;
	this.friends = ['a', 'b'];
}
Person.prototype = {
	constructor: Person,
	sayName: function () {
		alert(this.name);	
	}
}

var person1 = new Person('张三', 18, '前端工程师');
var person2 = new Person('李四', 10, '后端工程师');

person1.friends.push('c');
console.log(person1.friends); // ['a', 'b', 'c']
console.log(person2.friends); // ['a', 'b']
console.log(person1.friends === person2.friends); // false
console.log(person1.sayName === person2.sayName); // true

5. 动态原型模式

它把所有信息都封装在构造函数中,而通过在构造函数中初始化原型,又保持了同时使用构造函数和原型的优点。

js 复制代码
function Person(name, age, job) {
	// 属性
	this.name = name;
	this.age = age;
	this.job = job;
	// 方法
	if (typeof this.sayName != 'function') {
		Person.prototype.sayName = function(){
			alert(this.name);
		}
	}
}

不懂?后面添加

6. 寄生构造函数模式

这种模式的基本思路就是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象。

js 复制代码
function Person(name, age, job) {
	var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}
var friend = new Person('张三', 18, '前端工程师');
friend.sayName(); // '张三'

在这个例子中,Person函数创建了一个对象,并设置相应的属性和方法初始化这个对象,然后又返回这个对象。

特点:除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式跟工程模式其实是一模一样的。

构造函数在没有返回值的情况下,默认返回新对象实例,而添加return语句,则可以重写构造函数时的返回值。

说明:返回的对象与构造函数或者构造函数的原型属性之间没有关系,也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。所以不能依赖instanceof操作符来确定对象类型。

7. 稳妥构造函数模式

指的是没有公共属性,而且其方法也不引用this对象。 与寄生构造函数类似的模式,但也有不同,一是新创建对象的实例方法不引用this。二是不使用new操作符调用构造函数。

js 复制代码
function Person(name, age, job) {
    // 创建要返回的对象
    var o = new Object();
    // 定义私有变量和函数
    // 添加方法
    o.sayName = function () {
        alert(name);
    }
    // 返回对象
    return o;
}
var friend = Person('张三', 18, '前端工程师');
friend.sayName(); // '张三'
相关推荐
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&3 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch7 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光7 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   7 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发