首頁  >  文章  >  web前端  >  如何創建一個物件的方法及原型物件了解一下

如何創建一個物件的方法及原型物件了解一下

坏嘻嘻
坏嘻嘻原創
2018-09-13 16:11:021849瀏覽

很多朋友在學習前端的時候會遇到物件創建的難題,讓我來教大家一些方法,希望大家耐心學習哦。

一、建立一個物件的方法

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中创建对象的方法(附代码)

以上是如何創建一個物件的方法及原型物件了解一下的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn