一、this的指向(耐心看完,这个彻底理解,才不会成为一时的记忆)
1.我们先来看函数的参数:
function fn(a,b ) {//形参
console.log(a, b);//a:1,b:2
}
fn(1, 2)//实参
这没有问题的,其实函数的形参a,b就相当于声明了两个变量a,b,所以我们传入实参数值的时候就相当于给变量赋值,那么就能打印到a,b的值了
那么,函数fn,形参我传多余的参数,a,b,c,d,而实参呢,只有两个值,那么c,d打印的会是多少啊?
是undefined对不对啊,那么为什么呢,是因为声明了4个变量,只给前两个变量赋值,那么后两个变量声明了但没有赋值,我们是不是打印undefined啊
多说几句哈:
形参少传:就一个a, console.log(a, b);肯定b报错了啊,b没有声明,会报b没有被定义的错误
实参多传:那就打印a,b的值了,实参相当于赋值,连变量都没有,赋值给谁,打印谁啊,对吧
实参少传:实参就传一个值,其实实参少传不就是形参多传嘛,其实我们只去思考声明变量和赋值,就能知道打印结果了
2、什么是this?
this他就是一个参数,是一个函数内部隐含的参数,人家内部给你声明好的一个参数
function fn(a,b){
console.log(a,b)//a:1,b:2
console.log(this)//window
}
fn(1,2)
指向:一个对象——函数执行的上下文对象
指向:根据函数调用方式的不同,指向不同
1.以fn()函数的形式调用,this永远指向window
function fn() {
console.log(this);
}
fn()//Window
2.以obj.sayHi()方法的形式调用,this指向调用方法的那个对象,如obj
function fn() {
console.log(this);
}
let obj = {
name: '张三',
sayHi: fn
}
obj.sayHi() //this 就是 obj
以方法的形式调用,哪个对象调用的这个方法,这个方法的this就是哪个对象
3、箭头函数的this
箭头函数:没有自己的this 没有arguments、但是有剩余参数...arr
使用场景:适合替代匿名函数
自己没有,找他的上一级
// 箭头函数的this:自己没有,找他的上一级
const fun = () => {
console.log(this); //window
}
fun() //不是因为window.fun(),而是因为找父级作用域的this指向
对象方法的箭头函数this :
// 对象方法的箭头函数this
const obj = {
name: 'h',
sayHi: () => {
console.log(this); //window,找的上一级的指向,找的就是window
}
}
obj.sayHi()
// 对象方法的箭头函数this
const obj2 = {
name: 'j',
sayHi: function() {
console.log(this); //this:obj2
let i = 1
const count = () => {
console.log(this); //this:obj2
}
count()
}
}
obj2.sayHi()
DOM事件回调函数推荐不使用箭头函数,使用箭头函数,他就不指向DOM对象了,指向window
二、工厂方法创建函数
1、我们先创建几个对象:
let obj = {
name: '小新',
age: 5,
class: '向日葵小班',
sayName: function() {
alert(this.name);
}
}
let obj2 = {
name: '风间',
age: 5,
class: '向日葵小班',
sayName: function() {
alert(this.name);
}
}
let obj3 = {
name: '妮妮',
age: 5,
class: '向日葵小班',
sayName: function() {
alert(this.name);
}
}
obj2.sayName()
这样创建对象,重复性代码有点多,看起来较笨重,有没有利用重复性的代码呢
可以考虑写一个函数封装起来,然后调用一次是不是就生成了一个对象啊,就不用复制三分再去改了。
2.工厂方法创建函数
工厂方法创建函数就是一个函数,他能创建一个对象,理解工厂:批量的生产出来对象
function createPerson (name,age){
//第一步:要new 一个对象
let obj=new Object()
//第二步:要给对象里添加点属性
obj.name=name,
obj.age=age
obj.sayName=function() {
alert(this.name)
}
//第三步:返回值
return obj
}
//第四步:调用函数
let obj=createPerson("小新♥",5)
let obj2=createPerson("妮妮",5)
let obj3=createPerson("风间",5)
console.log(obj,obj2,obj3)
![](https://img-blog.csdnimg.cn/3d45d3bb7fd24d50a7d4d1cd1647d9c0.png)
这样就优雅的创建了三个对象,那么这里的this,指向哪里呢?
![](https://img-blog.csdnimg.cn/590ab775a5c148bc8ec70f88f4f0d596.png)
是不是以方法的形式调用的函数啊,那函数的this指向谁,obj3调用的就指向obj3了 ,所以函数sayName里的alert方法执行,this.name就是obj3对象里的name,就是风间了。
![](https://img-blog.csdnimg.cn/56b84c501aee4afa9557e63fba0cd0f8.png)
三、构造函数
1.什么是构造函数?
就是一个普通的函数,不过调用的方式不同
普通函数调用:函数名()
构造函数调用:new 函数名()
另外,写法上,常首字符大写(规范,不是规定),最好首字母大写哈
function Person(name, age) {
this.name = name
this.age = age
this.sayName = function() {
alert(this.name)
}
}
// 调用方式不同
let p = new Person('风间', 5)
let p2 = new Person('妮妮', 5)
console.log(p, p2); //p 就是一个对象,只不过他有名字,名字就是那个函数的名字
我们先看函数,先忽略里面的this
![](https://img-blog.csdnimg.cn/3233b335c509455d948d6c69d6d07634.png)
这回对象p,p2是不是有名字了啊
2.构造函数的this
// 看this:那就要看构造函数的执行流程了
// 1.你new 的方式调用了这个函数,那么(浏览器)就立即创建一个新的对象
// 2.(浏览器)将新创建的对象设置为函数中的this
// 3.逐行执行函数中的代码(代码咱们写的)
// 4.(浏览器)将新建的对象作为函数返回值返回
总而言之:
this的指向:谁调用的函数,指向谁!!
以函数调用,是不是window.函数名()啊,谁调用的:window,指向谁:指向window
那么构造函数谁调用的:new 函数名(),指向谁:new 函数名(),他把他赋值给变量p,那么变量p,就是new 函数名(),那么p就是对象,this就指向p
3.类、类的实例对象
这计算机概念性名字听起来挺难理解哈,别怕,他就是个名字,我们来理解他
使用同一个构造函数创建的对象,我们称为一类对象( p,p2是一个类的,d,d2是一个类的)
也将这个构造函数称为一个类(如:构造函数Person称为类,构造函数Dog称为类,这就是两个类)
将通过一个构造函数创建的对象,称为是该类的实例
谁是通过构造函数创建的对象:p p2 d d2 ,这玩意叫实例,p p2 d d2叫实例
(如:p,p2,d,d2是实例,p,p2是Person类的实例,d,d2是Dog类的实例)
![](https://img-blog.csdnimg.cn/3552dae232f74d3e8e27e5a7a8135315.png)
补充:
// instanceof 检查一个对象是否是一个类的实例
console.log(p instanceof Person); //true
console.log(d instanceof Person); //false
// Object 是所有对象的祖先
// 任何对象 instanceof Object 都会是true
console.log(p instanceof Object); //true
console.log(d instanceof Object); //true
4.问题
// 问题:什么叫类?这个构造函数称为一个类
// 什么叫实例?实例就是一个对象,构造函数干嘛的?创建对象的,通过构造函数创建出来的对象
// 什么叫构造函数?new 出来的一个函数
// 构造函数与普通函数的区别?调用方式不同
//构造函数的this指向? 谁调用的指向谁,构造函数的this指向他的实例对象。
5.补充
在构造函数内部创建了一个方法sayName,每个实例对象p1,p2,p3就都有了自己独立的方法,那么创建1000个实例对象,就会有1000个方法,这1000个方法都一摸一样,完全为了实现一个功能,这样太消耗内存了
// 构造函数
function Person(name, age) {
this.name = name
this.age = age
this.sayName = function() {
alert(this.name)
}
}
let p1 = new Person('小新', 5)
let p2 = new Person('妮妮', 5)
let p3 = new Person('风间', 5)
// p1.sayName()
// p2.sayName()
// p3.sayName()
console.log(typeof p1.sayName); //function
console.log(p1.sayName == p2.sayName); //false
把函数放到全局上,他就只有这么一个函数,提升性能,创建1000个实例对象,还是这一个方法
function Person(name, age) {
this.name = name
this.age = age
this.sayName = fn
}
let p1 = new Person('小新', 5)
let p2 = new Person('妮妮', 5)
let p3 = new Person('风间', 5)
function fn() {
alert(this.name)
}
console.log(p1.sayName == p2.sayName); //true
但是这样写是有问题的,污染了全局作用域的命名空间,别人在写个函数叫fn,就会覆盖你的fn了,所以我们把他写在原型上
function Person(name, age) {
this.name = name
this.age = age
// this.sayName = fn
}
let p1 = new Person('小新', 5)
let p2 = new Person('妮妮', 5)
let p3 = new Person('风间', 5)
Person.prototype.sayName = function() {
alert(this.name)
}
p1.sayName()
console.log(p1.sayName == p2.sayName); //true
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)