• 对象(类)的封装方式(面向对象的js基本知识)


    上一个月一直忙于项目,没写过笔记,今天稍微空下来了一点

    前几天在写项目的时候关于怎么去封装每一个组件的时候思考到几种方式,这里总结一下:

    1、构造函数方式(类似java写类的方式):把所有的属性和方法全部挂在构造函数内部的this上:

     1 function Textarea(opts) {
     2     this.defaults = {
     3         //...这是一些默认属性
     4     };
     5     this.options = $.extend(true, {}, this.defaults, opts);
     6     this.creatDom = function() {
     7         //...这里面很大一堆代码
     8     };
     9     this.setVal = function() {
    10         //...这是很大一堆代码
    11     };
    12     this.getVal = function() {
    13         //...这是很大一堆代码
    14     };
    15 }

    这种方法的优点是代码比较紧凑,比较好理解和代码的管理,但是这样我们每次实例化一个对象的时候都会新开一段内存来存储这个对象(包括方法和属性)
    我们改改:

     1 function Textarea(opts) {
     2     this.defaults = {
     3         //...这是一些默认属性
     4     };
     5     this.options = $.extend(true, {}, this.defaults, opts);//这是覆盖以后的属性
     6     this.creatDom = creatDom;
     7     this.setVal = setVal;
     8     this.getVal = getVal;
     9 }
    10 function creatDom() {
    11     //...这是很大一堆代码
    12 }
    13 function setVal() {
    14     //...这是很大一堆代码
    15 }
    16 function getVal() {
    17     //...这是很大一堆代码
    18 }

    这样会节约一些内存:但是牺牲了代码的紧凑度;
    我们可以知道,每次实例化对象的时候其实三个方法其实是公用的,所以出现了第二种方式去定义对象

    2、原型式写法:把属性和方法都挂在到对象的原型上:

     1 function Textarea() {}
     2 Textarea.prototype.defaults = {
     3     //...
     4 };
     5 Textarea.prototype.options = $.extend(true, {}, this.defaults);
     6 Textarea.prototype.creatDom = function() {
     7     //...
     8 };
     9 Textarea.prototype.setVal = function() {
    10     //...
    11 };
    12 Textarea.prototype.getVal = function() {
    13     //...
    14 };
    15 //当然也可以把所有属性和方法放在对象上面然后再挂在prototype上:
    16 function Textarea() {}
    17 Textarea.prototype = {
    18     defaults : {},
    19     options : $.extend(true, {}, this.defaults),
    20     creatDom : function() {},
    21     setVal : function() {},
    22     getVal : function() {}
    23 };

    但是这种方法是不可取的,因为这样不能通过参数来构造对象实例(一般每个对象的属性是不相同的);就像fe里面每个人名字不一致,但都能吃能笑能写代码;
    举个简单的例子:

    1 function Person(){}
    2 Person.prototype.name = "winter";
    3 Person.prototype.getName = function() { return this.name;}
    4 new Person("summer").getName();//得到的还是winter的大名;

    3、构造函数+原型结合的方式:

    1 function Textarea(opts) {
    2     this.defaults = {};
    3     this.option =  $.extend(true, {}, this.defaults, opts);
    4 }
    5 Textarea.prototype = {
    6     creatDom : function() {},
    7     setVal : function() {},
    8     getVal : function() {}
    9 };

    看看这种方式是不是很完美...
    貌似还不完美,这样Textarea.prototype还是在外面,
    我们把它也拿到对象里面去:如下

    1 function Textarea(opts) {
    2     this.defaults = {};
    3     this.option =  $.extend(true, {}, this.defaults, opts);
    4     Textarea.prototype = {
    5         creatDom : function() {},
    6         setVal : function() {},
    7         getVal : function() {}
    8     };
    9 }

    现在看似好了,但是我们每次实例化的时候会发生什么?
    都会去执行这对代码:

    1 Textarea.prototype = {
    2     creatDom : function() {},
    3     setVal : function() {},
    4     getVal : function() {}
    5 };

    所以我们再做一个步骤,就是让它只执行一次:

     1 function Textarea(opts) {
     2     this.defaults = {};
     3     this.option =  $.extend(true, {}, this.defaults, opts);
     4     if(!!this.init){
     5         Textarea.prototype = {
     6             creatDom : function() {},
     7             setVal : function() {},
     8             getVal : function() {}
     9         };
    10         this.init = true;
    11     }
    12 }

    OK!一般说来公共属性写在prototype下,需要在实例化的时候改变的属性写在this下
    另外我们在实例化对象的时候(new)的时候需要在new的过程中就执行初始化函数:
    比如上面的例子我们在var textarea = new Textarea(opts);的时候就想把creatDom函数执行了而不是new Textarea(opts).creatDom();
    这时候我们就需要这样:

     1 function Textarea(opts) {
     2     this.defaults = {};
     3     this.option =  $.extend(true, {}, this.defaults, opts);
     4     this.creatDom(this.options);
     5 }
     6 Textarea.prototype = {
     7     creatDom : function() {},
     8     setVal : function() {},
     9     getVal : function() {}
    10 };

    号外:构造函数下面的this

     1 var die = BlackBerry;
     2 function Phone(){
     3     console.log(this.die);
     4 }
     5 Phone()//BlackBerry
     6 var die = BlackBerry;
     7 function Phone(){
     8     this.die = "Nokia";
     9     console.log(this.die);
    10 }
    11 Phone()//Nokia

    构造函数直接调用会把this当作全局window
    所以以原型方式写出的对象中没有挂在this下面,直接调用构造函数将不会有这些属性和方法
    如果以构造函数的方式生成对象在构造函数直接调用的时候将在window下生成相应的对象和方法

    原型下面的this

     1 function Phone() {}
     2 Phone.prototype = {
     3     name : "Nokia",
     4     init : function() {
     5         this.name = "BlackBerry";
     6     }
     7 };
     8 var myPhone = new Phone();
     9 myPhone.init();
    10 console.log(myPhone.name);//BlackBerry
    11 console.log(Phone.prototype.name);//Nokia

    init里面的this指的是什么?Phone.prototype?

    这里的this指的是调用的实例化对象myPhone;而不是原型对象,看看下面:
    console.log(myPhone.hasOwnProperty("name"));//true
    这里为true的原因是在调用myPhone.init()是给实例化对象添加乐一个name属性

    console.log(myPhone.hasOwnProperty("init"));//false
    这里为false很明显,因为start是原型上面的属性而非实例化对象的属性

    我差点被骗了:我以为在代码执行的时候myPhone.init();this.name = "BlackBerry";会覆盖Phone.prototype下面的那么属性

  • 相关阅读:
    ExtJs之表单(form)
    tf.where
    kuiper流式计算完整实例演示
    centos下搭建kuiper以及kuiper-manager
    Centos搭建EMQX和EMQ-Dashboard(踩坑精华版)
    代码生成器
    [MIT新技术大会]Jeff Bezos把EC2、S3和土耳其机器人描述为亚马逊“11年来的大规模万维网计算”方面的结晶,强调把后台基础设施作为服务
    《商业周刊》封面文章《谷歌和云的智慧》,讲到谷歌的新战略是“把惊人的计算能力放到众人手里”
    C# 连接 Sqlserver2005 Analysis Service的总结
    POJ_1064 二分搜索
  • 原文地址:https://www.cnblogs.com/cdwp8/p/4307084.html
Copyright © 2020-2023  润新知