zoukankan      html  css  js  c++  java
  • Advanced JS 2

      阮一峰 JavaScript OOD 三部曲:

    封装

    JS 是一种基于对象(object-based)的语言. 但是JS不是一种真正的OOP语言, 因为语法中没有class.

    以下就是简单的封装. 把两个属性封装在一个对象里面. 但是,这样的写法有缺陷.

    1. 如果要多生成几个实例,写起来就非常麻烦.

    2. 实例与原型之间,没有任何办法看出联系.

    <script>
            var Cat = {
                name: '',
                color: ''
            }
            var cat1 = {};
            cat1.name = '黑猫';
            cat1.color = '黑色';
    
            var cat2 = {
                name: '白猫',
                color: '白色'
            };
            console.log(cat1);
            console.log(cat2);
        </script>

    改进方法

    我们可以写一个函数, 来解决代码重复的问题.

    <script>
            function dog(name, color) {
                return {
                    name: name,
                    color: color
                }
            }
            var dog1 = dog('二狗子','黑色');
            var dog2 = dog('狗蛋儿','黄色');
    
            console.log(dog1);
            console.log(dog2);
        </script>

    构造函数

    JS的构造函数和传统编程语言不同. 所谓"构造函数",其实就是一个普通函数, 但是内部可以使用this变量(JS this变量随笔), 并且this 变量会绑定在实例对象上. 只需要把function 名字首字母大写就来代表这个function是constructor

    通过构造函数, 我们现在原型就可以这么写了:

        <script>
            function Dog(name, color) {
                this.name = name;
                this.color = color;
            }
            var dog1 = new Dog('二狗子', '黑色');
            var dog2 = new Dog('狗蛋儿', '黄色');
    
            console.log(dog1);
            console.log(dog2);
    console.log(dog1.constructor === Dog); // true
              console.log(dog2.constructor === Dog); // true
          console.log(dog1 instanceof Dog); // true
          console.log(dog2 instanceof Dog); // true
    </script>

    构造函数的问题

    构造函数方法很好用,但是存在一个浪费内存的问题. e.g.

    这么做有一个弊端就是 property type 和 function eat()都是一模一样的内容, 每次生成一个实例, 都必须为重复的内容, 会多次占用内存. 这样缺乏效率和内存管理.

    我们有办法像.NET 中引用类型的用法, 指向内存地址,从而节约内存使用.  这个方法就是prototype.

    <script>
            function Dog(name, color) {
                this.name = name;
                this.color = color;
                this.type = '犬类';
                this.eat = function() {console.log('啥都吃');};
            }
            var dog1 = new Dog('二狗子', '黑色');
            var dog2 = new Dog('狗蛋儿', '黄色');
            console.log(dog1.type) // 犬类
            dog1.eat(); // 啥都吃
    
            console.log(dog1.eat === dog2.eat); // false
        </script>

    http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

    prototype

    JavaScript规定, 每个构造函数都有一个prototype属性, 指向另一个对象.  这个对象的所有属性和方法, 都会被构造函数实例继承.

    prototype 用.NET 知识来解释, 可以认为是引用类型.  指向内存同一块

    那什么时候使用prototype呢?  prototype应该储存那些在object中常被子类使用的公共类型而不经常改变的primitive和function.

    使用prototype可以减少使用资源.

    object里面其他的内容可以理解为值类型.

    prototype chain

    原型链是有OOD种继承的特性. 

     John 是从 Person 这个constructor中继承实例化得到的.  所以John的 __proto__ === Person.prototype // true

     我们看到 __proto__ 底下还有 __proto__.  这是因为 我们Person 这个constructor的prototype 是从 object中继承实例化得到的. 所以Person的__proto__ 拥有所有object的__proto__的特性.

    prototype 和 __proto__ 关系

    在developer tool中, __proto__ 就是object 中的prototype property.

    https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript

    Object.Create 和 新实例化的function constructor的区别

    Object.Create 只需要继承first argument(此例子中的calculateAge 这个function)

      Object.Create 的benefit 是可以让开发人员把一个非常复杂继承结构转换成一个简单的形式.

      因为开发人员可以直接的控制哪些prototype需要继承. 但是function constructor 需要继承所有的父中prototype.

    新实例化的function constructor需要从继承的function constructor 里面继承所有的prototype property. 

    // Object.create
    var personProto = {
        calculateAge: function() {
            console.log(2016 - this.yearOfBirth);
        }
    };
    
    var john = Object.create(personProto);
    john.name = "John";
    john.yearOfBirth = 1990;
    john.job = "teacher";
    
    var jane = Object.create(personProto, {
        name: {value: 'Jane'},
        yearOfBirth: {value: 1969},
        job: {value: 'dev'}
    });

    Prototype 的验证方法

    JavaScript 定义了一些方法去验证, 帮助我们使用prototype.

        <script>
            var Person = function (name, yearOfBirth, job) {
                this.name = name;
                this.yearOfBirth = yearOfBirth;
                this.job = job;
            }
    
            Person.prototype.calculateAge = function () {
                console.log(2016 - this.yearOfBirth);
            }
            Person.prototype.type = '哺乳动物';
    
            var john = new Person('John', 1990, 'teacher');
            var jane = new Person('Jane', 1969, 'designer');
            var mark = new Person('Mark', 1948, 'retried');
        </script>

     

    isPrototypeOf()

    这个method用来潘丹prototype对象和实例之间的关系.

    console.log(Person.prototype.isPrototypeOf(john)); //true
    
    console.log(Person.prototype.isPrototypeOf(jane)); //true

    hasOwnProperty()

    这个method是用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性.

    console.log(john.hasOwnProperty("name")); // true
    
    console.log(john.hasOwnProperty("type")); // false

    in 运算符

    in 运算符可以用来判断某个实例是否含有某个属性. 不管是不是本地属性

    console.log("name" in john); // true
            console.log("type" in jane); // true
  • 相关阅读:
    豆瓣评论9.5的《Effective Python》,帮你解决80%难题!
    编程科普|你知道的关于 Python 的那些知识,可能全错了!
    为什么建议使用 Linux?从“白嫖”到精通,只需要这几步!
    交易如钓鱼
    知识图谱学习一:啥是知识图谱,用来干啥,怎么做?
    openpyxl 学习笔记
    使用A卡(AMD Radeon RX470)进行机器学习的失败经历
    activemq 控制台报错 java.lang.SecurityException: User name [system] or password is invalid.
    activemq 安装配置二
    activemq 安装配置一
  • 原文地址:https://www.cnblogs.com/TheMiao/p/9740019.html
Copyright © 2011-2022 走看看