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(); // '张三'
相关推荐
WeiXiao_Hyy10 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡27 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone33 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js