高级的阶段,我们要理解其中的计算机运行的概念。设计计算机编程的时候,我们程序员赋给计算机逻辑运算体系。这种体系的严谨性和指向性让程序员给予很大的挑战。javascript这门编程语言是基于对象的语言,也是弱语言脚本语言。现在很多网上的博客大多数认为是面向对象的语言。面向对象的编程语言需要有 类 对象实例 封装 继承 多态 这几个特征。 javascript 没有类的概念。也不是面向对象的编程语言。但可以通过字面量 工厂方法 构造函数的方法来创建对象。实现面向对象的要素和功能。什么为类的概念呢?就是具有共同的特征的名称的集合。其他的编程语言大多数是有类的概念的。所以javascipt 是基于对象的语言。但是可以通过很多方法来创建对象。
1:通过字面量来创建我们解决问题的对象。
var person = { // 我们创建了一个人的对象实例,我们计算机系统运行的时候,需要对象和逻辑运算体系。解决问题 就是来创建问题本身所需要的对象。面向对象就是让我们来提高解决问题的效率。而不是面向过程那样复杂。创建解决问题的对象。当然,可以跟据业务的需要来分析对象的创建的范围
name : "小明", // 对象的属性 是对象自身带有的,当然,我们也可以自己的需要来给对象添加属性。属性名+冒号+属性值。属性值是可以任意数据类型。是数值和数组 也可以是字符串。是可以通过对象点属性的 是属性值。逗号是提示下面也有属性的。这是通过字面量的创建对象的语法格式。如果是最后的属性名的话,不用加逗号的。加的话会报错。
age : 18,
eatFood : function () { // 这是对象的方法。也就是对象的所具有的功能。可以解决问题的关键环节。当然,属性的作用是提供我们解决问题的材料。也是不可以避免的。属性+方法是我们来解决问题的完整体系。方法是函数的形式来创建的。
alert("吃饭");
}
}
// 通过工厂的方法来创建对象。
function person () {
var person = {}; // 创建一个模板 ,来大批量的生产同一的对象。
person.name = "小明"; //给予对象的属性赋值。
person.age = 18;
person.eatFunction = function () { // 给对象创建方法。
alert("吃食物") // 在工厂方法里面 js引擎没有创造原生对象。也不具备原生对象的相关知识。
}
}
// 通过构造函数的方法创建对象。
function person (name,age) {
this.name = name; // 通过构造函数来创造对象,是个范本。是具有相同的属性和方法。用this指针可以帮助我们优化代码,因为构造函数也是在调用的时候来有意义,this指针也是在具体的对象实例中来指向谁。谁调用i就指向谁。这也是封装的含义。this只能用在函数体当中。this就是指向new 开辟的内存空间。所以我们用构造函数来创建对象,对象的实例就必然用new来开辟空间 调用函数,然后再传参数。完成解决问题的整个过程。 注意:传参数时,我们要考虑参数的数据类型。因为是属性值的 在构造函数时,我们给予的参数是变量的。用变量来保存值。传参数时,我们可以是任意数据类型。如果是变量的话。要么是变量的转化为字符串,就是加双引号和单引号。要么是变量保存的值是字符串也可以。
this.age = age;
this.eatFunction = function () {
alert("吃食物")
}
}
var per1 = new person ("name",age) // 注意参数的类型。看变量保存的值。
我们创建了对象的实例后,我们知道对象的属性有很多,我们怎么样去访问对象的属性呢?我们是不是可以类比的数组的遍历的方式来访问对象的属性呢?// 通过for..in.循环的来访问。
答案是可以的。访问单个的属性直接调用用 对象 点 属性就可以了。就可以拿到这个属性的值。
for (var protopy in obj){
console.log(obj["protopy"]) // 访问对象的属性用两种方法 :1: 是 对象名+“.” 属性名。
2: 是 对象名+[] 中括号是里面是字符串的类型。或变量的保存值。 所以,我们可以扩展一下。在构造函数中,在js引擎中,编译的过程中,会自动创建原型对象,就是天生的原型。是在系统中隐式的创建。为什么要创建原型的对象呢?因为在构造函数中,优点很多,比如是特征化,把对象的属性和方法赋值在this 指针上 用this指针直接点属性和方法就可以了。在封装函数时,我们也可以用this指针来指向调用的函数对象。比较方便简化。但是会占内存。因为我们在构造函数时,我们就会造成内存占用。所以,用原生对象来保存一些公有的方法和属性。可以让构造函数的对象实例来访问,拿到的共同拥有的方法。我们用构造函数给予原生对象一些方法来供构造函数的对象实例使用。我们用这个属性 prototype 来访问原生对象。这个属性是一个指针的功能,可以帮我们找到我们需要的对应的原生对象。当然,原生对象也需要个指针的功能来指向构造函数。就constructor 的属性来指向构造函数。这样,就保证了语言的严谨性。
}
function creatObject () {
this.name = name;
this.age = age;
}
creatObject.prototype.sayHi = function () {
alert() // 所需要的方法 原生对象的方法。代码块。
}
var per1 = new creatObject ("xiaom",20);
per1.sayHi(); // 调用原型的方法。
注意:我们需要明白的不能通过_proto_来访问原生对象的。在语法上是禁止的。我们把构造函数看做是老大,对象实例是老二 也是说,对象实例可以通过查找对象属性的方法来调用原生对象的属性和方法。当然,改变老大的值,会间接改变老二的值。在高级的语法中,我们经常会犯这样的错,逻辑层次的混乱,对象的乱用。所以,我们要分清指向的对象。
原生对象的属性和方法是添加在自定义的构造函数 可以供构造函数的对象实例来使用。
构造函数的对象的实例, 如果有自身的属性和方法,在访问的时候(注意:只有在读取的时候,对象的实例可以自身用,不用向原生对象拿值。)如果是没有的属性和方法,对象实例会向原生对象拿值。如果也没有,原生对象会向Object 拿值,如果也没有,就会语法报错。所以,我们可以把方法和属性挂载原型上或者是Object. 比如,我们可以封装函数。
Object.prototype.isPrototype = function (arrt,obj) {
if(!(arrt in obj)) { // 我们来更加理解下if,,else 判断语句的用法。if 下的语句是为真的情况,也就是为 true 的情况。所以,遇见判断为布尔类型的值时,就可以直接写在if 语句上了。else是为false时,来执行else中的语句。if 和逻辑非(!)联合就可以包括所有的布尔判断类型。
return null
}else if (obj.hasOwnProperty(arrt)) { // 为true 时是实例对象的。
return ture
}else {
return false
}
}
// 这样就挂载在对象的根上了。Object 可以调用了。
// 在用原生对象挂载方法时,每当this指针的对象实例调用原生对象的函数时,都会重新写一次,在内存上造成浪费。所以就利用判断来避免这样的内存占用。
function person (name,age,sex) {
this.name =name;
this.age = age;
this.sex = sex;
if (typeOf this.sayHi != "function") { // 比较是判断的类型。function 是个字符串而不是变量。
person.prototype.sayHI = function () {
alert (this.name+"hello")
}
}
}
var per1 = new person("小明",18,"男");
var per2 = new person("小红",18,"女");
per1.sayHi(); //
per2.sayHi(); //
我们既然可以在实例对象和原型对象中有属性和方法,我们这么样去判断这个属性是实例的还是原型的?我们可以通过hasOwnPrototype 来判断实例有这个属性。还要用in来判断是个有没有这个属性。二者可以联合可以判断。先判断 in 再判断 hasOwnPrototype的用法。
今天我们学习的是继承。继承是面向对象的重要内容。我们对于继承的理解是生活中的父子继承遗产关系。也是生物学中的遗传基因。计算机编程也是生活中的设计者。计算机我们也会有继承关系。父级与子级的继承关系。面向对象的继承也是有继承树来实现的。我们创建对象时,我们通过需要构造函数来创建类的概念。既然是类,我们有一些共同的属性,和方法。我们之前的做法是,共同的属性用在构造函数里,共同的方法是通过原型来挂载方法。来节省空间。让大家的对象实例都利用起来方法。比如举个例子:
// 我们先构造函数来创造对象。(其实是类的概念)
function person () {
this.name = name;
this.age = age; // 这些都是属性。类的特征。
this.heigth = heigth;
this.sayHi = function () { // 这是个方法。我们在构造函数中去创造。这个对象的实例就可以调用了。但是通过new 来开辟空间,用this 指针来指向具体的对象实例。这样每个不同的实例都会通过new来开辟空间,内存将会占用。所以,我们将一些共同的方法挂载在原型上。这样我们就可以让不同的实例通过自己的内部指针来_proto_ 来访问查找原型对象。来调取原型对象的方法。这样就大大的节约空间了。提高我们的效率。
alert("hello")
}
}
person.prototype.eatFood = function ( ) {
alert("吃饭了"); // 这就是把共同的方法挂载在原型上。
}
继承的方法,我们需要最低俩个对象。父级和子级
function createAnimal () {
this.name = name;
this.age = age;
}
createAnimal.prototype.eatFood = function ( ) {
alert("吃食物");
}
function creatPerson () {
this.gener = gener;
this.height = heigth ;
// 我们来继承父级的name和age 属性 用call() 和apply()来创建。call()和 apply ()可以来改变this指针的指向。第一个参数就是改变this指针的指向对象和驱动父级构造函数。后面可以传参,这样我们就可以利用这两个特性来为继承服务。
createAnima.call(this,name,age) // 改变this的指针指向子级。然后传参,拿到我们需要取的值。
}
var per = new creatPerson("xiaozhang",18)
per.eatFood ();
2 : 通过原生链来继承。
function createAnimal () {
this.name = name;
this.age = age;
}
createAnimal.prototype.eatFood = function ( ) {
alert("吃食物");
}
function creatPerson () {
this.gener = gener;
this.height = heigth ;
// 我们通过原生链来继承。原理就是父级的对象实例来替换子级的原生对象。通过内部指针_proto_来形成原生链来继承父级的属性和方法。
creatPerson.prototype = new createAnimal ("xiaoming",17); // 只有在这个地方给父级实例对象传相对应的属性参数。不然,没有机会了。但是,我们的参数就是固定了,不够灵活了。
creatPerson.prototype.constructor = creatPerson;
}
var per = new creatPerson("xiaoming",17)
per.eatFood();
3 通过原生原型和改变this指针来组合继承。
function createAnimal (name,age) {
this.name = name;
this.age = age;
}
createAnimal.prototype.eatFood = function ( ) {
alert("吃食物");
}
function creatPerson (name,age,gener) {
this.gener = gener;
this.height = heigth ;
createAnimal.call(this,name,age)
creatPerson.prototype = new createAnimal();
creatPerson.prototype.constructor = creatPerson;
creatPerson.prototype.run = function () {
alert("跑步")
}
}
var per = new creatPerson("xingmong",20,"man")