对象_原型_原型链_继承

1、OOP 指什么?有哪些特性?

OOP是object oriented programming - 面向对象编程的缩写。 它具有三大特性: 封装、继承、多态。

  1. 封装:隐藏对象的属性和实现细节,仅对外公开接口
  2. 继承:子类能继承父类的属性和方法
    子类能添加新的属性和方法,还能重写父类的属性和方法
  3. 多态:指同一个实体同时具有多种形式,同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。

在面向对象程序设计中有两个重要概念

  1. 类:类是对现实生活中一类具有共同特征的事物的抽象

  2. 对象:对象是类的实例,对象包含属性和方法,属性是需要记忆的信息,方法是对象能够提供的服务。

2、如何通过构造函数的方式创建一个拥有属性和方法的对象?

属性可以通过this.xxx = xxx的方式直接赋值,方法可以通过this.prototype.xxx = function(){}的方式创建

//定义构造函数,默认命名第一个字母为大写
function People(name,age){
    this.name = name
    this.age = age
}
people.prototype.slogan = function(){
    console.log(this.name + ' is ' + this.age + ' years old ')     //jirengu is 30 years old
}
//使用new操作符进行实例化
var people = new Peoole('aaa',30)
people.slogan()   

3、prototype 是什么?有什么特性

  • JavaScript的每个对象都继承另一个对象,后者称为“原型”(prototype)对象。只有null除外,它没有自己的原型对象。
  • 原型对象上的所有属性和方法,都能被派生对象共享。
  • 通过构造函数生成实例对象时,会自动为实例对象分配原型对象。每一个构造函数都有一个prototype 属性,这个属性就是实例对象的原型对象。
  • prototype里的属性一旦更改,其实例内也将发生变化

在JavaScript中,所有的对象都是基于 Object;
所有的对象都继承了Object.prototype的属性和方法,它们可以被覆盖(除了以null为原型的对象,如 Object.create(null))。例如,新的构造函数的原型覆盖原来的构造函数的原型,提供它们自己的 toString() 方法.。对象的原型的改变会传播到所有对象上,除非这些属性和方法被其他对原型链更里层的改动所覆盖。
Object.prototype.constructor 用于创建一个对象的原型。
Object.prototype.proto 指向当对象被实例化的时候,用作原型的对象。

4、画出如下代码的原型图

function People (name){
  this.name = name;
  this.sayName = function(){
    console.log('my name is:' + this.name);
  }
}

People.prototype.walk = function(){
  console.log(this.name + ' is walking');  
}

var p1 = new People('aaa');
var p2 = new People('bbb');
原型图

原型链相关问题

问题7:有如下代码,解释Person、 prototype、proto、p、constructor之间的关联。

function Person(name){
    this.name = name;
}
Person.prototype.sayName = function(){
    console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
p._proto_ === Person.prototype   //ture,p是Person的实例对象,自动获得一个_proto_对象
Preson.prototype.constructor === Person  //ture

问题8: 上例中,对对象 p可以这样调用 p.toString()。toString是哪里来的? 画出原型图?并解释什么是原型链。

原型图

对象P是没有toString这个方法的,但是它有一个__proto__属性是指向Person.prototype,Person.prototype中也没有这个方法就沿着Person.prototype中的__proto__继续找,到了Object.prototype中就有了toString的方法,就可以调用了。这样沿着__proto__的“链”就是原型链。

问题9:对String做扩展,实现如下方式获取字符串中频率最高的字符

String.prototype.getMostOften = function(){
    var str = {}
    var max = 0 
    var max_key = ''

    for(var i = 0; i<this.length ;i++){
        var key = this[i]
        if(!str[key]){
            str[key] = 1
        }else{
            str[key]++
        }
    }
    for(key in str){
        if(str[key]>max){
            max = str[key]
            max_key = key
        }
    }
    return max_key
} 

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次

问题10: instanceOf有什么作用?内部逻辑是如何实现的?

instanceOf用来判断对象是否是另一个的对象的实例,并返回布尔值。

内部逻辑:顺着对象的原型连一直往上找,若原型链上的某一个__proto__指向了构造函数的prototype则返回true,找完了原型链也找不到则返回false。

Object.prototype.instanceOf = function(obj1,obj2){
        var obj1 = obj1.__proto__;
        while(obj1.__proto__){
          if(obj1 === obj2.prototype){
                   return true;
          }else{
              obj1 = obj1.__proto__;
             }
                return false;
        }

继承相关问题

问题11:继承有什么作用?

继承是指一个对象直接使用另一个对象的属性和方法,提高重用性,减少代码内存

问题12: 下面两种写法有什么区别?

//方法1
function People(name, sex){
    this.name = name;
    this.sex = sex;
    this.printName = function(){
        console.log(this.name);
    }
}
var p1 = new People('饥人谷', 2)

//方法2
function Person(name, sex){
    this.name = name;
    this.sex = sex;
}

Person.prototype.printName = function(){
    console.log(this.name);
}
var p1 = new Person('若愚', 27);

方法1:是将所有的属性和方法都写在构造函数中,每次新建对象都要创建一个printName函数,会造成很大的内存浪费。

方法2:把printName函数写在原型链上,新建对象可以共享这个方法,节省内存。

问题13: Object.create 有什么作用?兼容性如何?

Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。Object.create是在ES5中规定的,IE9以下无效。

问题14: hasOwnProperty有什么作用? 如何使用?

hasOwnPerperty是Object.prototype的一个方法,可以判断一个对象是否包含自定义属性而不是原型链上的属性,hasOwnProperty是JavaScript中唯一一个处理属性但是不查找原型链的函数。
用法

obj.hasOwnPerperty('key')    // true or false;

问题15:如下代码中call的作用是什么?

function Person(name, sex){
    this.name = name;
    this.sex = sex;
}
function Male(name, sex, age){
    Person.call(this, name, sex);    //这里的 call 有什么作用?
    this.age = age;
}

调用Person函数,使Male函数能够执行Person上的初始化代码,实现构造函数继承,并且使Person执行时的this指向Male

问题16: 补全代码,实现继承

function Person(name, sex){
    this.name = name
    this.sex = sex
}
Person.prototype.getName = function(){
    console.log('my name is '+ this.name)
};    


function Male(name, sex, age){
    Person.call(this,name,sex)
    this.age = age
}
Male.prototype = Object.create(Person.prototype)
Male.prototype.constructor = Male

Male.prototype.printName = function(){
    console.log(this.name)
}
Male.prototype.getAge = function(){
    console.log('age is'+ this.age)
};

var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容