JavaScript创建对象的方法和理解

来源:程序思维浏览:1237次
JavaScript创建对象的方法和理解

一、创建一个对象的方法

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);
精品好课
React实战视频教程仿京东移动端电商
React是前端最火的框架之一,就业薪资很高,本课程教您如何快速学会React并应用到实战,对正在工作当中或打算学习React高薪就业的你来说,那么这门课程便是你手中的葵花宝典。
HTML5基础入门视频教程易学必会
HTML5基础入门视频教程,教学思路清晰,简单易学必会。适合人群:创业者,只要会打字,对互联网编程感兴趣都可以学。课程概述:该课程主要讲解HTML(学习HTML5的必备基础语言)、CSS3、Javascript(学习...
jQuery视频教程从入门到精通
jquery视频教程从入门到精通,课程主要包含:jquery选择器、jquery事件、jquery文档操作、动画、Ajax、jquery插件的制作、jquery下拉无限加载插件的制作等等......
HTML5视频播放器video开发教程
适用人群1、有html基础2、有css基础3、有javascript基础课程概述手把手教你如何开发属于自己的HTML5视频播放器,利用mp4转成m3u8格式的视频,并在移动端和PC端进行播放支持m3u8直播格式,兼容...
最新完整React视频教程从入门到精通纯干货纯实战
React是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习React高薪就...
VUE2+VUE3视频教程从入门到精通(全网最全的Vue课程)
VUE是目前最火的前端框架之一,就业薪资很高,本课程教您如何快速学会VUE+ES6并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习VUE高薪就...
最新完整React+VUE视频教程从入门到精,企业级实战项目
React和VUE是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React和VUE并应用到实战,教你如何解决内存泄漏,常用库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习Re...
Vue2+Vue3+ES6+TS+Uni-app开发微信小程序从入门到实战视频教程
2021年最新Vue2+Vue3+ES6+TypeScript和uni-app开发微信小程序从入门到实战视频教程,本课程教你如何快速学会VUE和uni-app并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己...
收藏
扫一扫关注我们