js面向对象(二)

简介: js面向对象

三、继承


1、原型链继承


// 父类: 公共属性和方法
    function Person() {
        this.name = "why"
        this.age = 18
        this.friends = []
    }
    Person.prototype.eating = function () {
        console.log(this.name + " eating~")
    }
    // 子类: 特有属性和方法
    function Student() {
        this.sno = 111 //学号
    }
  // 在需要继承的对象上创建父类实例
    Student.prototype=new Person()
    Student.prototype.study=function(){
        console.log('学生学习');
    }
    const s=new Student()
    console.log(s.name,s.age);
    s.eating()
    s.study()
// 优点:实现了继承
// 弊端:
// 1、打印对象, 继承的属性是看不到的
// 2、存在引用值共享问题,就是当a中某个属性是引用数据类型的时候,b实例如果修改了这个属性的内容则其他的b实例中这个属性也会一起改变(正常来说应该是互不干扰的,原始数据类型属性就是互不干扰的)
// 3、实现类的过程中都没有传递参数


2、构造函数继承


// 父类: 公共属性和方法
    function Person(name,age) {
        //this Person的实例对象
        this.name = name //Student实例对象.name=name
        this.age = age
        this.friends = []
    }
    Person.prototype.eating = function () {
        console.log(this.name + " eating~")
    }
    // 子类: 特有属性和方法
    function Student(name,age,sno) {
        // this Student的实例对象
        Person.call(this,name,age)//改变Person构造函数中的this指向
        this.sno = sno //学号
    }
    Student.prototype = new Person()
    Student.prototype.study = function () {
        console.log('学生学习');
    }
    var stu1 = new Student("lilei",18,112)
    var stu2 = new Student("马六",18,112)
    console.log(stu1);
    stu1.friends.push('kabe')
    console.log(stu2);
// 弊端:
// 1、使用这种方法stu实例没有办法拿到Person函数原型上的属性和方法。
// 2、组合继承最大的问题就是无论在什么情况下,都会调用两次父类构造函数。一次在创建子类原型的时候;另一次在子类构造函数内部(也就是每次创建子类实例的时候);


3、寄生组合式


// 父类: 公共属性和方法
    function Person(name,age) {
        //this Person的实例对象
        this.name = name //Student实例对象.name=name
        this.age = age
        this.friends = []
    }
    Person.prototype.eating = function () {
        console.log(this.name + " eating~")
    }
    // console.log(Object.keys(Person.prototype));
    // 子类: 特有属性和方法
    function Student(name,age,sno) {
        // this Student的实例对象
        Person.call(this,name,age)//改变Person构造函数中的this指向
        this.sno = sno //学号
    }
    function Coder(name,age,lang){
        Person.call(this,name,age)
        this.lang=lang
    }
    //为每一个子类创建一个原型对象 让原型对象的隐式原型属性指向父类原型对象
    // Student.prototype=Object.create(Person.prototype)
    // Student.prototype.constructor=Student
Student.prototype=Object.defineProperty(Object.create(Person.prototype),'constructor',{
        value:Student
    })
    Student.prototype.study=function(){
        console.log('学生学习');
    }
    console.log(Object.keys(Student.prototype));
    const stu=new Student('zs',18,1198)
    console.log(stu);
    //创建了一个Coder的原型对象
    Coder.prototype=Object.create(Person.prototype)
    const c=new Coder('zsc',19,'java')
    console.log(c);
// 弊端:通过Object.create改变Student原型的指向后,Student原型上原有的属性和方法就消失了。


4、es6的extends类继承


class Person{
    constructor(n,a){
        this.name=n
        this.age=a
    }
    eating(){
        console.log('吃饭');
    }
}
class Student extends Person{
    constructor(name,age,sno){
        super(name,age)
        this.sno=sno
    }
    study(){
        console.log('学习');
    }
}
const s=new Student('zs',18,1111)
console.log(s);


四、this指向


1、函数的this指向


函数中的this始终指向函数的调用者


//全局作用域中的this指向 window
    console.log(this);
    //函数中的this指向 函数的调用者
    console.log(window);
    window.test()
    test()
    function test(){
        console.log(this);
    }
    const obj={
        name:'obj',
        fn:function(){
            console.log(this);
        }
    }
    obj.fn()//obj
    //箭头函数中的this指向 函数定义时的作用域中的this指向
    const obj1={
        name:'obj1',
        fn:()=>{
            console.log(this);
        }
    }
    obj1.fn()//window
    //在事件中,`this`指向触发这个事件的对象(dom)
    document.querySelector('#btn').onclick=function(){
        console.log(this);
    }


2、改变函数的this指向 call 、 apply 、 bind


function fn(n,m){
  console.log(n,m,this);
}
var obj={
  name:'zsc'
}
fn()// window
//需求: fn中的this指向 obj  obj.fn()
// 1.实现方案: 将函数放置在obj中
obj.fn=fn
obj.fn()
// 2.利用函数对象方法 call apply bind
// 注意: 使用call 和 apply方法时 是在调用该函数
fn.call(obj,1,2)
fn.apply(obj,[1,2])
var newfn=fn.bind(obj) //在调用bind方法时 函数并没有被调用
newfn(1,2)


call apply bind的区别【重点】:


call 和 apply 在调用时 函数会执行 ,而 bind 在调用时会返回一个新的函数 需要进行手动调用


call 和apply 再使用基本类似 但是在传参的时候 call 能够从第2个参数开始接收一个参数序列 a,b,c… apply方法在传参时需要将第二个参数设置为数组


3、绑定this指向的方式


默认绑定:全局环境中,this默认绑定到window


隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象


隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。


显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定


new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定


构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值


如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果


如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象


五、new关键字具体做了什么


p1. 在内存中创建一个新的对象(空对象);


p2. 这个对象内部的[[Prototype]]属性会被赋值为该构造函数的prototype属性;


p3. 构造函数内部的this,会指向创建出来的新对象;


p4. 执行函数的内部代码(函数体代码);


p5. 如果构造函数没有返回非空对象,则返回创建出来的新对象;


function Student(){
    1. const obj={}  // 创建一个空对象
    2. obj.[[Prototype]]=Student.prototype  // 把当前构造函数得原型赋给创建出来对象得隐式原型
    3. this=obj  // this,会指向创建出来的新对象;
    以上代码全部有js解析器执行 程序员看不到摸不着 
    //4.接下来就是执行程序猿所写代码了
    this.name=name
    this.age=age
    this.study=function(){
        console.log(`我是${this.name},我能够快乐的学习`);
    }
    //程序员所写代码执行完毕
    5.return  this //程序员看不到
}

目录
相关文章
|
20天前
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(三)
深入JS面向对象(原型-继承)
32 0
|
20天前
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
35 0
|
9月前
js- 面向对象进阶
Object.defineProperty等面向对象的信息
|
9月前
|
存储 JavaScript 前端开发
|
18天前
|
前端开发 JavaScript
前端 JS 经典:Class 面向对象
前端 JS 经典:Class 面向对象
12 1
|
19天前
|
JavaScript 前端开发
JavaScript 原型链继承:掌握面向对象的基础
JavaScript 原型链继承:掌握面向对象的基础
|
20天前
|
JavaScript 前端开发 API
在Node.js上使用dojo库进行面向对象web应用开发
请注意,虽然这个例子在Node.js环境中使用了Dojo,但Dojo的许多功能(例如DOM操作和AJAX请求)在Node.js环境中可能无法正常工作。因此,如果你打算在Node.js环境中使用Dojo,你可能需要查找一些适用于服务器端JavaScript的替代方案。
20 0
|
20天前
|
JSON JavaScript 前端开发
深入JS面向对象(原型-继承)(四)
深入JS面向对象(原型-继承)
28 0
|
20天前
|
设计模式 JavaScript 前端开发
深入JS面向对象(原型-继承)(二)
深入JS面向对象(原型-继承)
46 0
|
20天前
|
设计模式 前端开发 JavaScript
深入认识:JavaScript中的面向对象
深入认识:JavaScript中的面向对象
20 0