JS中构造函数的原型prototype

来来来,JavaScript核心基础语句送给你们
学JS你不会DOM算真的学会了吗?
对JavaScript中的 事件 进行疯狂 处理
用BOM来实现轮播图效果
我们来实现创建JavaScript中的自定义对象
JS中构造函数的原型prototype
还不明白JS中的内置对象吗? 快来这里!
JavaScript中数据如何存储在客户端?带你看看Cookie和WebStorage

原型prototypr

1. 简介

在构造函数中有一个属性叫prototype

  • prototype是一个对象属性,其属性值为对象,称为原型对象
  • 可以通过prototype来添加新的属性和方法,此时所有该构造函数创建的对象都会具有这些属性和方法
  • 由该构造函数创建的对象会默认链接到该属性上

语法:

  • 构造函数.prototype.属性名 = 值;
  • 构造函数.prototype.方法名 = function(){定义方法体};

访问对象属性的查找顺序:

  1. 首先在当前对象中查找对应的实例对象
  2. 如果没有,就会到该对象关联的构造函数的prototype属性中查找,即到原型对象中查找

作用:

  • 对象间共享数据
  • 为“类”(系统内置或自定义)增加新的属性、方法,并且新增内容对于当前页面中已经创建的而对象也由效
<script>
	//定义一个构造函数Student
	function Student(name,age){
     
		this.name = name;	//实例属性,每个实例都具有一个独立的该属性
		this.age = age;
		this.show = funciton(){
     	//实例方法,每个对象都具有一个独立的该方法
			console.log('我叫'+this.name+'年龄'+this.age);
		}
		/*
		this.sayhello = function(){
			console.log('您好');
		}
		this.sayDoodbye = function(){
			console.log('再见');
		}
		*/
	}
	//构造函数中存在一个名为prototype的属性
	//console.log(Student.prototype);
	//通过为构造函数的prototype添加属性和方法,从而让所有该构造函数创建的对象都能共享这些属性和方法
	this.sayhello = function(){
     		//原型方法
		console.log('您好');
	}
	this.sayDoodbye = function(){
     
		console.log('再见');
	}
	Student.prototype.class = '三年级二班';	//原型属性,所有对象共享的原型对象class

	//创建对象
	var stu1 = new Student('tom',26);
	stu1.class = '三年级一班';	//为stu1添加一个实例对象class
	console.log(stu1.name,stu1.age,stu1.calss);
	stu1.show();
	stu1.sayhello();
	stu1.sayGoodbye();

	var stu2 = new Student('alice',22);
	console.log(stu2.name,stu2.age,stu.class);
	stu2.show();
	stu2.sayhello();
	stu2.sayGoodbye();

	//stu1.sayhello()、sayGoodbye()和stu2.sayhello()、sayGoodbye()分别使用不同的内存空间,都要占用资源,但其内容完全相同,为了节省内存空间,希望能够公用。
	console.log(stu1 === stu2);
	console.log(stu1.name === stu2.name);
	console.log(stu1.show === stu2.show);
	console.log(stu1.sayhello === stu2.sayhello );
	console.log(stu1.sayGoodbye === stu2.sayGoodbye);

	//扩展Array
	var names = new Array('tom','jack','alice','mike','alex');
	//names.sort();
	//names.reverse();
	//names.join('-');

	//为Array类型添加显得功能(属性或方法)
	Array.prototype.sortReverseJoin = function(){
     
		console.log(this);	//this表示当前对象,即将来要操作的数组
		this.sort();
		this.reverse();
		var str = this.join('-');
		console.log(str);
	}
	console.log(Array.prototype);

	var hobbies = ['eat','sleep','play','study'];
	names.sortReverseJoin();
	bobbies.sortReverseJoin();
</script>

2. _ _ proto _ _(前后双下划线)

prototype是一个隐藏属性,于是为每个对象那个提供一个叫__proto__的属性

  • 对象的__proto__与创建它的构造函数的prototype本质上是同一个东西
  • __proto__是对象的属性,是站在对象的角度,来讨论其原型对象
  • prototype是构造函数的属性,是站在构造函数的角度,来讨论其原型对象
  • 由于__proto__是非标准属性,因此一般不建议使用
<script>
	function Student(name){
     
		this.name = name;
		this.show = function(){
     
			console.log('我叫'+this.name);
		}
	}
	Student.prototype.sayhello = function(){
     
		console.log('你好');
	}
	//构造函数的prototype属性
	//console.log(Student.prototype);
		
	//stu会自动链接到其构造函数的prototype属性上
	var stu = new Student('tom');
	//stu.sayhello();
	console.log(stu);
	console.log(stu.__proto__);	//__proto__是对象的属性,是站在对象的角度,来讨论其原型对象
	console.log(Student.prototype);	//prototype是构造函数的属性,是站在构造函数的角度,来讨论其原型对象
	console.log(stu.__proto__ === Student.prototype);

	//由于__proto__是非标准属性,因此一般不建议使用
	//stu.__proto__.sayhello();
	stu.sayhello();
	
</script>

3. 对象的类型

判断数据的类型:

  • 使用typeof

    可以判断任意变量的类型
    判断对象的类型时总是返回object

  • 使用instanceof

    只能判断对象是否为某种类型,需要指定判断的目标数据类型,无法获取对象的类型名称
    语法:对象 instanceof 数据类型,返回boolean值

获取对象的类型:

  • 函数有一个name属性,通过该属性可以获取函数的名称
  • 构造函数的名称就是对象的名称
var stu = new Student()   ------->Student类型
var p = new Person()    ------->Person类型
var nums = new Array()    -------->Array类型
var obj = new Object()   ------->Object类型
function Student(){
     };
function Teacher(){
     };

var obj1 = new Object();
var obj2 = new Array();
var obj3 = new Student();
var obj4 = new Teacher();

//typeof只能判断简单的数据类型,判断对象的类型时总是返回object
//console.log(typeof obj1);
//console.log(typeof obj2);
//console.log(typeof obj3);
//console.log(typeof obj4);

//instanceof用来判断对象的类型,判断对象是否为某种类型,返回boolean
console.log(obj1 instanceof Object);
console.log(obj2 instanceof Array);
console.log(obj3 instanceof Student);
console.log(obj4 instanceof Teacher);

//结论:构造函数的名称就是对象的类型名

4. constructor属性

每个对象都有一个constructor属性,该属性描述的就是其构造函数。

对象的constructor属性是原型对象提供的,因为每个对象都链接到其原型对象上。

如果想要获取一个对象的构造函数的名字,我们就可以使用constructor属性和name属性

//运用上面例子中创建的对象
console.log(obj3.constructor.name);		//通过构造函数的name属性,获取构造函数的名称

5. call()方法和apply()方法

作用:以某个对象的身份来调用另一个对象的方法

区别:传参的方式不同

  • 第一个参数是相同的,都是表示由该对象来调用执行

  • 后面的参数不同

    call是逐个传参,后面参数可以有多个,逗号隔开
    apply是以数组形式传参,后面参数只能有一个,会自动拆分为多个元素传入

//定义一个对象,包含属性和方法
var stu = {
     
	name:'tom',
	age:18,
	study:function(){
     
		console.log('我叫'+this.name+',年龄:'this.age);
	}
}
//stu.study();	//调用对象的方法
function run(){
     
	console.log('跑步');
}
run();		//window直接调用函数

/**
 *	如果stu想要调用run()方法,怎么办?
 */

//方式一:为stu添加run()方法,永久添加
stu.run = run;	//为stu添加run()方法,指向run()函数
stu.run();

//方式二:只想临时调用(注意这里的写法)
run.call(stu);	//以stu对象的身份来调用run()函数
run.apply(stu);		//此处两个函数能实现相同的功能

//this的转变

window.run();		//直接调用,此时的this表示window
run.call(stu);		//对象临时调用,此时的this表示调用的对象,即stu,称为对象冒充


/**
 *	call()和apply()的区别
 */
function calc(a,b,c){
     
	console.log(a+b+c);
}
calc.call(stu,1,2,3);		//逐个传参
calc.apply(stu,[1,2,3]);		//数组形式传参,只能传一个参数


/**
 *	应用场景
 */
 //在stu对象中添加一个属性
stu.sex = 'male';		//直接添加
Array.prototype.push.call(stu,'male');	//通过push()方法添加
Array.prototype.push.call(stu,'hobby');

//Object.prototype.toString()方法,用来判断值的类型
console.log(Object.prototype.toString.call('hello'));
console.log(Object.prototype.toString.call(true));
console.log(Object.prototype.toString.call(undefined));
console.log(Object.prototype.toString.call(null));
console.log(Object.prototype.toString.call(new Array()));

6.继承

JS实现继承的三种方式:

  • 对象冒充继承,也称为构造继承

    核心:使用call,以对象冒充的形式调用父类的构造函数,相当于是复制父类的实例属性给子类

    缺点:只能继承父类构造函数中的属性和方法,无法继承原型中的属性和方法

  • 原型链继承

    核心:使用prototype,将父类的实例作为子类的原型

    缺点:创建子类实例时,无法向父类构造函数传参,导致继承的父类属性没有值

  • 组合继承

    对象冒充+原型链

 function Person(name,age){
     
            this.name = name;
            this.age = age;
            this.run = function(){
     
                console.log('跑步');
            }
        }
        Person.prototype.sex = 'male';
        Person.prototype.show = function(){
     
            console.log('我叫'+this.name+',年龄:'+this.age+',性别:'+this.sex);
        }

        /**
         *  方式1:对象冒充继承,也称为构造函数 
         */
        function Student(name,age){
     
            Person.call(this,name,age);    //此处Person中的this指向的是将来创建的Student对象
        }
        var stu = new Student('tom',20);
        //可以继承父类构造函数中的属性和方法
        console.log(stu.name,stu.age);
        stu.run();
        //无法继承父类原型中的属性和方法
        console.log(stu.sex);
        stu.show;


        /**
         *  方式2:原型链继承 
         */
        function Student(name,age){
     }

        Student.prototype = new Person();   //将Student原型链指向Person对象,从而继承Person
        console.log(Student.prototype);

        var stu = new Student('tom',20);
        console.log(stu.name,stu.age);  //name和age属性都是undefined,无法获得父类对象的属性
        stu.run();
        console.log(stu.sex);
        stu.show();

        /**
         *  方式3:组合继承(对象冒充+原型链)
         */ 
        function Student(name,age){
     
            Person.call(this,name,age); //对象冒充
        }
        //(1)调用两次父类的构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了,所以性能稍差一点)
        Student.prototype = new Person();
        //(2)将Student原型指向Person原型
        Student.prototype = Person.prototype;

        var stu = new Student('tom',20);
        console.log(stu);
    </script>

7. 原型链

任何对象都有其原型对象,原型对象也有原型对象,对象的原型对象一直往上找,直到null为止。

在这一过程中,有一个Object类型的对象,它就是Object prototype位于顶层。

JS中构造函数的原型prototype_第1张图片

/**
 *	nums对象的原型链
 *		nums——>Array.prototype——>Object.prototype——>null
 *		nums.__porto__与Array.prototype是同样的
 */
var nums = new Arrray(12,43,5,3,8);
nums.push(24);
nums.reverse();
console.log(nums);

/**
 *	stu对象的原型链结构
 *		stu——>Student.prototype——>Object.prototype——>null
 *			stu.__prototype__与Student.prototype是同样的
 */
function Student(name){
     
	this.name = name;
}
Student.prototype.sex = 'male';

var stu = new Student('tom');
console.log(stu);

//Object的原型链结构
var o1 = new Object();
console.log(o1);	//创建对象
console.log(Object.prototype);	//对象的原型,站在构造函数的角度
console.log(o1.__proto__);		//对象的原型,站在对象的角度
console.log(Object.prototype.constructor);		//构造函数

你可能感兴趣的:(JavaScript)