• 彻底搞清javascript中this, constructor, prototype


    说起这三个属性,肯定有一些同学和我一样,初学js时非常困惑,头大,一脸的迷茫。今天就来给大家彻底解决这些担心受怕的问题。

    先看this

    this定义:
    
        this就是函数赖以执行的对象。
    
    分析这句话:
    
      1. this是对象。  
        2. this依赖函数执行的上下文环境。 
        3. this存在函数中。
    
    直接看例子:
    
        alert(this); //在全局环境调用this, this指向window,  输出[Object window]
       
         function Person(){
             alert(this);
        } 
    
         方式一:  
          Person(); // 全局环境用Person函数, this指向window,  输出[Object window]
    
         方式二: 
         var obj = new Person(); //把Person当做构造函数, 实例化一个对象
                                 //此时this指向了obj, 不再指向window,  输出[Object object]
         
         function Person(){
            alert(this.name); //此时无法判断this的身份
         }
         
         Person(); //this在全局环境中被调用, this.name == window.name, 输出了窗口的名字
         var obj = new Person(); //this在obj环境下被调用, this.name == obj.name, 由于name没被赋值, 所以输出undefined
         
         
         由此可以看出, 我们在阅读代码或者写代码时,看到某个函数中定义的this时, 还无法去判断那个this身份,必须找到它依赖执行的环境(对象)。
         再回头看看this的定义,大家就清楚自然了。

     再看constructor和prototype

    constructor和prototype的关系非常密切。
    
    constructor是一个对象的属性,这个属性存在在此对象的prototype中, 指向此对象的构造函数。
    
    分析这句话:
        1.constructor是一个对象属性。
        2.constructor在prototype中
        3.constructor指向构造函数
        
    例子1:
    
        function Person(name, age){
            this.name = name;
            this.age = age;
        }
        Person.prototype.getName = function(){
            alert(this.name);
        }
        Person.prototype.getAge = function(){
            alert(this.age);
        }
        var obj = new Person();
        alert(obj.constructor == Person);// true
        此种方式定义的prototype, constructor是隐藏的, 默认指向Person
        
    例子2:
        function Person(name, age){
            this.name = name;
            this.age = age;
        }
        Person.prototype = {
            getName: function(){
               alert(this.name);
            },
            getAge: function(){
               alert(this.age);
            }
        }
        var obj = new Person();
        alert(obj.constructor == Person);// false
        
        为什么是false? 这种定义prototype, 是把prototype重写了, 覆盖了默认的constructor。
        换句话说, 其实这种方式就是给属性重新赋值了, 所以导致默认的constructor被覆盖。
        此时的obj.constructor将指向的是Object。
        
        改写一下上面的:
        Person.prototype = {
            constructor: Person, //强制指向Person
            getName: function(){
               alert(this.name);
            },
            getAge: function(){
               alert(this.age);
            }
        }
        此时constructor就指向Person了。
        
        prototype是一个函数属性, 此属性同时也是一个对象, 保存着对象实例所共有的属性和方法。
        
        分析这句话:
            1.prototype是函数属性, 只要是函数, 就有prototype属性. 而不管是构造函数还是普通函数.
            2.prototype同时也是对象.
            2.prototype放的是公共的东西, 包括属性和方法.
            
        例子1.
            function Person(name, age){
                this.name = name;
                this.age = age;
            }
            
            //是函数就有prototype属性, 这个属性也是一个对象
            Person.prototype = {
                getName: function(){ //所有对象实例都共享
                    return this.name;
                },
                getAge: function(){//所有对象实例都共享
                    return this.age;
                }
            }
        
            var obj = new Person('tom', 23);
            obj.getName(); //'tom'
            var obj2 = new Person('jack', 23);
            obj2.getName(); //'jack'
            obj.getName == obj2.getName; //true, 所有实例共享
            Person.prototype.getName(); //当做普通函数属性, 根据this定义, 此时this指向的是Person.prototype, 所以返回undefined
      
      以上就是this, constructor, prototype的定义和他们之间的关系. 可能还有些粗糙, 欢迎大家补充.
      
      综合例子:
        
        var Tinker = function(){
            this.elements = [];
        
        };
            Tinker.fn = Tinker.prototype = {
                constructor: Tinker,
                extend: function(obj){
                    var p;
                    for(p in obj){
                        this.constructor.prototype[p] = obj[p];//此处若看明白了, 那么前面的就理解了
                    }
                }
            
            }
            Tinker.fn.extend({
               get: function(){
                    var length = arguments.length,
                    i = 0;
                   for(; i < length; i++){
                       this.elements.push(document.getElementById(arguments[i])); //此处若看明白了, 那么前面的就理解了
                   }
                   return this;//此处若看明白了, 那么前面的就理解了
               },
               each: function(fn){
                    var i = 0,
                        length = this.elements.length;
                    for(; i < length; i++){
                        fn.call(this.elements[i], i, this.elements[i]);
                    }
                    return this;//此处若看明白了, 那么前面的就理解了
               }
                
            });
        
       这个例子其实很简单, 就是向一个对象原型添加方法.一个方法是get, 用于查找页面id. 一个是each, 用于对找到的id元素执行一个方法
    //假设有id = 'data', id = 'message' var obj = new Tinker(); obj.get('data', 'message').each(function(i, item){
        this.style.cssText = 'height:20px; background:#ff0000';
      })
  • 相关阅读:
    10-10-12分页机制(xp)
    段间跳转之任务门
    段间跳转之TSS段
    mysql索引
    cat /proc/meminfo
    This system is not registered to Red Hat Subscription Management报错
    CentOS 6.5安装zabbix
    KVM(系统虚拟化模块)安装
    Linux时区更改
    学习ruby/rails, rvm是必不可少的工具之一
  • 原文地址:https://www.cnblogs.com/tinkbell/p/3171303.html
Copyright © 2020-2023  润新知