天天看點

面向對象二1.​主題:2.拖拽的構造函數實作3.構造函數繼承4.原型的繼承5.原型的深拷貝繼承6.原型鍊7.拖拽的邊界需求 :通過繼承來解決8.ES6中的類9.包裝對象10.常用方法

目錄

1.​主題:

2.拖拽的構造函數實作

2.1- 拖拽的面相過程寫法

2.2- 拖拽的面相對象寫法

3.構造函數繼承

3.1構造函數繼承:

4.原型的繼承

5.原型的深拷貝繼承

5.1JSON序列化繼承原型

5.2自定義深拷貝函數:

5.3使用自定義深拷貝函數實作原型繼承:

5.3組合繼承

6.原型鍊

7.拖拽的邊界需求 :通過繼承來解決

8.ES6中的類

8.1類的寫法

8.2靜态方法和屬性:執行個體不會繼承的屬性和方法,但是子類還是會繼承父類的靜态方法和屬性

8.3類的繼承:extends

8.4子類重寫父類方法

8.5使用class繼承實作拖拽

9.包裝對象

10.常用方法

10.1hasOwnProperty():看是不是對象自身底下的屬性

10.2contructor()檢視對象的構造函數 可以用來做判斷是屬于哪個構造函數:

10.3instanceof():對象與構造函數是否在原型鍊上有關系。檢測的是原型:

10.4typeof() 傳回的是表達式的資料類型:

10.5toString()判斷類型;

1.​主題:

  1. 拖拽案例
  2. ​構造函數繼承
  3. ​原型的繼承
  4. ​拖拽案例的繼承改造
  5. ​es6中的類的用法

2.拖拽的構造函數實作

2.1- 拖拽的面相過程寫法

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #div1 {
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            top: 20px;
            left: 50px;
        }
        #div2 {
            width: 100px;
            height: 100px;
            background: blue;
            position: absolute;
            top: 200px;
            left: 400px;
        }
    </style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
    //需求:面向過程方法實作拖拽
    let div1 = document.querySelector("#div1");
    div1.addEventListener("mousedown",function(ev){
        //浏覽器相容
        let e = ev || window.event;

        //擷取初始化滑鼠坐标
        let startPos = {};
        startPos.x = e.clientX;
        startPos.y = e.clientY;

        //擷取初始left和top
        let left = div1.offsetLeft;
        let top = div1.offsetTop;
        // console.log(startPos);
        function move(ev){
            let e = ev || window.event;
            let curPos = {};
            curPos.x = e.clientX;
            curPos.y = e.clientY;
            // console.log(curPos);
            console.log(curPos.x - startPos.x + div1.offsetLeft);
            console.log(curPos.y - startPos.y + div1.offsetTop);
            
            div1.style.left = curPos.x - startPos.x + left + 'px';
            div1.style.top = curPos.y - startPos.y + top + 'px';
        }
        document.addEventListener("mousemove",move);
        document.addEventListener("mouseup",function(){
            document.removeEventListener("mousemove",move);
        },{
            once:true
        });
        
    });
    
}
</script>
</body>
</html>
           

2.2- 拖拽的面相對象寫法

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #div1 {
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            top: 20px;
            left: 50px;
        }
        #div2 {
            width: 100px;
            height: 100px;
            background: blue;
            position: absolute;
            top: 200px;
            left: 400px;
        }
    </style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
    //需求:面向對象方法實作拖拽

    //構造函數一般隻寫屬性
    function Drag(ele){
        this.ele = ele;
        this.mouseDown();
    }
    Drag.prototype.mouseDown = function(){
        //需要将this傳遞到事件裡:指派或者箭頭函數
        this.ele.addEventListener("mousedown",ev=>{
            //浏覽器相容
            let e = ev || window.event;

            //擷取初始化滑鼠坐标,直接求出初始化時滑鼠坐标和left/top的值,以免要傳遞多個參數
            let x = e.clientX - this.ele.offsetLeft;
            let y = e.clientY - this.ele.offsetTop;

            this.mouseMove(x,y);
            this.mouseUp(x,y);
        });
    }
    //由于move方法也需要共用,是以也寫在原型上
    Drag.prototype.setStyle = function(l,t){
        this.ele.style.left = l + 'px';
        this.ele.style.top = t + 'px';
    }
    Drag.prototype.mouseMove = function(x,y){
        //如果将onmousemove加在document上并使用監聽和匿名函數,則在move方法中的this會指向document,是以需要加在this.ele
        //使用監聽時不好傳遞參數
        document.onmousemove = ev=>{
            let e = ev || window.event;
            let left = e.clientX - x;
            let top = e.clientY - y;

            this.setStyle(left,top);
        };
    }
    Drag.prototype.mouseUp = function(x,y){
        document.onmouseup = ev=>{
            //清除滑鼠移動事件可以直接使this.ele.onmousemove = "";
            document.onmousemove = "";
        };
    }
    let div1 = document.querySelector("#div1");
    let div2 = document.querySelector("#div2");
    let drag1 = new Drag(div1);
    let drag2 = new Drag(div2);
    
}
</script>
</body>
</html>
           

3.構造函數繼承

  1. 繼承:子類繼承父類所有屬性和行為,父類不受影響。
  2. 目的:找到類之間的共性精簡代碼
  3. ES5中,使用call()/apply()/bind()修改this指向來實作繼承
  4. 隻會繼承父類的構造函數,而不會繼承父類的原型
  5. 解決原型不會繼承繼承問題:直接将父類原型指派給子類,JOSN序列化拷貝對象,自定義深拷貝方法,組合繼承
  6. 簡單原型繼承(直接将父類原型指派給子類),當子類修改原型時會影響父類的情況(傳址給子類);
  7. JOSN序列化原型繼承:當對象中存在undefined和函數時,拷貝的對象會忽略

3.1構造函數繼承:

通過call()/apply()/bind()修改this指向來實作,子類繼承父類所有屬性和行為

//繼承:子類繼承父類的所有屬性和行為,父類不受影響
    function Parent(name){
        this.eyes = 2;
        this.name = name;
        this.legs = 2;
    } 
    //寫子類,通過call()/apply()/bind()方法修改子類的this指向,并傳入參數即可
    function Son(name){
        Parent.call(this,name);
        //并由自己的獨特屬性
        this.hobby = "打籃球";
    } 

    //發現子類繼承父類後,擁有所有父類的屬性和行為,父類不受影響
    let parent = new Parent("老張");
    let son = new Son("小明");
    console.log(parent);//Parent {eyes: 2, name: "老張", legs: 2} 
    console.log(son);//Son {eyes: 2, name: "小明", legs: 2, hobby: "打籃球"}
           

- 繼承問題:繼承隻會繼承父類的構造函數,而不會繼承父類的原型

//繼承:隻會繼承父類的構造函數,而不會繼承父類的原型
    Parent.prototype.job = function(){
        console.log("程式員");
    }
    let parent = new Parent("老張");
    let son = new Son("小明");
    parent.job();//程式員
    son.job();//報錯:Uncaught TypeError: son.job is not a function
           

4.原型的繼承

解決構造函數繼承不能繼承原型問題:直接将父類原型指派給子類;JSON序列化;自定義深拷貝繼承;組合繼承

  • - 簡單原型繼承(直接将父類原型指派給子類),出現影響父類的情況;

如下:直接将父類原型指派給子類後,子類擁有了父類的原型,但是當子類修改了原型時,父類原型也收到了影響。是以這種方式不可用。解決:進行深拷貝,見下一節。

//簡單繼承:直接将父類原型指派給子類。問題:修改子類原型時會影響父類
    Son.prototype = Parent.prototype;
    let parent = new Parent("老張");
    let son = new Son("小明");
    parent.job();//程式員
    son.job();//程式員
    //當通過子類Son修改指派得到的原型時,發現父類的原型也發生了改變
    Son.prototype.job = function(){
        console.log("銷售");
    }
    parent.job();//銷售
    son.job();//銷售
           

5.原型的深拷貝繼承

深拷貝繼承(JSON序列化/自定義深拷貝函數);組合繼承

Object.assign()方法隻會拷貝一層;arr.flat()方法扁平化多元數組,都不适合多層的深拷貝。

- 傳值和傳址問題:

  1. - 基本資料類型傳值:Number、String、Boolean、Null、Undefined
  2. - 複雜資料類型/引用資料類型傳址:Array、Date、Math、RegExp、Object、Function等

5.1JSON序列化繼承原型

- JSON序列化的不足:

  • 如果拷貝對象包含函數,或者undefined等值,此方法就會出現問題,不會進行拷貝函數和undefined。

是以如果原型上有為undefined或者函數時,盡量不要使用JSON進行原型拷貝。

//JSON序列化解決不能繼承原型的問題。問題:當對象中有undefined或函數時,不會進行拷貝
    let parentProto = {
        name:"張三",
        age:20,
        test:undefined,
        fn:function(){
            console.log("fn...");
        }
    };
    let sonProto = JSON.parse(JSON.stringify(parentProto)); 

    console.log(parentProto);//{name: "張三", age: 20, test: undefined, fn: ƒ} 
    console.log(sonProto);//{name: "張三", age: 20}
           

5.2自定義深拷貝函數:

如果對象上有多層對象嵌套,可以進行深拷貝。

問題1:for...in循環會循環原型上的屬性或方法,是以需要使用hasOwnProperty()方法判斷,傳入的對象自身的屬性而不是原型上的屬性,再進行深拷貝

問題2:但是如果有屬性值為null,通過自定義深拷貝函數進行拷貝後,得到的對象中,null會轉為一個空對象。

//自定義深拷貝函數
    let parentProto = {
        name:"張三",
        age:20,
        gender:undefined,
        addr:null,
        fn:function(){
            console.log("fn...");
        }
    };

    function deepCopy(obj){
        //判斷參數是對象還是數組,如果是數組就建立新數組進行拷貝,如果是對象就建立新對象進行拷貝
        let newObj = Array.isArray(obj)?[]:{};
        //通過for...in循環進行拷貝
        for(let key in obj){
            //hasOwnProperty():看是不是對象自身底下的屬性
            //for...in循環會循環原型上的屬性或方法,是以需要使用hasOwnProperty()方法判斷,傳入的對象自身的屬性而不是原型上的屬性,再進行深拷貝
            if(obj.hasOwnProperty(key)){
                //如果得到的屬性仍然是一個對象,就繼續進行循環
                if(typeof obj[key] == "object"){
                    newObj[key] = deepCopy(obj[key]);
                }else{
                    newObj[key] = obj[key];
                }
            }
        }
        return newObj;
    }
    let sonProto = deepCopy(parentProto);
    console.log(parentProto);//{name: "張三", age: 20, gender: undefined, addr: null, fn: ƒ}
    console.log(sonProto);//{name: "張三", age: 20, gender: undefined, addr: {…}, fn: ƒ}
           

5.3使用自定義深拷貝函數實作原型繼承:

注意:必須在進行深拷貝時是直接将父類進行拷貝後的對象指派給子類,會覆寫掉原有的原型對象上的constructor。這樣當需要通過原型上的contructor 判斷屬于哪個構造函數時,會失效。是以,需要将原型中的構造函數進行追加Son.prototype.constructor = Son; 

//繼承:子類繼承父類的所有屬性和行為,父類不受影響
    function Parent(name){
        this.eyes = 2;
        this.name = name;
        this.legs = 2;
    } 
    function Son(name){
        Parent.call(this,name);
        this.hobby = "打籃球";
    } 

    //繼承:隻會繼承父類的構造函數,而不會繼承父類的原型
    Parent.prototype.job = function(){
        console.log("程式員");
    }
    //自定義深拷貝實作原型繼承
    function deepCopy(obj){
        let newObj = Array.isArray(obj)?[]:{};
        for(let key in obj){
            if(obj.hasOwnProperty(key)){
                if(typeof obj[key] == "object"){
                    newObj[key] = deepCopy(obj[key]);
                }else{
                    newObj[key] = obj[key];
                }
            }
        }
        return newObj;
    }
    Son.prototype = deepCopy(Parent.prototype);
    //執行個體化後的對象有構造函數和原型構成,如果隻拷貝原型會丢失構造函數,是以還需要将構造函數傳回
    //有時候會通過constructor來判斷執行個體化後的對象是屬于哪個構造函數,如果Son.prototype.constructor = Son;不寫就判斷不了
    Son.prototype.constructor = Son;
    let parent = new Parent("老張");
    let son = new Son("小明");
    Son.prototype.job = function(){
        console.log("銷售");
    }
    parent.job();//程式員
    son.job();//銷售
           

 重新追加constructor :Son.prototype.constructor = Son; 

//如果不寫Son.prototype.constructor = Son;時
    console.log(son.constructor);// Object() { [native code] }
    Son.prototype.constructor = Son;
    console.log(son.constructor);//Son(name){Parent.call(this,name);this.hobby = "打籃球";}
           

需要追加constructor 的作用:可以通過constructor來判斷,其屬于哪個構造器

//需要追加constructor的作用:可以通過constructor來判斷,其屬于哪個構造器
    console.log(son.constructor === Son);//true
    let str = 'abc';
    console.log(str.constructor === String);//true
           

5.3組合繼承

  • 寫一個空的構造函數;
  • 把父級原型指派給這個空的構造函數;
  • 再把執行個體化這個空構造函數并指派給自己的原型
function Parent(name){
        this.eyes = 2;
        this.name = name;
        this.legs = 2;
    } 
    function Son(name){
        Parent.call(this,name);
    } 
    Parent.prototype.job = function(){
        console.log("程式員");
    }

    //寫一個空的構造函數;
    // 把父級原型指派給這個空的構造函數;
    // 再把執行個體化這個空構造函數并指派給自己的原型
    let Link = function(){};
    Link.prototype = Parent.prototype;
    Son.prototype = new Link();
    //無論哪種方式實作繼承都需要設定會子類的構造函數
    Son.prototype.constructor = Son;

    let parent = new Parent("張三");
    let son = new Son("李四");
    Son.prototype.job = function(){
        console.log("銷售");
    }
    parent.job();//程式員
    son.job();//銷售
           

6.原型鍊

構造函數有構造函數自身和原型兩部分組成。而原型本身也是一對對象,是以構造函數的原型又由其自身和原型組成。一直鍊條式進行。

查找順序:先找自身構造函數->再找自身的原型->Object底層的原型->最終找不到傳回undefined

原型鍊是指對象在通路屬性或方法時的查找方式。

1.當通路一個對象的屬性或方法時,會先在對象自身上查找屬性或方法是否存在,如果存在就使用對象自身的屬性或方法。如果不存在就去建立對象的構造函數的原型對象中查找 ,依此類推,直到找到為止。如果到頂層對象中還找不到,則傳回 undefined。

2.原型鍊最頂層為 Object 構造函數的 prototype 原型對象(Object的原型prototype不會再有原型,即Object.prototype再也沒有原型了),給 Object.prototype 添加屬性或方法可以被除 null 和 undefined 之外的所有資料類型對象使用。

面向對象二1.​主題:2.拖拽的構造函數實作3.構造函數繼承4.原型的繼承5.原型的深拷貝繼承6.原型鍊7.拖拽的邊界需求 :通過繼承來解決8.ES6中的類9.包裝對象10.常用方法

如下圖:此處:首先在執行個體化對象parent本身的構造函數Parent上查找name,如果沒有找到,會到執行個體化對象parent的原型上即Parent.prototype上查找,還是沒有找到就到底層Object.prototype上查找,最終都沒有找到就傳回undefined

//原型鍊
    function Parent(){
        this.name = "張三";
    }
    Parent.prototype.name = "李四";
    Object.prototype.name = "王五";
    let parent = new Parent();
    //此處:首先在執行個體化對象parent本身的構造函數Parent上查找name,如果沒有找到,會到執行個體化對象parent的原型上即Parent.prototype上查找,還是沒有找到就到底層Object.prototype上查找,最終都沒有找到就傳回undefined
    console.log(parent.name);
           

7.拖拽的邊界需求 :通過繼承來解決

需求:2個div實作拖拽 其中第二個需要設定邊界不能拖出可視區域

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #div1 {
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            top: 20px;
            left: 50px;
        }
        #div2 {
            width: 100px;
            height: 100px;
            background: blue;
            position: absolute;
            top: 200px;
            left: 400px;
        }
    </style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
    //需求:使用繼承實作第二個div不超出邊界

    //構造函數一般隻寫屬性
    function Drag(ele){
        this.ele = ele;
        this.mouseDown();
    }
    Drag.prototype.mouseDown = function(){
        //需要将this傳遞到事件裡:指派或者箭頭函數
        this.ele.addEventListener("mousedown",ev=>{
            //浏覽器相容
            let e = ev || window.event;

            //擷取初始化滑鼠坐标,直接求出初始化時滑鼠坐标和left/top的值,以免要傳遞多個參數
            let x = e.clientX - this.ele.offsetLeft;
            let y = e.clientY - this.ele.offsetTop;

            this.mouseMove(x,y);
            this.mouseUp(x,y);
        });
    }
    //由于move方法也需要共用,是以也寫在原型上
    Drag.prototype.setStyle = function(l,t){
        this.ele.style.left = l + 'px';
        this.ele.style.top = t + 'px';
    }
    Drag.prototype.mouseMove = function(x,y){
        //如果将onmousemove加在document上并使用監聽和匿名函數,則在move方法中的this會指向document,是以需要加在this.ele
        //使用監聽時不好傳遞參數
        document.onmousemove = ev=>{
            let e = ev || window.event;
            let left = e.clientX - x;
            let top = e.clientY - y;

            this.setStyle(left,top);
        };
    }
    Drag.prototype.mouseUp = function(x,y){
        document.onmouseup = ev=>{
            //清除滑鼠移動事件可以直接使this.ele.onmousemove = "";
            document.onmousemove = "";
        };
    }
    let div1 = document.querySelector("#div1");
    let drag1 = new Drag(div1);
    
    //給第二個div建立子類繼承父類
    function Div2Drag(ele){
        //繼承的同時要把所有參數傳遞過去
        Drag.call(this,ele);
    }
    //聲明新的Temp空構造,将父級原型指派給這個空構造的原型
    let Temp = function(){};
    Temp.prototype = Drag.prototype;
    //将示例化後的Temp指派給子級的原型
    Div2Drag.prototype = new Temp();
    //還原子級原有的構造方法
    Div2Drag.prototype.constructor = Div2Drag;

    //重寫Div2Drag的滑鼠移動方法
    Div2Drag.prototype.mouseMove = function(x,y){
        document.onmousemove = ev=>{
            let e = ev || window.event;
            let left = e.clientX - x;
            let top = e.clientY - y;
            //限定邊界
            left = Math.max(0,left);
            top = Math.max(0,top);
            left = Math.min(document.documentElement.clientWidth - this.ele.offsetWidth,left);
            top = Math.min(document.documentElement.clientHeight - this.ele.offsetHeight,top);
            this.setStyle(left,top);
        };
    }

    let div2Drag = new Div2Drag(div2);
    
}
</script>
</body>
</html>
           

8.ES6中的類

ES6中的方法會自動加到原型中;

父類的靜态屬性和方法,不能通過執行個體化後的對象擷取;

子類可以繼承父類的靜态屬性和方法,但是子類執行個體化後的對象不能擷取到父類的靜态屬性和方法;

8.1類的寫法

class Person{
  	height="178cm";
    constructor(name,age){
        //屬性
        this.name = name;
        this.age = age;
    }
    //方法
    getName(){
        console.log("姓名是:"+this.name);
    }
}
let student = new Person("張三",20);
student.getName();
           

8.2靜态方法和屬性:執行個體不會繼承的屬性和方法,但是子類還是會繼承父類的靜态方法和屬性

class Person{
      //靜态方法
      static hobby(){
          console.log("喜歡籃球");
      }
  }
  //靜态屬性
  Person.height = "178cm";
  //通過類來調用
  Person.hobby();
  console.log(Person.height);
           

8.3類的繼承:extends

class Dad{
      name = "張三";
      age = 40;
      constructor(height){
          this.height = height;
      }
      hobby(){
          console.log("喜歡籃球");
      }
  }
  class Son extends Dad{
      constructor(height){
          //表示父類的構造函數
          super(height);
      }
  }
  let son1 = new Son("178cm");
  son1.hobby();
  console.log(son1.height);
           

8.4子類重寫父類方法

class Dad{
      name = "張三";
      age = 40;
      constructor(height){
          this.height = height;
      }
      hobby(){
          console.log("喜歡籃球");
      }
  }
  class Son extends Dad{
      constructor(height){
          //表示父類的構造函數
          super(height);
      }
      hobby(){
          super.hobby();
          console.log("也喜歡足球");
      }
  }
  let son1 = new Son("178cm");
  son1.hobby();//喜歡籃球 也喜歡足球
  console.log(son1.height);//178cm
           

8.5使用class繼承實作拖拽

<!DOCTYPE html>
<html >

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #div1 {
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            top: 20px;
            left: 50px;
        }

        #div2 {
            width: 100px;
            height: 100px;
            background: blue;
            position: absolute;
            top: 200px;
            left: 400px;
        }
    </style>
</head>

<body>
    <div id="div1"></div>
    <div id="div2"></div>
    <script>
        {
            //需求:ES6的繼承,class實作繼承沒有原型的淺拷貝問題
            class Drag {
                constructor(ele) {
                    this.ele = ele;
                    this.mouseDown();
                }
                mouseDown() {
                    this.ele.addEventListener("mousedown", ev => {
                        //浏覽器相容
                        let e = ev || window.event;

                        //擷取初始化滑鼠坐标,直接求出初始化時滑鼠坐标和left/top的值,以免要傳遞多個參數
                        let x = e.clientX - this.ele.offsetLeft;
                        let y = e.clientY - this.ele.offsetTop;

                        this.mouseMove(x, y);
                        this.mouseUp();
                    });
                }
                setStyle(l, t) {
                    this.ele.style.left = l + 'px';
                    this.ele.style.top = t + 'px';
                }
                mouseMove(x, y) {
                    document.onmousemove = ev => {
                        let e = ev || window.event;
                        let left = e.clientX - x;
                        let top = e.clientY - y;
                        this.setStyle(left, top);
                    };
                }
                mouseUp() {
                    document.onmouseup = function () {
                        document.onmousemove = "";
                    }
                }
            }
            let div1 = document.querySelector("#div1");
            let drag1 = new Drag(div1);

            //給第二個div建立子類繼承父類
            class Div2Drag extends Drag {
                constructor(ele) {
                    super(ele);
                }
                mouseMove = function (x, y) {
                    document.onmousemove = ev => {
                        let e = ev || window.event;
                        let left = e.clientX - x;
                        let top = e.clientY - y;
                        //限定邊界
                        left = Math.max(0, left);
                        top = Math.max(0, top);
                        left = Math.min(document.documentElement.clientWidth - this.ele.offsetWidth, left);
                        top = Math.min(document.documentElement.clientHeight - this.ele.offsetHeight, top);
                        this.setStyle(left, top);
                    };
                }
            }
            
            let div2Drag = new Div2Drag(div2);
        }
    </script>
</body>

</html>
           

9.包裝對象

- 除過null,undefined,基本類型都有自己對應的包裝對象:String Number Boolean    

- 包裝對象把所有的屬性和方法給了基本類型,然後包裝對象消失

當基本資料類型需要用到包裝類型上的方法時,對自動生成包裝對象。

原理分析:

//包裝對象:String Number Boolean    
    let str = "a b c";

    //基本資料類型調用包裝對象的方法時,原理分析
    function mySplit(str,method,arg){
        let temp = new String(str);
        //最終包裝完後系統會銷毀包裝對象
        return temp[method](arg);
    }

    let res = mySplit(str,"split"," ");
    console.log(res);//(3) ["a", "b", "c"]
           

10.常用方法

javascript中判斷資料類型的四種方法及typeof、instanceof、constructor、toString的詳細講解參考連結:https://blog.csdn.net/liwenfei123/article/details/77978027

  1. - hasOwnProperty():看是不是對象自身底下的屬性(而不是屬于原型的)。如自定義深拷貝
  2. - contructor查()看對象的構造函數 可以用來做判斷是屬于哪個構造函數
  3. - instanceof():對象與構造函數是否在原型鍊上有關系
  4. typeof():typeof 是一個操作符,其右側跟一個一進制表達式,并傳回這個表達式的資料類型。而對于Date,Array,RegExp等都是傳回原型鍊最頂端的Object。
  5. - toString()判斷類型; 轉換字元串 進制轉換

10.1hasOwnProperty():看是不是對象自身底下的屬性

function deepCopy(obj){
        //判斷參數是對象還是數組,如果是數組就建立新數組進行拷貝,如果是對象就建立新對象進行拷貝
        let newObj = Array.isArray(obj)?[]:{};
        //通過for...in循環進行拷貝
        for(let key in obj){
            //hasOwnProperty():看是不是對象自身底下的屬性,而不是原型鍊
            //for...in循環會循環原型上的屬性或方法,是以需要使用hasOwnProperty()方法判斷,傳入的對象自身的屬性而不是原型上的屬性,再進行深拷貝
            if(obj.hasOwnProperty(key)){
                //如果得到的屬性仍然是一個對象,就繼續進行循環
                if(typeof obj[key] == "object"){
                    newObj[key] = deepCopy(obj[key]);
                }else{
                    newObj[key] = obj[key];
                }
            }
        }
        return newObj;
    }
           

10.2contructor()檢視對象的構造函數 可以用來做判斷是屬于哪個構造函數:

let str = 'abc';
    console.log(str.constructor === String);//true
           

10.3instanceof():對象與構造函數是否在原型鍊上有關系。檢測的是原型:

//instanceof函數:instanceof 檢測的是原型
    let arr = [];
    let obj = {};

    console.log(arr instanceof Array);//true
    console.log(obj instanceof Object);//true
    //因為instanceof判斷的是原型鍊上的關系,而數組本身也是複雜資料類型-對象。是以不能使用instanceof來判斷一個數組是否是Array
    console.log(arr instanceof Object);//true

    //因為字元串str是基本資料類型,沒有原型,而instanceof判斷的是原型,是以會傳回false
    let str = "abc";
    let str1 = new String("sdf");
    console.log(str instanceof String);//false
    console.log(str1 instanceof String);//true
    console.log(str);
    console.log(str1);//String {"sdf"}
           

10.4typeof() 傳回的是表達式的資料類型:

console.log(typeof arr);//object
   console.log(typeof obj);//object
           

10.5toString()判斷類型;

轉換字元串 進制轉換:用Object.prototype.toString.call(arr)方法判斷的類型最為準确。但是必須通過 call 或 apply 來調用,而不能直接調用 toString()

console.log(Object.prototype.toString.call(arr));//[object Array]
    console.log(Object.prototype.toString.call(obj));//[object Object]
    console.log(Object.prototype.toString.call(str));//[object String]