JavaScript面向对象学习笔记基础与进阶

本篇笔记适合有一定有js面向对象基础的同学看。笔记的思路是由整体到局部,有浅层到深层!

1.面向对象的概念

  • 如果我们将属性和功能理解成一个个工具,那么一个对象就是这些工具的集合,也就是工具包。
  • 传统方式是直接写细节,面向对象方式是先宏观思考,想出一个个工具,再写细节去实现这些工具

1.1.面向对象语法

我们知道,对象都有自己的属性和方法。所以用代码实现对象,就是分别实现它的属性和方法

构造函数放置属性,原型对象放置方法

function Person(name,age){
    this.name = name;
    this.age = age;
}

Person.prototype.getName = function(){
    console.log(this.name);
}
Person.prototype.getAge = function(){
    console.log(this.age);
}
var p = new Person("geekWeb",20);
p.getName();
p.getAge();

从上面的代码中可以看出,如果我们的属性和方法不止一个,这种方式写出来代码的冗余性很强。可以用json的形式写出来

function Person(option){
    this.name = option.name;
    this.age = option.age;
}

Person.prototype = {
    getName:function(){
        console.log(this.name);
    },
    getAge:function(){
        console.log(this.age);
    }
}

var p = new Person({name:"geekWeb",age:20});
p.getName();
p.getAge();

1.2.json

对于json,这里有几点补充理解:
1. json协议:是数据传输通用协议。它是一种前端与服务器端的数据交换格式,它不是语言,只是一个规范,按照这种规范写法就能实现数据传递
2. json字符串:后台传递给前端的数据格式一般是json字符串,我们需要将其转换成json对象,再做其他处理
3. json对象与json字符串的相互转换:
* json对象——>json字符串:JSON.stringify(obj)
* json字符串——>json对象:JSON.parse(string)
4. json与xml:
* 相同点:都是一种通用协议;都可以用来描述数据
* 不同点:
JSON相对于XML来讲,数据的体积小,传递的速度更快些。
json占用带宽小,xml占用带宽大,
json没有xml这么通用
json可以和js对象互相转换,和js是天生的一对,因此广泛用于前端开发

1.3.面向对象的作用:

  1. 面向对象编程
  2. 封装框架
  3. 数据绑定——将后台返回的json数据和前端的元素进行绑定

小结:其实面向对象的语法规范并不是特别重要,重要的是面向对象的编程思维:对于一个新事物,要用面向对象的思维根据实际需求进行分析

2.构造函数

构造函数:我们知道对象其实是使用函数实现的,并且对象本身也是一个函数。我们将用于创建对象的函数叫做构造函数。
1. 语法规范:
* 成员属性:this.name = …
* 成员方法:this.getName = function(){…}
2. 属性访问与修改:使用点语法
3. 属性遍历:for…in
4. 万物皆属性,万物皆变量

变量声明提升与函数声明提升

当前作用域内的变量、函数声明都会提升到作用域的最前面。
* 变量提升的只是声明,并没有赋值
* 对于函数,如果采用函数声明式语法function fn(){…},会提升整个函数体;而如果采用函数表达式语法var fn = function(){…},提升的只是变量的声明,函数体并没有声明。

var name = 'geekWeb';
function fn(){
    console.log(name);
    getName();
    var name = "geekWeb1";
    var getName = function(){
        console.log('geekWeb2');
    }
    function getName(){
        console.log('geekWeb3');
    }

}
fn();

输出:undefined geekWeb3
解析:由于变量、函数提升,实际的代码执行为:

var name = 'geekWeb';
function fn(){
    var name,getName;
    function getName(){
        console.log('geekWeb3');
    }
    console.log(name);
    getName();
    name = "geekWeb1";
    getName = function(){
        console.log('geekWeb2');
    }
}
fn();

因为局部优先级大于全局,所以第一个参数打印结果为:undefined。

2.1.公有和私有

  • 有过后台语言经验的同学都知道,对象的属性、方法都包括公有和私有,通过设置不同的权限来达到一些不同的目的。
  • 在js中,对象的属性还有方法也有公私之分:设置私有属性就类似函数闭包一样,减少污染;设置私有方法可以让避免别人看见我们的代码核心逻辑
  • 注意几个点:
    1. 通过var定义私有属性和方法
    2. 私有属性直接访问即可,通过this.属性的方式是错误的!
function Person(option){
    // 设置公有属性
    this.name = option.name;
    this.age = option.age;
    // 设置私有属性
    var className = "私有属性";
    // 设置公有方法
    this.getAge = function(){
        console.log(this.age);
    }
    // 设置私有方法
    var publicFn = function(){
        console.log(this.name); // 访问公有属性
        console.log(className); // 访问私有属性,通过变量名直接访问
        console.log(this.className); // undefined,className是私有属性
    }
}

2.2.实例化

关于内存: 一切数据(数字、字符串、对象….)都是通过变量来管理,而定义变量的过程其实就是内存分配的过程,所以本质上:一切数据都是通过变量存放在内存中!
实例化的过程其实就是在内存中开辟新空间,拷贝构造函数属性并赋以实例的值的过程!
* 除了拷贝以外还会自动生成一个constructor属性,用于识别其是根据哪个构造函数创建的实例!

instanceof

判断某个实例是不是根据某个构造函数创建的

var p = new Person();
if(p instanceof Person){
    alert(true);
}

数据类型检测

JavaScript中可以将数据类型分为:
* 数值型:Number
* 布尔型:Boolean
* 字符串:String
* 对象:Object
* 数组:Array
* 空值:Null
* 未定义:Undefined

var num = 1
var str = 'geekWeb'
var bool=false;
var arr=[];
var obj={name:'geekWeb'};
var date = new Date();
var fn = function(){}
  1. typeof
console.log(typeof undefined)//'undefined'
console.log(typeof null) // 'object'
console.log(typeof true) //'boolean'
console.log(typeof 123)  //'number'
console.log(typeof "abc")  //'string'
console.log(typeof function() {}) //'function'
var arr=[];
console.log(typeof {}) //'object'
console.log(typeof arr)//'object'
console.log(typeof unknownVariable) //'undefined'

在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。

  1. toString.call

    • toString.call(r)其实就是r.toString
console.log(toString.call(123))          //[object Number]
console.log(toString.call('123'))        //[object String]
console.log(toString.call(undefined))    //[object Undefined]
console.log(toString.call(true))         //[object Boolean]
console.log(toString.call({}))           //[object Object]
console.log(toString.call([]))           //[object Array]
console.log(toString.call(function(){})) //[object Function]

console.log(Object.prototype.toString.call(str) === '[object String]')   //-------> true;
console.log(Object.prototype.toString.call(num) === '[object Number]')   //-------> true;
console.log(Object.prototype.toString.call(arr) === '[object Array]')    //-------> true;
console.log(Object.prototype.toString.call(date) === '[object Date]')     //-------> true;
console.log(Object.prototype.toString.call(fn) === '[object Function]') //-------> true;
  1. instanceof
console.log(arr instanceof Array)     //---------------> true
console.log(date instanceof Date)     //---------------> true
console.log(fn instanceof Function)   //------------> true
//    alert(f instanceof function)        //------------> false
//    注意:instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
  1. constructor
console.log(arr.constructor === Array)   //----------> true
console.log(date.constructor === Date)   //-----------> true
console.log(fn.constructor === Function) //-------> true
  1. 在jQuery中,也提供了一些列的工具方法用来判断数据类型
    jQuery.isArray():是否为数组。
    jQuery.isEmptyObject():是否为空对象(不含可枚举的属性)。
    jQuery.isFunction():是否为函数。
    jQuery.isNumeric():是否为数字。
    jQuery.isPlainObject():是否为使用“{}”或“new Object”生成的对象,而不是浏览器原生提供的对象。
    jQuery.isWindow():是否为window对象。
    jQuery.isXMLDoc():判断一个DOM节点是否处于XML文档之中。

3.原型对象

为什么要引入原型对象:我们知道,每次实例化都需要分配内存存储这些数据,如果实例很多,那就要分配很多内存存储。而一般每个实例的属性不一样但行为是一样的,所以我们希望每次实例化的时候,只分配内存保存不一样的数据。而像方法,可以之分配一次空间,所有的实例共享这些方法,那就需要原型对象
原型对象:不管实例化多少次,都只会分配一次内存!它的本质是,原型对象中的属性和方法被所有的实例所共享。
结论: 将公有方法放在原型对象中,将不一样的属性放在构造函数中。

3.1.双对象法则和双隐藏属性法则

  • 通过原型实例化对象,其实是创建了两个对象:
    1. 构造函数对象
    2. 原型对象
  • 当我们实例化的时候,该实例自动拷贝构造函数的所有属性和方法,而对于原型对象,则不拷贝,而是通过一个属性‘铁链’
  • 其实,任何实例都隐藏了很多属性,这其中就包括:
    1. contructor:该实例的构造函数方法
    2. prototype:将实例和原型对象连在一起,这样我们就可以访问到原型对象中的方法,而不用拷贝

3.2.原型链

那么既然实例不拷贝原型中的属性方法,如何访问到其属性呢??通过原型链
JavaScript面向对象学习笔记基础与进阶_第1张图片

属性搜索机制:

先在自己的属性列表中寻找,如果找到则直接返回,如果找不到,则先找自身的一个隐藏属性proto,通过proto属性中保存的地址来链

属性屏蔽理论:

如果构造函数和原型中有相同的属性
1. 根据属性搜索机制,原型中的属性会被屏蔽掉
2. 如果想要访问原型中的属性,有两种方法
1. delete:delete product.name
2. 使用全称:Product.prototype.name

3.3.属性判断:

hasOwnProperty() 方法

该方法继承自 Object,判断一个属性是不是对象自身的属性
1. 用在普通对象上,可以判定一个属性是存在于构造对象的实例上还是原型对象上。
+ 如果是实例对象—ture
+ 如果是原型对象 – false
2. 用在json对象上,可以判断属性是不是该对象的直接属性

var iphone = {
    name:'iphone',
    age:100,
    address:{home:'江苏',current:'北京昌平'}
}
console.log(iphone.hasOwnProperty('name'))      //true
console.log(iphone.hasOwnProperty('age'))       //true
console.log(iphone.hasOwnProperty('address'))   //true
console.log(iphone.hasOwnProperty('home'))      //false

3.3.几个术语

有过后台语言基础的同学都知道,高级语言面向对象很多都有继承、多态、重写、覆盖的概念。虽然js本不是面向对象的语言,但是我们可以将js中一些面向对象的行为强行按照高级语言的那些概念上理解。

1.继承

构造函数创建的实例为什么能访问原型对象的方法属性?
原型对象继承了构造函数对象,因而可以访问构造函数对象的一切方法,属性。

2.重载

函数参数列表不同,包括个数、名称、顺序

 3.覆盖

对于构造函数中已经有的属性和方法,在原型对象中又定义了同样的属性、方法,可以理解成覆盖。
但是根据属性屏蔽理论,优先访问构造函数中的属性和方法。

 4.内存机制

想深入学习js,必须知道它的内存机制

4.1.内存分配

学习内存分配之前,先要了解两种数据类型:
* 值类型:Number,String,Boolean,Undefined
* 引用类型:函数,数组,对象,Null,new Number()…
这两种数据类型在内存中的分配为:
* 栈内存:存放值类型和;存放引用类型的变量,变量中保存的是对象所在的地址
* 堆内存:存放对象真正保存的数据
可以总结值类型和引用类型的区别:
1. 内存分配机制不一样
* 值类型:创建一个变量,在栈内存中创建一个区域
* 引用类型:创建一个变量,在栈内存中保存的是变量真实入口的地址,在堆内存中保存的是对象真正保存的数据
2. 变量赋值是否的区别
* 值类型赋值,重新分配一个内存
* 引用类型赋值,只是复制了一个入口地址,指向的是同一块堆内存
用一个图形象描述:

JavaScript面向对象学习笔记基础与进阶_第2张图片

小结:一切数据都是通过变量来管理,定义变量的过程其实就是分配内存的过程!所以,一切数据否是通过变量来存储的
从一个简单例子来理解js引用类型指针的工作方式

4.2.内存生命周期

js分配的内存一般有三个生命周期:内存分配,内存使用,内存回收

4.2.1内存回收

js中的内存回收其实就是自动释放内存的过程。
1. 值类型自动释放内存:函数执行时,将值类型变量存放在栈内存中,函数执行完成,将值类型变量从栈内存中释放。闭包除外
2. 引用类型自动释放内存:通过引用计数来实现。每当实例化一次,引用计数就+1,当实例化被释放,引用计数-1。当引用计数为0时,内存完全释放,为空!

4.2.2内存泄露

内存泄露是指一块被分配的内存既不能使用,又不能回收,这样泄露越多,最终导致占用内存越来越多,最终使得应用崩溃,甚至导致浏览器崩溃,最恶毒的就是导致系统也崩溃

5.多种方式创建对象

创建对象的几种方式:
1. 字面量
2. Object
3. 内置对象
4. 构造函数
5. 原型对象
6. 拷贝模式
7. 工厂模式
8. 第三方

5.1.object创建对象

var o = new Object(); // 创建一个空对象,效果等同{}.

获取/设置对象的值:

  1. 点语法:p.name
  2. 中括号:p[‘name’];

5.2.工厂模式创建对象:

很多时候,我们初始化一些对象时,它的属性值和方法都是一样的,我们希望执行函数时就直接生成一个对象。对于不一样的属性,通过参数的形式暴露出来。

function createPerson(name){
    //1.原料
    var obj = new Object();
    //2.加工
    obj.name = name;
    obj.HP=100;
    obj.MP=100;
    obj.technologys=['普通攻击','横扫千军','地狱火','漫天飞雪'];
    obj.attack = function(){
        alert(obj.name+'发出攻击,导致对方10点伤害值')
    };
    obj.run = function(){
    };
    //3.出场
    return obj;
}
var boy = createPerson('剑侠客');
boy.attack();
boy.run()

对象不需要new 直接运行函数即可(工厂加工一下)

5.3.拷贝模式创建对象

核心:将一个json对象的所有属性拷贝给另一个对象

// target:目标对象
// source:原始对象
function extend(target,source) {
    //遍历对象
    for(var i in source){
        target[i] = source[i];
    }
    return target;
}

使用:

var boy = {
    name:'郭靖'
    ,image:'男性头像'
    ,age:20
    ,sex:'男'
};

var girl = {
    name:'黄蓉'
    ,age:18
    ,image:'女性头像'
    ,sex:'女'
};

var zuixiake = extend({}, boy);
var huangrong = extend({},girl)

6.js中的对象

在js中万物皆对象。可以将对象分为三类:
1. BOM对象:windows,document,location,history,navigator,screen…
2. 内置对象:
3. 自定义对象

6.1.BOM对象

Browser Object Model 浏览器对象模型

6.1.1.Windows对象

任何我们自定义的全局变量,全局函数,全局对象等都会成为Windows对象的属性。
1. 全局常量:Infinity,NaN,undefined,null
* Infinity:表示js中能识别的最大值
* NaN:是Number类型,表示“不是数字”的数字。它不可以参与运算
* isNaN():判断某个数是不是NaN,即判断某个数是不是可以参与运算
2. 全局方法:eval(), isFinite(), isNaN(), parseFloat(), parseInt(),decodeURI(),decodeURIComponent(), encodeURI(), encodeURIComponent()
3. 弹出框:
* alert() 对话框中有一个确认按钮
* confirm() 对话框中有一个确认和取消按钮
* prompt() 对话框中有一个文本输入框,一个确认和取消按钮
4. 新窗口:open()打开一个新窗体; close()关闭窗体
5. 窗体控制
* moveBy(x,y) 从当前位置水平移动窗体x个像素,垂直移动窗体y个像素,x为负数,将向左移动窗体,y为负数,将向上移动窗体
* moveTo(x,y) 移动窗体左上角到相对于屏幕左上角的(x,y)点,当使用负数做为参数时会吧窗体移出屏幕的可视区域
* resizeBy(w,h) 相对窗体当前的大小,宽度调整w个像素,高度调整h个像素。如果参数为负值,将缩小窗体,反之扩大窗体
* resizeTo(w,h) 把窗体宽度调整为w个像素,高度调整为h个像素
6. 窗体滚动轴控制:
* scrollTo(x,y) 在窗体中如果有滚动条,将横向滚动条移动到相对于窗体宽度为x个像素的位置,将纵向滚动条移动到相对于窗体高度为y个像素的位置
* scrollBy(x,y) 如果有滚动条,将横向滚动条移动到相对于当前横向滚动条的x个像素的位置(就是向左移动x像素),将纵向滚动条移动到相对于当前纵向滚动条高度为y个像素的位置(就是向下移动y像素)

6.1.2.Location对象

地址栏,一般包括url网址,协议,端口号,查询字符串
1. 属性:
* hash 设置或返回从井号 (#) 开始的 URL(锚)
* host 设置或返回主机名和当前 URL 的端口号
* hostname 设置或返回当前 URL 的主机名
* href 设置或返回完整的 URL
* pathname 设置或返回当前 URL 的路径部分
* port 设置或返回当前 URL 的端口号
* protocol 设置或返回当前 URL 的协议
* search 设置或返回从问号 (?) 开始的 URL(查询部分)
2. 方法:
* assign(),reload(),replace()…

查询字符串

  • test.html?geekWeb,2013303056
  • 查询字符串就是?geekWeb,2013303056
    方法:
    * window.location.href: 返回test.html?geekWeb,2013303056
    * window.location.search: 返回?geekWeb,2013303056

6.1.3.History对象

  1. 属性:length 返回浏览器历史列表中的url数量
  2. 方法:go(-1)返回上一页; .back() 后退; .forward() 前进

6.1.4.Document对象

DOM是我们学习的重点,涉及的知识点特别多。考虑到篇幅问题吗,不多做讲解。
* 我们编写的html内容会被编写成dom舒
* 操作dom树,其实就是对其增删改查
*
1. 普通属性:
JavaScript面向对象学习笔记基础与进阶_第3张图片

  1. 集合属性:
    JavaScript面向对象学习笔记基础与进阶_第4张图片

  2. 方法:
    JavaScript面向对象学习笔记基础与进阶_第5张图片

6.2.内置对象

  • Object对象
  • Array对象
  • 函数对象Function – 详解 重点
  • 字符串对象String
  • 数学对象Math
  • 日期对象Date
  • 正则表达式对象Reg
  • 数字对象Number
  • 错误对象Error

Function对象

js中每个函数都是一个Function对象。对象都是通过函数实现的

Arguments

保存函数实参的组成的伪数组
伪数组:是一个包含length属性的json对象。特点:
* key是1,2,3…(起始不确定,由自己决定)
* 含有length属性,伪数组每次都要自己去计算length长度
* 不是数组,没有数组对象的方法

var json = {1:'',2:'',length:2}

arguments,通过document获取的数组都是伪数组,jQuery也是通过伪数组实现的 !

将伪数组转化为真数组

Array.prototype.slice.call(weiArr)

var fackArray1 = {0:'first',1:'second',length:2};
Array.prototype.slice.call(fackArray1);//  ["first", "second"]
var fackArray2 = {length:2};
Array.prototype.slice.call(fackArray2);//  [undefined, undefined]
callee

callee是arguments 的一个属性成员,它表示对函数对象本身的引用,返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文。常见用法:
1. 判断实参与形参个数是否一致
* argument.length:实参
* argument.callee.length:形参
2. 用于递归

// 传统方式
var fn=function(n){
    if(n>0) return n+fn(n-1);
    return 0;
}

// callee方式
var fn1=(function(n){
    if(n>0) return n+arguments.callee(n-1);
    return 0;
})(10);
caller

返回函数的调用者

call

作用:
1. 借用:一个对象借用另一个对象的方法
2. 更改被借用方法的this指向,指向自身

function add(a, b) {
    alert(a + b);
}

function sub(a, b) {
    alert(a - b);
}

add.call(sub, 3, 1); // 4 
用户名:"text" id="myText"   value="input内容" />
<script>
    var value = 'geekWeb'
    function Fn1(){
        console.log(this.value); // geekWeb
    }
    Fn1();
    Fn1.call(document.getElementById('myText')); // input内容
script>

apply

apply的功能用法与call一模一样。
它与call的区别:
* call传递是参数是平铺
* apply传递的参数是数组,使用的时候它会将数组拆分成很多个参数
使用apply借用的方法,参数必须是可变的

计算数组最大值:

function getMax(arr){
    return Math.max.apply(null,arr);
   /* return Math.max.call(null,1,2,3,4,5);*/
}

拼接两个数组

Array.prototype.push.apply(arr1,arr2);

可以使用apply实现继承构造函数中的属性方法,不能继承原型对象中的属性方法。

function Person(name,age){
    this.name=name     //名字
    this.age=age       //年龄
    this.sayhello=function(){
        console.log("人对象方法")
    }
}
Person.prototype={
    buy:function(){
        console.log('测试是否能够继承原型中的方法')
    }
}

//输出打印对象
function Print(){            //显示类的属性
    this.funcName="我是打印对象"
    this.show=function(){
       console.log ('打印对象方法')
    }
}

//学生对象
function Student(name,age,grade,school){    //学生类
    Person.apply(this,arguments)
    Print.apply(this,arguments)
    this.grade=grade                  //年级
    this.school=school                    //学校
}

Error对象

当我们代码写错的时候,会定义一个对象用于保存出错的场景,各种信息等。使用try catch

try{
  // 要检测的执行语句
}catch(e){
  // 当出现错误时,执行的语句
}finally{
  // 一定会执行的语句
}

属性:
* e.message:返回错误信息
* e.name:返回错误类型

7.深度理解js中的原型链

在理解原型链之前我们先来了解两个概念:prototype,proto
* prototype:是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。
* proto是一个对象拥有的内置属性,是JS内部使用寻找原型链的属性。
注意:prototype是函数的内置属性,proto是对象的内置属性

new过程

new的过程拆分成以下三步:

var Person = function(){};
var p = new Person();

(1) 初始化一个空对象p,拷贝构造函数中的属性方法:var p={};
(2) p.proto = Person.prototype;
(3) 构造p对象:Person.call(p);

属性搜索机制

首先在构造函数中寻找属性方法,如果没有找到,就通过实例对象的隐藏属性proto寻找原型对象Person.prototype中属性方法,如果没有找到继续向上寻找,直至proto为null
所以:属性搜索机制的底层就是通过proto属性链接起来的

Object的proto属性

Object对象是Function对象的一个实例,所以Object的proto属性指向Function对象的原型

Object.__proto__ === Function.prototype

Object.prototype也是对象,也有proto属性,其为null

Object.prototype.__proto__ === null

Object的实例对象obj也是对象,它的proto属性为Object的原型对象:Object.prototype
所以,有:

obj.__proto__ === Object.prototype === Function.prototype.__proto__ === Object{...}

内置对象的proto属性

和Object对象一样,所有的内置对象都是Function对象的一个实例,所以他们的proto属性指向Function对象的原型

Number.__proto__ === Function.prototype  // true
Boolean.__proto__ === Function.prototype // true
String.__proto__ === Function.prototype  // true
Object.__proto__ === Function.prototype  // true
Function.__proto__ === Function.prototype //true 
Array.__proto__ === Function.prototype   // true
RegExp.__proto__ === Function.prototype  // true
Error.__proto__ === Function.prototype   // true
Date.__proto__ === Function.prototype    // true

和Object对象一致:内置对象对应的实例对象的proto属性指向它们构造函数的prototype属性

num.__proto__ === Number.prototype === Function.prototype.__proto__ === Number{...}

自定义对象的proto属性

自定义对象是Function对象的实例对象,所以他的proto属性指向Function对象的原型

Person.__proto__ === Function.prototype

自定义对象原型对象的proto执行Object的原型对象

Person.prototype.__proto__ === Object.prototype

总结:

  • Object,内置对象,自定义对象是函数,也是Function对象实例,所以它们的proto属性指向Function对象的原型
  • Object.prototype是一切链式循环的终点,但是Object对象本身也是Function的一个对象实例
  • 一个自定义对象可以访问到Function对象的所有属性和方法,也可以访问到Object对象的所有属性和方法
    JavaScript面向对象学习笔记基础与进阶_第6张图片

8.面向对象的3大特性

当前主流语言都是面向对象的语言,那么面向对象的特性是什么?封装,继承,多态。

继承

将相同的属性,方法定义在父类中,将自身独特的属性,方法定义在子类。这样,子类既拥有父类的属性方法(共性),也拥有自身的属性方法(特性)

继承语法结构

分两步:
第一步,构造函数继承: Person.call(this, a,b); 使用call或者apply都可以
第二步,原型继承:Student.prototype = new Person();

//基类 父类
var Person = function(){
    this.name = '张三';
    this.age = 20;
}
Person.prototype = {
    say : function(){
        console.log('Person.prototype - say');
    }
}

var Student = function(){
    Person.call(this, a,b);
    //子类也可以拥有自己的一些属性和方法
    this.sID='000001'
    this.jiemu = '唱歌'
    this.luobenTimes= 0
}

//原型继承
Student.prototype = new Person();

//子类也可以拥有自己的一些属性和方法
Student.prototype.getTeacher = function(){
    console.log('王书奎');
}
  1. 继承的本质就是通过proto指针指向某个对象,系统能够自动链式访问所指向对象的属性方法。所以,js中一切对象都继承自Object
  2. 继承的多种方式
    • 构造函数继承:不能继承父类原型对象的属性方法
    • 原型继承:无法通过传参定义对象,在Student的构造方法中,无法使用new Student(“201303056”,”geekWeb”,22)创建对象。要想创建对象并且初始化那么,age属性,必须通过stu.name和stu.age的方式进行赋值
    • 混合方式:通常就是这么用。构造函数继承属性,原型对象继承方法。缺点是,无论什么时候都会调用超过两个父类的构造函数:一次是创建子类原型时;一次是在子类构造函数内部

封装

将属性方法归到一个类中,以保证类的属性或方法不被外部看见,这就是对象的封装性。

多态

面向对象程序运行时,相同的消息会送给多个不同类的对象,而系统可根据对象所属类,引发对应类的方法,而有不同的行为。
js不直接支持多态

你可能感兴趣的:(JavaScript)