zoukankan      html  css  js  c++  java
  • JavaScript原型与原型链,原型的实际应用

    原型链是js面向对象的基础,非常重要。
    一,创建对象的几种方法:
    1,字面量
    var o1 = {
        name:'o1'
    };
    2,构造函数
    var M = function(name){
        this.name = name;
    };
    var o2 = new M('o2');
    var a = {} 其实是 var a = new Object()的语法糖,推荐使用前者
    var a = [] 其实是 var a = new Array()的语法糖,推荐使用前者
    function Foo(){} 其实是 var Foo = new Function()的语法糖,推荐使用前者
     
    3,Object.create(Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 )
    var P = {name:'o3'};
    var o3 = Object.create(P);

     二,原型链

    JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
    那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
     Object.getPrototypeOf(Object.prototype) //null

    Object.prototype === Object.getPrototypeOf( {} ); //true
    5条原型规则
    1,所有的引用类型(数组,对象,函数),都具有对象特性,即可自由扩展属性
    2,所有的引用类型(数组,对象,函数),都有一个__proto__属性(隐式原型),属性值是一个普通的对象
    3,所有的函数,都有一个prototype属性(显式原型),属性值也是一个普通的对象
    4,所有的引用类型(数组,对象,函数)__proto__属性值指向它的构造函数的prototype属性值
    5,当试图得到一个引用类型(数组,对象,函数)的某个属性时,如果这个引用类型本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

    看下图

     

    三,instanceof原理

    判断一个函数是否是一个变量的构造函数

    工作原理:判断实例对象的__proto__属性和构造函数的prototype是否同一个地址,只要在原型链上的构造函数,都会被instanceof认为是实例的构造函数。如图:

        // 判断实例对象的proto属性和构造函数的prototype是否同一个地址
        // 只要在原型链上的构造函数,都会被instanceof认为是实例的构造函数
        var M = function(name) { this.name = name; };
        var o2 = new M('o2');
        o2.__proto__ === M.prototype //true
        M.prototype.__proto__ === Object.prototype //true
        o2.__proto__.__proto__ === Object.prototype //true
    
        o2 instanceof M //true
        o2 instanceof Object //true
    
        // 用constructor属性判断更严谨
        o2.__proto__.constructor === M //true
        o2.__proto__.constructor === Object //false

    四,new运算符工作原理

        // new运算符及背后工作原理 new后跟构造函数
        // 1,一个新对象被创建,它继承自func.prototype(构造函数的原型对象)
        // 2,构造函数func被执行,执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例
        // 3,如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果,如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象
        var new2 = function(func) {
            var o = Object.create(func.prototype);
            var k = func.call(o);
            if (typeof k === 'object' && k != null) {
                return k;
            } else {
                return o;
            }
        };

     五,原型链继承的例子

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>proto</title>
    </head>
    
    <body>
        <div id="div1">123</div>
        <script>
        // 封装DOM查询
        function Elem(id) {
            this.elem = document.getElementById(id);
        }
    
        Elem.prototype.html = function(val) {
            var elem = this.elem;
            if (val) {
                elem.innerHTML = val;
                return this;//方便链式操作
            } else {
                return elem.innerHTML;
            }
        }
    
        Elem.prototype.on = function(type, fn) {
            var elem = this.elem;
            elem.addEventListener(type, fn);
            return this;//方便链式操作
        }
    
        var div1 = new Elem('div1');
        console.log(div1.html());
        div1.html('<p>234p</p>').on('click', function() {
            alert('1');
        }).html('<p>js</p>');
        </script>
    </body>
    
    </html>

    六:原型实际应用

    1,看一个平时使用jquery或者zepto的例子:
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>jquery</title>
    </head>
    
    <body>
        <p>jquery 1</p>
        <p>jquery 2</p>
        <p>jquery 3</p>
        <div id="div1">
            <p>jquery test in div</p>
        </div>
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <script>
        var $p = $('p');
        $p.css('color', 'red'); //css是原型方法
        console.log($p.html()); //html是原型方法,这里只打印第一个   jquery 1
    
        var $div = $('#div1');
        $div.find('p').css('color', 'blue'); //find,css是原型方法
        console.log($div.html()); //html是原型方法  <p style="color: blue;">jquery test in div</p>
        </script>
    </body>
    
    </html>
    2,zepto如何使用原型(简化版)-my-zepto.js
    (function(window) {
         // 空对象
         var zepto = {};
    
         // 构造函数
         function Z(dom, selector) {
             var i, len = dom ? dom.length : 0;
             for (i = 0; i < len; i++) {
                 this[i] = dom[i];
             }
             this.length = len;
             this.selector = selector || '';
         }
    
         zepto.Z = function(dom, selector) {
             // 注意,出现了 new 关键字
             return new Z(dom, selector);
         }
    
         zepto.init = function(selector) {
             // 源码中,这里的处理情况比较复杂,但因为本次只针对原型,因此这里就弱化了
             var slice = Array.prototype.slice;
             var dom = slice.call(document.querySelectorAll(selector));
             return zepto.Z(dom, selector);
         }
    
    
         // 使用zepto的$
         var $ = function(selector) {
             return zepto.init(selector);
         }
         window.$ = $;
    
    
         $.fn = {
             constructor: zepto.Z,
             css: function(key, value) {
                 console.log('css');
    
             },
             html: function(value) {
                 // console.log('html');
                 return '这是一个模拟的html函数';
             }
         }
    
         zepto.Z.prototype = Z.prototype = $.fn; //!!!
    
     })(window) 
    测试:新建zepto.html
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>zepto</title>
    </head>
    
    <body>
        <p>zepto 1</p>
        <p>zepto 2</p>
        <p>zepto 3</p>
        <div id="div1">
            <p>zepto test in div</p>
        </div>
        <script src="./my-zepto.js"></script>
        <script>
        var $p = $('p');
        $p.css('color', 'red'); //css是原型方法
        console.log($p.html()); //html是原型方法,这是一个模拟的html函数"
        </script>
    </body>
    
    </html>
    3,jquery如何使用原型(简化版)-my-jquery.js
    (function(window) {
        var jQuery = function(selector) {
            // 注意new关键字,第一步就找到了构造函数
            return new jQuery.fn.init(selector);
        }
        window.$ = jQuery;
    
        // 初始化 jQuery.fn
        jQuery.fn = jQuery.prototype = { //!!!
            constructor: jQuery,
    
            // 其他函数
            css: function(key, value) {
    
            },
            html: function(value) {
                return 'html';
    
            }
        }
    
        // 定义构造函数-简化版
        var init = jQuery.fn.init = function(selector) {
            var slice = Array.prototype.slice;
            var dom = slice.call(document.querySelectorAll(selector));
    
            var i, len = dom ? dom.length : 0;
            for (i = 0; i < len; i++) {
                this[i] = dom[i];
            }
            this.length = len;
            this.selector = selector || '';
        }
       
        // 定义原型
        init.prototype = jQuery.fn;
        
    })(window)

     测试:新建jquery.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>jquery</title>
    </head>
    
    <body>
        <p>jquery 1</p>
        <p>jquery 2</p>
        <p>jquery 3</p>
        <div id="div1">
            <p>jquery test in div</p>
        </div>
        <script src="./my-jquery.js"></script>
        <script>
        var $p = $('p');
        $p.css('color', 'red'); //css是原型方法
        console.log($p.html()); //html是原型方法,这里只打印第一个   "jquery 1"
        </script>
    </body>
    
    </html>
    4,如何体现原型的扩展性-插件机制
    思考:为何要把原型方法放在$.fn?:扩展插件。(第一,构造函数的 prototype 肯定得指向能扩展的对象;第二,$.fn 肯定得指向能扩展的对象)
    看一个简单的插件的例子:
    $.fn.getNodeName = function(){
        return this[0].nodeName;
    }

     好处:

    1,只有$会暴露在window全局变量
    2,将插件扩展统一到 $.fn.xxx 这一个接口,方便使用

    实践:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>jquery</title>
    </head>
    
    <body>
        <p>jquery 1</p>
        <p>jquery 2</p>
        <p>jquery 3</p>
        <div id="div1">
            <p>jquery test in div</p>
        </div>
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
        <script>
            // 插件扩展
            $.fn.getNodeName = function(){
                // console.log(this);
                console.log(this[0].nodeName);
            }
        </script>
        <script>
            // 验证
            var $p = $('p');
            $p.getNodeName()  //P
            $div1 = $('#div1');
            $div1.getNodeName()  //DIV
        </script>
    </body>
    
    </html>

  • 相关阅读:
    JSON跨域请求
    2013.9.26 心得体会
    MemCached用法
    使用SQL联合查询来构建临时vo对象的应用
    ubuntu 16.04 安装php 5 6等版本
    mac php版本切换
    windows 查看端口占用
    nginx 反向代理到目录
    linux挂在samba服务器到本地(用于备份文件到nas或者windows的文件服务器)
    ubuntu 加载新硬盘或分区
  • 原文地址:https://www.cnblogs.com/iceflorence/p/8920025.html
Copyright © 2011-2022 走看看