js2--函数(原型)

159 阅读5分钟

1.原型

1.1

原型:内存空间复用

1)任何函数都有一个属性prototype 是一个对象 new Object()/{}/{}

2)任何对象都有一个__proto__属性 是创建它的函数的prototype属性

3)任何对象都是函数创建出来的 任何对象都有"类型" (构造函数)

1.2 思想

用函数创建对像,这个创建出来的对象有个原型对象1,又用这个函数创建对象 这个创建出来的对象有个原型对象2,原型对象1和原型对象2是同一个对象。

image.png

1.3 案列解析

function fn(){
        this.a=20
    }
    //隐式操作:fn.prototye={}
    
    function  fm () {
        this.a=30
    }
    //隐式操作:fm.prototye={fn:{a:20,__proto__:{}}}
    //new fn()==>{__proto__:fn.prototye}==>{a:20,__proto__:{}}
    
    fm.prototype.fn=new fm()
    
    var f1=new fm()
    //new fm()
    //{__proto__:fm.prototype,a:30}==>{__proto__:{fn:{a:20,__proto__:{}}},a:30}
    
    
    console.log(f1)//写出它的结构(只写a)
    //{a:30,__proto__:{fn:{a:20}}}
    

分析: fm.prototype.fn 给fm函数的原型对象添加一个fn成员 fm.prototype.fn=new fn() fn成员为new fn()---{fn:{a:20,proto:{}},proto:{}}

new fm()----{proto:fm.prototype,a:30}---{proto:{fn:{a:20,proto:{}}},a:30},既f1打印为{a:30,proto:{fn:{a:20}}}

2.构造函数分类

1.自定函数

2.官方提供的函数:Function Object String Number Bloolean Array Date Math

           var obj1=new Object()
           var arr1=new Array()
           

3.语法糖

语法糖: 对象直接量 (代码有多种写法时 简便的写法就是语法糖 )

列:

@click="fn" =>onlick="fn()"
obj.age==>obj["age"]

4.原型链案列

1)案例: 自定义构造函数的原型对象也是一个自定义构造函数创建的对象

 function  Kedou() {
  	  this.life=1
      this.tail=1		  
  }
  
  var k1=new Kedou()
  
  function  Qingwa () {
  	   this.tui=4
       this.yanjing=2
  }
  Qingwa.prototype=new Kedou()		  
  var q1=new Qingwa()
  console.log(q1.life)
  
  k1是不是q1原型对象?
   console.log(q1.__proto__==k1)//false

分析:k1不是q1的原型对象

image.png

    function Element(){
         this.width="20px"
         this.color="red"
         this.fontSize="20px"
    }
    function  Div() {
        this.value=123
        this.innerHTML="hello"
    }
    var el=new Element()
    el.height="40px"
    
    Div.prototype=el //执行以后 用Div创建的对象有Element创建的对象的功能
    var div1=new Div()
    div1.className="box"
    console.log(div1.value,div1.innerHTML,div1,div1.width)
    
    var div2=new Div()
    console.log(div2.value,div2.innerHTML,div2,div2.width)
    
    
    console.log(div2.className,div2.height,div1.height,div1.className)//und  40px
    

分析

image.png

5.对象属性的存取及原型的存取

5.1 对象属性的存取

1)obj.a=20 obj对象的原型链上无论有没有a成员的,a一定会添加或更新obj自己的这一层

2)console.log(obj.a) 先取自己的 自己没有就去原型链取 null都没有就得到undefined

3)console.log(obj.x1) 如果x1是原型链上成员:可以取出使用

4)obj.x1=[10,20,40] 如果x1是原型链上的成员或者不是原型链上的成员 都不能修改这个x1属性(因为会把x1属性添加/更新到obj自己上)

5)若x1是原型链上的属性 虽然不能修改 但是可以操作

    obj={name:“karen”,x1:{x2:2}}
    obj.x1.x2=30
    obj.x2.push(123)
    

5.2 原型的存取

1)构造函数的prototype属性可以操作

2)内置构造函数的prototype不能修改(不能用等号直接赋值) 但是可以操作(可以给原型属性添加成员)

Array.prototype.push = 代码

3)对象的__proto__也可以操作和修改,内置的对象不能修改,若修改则会跳过编译(静默)

   var arr=new Array(10,20,40)
    arr.__proto__.fn=90
    var arr2=[10]
    console.log(arr2.fn)
    

image.png

5.3 笔试题练习

 function Parent() {
		this.a = 1;
		this.b = [1, 2, this.a];
		this.c = {
			demo: 5
		};
		this.show = function() {
			console.log(this.a, this.b,              this.c.demo);
		}
	}

	function Child() {
		this.a = 2;
		this.change = function() {
			this.b.push(this.a);
			this.a = this.b.length;
			this.c.demo = this.a++;
		}
	}
	Child.prototype = new Parent();
	//后面的代码用Child函数创建的对象的原型对象是new Parent()
	//Child.prototype =O1{a:1,b:[1,2,1],c:{demo:5},show:上面的函数,__proto__:O3{}}


	var parent = new Parent();
	//parent=O2{a:1,b:[1,2,1],c:{demo:5},show:上面的函数,__proto__:O3{}}

	var child1 = new Child();
	//child1={a:2,change:上面的函数,__proto__:O1}


	var child2 = new Child();
	//child2={a:2,change:上面的函数,__proto__:O1}	
		
	child1.a = 11; //无论child1的原型链上是否有a成员 都会把a添加/更新到child1自己child1={a:11,change:上面的函数,__proto__:O1}		
	child2.a = 12;//child2={a:12,change:上面的函数,__proto__:O1}

	parent.show(); //console.log(this.a, this.b, this.c.demo);==>parent就是this 
                    也就是O2对象  O2.a=>1 O2.b==>[1,2,1]  O2.c.demo==>5 
	//打印 1 [1,2,1] 5
	child1.show(); //show函数是原型对象的方法 child1自己没有 就访问了原型的 但是调
                         用者(函数内部的this)是child1 ===>console.log(this.a, this.b, this.c.demo);
	//this.a==>11  this.b==>自己没有去访问原型的=>[1,2,1]   this.c.demo==>自己没有去访问原型的=>5
	//打印 11 [1,2,1] 5

	child2.show();
	//show函数是原型对象的方法 child2自己没有 就访问了原型的 
            但是调用者(函数内部的this)是child2 ===>console.log(this.a, this.b, this.c.demo);
	//this.a==>12 this.b==>自己没有去访问原型的=>[1,2,1] this.c.demo==>自己没有去访问原型的=>5
	//打印12 [1,2,1] 5

	child1.change();
	/*
	this是child1
	
	this.b.push(this.a);//b是原型对象的属性 但是这个代码没有修改b  只是操作了b内部的数据
                              是可以让原型对象内部的数据改变 ,
                              this.a取值会优先取原型链的最顶层的属性11 ==> 原型对象的数组末尾添加了11
                       Child.prototype =O1{a:1,b:[1,2,1,11],c:{demo:5},show:上面的函数,__proto__:O3{}}

	
	this.a = this.b.length;
	//给child1自己添加/更新 a属性 值为4 child1的原型对象的属性b的长度 
            child1={a:4,change:上面的函数,__proto__:O1}
	
	this.c.demo = this.a++;
	//this.c.demo=先取值4  再把a的值加1
            child1={a:5,change:上面的函数,__proto__:O1}
	//this.c属性是原型对象的属性  但是没有修改这个属性的情况下 是可以操作其内部的数据的
	 //因此原型对象的的c属性中的demo属性改为4
              Child.prototype =O1{a:1,b:[1,2,1,11],c:{demo:4},show:上面的函数,__proto__:O3{}}
           */

	child2.change();
	/*
	this是child2
	this.b.push(this.a);==>同上 b是原型对象的属性 但是这个代码没有修改b 
                               只是操作了b内部的数据是可以让原型对象内部的数据改变  
                               this.a取值会优先取原型链的最顶层的属性12,原型对象的数组末尾添加了12
            Child.prototype =O1{a:1,b:[1,2,1,11,12],c:{demo:4},show:上面的函数,__proto__:O3{}}
	 
	this.a = this.b.length;
	//this.a = 原型对象的b属性的length==>5;
            child2={a:5,change:上面的函数,__proto__:O1}
	
	this.c.demo = this.a++;
	// this.c.demo=取值5(修改了原型对象)  a再加1
            child2={a:6,change:上面的函数,__proto__:O1}
            Child.prototype =O1{a:1,b:[1,2,1,11,12],c:{demo:5},show:上面的函数,__proto__:O3{}}
	
	*/

	parent.show();
	//show函数内部的this是parent
	//console.log(this.a, this.b, this.c.demo);
	//1 [1,2,1] 5 
	
	
	child1.show();
	//show函数内部的this是child1
	//console.log(this.a, this.b, this.c.demo);
	// 5 [1,2,1,11,12] 5  (this.b,this.c都是原型上的)
	
	
	child2.show();
	//show函数内部的this是child2
	//console.log(this.a, this.b, this.c.demo);
	//6 [1,2,1,11,12] 5 (this.b,this.c都是原型上的)