如果没有面向对象这种抽象概念的小伙伴,建议先看一下我写的
JS基础入门篇(三十四)—面向对象(一)????
1.非常非常重要而又简单的概念—原型链
想要以下为 f 添加一个say方法,有三种方法。
方法一:相当于添加一个自定义属性,此属性是一个方法。
方法二:为构造函数.prototype添加一个say方法。
方法三:为Object.prototype添加一个say方法。
疑问?️:
方法二中挂在构造函数的方法,和方法三中挂在Object的方法, f 为什么能查找的到???
解析(此解析一定要看懂,没有看懂多看几遍或者百度下):
是原型链的概念。就是js内部的查找机制。首先要明白:
1.prototype 原型
当一个函数被申明的时候,该函数下默认有一个属性:prototype,该属性的值是一个对象。
举例说明:
结果如图所示:
2.__proto__
当一个对象被创建的时候,该对象会自动被添加上一个属性:__proto__,他的值也是一个对象,并且该属性 就是 当前这个对象的构造函数的prototype
举例说明:
结果如图所示:
3.对象.__proto__ === 构造函数.prototype
举例说明
结果如图所示:
所以查找机制为:
调用f.say( );时
if( 对象 f上面是否say方法 ){//为真,执行if内部的代码则调用f上面的say方法
}else if(Fn.prototype是否有say方法){//为真,执行else if内部的代码第一步:f.__proto__ === Fn.prototype由这个查找到f对应的构造函数的原型,即为 Fn.prototype。第二步:查看Fn.prototype是否有say方法,有的话,则调用Fn.prototype是上面的say方法。}else if( Object.prototype是否有say方法 ){第一步:Fn.prototype.__proto__ === Object.prototype由这个查找到Fn.prototype对应的构造函数的原型,即为 Object.prototype。第二步:Object.prototype是否有say方法,有的话,则调用Object.prototype是上面的say方法。}else{//如果以上都没有say方法 会报错。
}
举例说明
2.hasOwnProperty, constructor, instanceof
1.hasOwnPropert
???
作用用来判断某个对象是否含有 指定的 自身属性语法boolean object.hasOwnProperty(prop)参数object要检测的对象prop要检测的属性名称。注意:不会沿着原型链查找属性,只查找自身属性
如果以上文字都看不懂,可以先看例子,再看文字。
2.constructor
???
函数的原型prototype的值是一个对象,初始化会有一个属性为constructor,对应的值为拥有这个原型的函数注意:prototype的值是可以修改的,修改了prototype的值,要手动将constructor指向函数
3.instanceof
???
instanceof是一个二元运算符,返回布尔值
运算检测 一个 对象原型 是否 在要检测的对象的原型链上使用:object instanceof constructor
3.this的指向
1.谁调用就指向谁。
2.谁触发就指向谁。
举例说明1
举例说明2
4.修改this指向的三种方式
1.call
1. 函数**`会`**立刻执行
2. 函数执行时候,函数**`第一个参数`**是内部的**`this指向`**
3. **`第一个参数之后的参数,都是指 函数执行时候 ,内部的实参`**
直接撸代码,举例说明
2.bind
1. 函数**`不会`**立刻执行
2. 函数执行时候,**函数第一个参数是内部的this指向**
3. **第一个参数之后的参数,都是指 函数执行时候 ,内部的实参**
4. **`返回的是 修改了 this指向的新函数`**与call的区别就是函数不会立刻执行。
举例说明
3.apply
与call很相似,只是第二个参数值接受数组
举例说明
5.数组的检测
因为由typeof打印出来,数组和对象的结果都是object。有时候我们需要判断变量是否是数组
。
方法一:
var arr = [1,2,3];console.log( arr.toString() );//1,2,3Array.prototype.toString = Object.prototype.toString;//重新赋值Array.prototype.toString的方法。但是下次在别的情况调用Array.prototype.toString,此方法已被重新覆盖。所以不太好console.log( arr.toString() );//[object Array]
var arr = [1,2,3];
console.log( Object.prototype.toString.call(arr) );
// 使用 Object.prototype.toString
// 同时 修改内部的this指向 arr
console.log( arr );//[object Array]
方法二:
6.继承
继承
在Javascript中,继承就是让一个对象(子类)拥有另一个对象(父类)的属性/方法(还有原型上的属性和方法)。其中原则就是:
1.子类的修改不能影响父类
2.子类可以 在 父类 基础上 添加自己的属性 和 方法
1.通过prototype 赋值 (行不通,但是还是要看行不通的原因)
举例说明:上代码
2.原型链继承
子类的原型 = 父类的实例注意 : 在为 子类 原型 赋值的时候去修正 constructor弊端 : 子类构造函数内的地址的修改会修改其他子类。因为所有子类构造函数的原型共享一个实例。
举例说明
对原型链继承遇到问题的解决的方案一:
改为:
function Coder() {this.arr=[1,2,3];//这样查找的时候,对象上面就有了,不会查找到上一层,既不会修改到。
}
解析:此方法麻烦,如果父类有很多自定义属性都是对象或者方法,那么子类都要重新复制一遍。
对原型链继承遇到问题的解决的方案二:
借用构造函数在子类中执行父类的构造函数修改子类构造函数中的 this指向只能继承父类构造函数中的方法和属性继承不到父类构造函数原型链中的方法和属性
改为:
function Coder() {CreatPerson.call(this);// // 此处的 this 指的 是 Coder 的 实例}
总结:通过原型链继承的正确写法。
提醒自己: Coder.prototype.constructor=Coder;//在为 子类 原型 赋值的时候去修正 constructor。 不要忘记修正子类的constructor。
3.拷贝式继承
1. 完成拷贝式继承首先要知道如何拷贝对象。所以先来拷贝对象
2.拷贝继承