zoukankan      html  css  js  c++  java
  • 关于原型的一些理解,尽量写的详细一点。

     学了前端一段时间了,对js当时花了很多时间但是随着后面学习框架有些就忘了。现在从新开始记录下重要的知识点。有很多知识也是查阅js高程和别人的博客,所用的一些例子也是引用那些觉得很有代表意义的,在文章最后贴出有关的博客。有错的地方也请大家指出。有些知识深究的话我能力有限,也不知道;所以很多作为一个结论记住就行。

    1.首先什么是对象,什么是函数对象。有些地方也叫函数,我查了下函数和函数对象应该是指代的同一个东西,没有区别。首先

     var a={"name":"hello"}; 这是一个普通的对象。 function f1(){};    var f2 = function(){}; 这是函数对象。那么函数对象和对象又有什么不同了。函数有个叫原型的东西是个对象,但是对象没有。这里引入了 prototype 这个属性,那么这个就是原型对象了,当然不是。它是个指针指向原型对象。这里要记住prototype是个指针后面虽然还有继承有关但是先记住是个指针。这里就先说到这里,区别函数对象和对象,以及一个重要属性prototype,对象没这个属性。

    2,那么对象和函数对象又有什么联系了,首先创建一个普通的对象var person = {}或者var 0=new object()。这是个普通的对象,通过这种字面量可以创造很多单个对象。但是会产生大量重复代码,所以有了工厂模式的出现。

    function creatPerson (name, age) {
        var person = new Object(); 
        person.name = name;
        person.age = age;
        person.sayName = function () {
            alert(this.name);
        };
        return person; 
    }

    var person1= creatPerson ("tom",29)
     

    他能创建一个包含一些信息的person对象,可以多次调用这个函数。但是却没有解决对象的识别问题(不知道这个对象的类型)。所以之后重头戏来了,有了构造函数,这个知识点就涉及原型了。

    function CreatePerson(name, age, say){
        this.name = name;
        this.age = age;
        this.say = say;
        this.should = function(){
            console(this.say);
        }
    }
    var person1 = new CreatePerson("","","");

    这个函数也很简单,但是和之前的工厂模式有了些区别。这个函数有个很重要的 new 操作符。看一个实例:

    function Animal(name){
               this.name = name;
             }
        Animal.color = "black";
        Animal.prototype.say = function(){
                console.log("I'm " + this.name);
             };
        var cat = new Animal("cat");
    
        console.log(
                cat.color, //undefine
                cat.name  //cat
     );
        cat.say(); //I'm cat
    
         console.log(
                Animal.name, //Animal
                Animal.color //back
       );
        Animal.say(); //Animal.say is not a function

    这个函数没看答案之前有可能你是不太清楚,但是看了答案你是应该是能得出一些结论的。虽然你可能不知道发生了什么。首先  console.log( Animal.name, //Animal Animal.color //back ); 这个比较简单没什么说的,不懂的函数的name属性可以看下。 cat.color, //undefine 这个是重点,这里看的出来构造出来的实例并没有继承到color这个属性,那么就要引入构造函数的工作的模式了。关键的new字符,js高程是这么解释的:

    1'创建一个新的对象;

    2'将构造函数作用域赋给新的对象(即this指向新对象);

    3'执行构造函数里面的代码;

    4'返回新的对象。 

    new Animal("cat") = {
    
        var obj = {};
    
        obj.__proto__ = Animal.prototype;
    
        var result = Animal.call(obj,"cat");
    //var result = obj.Animal("cat")。相当于Animal在obj作用域里面运行
    return typeof result === 'object'? result : obj; }

    这是一个模仿new运行机制的伪代码,这里我们看到一个新的东西出现了 __proto__  ,先给这个过程看完:obj的__proto__ 指向Animal的原型对象prototype然后你大概懂了

      cat.say(); //I'm cat 之后,在obj对象的执行环境调用Animal函数并传递参数“cat”。 相当于var result = obj.Animal("cat")。 当这句执行完之后,obj便产生了属性name并赋值为"cat"。可能第二个你看的不太明白那你就可以看看call属性,以及this了。这里先不提,后面可以在仔细做下笔记。引入了__proto__ 那么就相当于引入了原型链了,当你实例化一个对象,就会形成一个原型链,他会去找构造函数的prototype,然后逐级向上寻找,其实原型的重点是__proto__ ,我这里将引入一两道例题帮助自己记忆,以及自己的理解。

      var animal = function(){};
        var dog = function(){};
        animal.price = 2000;
        dog.prototype = animal;
        var tidy = new dog();  //tidy.constructor=dog;实例tidy可以通过授权找到它并用以检测自己的构造函数
        console.log(dog.price);   //undefined
        console.log(tidy.price);   // 2000

    1'首先 dog.prototype = animal;这里没有问题的, 我们可以赋值任何类型的对象到原型上,但是不能赋值原子类型的值, 比如如下代码是无效的: Foo.prototype = 1;

    2'将 animal的值赋给dog的原型对象。 console.log(dog.price);针对这句代码。首先是dog自己的本身的函数是没price这个属性的,然后原型上有,但是两者是没有关系的。

    3’ 它先通过查找自生,然后再循着__proto__去原型链中寻找,全局中也没有,都没有所以读取不到price这个属性。

        var Animal = function(){};   Animal.prototype.say = function(){ alert("a"); };     Animal.say()   //Animal.say s not a function            

    这个简短的例子也是能说明问题的,然后在来看下面这个例子:

      var animal = function(){};
        var dog = function(){};
    
        animal.price = 2000;
        dog.__proto__ = animal;
        var tidy = new dog();
    
        console.log(dog.price) //2000
        console.log(tidy.price) // undefined
    1. dog.__proto__ = animal;直接找到 animal,获取值dog.price==2000;
    2. tidy.__proto__= dog.prototype;
    3.
    tidy.__proto__.__proto__ === dog.prototype.__proto__=== Object.prototype;通过这个原型链确实找不到。这里要区别prototype和__proto__

    ....................................................................................................................................................................................................................................................................

    现在还有个constructor。,constructor始终指向创建当前对象的构造函数。

    function Person(name,age){
      this.name = name;
      this.age = age;
    }
     
    Person.prototype = {
      getName:function(){
        return this.name;
      },
      getAge:function(){
        return this.age;
      }
    }
     
    var p = new Person("Nicholas",18);
    console.log(p.constructor); //Object()

    这里p.constructor不等于person是因为上面的给她相当于从new成一个新的对象

    Person.prototype = new Object({
      getName:function(){
        return this.name;
      },
    所以结果是boject。然后现在对new constructor prototype __proto__有了认识之后来说说原型链。首先是构造函数的原型链。

      构造函数也是有 __proto__属性的,然后也会形成一个原型链。

    Constructor ----> Function.prototype ----> Object.prototype ----> null  

     

    1,Constructor 的 __proto__ 是 Function.prototype
    2,Function.prototype 的 __proto__ 是 Object.prototype
    3,Object.prototype 的 __proto__ 是 nullda
    答:这个了也只能这么理解,一个函数由于是Function类型,所以它的__proto__是Function.prototype,而Function本身也是个函数(可以new Function嘛),所以Function的__proto__也是Function.prototype。然而然后Function.prototype自然是一个对象,所以Function.prototype的__proto__是Object.prototype。最后指向js的万恶之源null。为什么说是万恶之源了,因为才学js就听说万物皆继承于null。
     
    然后构造函数的实例又是怎么形成的原型链了,

    function f()={};

    var obj=new f();

    这是一个普通实例的原型的原型链。

     

     还有很多没搞懂的,这部分内容确实多先到这吧,以后在慢慢更新。

  • 相关阅读:
    数据库事务的四个隔离级别
    synchronized与Lock的区别
    线程池的注意事项
    守护线程与非守护线程
    wait与sleep的区别
    String,StringBuffer,StringBuilder
    2019牛客暑期多校训练营 第二场
    2019牛客暑期多校训练营 第一场
    Codeforces Round #568 (div. 2)
    Codeforces Round #570 (Div. 3)
  • 原文地址:https://www.cnblogs.com/manu-yyj/p/9102991.html
Copyright © 2011-2022 走看看