视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
如何创建一个对象的方法及原型对象了解一下
2020-11-27 19:30:49 责编:小采
文档
很多小伙伴在学习前端的时候会遇到对象创建的难题,让我来教大家一些方法,希望大家耐心学习哦。

一、创建一个对象的方法

1.工厂模式

在函数中创建对象,并给这个对象添加属性,然后在这个函数中返回这个对象。在函数外部调用这个函数来创建对象的实例。

function createPerson(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 person1=createPerson("xiaowang","22","workers");//在函数外部创建对象的实例,不用new
var person1=createPerson("xiaoliu","22","workers");

问题:没有解决对象的识别问题(不能知道一个对象的类型)

2.构造函数模式(可以用来创建特定类型的对象)

function Person(name,age,job){//注意构造函数开头的字母应该大写
//构造函数中使用this
 this.name=name;
 this.age=age;
 this.job=job;
 this.sayName=function(){
 alert(this.name);
 }
}
var person1=new Person("xiao",22,"tech");//使用new创建实例
var person2=new Person("li",32,"sin");

与工厂模式的不同之处:

(1)没有显示的创建对象

(2)直接将属性和方法赋值给this指向的对象

(3)没有return 语句

这两个实例都有一个constructor属性,指向Person。

构造函数可以识别其实例是什么类型的对象,使用instanceof操作符更可靠一些。

问:构造函数和普通函数有什么不同?

答:用new操作符来调用的就是构造函数,不用new来调用的是普通函数。

构造函数的问题:每个方法都要在每个实例上重新创建一遍。

3.原型模式

将对象实例所共享的属性和方法不放在构造函数中,而是全部放在原型对象之中。

function Person(){ };//构造函数什么也不设置
Person.prototype.name="xiao";//全部都放在原型对象上
Person.prototype.age=22;
Person.prototype.job="stu"'
Person.prototype.sayName=function(){
 alert(this.name);
}

var person1=new Person();
var person2=new Person();
console.log(person1.sayName==person2.sayName);//true

原型模式的问题:对于包含应用类型值的属性来说,由于原型模式的共享性,改变一个实例的该引用类型值改变,则其他的实例的该属性值也被改变了。

function Person={}
Person.prototype={
 constructor:Person,
 name:"Nick",
 age:29,
 friends:['a','b'];//引用类型的值
 sayName:function(){
 alert(this.name);
 }
}
var person1=new Person();
var person2=new Person();
//想要改变person1实例的friends属性
person1.friends.push("c);
alert(person1.friends);//["a","b","c"]
alert(person2.friends);//["a","b","c"];
alert(person1.friends==person2.friends);//true;

4.组合模式(构造函数和原型)

构造函数定义实例的属性,原型定义方法和共享的属性。

function Person(name,age,job){
 this.name=name;
 this.age=age;
 this.job=job;
}

Person.prototype={
 constructor:Person,
 sayname:function(){
 alert(this.name)
 }
}

二.原型对象的理解

1.理解

每个构造函数Person都有一个prototype属性指向它的原型对象,既原型对象为Person.prototype;而每个原型对象中有一个constructor方法,用来指回构造函数Person。另外,调用构造函数创建的实例person1,有一个[[Prototype]]属性(_proto_),也指向构造函数的原型对象。 注意,连接发生在实例和构造函数的原型对象之间!而实例和构造函数没有任何关系。

isPrototypeOf()方法:检测原型对象和实例是否有原型连接的关系

Person.prototype.isPrototypeOf(person1);//true

Object.getPrototypeOf()方法:该方法返回[[prototype]]的值,既返回一个实例的原型对象。

Object.getPrototypeOf(person1);// Person.prototype

注意:一定要先设置构造函数的原型对象,再new实例。(原型的动态性)

实例:

function Person(){ }
 var friend=new Person();
 Person.prototype={
 constructor:Person,
 name:'Nick',
 age:29,
 job:'student',
 sayName:function () {
 alert(this.name);
 }
 };
 friend.sayName();//error

这样的话,Person的原型被重写了:p.157

2.属性的访问

问:原型([[Prototype]])引用有什么作用?

答:当引用对象的属性的时候,会触发底层的[[Get]]操作。对于默认的[[Get]]操作来说,第一步是检查对象本身是否有这个属性,如果有的话就使用它,如果没有的话,这时候[[Prototype]]链就派上用场了。如果对象本身没有所要的属性的时候,就继续沿着整条原型链查找,找到的话就返回该属性的值,找不到的话就返回undefined。

for...in... 遍历对象的原理和查找[[Prototype]]链类似。使用in操作符来检查属性在对象中是否存在时,也会检查对象的整条原型链(不论属性是否被枚举)。

[[Prototype]]原型链的最顶端设置为Object.prototype对象。

3.属性的设置与屏蔽

myObject.foo="bar";//设置属性foo

step1:当myObject对象中有foo这个属性的时候,则直接将foo修改为“bar”;

step2:当foo属性既存在于myObject,又存在于原型链上,则myObject上foo属性会屏蔽原型链上所有的foo属性;

step3:当myObject对象中没有foo这个属性的时候,则会往上查找而存在于myObject的原型链;

3.1如果[[Prototype]]链上层存在foo属性,并且其没有标记为只读(writable:false),那么在myObject上直接添加一个foo属性,它是屏蔽属性;

var myObject={ };
myObject.prototype={
 foo:"c"
};
myObject.foo="b";
console.log(myObject.foo);//b

3.2如果foo属性被标记为只读,那么无法在myObject上修改已有属性或创建屏蔽属性。如果在严格模式下会抛出错误。

var myObject={

};
myObject.prototype={
 foo:"c" 
};
Object.defineProperty(myObject,"foo",{
 writable:false
})
myObject.foo="b";
console.log(myObject.foo);//undefined

3.3如果在[[Prototype]]上存在foo并且是一个setter,则一定会调用这个setter。foo不会被添加到myObject,也不会重新定义setter这个属性。

var myObject={ };
myObject.prototype={
 //foo是一个setter
 set foo(val){
 alert(this.val);
 }
}
myObject.foo="f";
console.log(myObject.foo)//f foo还是原来的setter函数,没有被修改

如果在3.2和3.3这两种情况下,则不能使用=操作符在赋值,而是使用Object.defineProperty(...)方法来添加,

step4:如果myObject对象和原型链上都没有foo属性的时候,直接添加到myObject上。

var myObject={ };
myObject.prototype={
 foo:"c"
};
myObject.foo="b";
console.log(myObject.foo);//b

4.属性的修改

对象实例可以修改对象原型的属性值吗?

答:分两种情况:一:当原型里的属性是值类型的话,不会被修改;

 function ClassA(){};
 ClassA.prototype.num=4;//num为值类型
 const a=new ClassA();
 a.num=3;
 const b=new ClassA();
 console.log(b.num);

二:当原型里的属性是引用类型的话,则会被修改。

function ClassA(){};
 ClassA.prototype.obj={
 num:4//num在object中,是引用类型
 };
 const a=new ClassA();
 a.obj.num=3;
 const b=new ClassA();
 console.log(b.obj.num);

相关推荐:

JavaScript 基于原型的对象(创建、调用)_js面向对象

js如何创建对象?js中创建对象的方法(附代码)

下载本文
显示全文
专题