<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      JS中關于構造函數、原型鏈、prototype、constructor、instanceof、__proto__屬性

      在Javascript不存在類(Class)的概念,javascript中不是基于類的,而是通過構造函數(constructor)和原型鏈(prototype chains)實現的。但是在ES6中引入了Class(類)這個概念,作為對象的模板。通過class關鍵字,可以定義類?;旧希珽S6的class可以看作只是一個語法糖,它的絕大部分功能,ES5都可以做到,新的class寫法只是讓原型對象的寫法更加清晰、更像面向對象編程的語法而已。

       

      1、構造函數的簡單介紹

      構造函數就是提供了一個生成對象的模板并描述對象的基本結構的函數。一個構造函數,可以生成多個對象,每個對象都有相同的結構??偟膩碚f,構造函數就是對象的模板,對象就是構造函數的實例。

      構造函數的特點有:

        a:構造函數的函數名首字母必須大寫。

        b:內部使用this對象,來指向將要生成的對象實例。

        c:使用new操作符來調用構造函數,并返回對象實例。

      function Person(){
        this.name = 'keith';
      } 
      var boy = new Person();
      console.log(boy.name); //'keith'

       

      2、構造函數的缺點

      所有的對象實例都可以繼承構造函數中的屬性和方法。但是,同一個對象實例之間,無法共享屬性。

      function Person(name, height) {
        this.name = name;
        this.height = height;
        this.hobby = function () {
          return 'watching movies';
        }
      }
      var boy = new Person('keith', 180);
      var girl = new Person('rascal', 153);
      console.log(boy.name); //'keith'
      console.log(girl.name); //'rascal'
      console.log(boy.hobby === girl.hobby); //false

      上面代碼中,一個構造函數Person生成了兩個對象實例boy和girl,并且有兩個屬性和一個方法。但是,它們的hobby方法是不一樣的。也就是說,每次使用new來調用構造函數生成一個對象實例的時候,都會創建一個hobby方法。這既沒有必要,又浪費資源,因為所有hobby方法都是同樣的行為,完全可以被兩個對象實例共享。

      所以,構造函數的缺點就是:同一個構造函數的生成的對象實例之間無法共享屬性或方法。

       

      3、構造函數的prototype屬性(指向原型對象)

      為了解決構造函數的對象實例之間無法共享屬性的缺點,JS 提供了prototype屬性。

      原型屬性(prototype)是函數特有的屬性,這個屬性是一個指針,指向一個對象,這個對象的用途就是包含所有實例共享的屬性和方法(我們把這個對象叫做原型對象,一個實例對象的原型對象可以通過該實例對象的 __proto__ 屬性獲?。?。通過prototype定義的屬性及方法能被所有對象實例所共享,這就是prototype的意義。

      通過構造函數生成對象實例時,會將對象實例的原型指向構造函數的 prototype 屬性。每一個構造函數都有一個prototype屬性,函數的這個屬性值就是對象實例的原型對象。

      function Person(name, height) {
        this.name = name;
        this.height = height;
      }
      Person.prototype.hobby = function () { // 生成的對象實例會共享這樣聲明的構造函數方法
        return 'watching movies';
      }
      var boy = new Person('keith', 180);
      var girl = new Person('rascal', 153);
      console.log(boy.name); //'keith'
      console.log(girl.name); //'rascal'
      console.log(boy.hobby === girl.hobby); //true 表明生成的對象實例共享著同一個方法

      上面代碼中,如果將hobby方法放在原型對象上,那么兩個實例對象都共享著同一個方法。對于構造函數來說,prototype是作為構造函數的屬性;對于對象實例來說,prototype是對象實例的原型對象。所以 prototype 即是屬性,又是對象。

      只要修改原型對象上的屬性和方法,變動就會立刻體現在所有對象實例上。

      Person.prototype.hobby = function(){
        return 'swimming';
      }
      console.log(boy.hobby === girl.hobby); //true
      console.log(boy.hobby()); //'swimming'
      console.log(girl.hobby()); //'swimming'

      上面代碼中,當修改了原型對象的hobby方法之后,兩個對象實例都發生了變化。這是因為對象實例其實是沒有hobby方法,都是讀取原型對象的hobby方法。也就是說,當某個對象實例沒有該屬性和方法時,就會到原型對象上去查找。如果實例對象自身有某個屬性或方法,就不會去原型對象上查找。

      boy.hobby = function(){
        return 'play basketball';
      }
      console.log(boy.hobby()); //'play basketball'
      console.log(girl.hobby()); //'swimming'

      上面代碼中,boy對象實例的hobby方法修改時,就不會在繼承原型對象上的hobby方法了。不過girl仍然會繼承原型對象的方法。

      總結:

        a:原型對象的作用,就是定義所有對象實例所共享的屬性和方法。

        b:prototype 對于構造函數來說,它是一個屬性;對于對象實例來說,它是一個原型對象。

       

      4、原型鏈(prototype chains)

      對象的屬性和方法,有可能是定義在自身,也有可能是定義在它的原型對象上。由于原型對象本身也是對象,它也有自己的原型,所以形成了一條原型鏈(prototype chain)。比如,a的原型對象是b,b的原型對象是c,以此類推。所有一切的對象的原型頂端,都是Object.prototype,即 Object 構造函數的 prototype 屬性指向的那個對象。

      當然,Object.prototype對象也有自己的原型對象,那就是沒有任何屬性和方法的 null 對象,而 null 對象沒有自己的原型。

      console.log(Person.prototype.isPrototypeOf(boy))      //true  假設person是boy的原型
      console.log(Object.getPrototypeOf(Object.prototype)); //null  此處表明 Object.prototype 的原型對象是 null

      原型鏈(prototype chain)的特點有:

        a:讀取對象的某個屬性時,JavaScript 引擎先尋找對象本身的屬性,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的 Object.prototype 還是找不到,則返回 undefined。

        b:如果對象自身和它的原型,都定義了一個同名屬性,那么優先讀取對象自身的屬性,這叫做“覆蓋”(overiding)。

        c:一級級向上在原型鏈尋找某個屬性,對性能是有影響的。所尋找的屬性在越上層的原型對象,對性能的影響越大。如果尋找某個不存在的屬性,將會遍歷整個原型鏈。

       

      下面利用代碼來講解:

      var arr = [1,2,3]; 
      console.log(arr.length);   //3
      console.log(arr.valueOf()) //[1,2,3]
      console.log(arr.join('|')) //1|2|3

      上面代碼中,定了一個數組arr,數組里面有三個元素。我們并沒有給數組添加任何屬性和方法,可是在調用 length,join(),valueOf() 時,卻不會報錯。

      length 屬性是繼承自 Array.prototype 的,屬于原型對象上的一個屬性。join 方法也是繼承自 Array.prototype 的,屬于原型對象上的一個方法。這兩個方法是所有數組所共享的。當實例對象上沒有這個 length 屬性時,就會去原型對象查找。valueOf 方法是繼承自Object.prototype 的。首先,arr數組是沒有 valueOf 方法的,所以就到原型對象 Array.prototype 查找。然后,發現 Array.prototype 對象上也沒有valueOf方法。最后,再到它的原型對象 Object.prototype 查找,Object.prototype 上面有這個方法。

      來看看 Array.prototype 對象和 Object.prototype 對象分別有什么屬性和方法。

      console.log(Object.getOwnPropertyNames(Array.prototype))      //["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", "forEach", "map", "filter", "reduce", "reduceRight", "some", "every", "find", "findIndex", "copyWithin", "fill", "entries", "keys", "values", "includes", "constructor", "$set", "$remove"]
      console.log(Object.getOwnPropertyNames(Object.prototype))     // ["toSource", "toString", "toLocaleString", "valueOf", "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__proto__", "constructor"]

       

      5、實例對象的constructor屬性(返回對象實例的構造函數)

      實例對象的constructor屬性返回實例對象的構造函數。

      function A(){};
      var a = new A(); 
      console.log(a.constructor); //A

      constructor 屬性實際上是原型對象的屬性,這個屬性包含了一個指針,指回原構造函數,它被所有實例對象繼承。

      function A(){};
      var a = new A();
      console.log(a.constructor === A );          //true
      console.log(A === A.prototype.constructor)  //true 通過原型對象訪問constructor屬性返回的是原型對象所處的構造函數
      console.log(A.hasOwnProperty('prototype'));             //true
      console.log(A.prototype.hasOwnProperty('constructor')); //true

       

      5.1、constructor屬性的作用

        a:判斷對象實例的構造函數

      function A(){};
      var a = new A(); 
      console.log(a.constructor === A)    //true
      console.log(a.constructor === Array) //false

        b:從實例新建另一個實例

      function A() {};
      var a = new A();
      var b = new a.constructor();  //從a.constructor間接調用構造函數。
      console.log(b instanceof A); //true

       

      6、instanceof運算符

      instanceof 用于判斷對象是否為某個構造函數的實例。

      function A() {};
      var a = new A();
      console.log(a instanceof A); //true
      console.log(a instanceof Object); //true 對整個原型鏈上的對象都有效

      注意,instanceof對象只能用于復雜數據類型(數組,對象等),不能用于簡單數據類型(布爾值,數字,字符串等)。而且 null 和 undefined 都不是對象,所以instanceof 總是返回false。

      console.log([1] instanceof Array);     //true
      console.log({} instanceof Object);     //true
      console.log(true instanceof Boolean);  //false
      console.log('aaa' instanceof String);  //false
      
      console.log(null instanceof Object);      //false 
      console.log(undefined instanceof Object); //false

      利用instanceof運算符,還可以巧妙地解決,調用構造函數時,忘了加new命令的問題。

      function Keith(name,height) {
        if (!this instanceof Keith) {
          return new Keith(name,height);
         }
         this.name = name;
         this.height = height;
      }

       

      7、實例對象的__proto__屬性(返回實例對象的原型對象)

      實例對象的屬性 __proto__ (注意,寫法是兩邊都是兩個_符號)返回該實例對象的原型對象,即構造函數的 prototype 屬性值,通過該屬性可以訪問原型對象的所有方法。

      var Person = function(name){
        this.name = name;
      }
      var a = new Person('jack');
      console.log(a.__proto__  === Person.prototype);    //true  同樣的,Person也有原型對象,通過Person的 __proto__ 屬性也可以訪問到它的原型對象,以此類推,可以實現原型鏈的向上追溯。

      可以通過 __proto__ 屬性繼承其他對象的屬性,但非常不建議這么做,對性能影響非常大。詳情查看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

      var Person = function (name) {
        this.name = name;
      }
      var a = new Person('jack');
      console.log(a.name);     //jack
      var b = {
        age: 10
      }
      a.__proto__ = b;
      console.log(a.name,a.age);   //jack 10

      相對于通過 __proto__ 屬性繼承其他對象的屬性而言,Object.create() 方法是一個更加值得推薦的方法。該方法接收一個對象作為參數,返回一個以該對象為原型對象的新對象,即繼承了作為參數的對象的屬性及方法。

      let b = {
        age: 10
      }
      let a = Object.create(b);
      console.log(a.age);     //10
       

      8、Function.prototype和Object.prototype

      Function 和 Object 其實就是一個構造函數。

      function Person(a,b){
        this.a = a;
        this.b = b;
      }
      let man = new Person('a','b');
      console.log(Person.constructor);                //輸出 ? Function() { [native code] }
      console.log(Person.constructor.constructor);    //? Function() { [native code] }
      console.log(Function == Person.constructor);    //true 此處表明 Function 就是一個構造函數,并且普通函數的構造函數就是 Function
      console.log(Function.prototype == Person.__proto__);  //true
      let obj = {}
      console.log(obj.constructor);              //輸出 ? Object() { [native code] }
      console.log(Object == obj.constructor);    //true 此處表明 Object就是一個構造函數,并且普通對象的構造函數就是 Object
      console.log(Object.prototype == obj.__proto__);  //true

      面試題:是否所有的對象都繼承 Object

      不是,JS 中不是所有對象都繼承Object,也有特例,null 和 undefined 不是繼承自 Object。

       

      posted @ 2018-12-26 14:10  wenxuehai  閱讀(745)  評論(0)    收藏  舉報
      //右下角添加目錄
      主站蜘蛛池模板: 国产成人免费永久在线平台| 日韩在线观看精品亚洲| 免费无码成人AV在线播放不卡 | 一区二区三区精品不卡| 四虎永久精品在线视频| 中文国产人精品久久蜜桃| 99精品国产中文字幕| 精品成在人线av无码免费看| 亚洲午夜精品国产电影在线观看| 无码无需播放器av网站| 美乳丰满人妻无码视频| 松潘县| 乱人伦中文字幕成人网站在线| 九九热在线免费精品视频| 少妇又紧又色又爽又刺激视频| 精品视频不卡免费观看| 在线观看成人av天堂不卡| 国产精品中文字幕av| 久久91精品牛牛| 美女又黄又免费的视频| 亚洲国产精品综合一区二区| 精品亚洲没码中文字幕| 南陵县| 好日子在线观看视频大全免费动漫| 久久涩综合一区二区三区| 亚洲精品一二三四区| 午夜福利影院不卡影院| 日本美女性亚洲精品黄色| 精品无码一区在线观看| 板桥市| 日韩午夜福利片段在线观看| 和艳妇在厨房好爽在线观看| 99噜噜噜在线播放| 人妻av中文字幕无码专区| 欧美日韩精品一区二区视频| 日日摸夜夜添夜夜添国产三级| 中文字幕av无码免费一区| 国产精品亚洲综合久久小说| 亚洲熟女片嫩草影院| 民乐县| 人人爽人人爽人人片av东京热 |