javaScript(小细节)你了解吗?instanceof、面向对象的设计模式...

308 阅读5分钟

前言

秉着学习、交流、思考、总结的态度,和大家分享这段时间通过阅读js高级程序设计,发现的一些小细节,小知识点,一起交流,一起进步!查漏补缺ing...

操作符----instanceof

  • 在 JavaScript 中,我们判断一个变量的类型常常会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object";
  • instanceof 与 typeof 方法不同的是,instanceof 方法帮助开发者明确地确认对象为某特定类型。
var obj = new Object("some texrt");
console.log(obj instanceof Number);	//输出 false
console.log(obj instanceof String);	//输出 true
  • 原理:instanceof是根据引用数据类型的prototype来判断真实的数据类型。

变量、作用域和内存问题

  • 复制变量值问题

    • var num = 2;
      var num1  = num;   // 此时 num1  = 2  复制了num
      var num1 = 3;    //此时num1 = 3,num依然为2
      
    • var obj1 = new Object()
      var obj2 = obj1;
      obj1.name = "MG";
      alert(obj2.name); //此时obj2.name = MG
      

    变量对象的指向: obj1创建了一个对象新实例,然后复制给了obj2。此时他们指向的都是堆内存中的同一个对象;当obj1添加name属性之后,obj2来访问这个属性,此时他们访问的都是存储在这个堆内存中的一个对象。

  • 声明变量

    function add(num1,num2){
          var sum = num1+num2;
          return sum;
      }
      var result = add(10,20);
      alert(sum);	// sum is not defined---(var声明在了局部环境,全局无法访问到)
    
     function add(num1,num2){
            sum = num1 + num2;
            return sum
        }
        var result = add(10,20)
        alert(sum);	// 30
    

    var: var声明变量会自动被添加到最接近的环境中;在函数内部最接近的环境就是函数的局部环境;如果初始化变量时(代码块2所示),没有使用var关键字,所以sum属于全局环境,那么当add()执行完毕之后,sum也可以被访问到。

  • 垃圾收集机制

    • javascript内部机制具有自动垃圾收集机制。不必关心内存分配和回收问题。
    • 标记清除是主流的垃圾收集算法。另外一种是引用计数算法。

创建对象

  • 工厂模式

    • 这是一种广为人知的设计模式,说白了就是实现同一事情的相同代码,放到一个函数中,以后如果再想实现这个功能,就不需要重新编写这些代码了,只要执行当前的函数即可;
    • 弊端:这种模式没有解决对象识别的问题(即怎样知道一个对象的类型)用起来还是不够灵活;
    function creatPerson(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 = creatPerson("mangguo",21,"fe");
     var person2 = creatPerson("MG",21,"前端");
    
  • 构造函数模式

    • 典型用法是:new操作符来创建一个新的对象;注意哦,构造函数模式函数名首字母要使用大写;
    • 弊端:这种构造函数的方式会导致不同的作用域链和标识符被解析,但是创建新实例的机制仍然是相同的;
    function Person(name,age,job){
         var o = new Object();    // 新建一个函数
         o.name = name;
         o.age = age;
         o.job = job;
         o.sayName = function (){
             alert (this.name);
         }; 
     }
     var person1 = new creatPerson("mangguo",21,"fe");
     var person2 = new creatPerson("MG",21,"前端");
    

小伙伴们可以根据这些实例,自己总结一下上边的这两种模式还有什么不一样的地方,进一步巩固哦!

  • 原型模式

    • hasOwnProperty()方法,可以用来检测一个属性是存在于实例中,还是存在于原型中;
    • 只有当实例真正重写原型里边的属性时, hasOwnProperty()才会返回true;
    • 使用in操作符时,只要通过对象能够访问到属性就会返回true;
    • 要注意区别 hasOwnProperty()和 hasPrototyeProperty();当对象属性重写之后,hasPrototyeProperty()会返回false;
    • 实例和原型之间的连接是一个指针prototype
       function Person(){}
       Person.prototype = {
            name :"MG",
            adress :"beijing",
            sayName :(()=>{ 
            console.log(this.name);
       	  }) 
        }
        var person1 = new Person();
        var person2 = new Person();
        console.log(person1.hasOwnProperty("name"));	// 输出 false
    	console.log("name" in person1);	// 输出 true
        person1.name = "mangguo"
        console.log(person1.hasOwnProperty("name"));	// 输出 true
    	console.log("name" in person1);	// 输出 true
    
  • 构造函数和原型混成的模式

    • 混成模式集两种模式之长,是目前使用最广泛,认同度最高的一种创建自定义类型的方法;
    • 这样会最大程度的节省内存,这样的实例就会不仅有自己的实例属性,还会共享着原型上的属性和方法,真正的实现1+1>2;
    function Person(name,age,job){
         var o = new Object();    // 新建一个函数
         o.name = name;
         o.age = age;
         o.job = job;
         this.friends = ["Mar","Court"];
     }
     Person.prototype = { 
          constructor:Person, //  这里是声明所有实例的共享属性,constructor'
          sayName:function(){
              alert(this.name);
          }
      }
     var person1 = new creatPerson("mangguo",21,"fe");
     var person2 = new creatPerson("MG",21,"前端");
     person1.friends.push("Van");
     console.log(person1.friends);    // 输出 "Mar, Court, Van"
     console.log(person2.friends);    // 输出 "Mar, Court" ,可以看出修改person1的修改并不会影响到person2
     console.log(person1.friends === person2.friends); // 输出 false
     console.log(person1.sayName === person2.sayName); // 输出 true
    
    

除了以上几种模式还有动态原型模式寄生构造函数模式稳妥构造函数模式,但由于这些都不太常用,所以就不介绍了,有兴趣的小伙伴可以参考js红宝书第六章,里边介绍的很详细哦!

小结

这些是在阅读红宝书的过程中,发现的一些小细节,或许还不够深入,需要小伙伴们一起多积累多练习,大家一起学,一起交流进步才会更快哦,一起加油!持续更新中~