当前位置: 首页 > Web前端 > JavaScript

构造函数模式

时间:2023-03-27 00:52:55 JavaScript

ECMAScript中的构造函数用于创建特定类型的对象。像Object和Array这样的原生构造函数在运行时在运行时环境中是可用的。当然你也可以自定义构造函数,以函数的形式为你自己的对象类型定义属性和方法。1.使用工厂模式:functioncreatePerson(name,age,job){leto=newObject();o.name=名字;o.age=年龄;o.job=工作;o.sayName=function(){console.log(this.name);}returno;}letperson1=createPerson('张三',23,'Web前端开发');letperson2=createPerson('李四',20,'IOS开发');这里,函数createPerson()接受三个参数,根据这些参数构造一个包含Person信息的对象。可以使用不同的参数多次调用此函数,每次返回一个包含3个属性和1个方法的对象。工厂模式虽然可以解决创建多个相似对象的问题,但是并没有解决对象识别(即新创建的对象是什么类型)的问题。2.还是上面的例子,使用构造函数:functionPerson(name,age,job){this.name=name;这个。年龄=年龄;这个.job=工作;this.sayName=function(){console.log(this.name);}}letperson1=newPerson('张三',23,'Web前端开发');letperson2=newPerson('李四',20,'IOS开发');3.在本例中,Person()构造函数替换了createPerson()工厂函数。其实Person()的内部代码与createPerson()的内部代码基本相同,除了以下几点不同。1.没有显式创建对象。2.属性和方法直接赋值给this。3.没有回报。另外,请注意函数名称Person的首字母大写。按照惯例,构造函数名称以大写字母开头,非构造函数名称以小写字母开头。这是从面向对象语言中借用的,这有助于将构造函数与ECMAScript中的普通函数区分开来。毕竟,ECMAScript构造函数是创建对象的函数。4.要创建Person实例,应使用new运算符。以这种方式调用构造函数会执行以下操作。1.在内存中创建一个新对象。2.这个新对象的内部[[Prototype]]属性被指定为构造函数的原型属性。3.在构造函数内部,给this赋值新对象(即this指向新对象)。4.执行构造函数内部的代码(为新对象添加属性)。5.如果构造函数返回一个非空对象,返回那个对象;否则,返回刚刚创建的新对象。5、在上一个例子的最后,person1和person2分别保存了Person的不同实例。两个对象都有一个指向Person的constructor属性,如下所示:console.log(person1.constructor===Person);//trueconsole.log(person2.constructor===Person);//true6.constructor本来是用来识别对象类型的。但是,instanceof运算符通常被认为是一种更可靠的确定对象类型的方法。在前面的示例中,每个对象都是Object的实例,也是Person的实例,调用instanceof运算符的结果如下所示:console.log(person1instanceofPerson);//trueconsole.log(person1instanceofObject);//trueconsole.log(person2instanceofPerson);console.log(person2instanceofObject);//true定义一个自定义的构造函数可以保证实例被识别为特定的类型,这相对于工厂模式来说是一个很大的好处。在此示例中,person1和person2也被视为Object的实例,因为所有自定义对象都继承自Object。7、构造函数不一定非得是携程函数声明的形式。分配给变量的函数表达式也可以表示构造函数:letPerson=function(name,age,job){this.name=name;这个。年龄=年龄;这个.job=工作;this.sayName=function(){console.log(this.name);};}letperson1=newPerson('张三',23,'Web前端开发');letperson2=newPerson('李四',20,'IOS开发');person1.sayName();//张三person2.sayName();//李四console.log(person1instanceofObject);//trueconsole.log(person1instanceofPerson);//trueconsole.log(person2instanceofObject);//trueconsole.log(person2instanceofPerson);//true8.实例化的时候,如果不想传递参数,那么构造函数后面的括号可以加也可以不加。只要有new操作符,就可以调用对应的构造函数:functionPerson(){this.name='Chen';this.sayName=function(){console.log(this.name);}}letperson1=newPerson();letperson2=newPerson();person1.sayName();//Chenperson2.sayName();//Chenconsole.log(person1instanceofObject);//trueconsole.log(person1instanceofPerson);//trueconsole.log(person2instanceofObject);//trueconsole.log(person2instanceofPerson);//true9.构造函数也是一个函数。构造函数和普通函数之间的唯一区别是调用方法。此外,构造函数也是函数。没有将函数定义为构造函数的特殊语法。任何使用new运算符的函数都是构造函数,不使用new运算符调用的函数是普通函数。比如上一个例子中定义的Person()可以这样调用://作为构造函数letperson=newPerson('张三',23,'Web前端开发');person.sayName();//张三//调用Person('Chen',23,'Web前端开发')作为函数;window.sayName();//'Chen'//在另一个对象的范围内调用leto=newObject();Person.call(o,'李四',20,'IOSDevelopment');o.sayName();//开头'李四'的例子展示了一个典型的构造函数调用公式,即使用new操作说明符创建一个新对象。然后就是调用普通函数的方式。这时候,new操作符并没有被用来调用Person(),结果会是给window对象添加属性和方法。这里要记住,当调用函数时没有显式设置this值(即没有将方法作为对象调用,或者没有使用call()/apply()调用),this总是指向Global对象(在浏览器中是窗口对象)。所以在上面的调用之后,window对象上有一个sayName()方法,调用它会返回“Chen”。最后一种调用方式是通过call()(或apply()调用函数),同时使用特定对象作为作用域。这里的调用指定了对象o作为Person()内部的this值,所以函数代码执行后,所有的属性和sayName()方法都会被添加到对象o中。10.构造函数问题。构造函数虽然有用,但并非没有问题。构造函数的主要问题是它们定义的方法是在每个实例上创建的。所以对于前面的例子,person1和person2都有一个名为sayName()的方法,但是这个方法不是同一个Function实例。我们知道ECMAScript中的函数是对象,所以每次定义一个函数,都会初始化一个对象。从逻辑上讲,这个构造函数实际上看起来像这样:functionPerson(name,age,job){this.name=name;这个。年龄=年龄;这个.job=工作;this.sayName=newFunction("console.log(this.name)");//逻辑等价}11.这样理解狗的构造函数可以更清楚的是每个Person实例都会有自己的Function实例来显示name属性。当然,以这种方式创建函数会引入不同的作用域链和表示解析。但是创建新Function实例的机制是相同的。因此,虽然不同实例上的函数同名,但并不相等,如下所示:console.log(person1.sayName===person2.sayName);//false12。因为他们都在做同样的事情,所以没有必要定义两个不同的Function实例。此外,this对象可以将函数与对象的绑定推迟到运行时。要解决这个问题,可以将函数定义移到构造函数之外:functionPerson(name,age,job){this.name=name;这个。年龄=年龄;这个.job=工作;this.sayName=sayName;}functionsayName(){console.log(this.name);}letperson1=newPerson("张三",23,"Web前端开发");letperson2=newPerson("李斯",20,"IOS开发");这里,sayName()是在构造函数之外定义的。子构造器内容,sayName属性等于全局sayName()函数。因为这次sayName属性只包含一个指向外部函数的指针,所以person1和person2共享在全局范围内定义的sayName()函数。虽然这解决了具有相同逻辑的函数重复定义的问题,但全局作用域也变得一团糟,因为该函数实际上一次只能在一个对象上调用。如果此对象需要多个方法,则必须在全局范围内定义多个函数。这会导致自定义类型引用的代码不能很好地聚集在一起。这个新问题可以用原型模式来解决。13.本期分享到此结束,希望对大家有所帮助,让我们一起努力,勇攀高峰!