2021-02-01

本文详细介绍了JavaScript中构造函数的使用方法,包括构造函数的基本概念、如何使用构造函数创建对象、构造函数与普通函数的区别等。同时深入探讨了原型对象的作用及其实现原理,并通过实例演示了如何利用原型来提高代码性能。
摘要由CSDN通过智能技术生成

提示:从63节开始记录,地址https://www.bilibili.com/video/BV1p4411u7TT?p=63&spm_id_from=pageDriver

JS基础

一、使用工厂方法创建对象

大量的重复代码,考虑把重复代码提取出来。——工厂

eg:一个愚蠢的例子
var obj={
	name:“孙悟空”,
	age:18,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
}
var obj={
	name:“猪八戒”,
	age:18,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
}
var obj={
	name:“沙和尚”,
	age:18,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
}
//使用工厂创建对象
function creatPerson(name,age,gender){
	var obj=new Object();
	obj.name=name;
	obj.age=age;
	obj.gender=gender;
	obj.sayName=function(){
		alert(this.name);
	}
	return obj;
}
var obj2=creatPerson("孙悟空",18,"男");
var obj3=creatPerson("猪八戒",18,"男");
var obj4=creatPerson("沙和尚",18,"男");

obj2.sayName;
obj3.sayName;
obj4.sayName;

二、构造函数

如上例所示(也可以使用上面的函数创建一个小狗的对象,创建后的对象属性都是Object对象,看对象属性分不出是人还是狗),使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型。就导致我们无法区分出多种不同的数据类型

  • 创建一个构造函数,专门来创建Person对象的,构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上不同(首字母大写)
  • 构造函数和普通函数的区别就是调用方式的不同。
  • 普通函数是直接调用、构造函数需要使用new关键字来调用
    构造函数的执行流程
  1. 立即创建一个新的对象
  2. 将创建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
  3. 执行函数中的代码
  4. 将创建的对象作为返回值返回
    使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类
    我们将同一个构造函数创建的对象,称为是该类的实例
    加了new就是构造函数,不加就是普通函数。构造函数的首字母大写
function Person(){
}
var per=Person();//普通函数的调用
var per2=new Person();//构造函数的调用

console.log(per);//undefined
console.log(per2);//object object(函数没有返回值,但是per2确实是有个对象,对象哪来的呢)
function Person(name,age,gender){
	this.name=name;
	this.age=age;
	this.gender=gender;
	this.sayName=function(){
		alert(this.name);
	}
}
var per2=new Person("孙悟空",18,"男");//构造函数的调用
var per2=new Person("猪八戒",18,"男");//构造函数的调用

function Dog(){
}
var per3=new Dog();
console.log(per3);//Dog{}
console.log(per2 instanceof Person);//true
console.log(per2 instanceof Object);//true
//所有对象都是Object的后代,所以任何对象和Object在instanceof检查时都会返回true

使用 instanceof 可以检查一个对象是否是一个类的实例
句法:
对象 instanceof 构造函数名字
如果是,返回true,否则false

this的情况

  1. 当以函数的形式调用时,this就是window
  2. 当以方法的形式调用时,谁调用方法this就是谁
  3. 当以构造函数的形式调用时,this就是新创建的那个对象

三、构造函数的修改

//创建一个Person构造函数
function Person(){
	this.name=name;
	this.age=age;
	this.gender=gender;
	this.sayName=function(){
		alert("Hello,我是"+this.name);
	}
}
//创建Person实例
var per=new Person("孙悟空",18,"男");

在Person构造函数中,为每一个对象都添加了一个sayName方法,
目前我们的方法是在构造函数内部创建的,
也就是构造函数每执行一次就会创建一个新的sayName方法,
也就是说所有的sayName都是唯一的。
这样就导致了构造函数每执行一次就会创建一个新的方法,
执行一万次就创建一万个新的方法,而一万个方法都是一模一样的。
这是完全没有必要的,完全可以使所有的对象共享一个方法

提升性能的一种方法:
在构造函数内部中定义的方法,每实例化一次构造函数,就会创建一次方法。
可以把在构造函数内部定义的方法拿出作为全局下的,在构造函数中引用(所有对象共享同一个方法)。如下:
这种方法有一种缺陷:

将函数在全局中定义

  1. 将函数定义在全局作用域,污染了全局作用域的命名空间
  2. 而且定义在全局作用域中很不安全(名字不能重复,多人开发中很容易重复了,直接就被覆盖了!)
    针对这个缺陷提出了——原型prototype
//创建一个Person构造函数
function Person(){
	this.name=name;
	this.age=age;
	this.gender=gender;
	this.sayName=fun;//这儿不需要加括号
}
function fun(){
	alert("Hello,我是"+this.name);
}
//创建Person实例
var per=new Person("孙悟空",18,"男");

四、原型对象

我们创建每个函数,解析器都会向函数中添加一个属性:prototype
这个属性对应着一个对象,这个对象就是我们所谓的原型对象

  • 如果函数作为普通函数调用prototype没有任何作用
  • 当函数以构造函数调用时,它所创建的对象中都会有一个隐函的属性,指向该构造函数的原型对象,我们可以通过_proto_来访问该属性(存的是构造函数的原型对象的地址)
  • 原型对象就相当于一个公共区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的对象,统一设置到原型对象中。
  • 当我们访问对象的一个属性活方法时,它会先在对象的自身中寻找,如果有则直接使用,如果没有则会取原型对象中寻找,如果找到则直接使用
  • 以后我们创建构造函数时,可以将这些公共的方法和属性,统一添加到构造函数的原型对象中
function Person1(){
}
console.log(Person1.prototype);//[object Object]
function Person2(){
}
console.log(Person2.prototype==Person1.prototype);//false

说明每个函数都会有自己的prototype属性,都是唯一的,都是自己的
function MyClass(){

}
var mc=new MyClass();
var mc2=new MyClass();
console.log(mc._pro_);
console.log(mc._proto_==MyClass.protostyle);//true

mc.a="我是mc中的a";
console.log(mc.a);//我是mc中的a
console.log(mc2.a);//我是mc中的a
function MyClass(){
}
var mc=new MyClass();
MyClass.prototype.a="123";//在原型对象中添加a
var mc=new MyClass();
console.log(mc.a);//123
//当我们访问对象的一个属性活方法时,它会先在对象的自身中寻找,
//如果有则直接使用,如果没有则会取原型对象中寻找,如果找到则直接使用

//向mc中添加a属性
mc.a="我是mc中的a";
console.log(mc.a);//我是mc中的a
//向MyClass中添加一个方法
MyClass.prototype.sayHello=function(){
 console.log("hello");
}
mc.sayHello();//hello

综上,使用原型方法,可以在创建的对象中直接添加方法和属性,不会污染全局作用域。
若在每个对象中都需要,可以放在公共的区域





原型对象的prototype和_proto_关系

  • 对象.hasOwnProperty()
  • 判断对象自身中是否有该属性,使用该方法只有对象自身中含有该属性,才会返回true
  • 而hasOwnprototy属性在原型中
    hasOwnPrototy属性用法
console.log(mc._proto_.hasOwnProperty("hasOwnProperty"));//false
//可见在原型中也没有hasOwnProperty,那它是怎么来的?

在这里插入图片描述

在这里插入图片描述

console.log(mc._proto_._proto_.hasOwnProperty("hasOwnProperty"));//true

在这里插入图片描述

五、toString

在这里插入图片描述

  • 当我们直接在页面中打印一个对象时,实际上输出对象的toString()方法的返回值
  • 下面的效果一样
  • console.log(per);
  • console.log(per.toString());
console.log(per._proto_.hasOwnProperty("toString"));//false
console.log(per._proto_._proto_.hasOwnProperty("toString"));//true

在这里插入图片描述

  • 这样在原型中加入了,实例化构造函数时,每个对象都会有这个属性了

六、垃圾回收(GC)

在这里插入图片描述
在这里插入图片描述

七、数组

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 数组中,若读取不存在的索引,不会提示报错,返回undefined
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 向数组的最后一个位置添加元素
  • arr[arr.length]=10;
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 数组中可以放任意类型的数据类型(数组,布尔,对象,null,undefined,函数(因为函数也是对象)…)
  • 数组中存函数的调用方式:arr0
    在这里插入图片描述
    在这里插入图片描述

八、数组的几个方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

九、数组的遍历

  • forEach:只支持IE8以上的浏览器,IE8及以下的浏览器均不支持该方法,所以要兼容IE8,还是使用for循环来遍历
  • 需要一个函数作为参数
function fun(){
}
arr.forEach(fun);//参数为一个函数

一般在参数中直接定义函数
在这里插入图片描述
加粗样式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十、函数对象的方法

(一)call()

(二)apply()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用apply或者call,可以指定this,参数是谁,this就是谁
在这里插入图片描述
在这里插入图片描述

(三)arguments 实参

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十一、Date 函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十二、Math 对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值