详解JavaScript对象继承方式
一、对象冒充
其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 Parent 构造函数
成为 Children 的方法,然后调用它。Children 就会收到 Parent 的构造函数中定义的属性和方法。例如,用下面的方式定义 Parent 和 Children:
- ]// 父类构造函数
- var Parent = function(name){
- this.name = name;
- this.sayHi = function(){
- console.log("Hi! " + this.name + ".");
- }
- };
- // 子类构造函数
- var Children = function(name){
- this.method = Parent;
- this.method(name); // 实现继承的关键
- delete this.method;
- this.getName = function(){
- console.log(this.name);
- }
- };
- var p = new Parent("john");
- var c = new Children("joe");
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! joe.
- c.getName(); // 输出: jo
原理:就是把 Parent 构造函数放到 Children 构造函数里面执行一次。那为什么不直接执行,非要转个弯把 Parent 赋值给 Children 的 method 属性再执行呢?
这跟 this 的指向有关,在函数内 this 是指向 window 的。当将 Parent 赋值给 Children 的 method 时, this 就指向了 Children 类的实例。
二、原型链继承
众所周知,JavaScript 是一门基于原型的语言,在 JavaScript 中 prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制:
- // 父类构造函数
- var Parent = function(){
- this.name = "john";
- this.sayHi = function(){
- console.log("Hi! " + this.name + ".");
- }
- };
- // 子类构造函数
- var Children = function(){};
- Children.prototype = new Parent(); // 实现继承的关键
- var p = new Parent();
- var c = new Children();
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! john.
注意:调用 Parent 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
三、使用 call 或 applay 方法
这个方法是与对象冒充方法最相似的方法,因为它也是通过改变了 this 的指向而实现继承:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- this.sayHi = function(){
- console.log("Hi! " + this.name + ".");
- }
- };
- // 子类构造函数
- var Children = function(name){
- Parent.call(this, name); // 实现继承的关键
- this.getName = function(){
- console.log(this.name);
- }
- };
- var p = new Parent("john");
- var c = new Children("joe");
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! john.
- c.getName(); // 输出: joe
apply 方法本人就不举列了,它和 call 方法的区别在于它的第二个参数必须是数组。
四、混合方式
对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。如何选择呢?答案很简单,两者都用。
在 JavaScript 中创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- };
- Parent.prototype.sayHi = function(){
- console.log("Hi! " + this.name + ".");
- };
- // 子类构造函数
- var Children = function(name, age){
- Parent.call(this, name); // 实现继承的关键
- this.age = age;
- };
- Children.prototype = new Parent(); // 实现继承的关键
- Children.prototype.getAge = function(){
- console.log(this.age);
- };
- var p = new Parent("john");
- var c = new Children("joe",30);
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! joe.
- c.getAge(); // 输出: 30
五、使用Object.create 方法
Object.create 方法会使用指定的原型对象及其属性去创建一个新的对象:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- };
- Parent.prototype.sayHi = function(){
- console.log("Hi! " + this.name + ".");
- };
- // 子类构造函数
- var Children = function(name, age){
- Parent.call(this, name); // 实现继承的关键
- this.age = age;
- };
- Children.prototype = Object.create(Parent.prototype); // 实现继承的关键
- Children.prototype.constructor = Children; // @
- Children.prototype.getAge = function(){
- console.log(this.age);
- };
- var p = new Parent("john");
- var c = new Children("joe",30);
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! joe.
- c.getAge(); // 输出: 30
@ 当执行 Children.prototype = Object.create(Parent.prototype) 这个语句后,Children 的 constructor 就被改变为 Parent ,因此需要将 Children.prototype.constructor 重
新指定为 Children 自身。
六、extends 关键字实现继承
这个是 ES6 的语法糖,下面看下es6实现继承的方法:
- class Parent {
- constructor(name, age) {
- this.name = name;
- this.age = age;
- }
- }
- class Children extends Parent {
- constructor(name, age, job) {
- this.job = job; // 这里会报错
- super(name, age);
- this.job = job; // 正确
- }
- }
上面代码中,子类的constructor
方法没有调用super
之前,就使用this
关键字,结果报错,而放在super
方法之后就是正确的。子类Children
的构造函数之中的super()
,代表调用父类Parent的构造函数。这是必须的,否则 JavaScript 引擎会报错。
注意,super
虽然代表了父类Parent的构造函数,但是返回的是子类Children的实例,即super
内部的this
指的是Children,因此super()
在这里相当于Parent.prototype.constructor.call(this)
。
详解JavaScript对象继承方式的更多相关文章
- 详解Javascript的继承实现(二)
上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
- 详解Javascript的继承实现
我最早掌握的在js中实现继承的方法是在w3school学到的混合原型链和对象冒充的方法,在工作中,只要用到继承的时候,我都是用这个方法实现.它的实现简单,思路清晰:用对象冒充继承父类构造函数的属性,用 ...
- 一文详解JavaScript的继承模式
1 原型链继承 #### ES6中通过原型继承多个引用类型的属性和方法,由于原型和实例的关系,即每个构造函数都有自己的原型对象,同时原型有一个属性指向构造函数,并且实例有一个内部的指针指向原型.如果存 ...
- JavaScript对象继承方式
一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Parent 构造函数 成为 Children 的方法, ...
- 详解javascript中的this对象
详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...
- JavaScript 的对象继承方式,有几种写法?
JavaScript 的对象继承方式,有几种写法? 一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Pa ...
- 架构师JavaScript 的对象继承方式,有几种程序写法?
架构师JavaScript 的对象继承方式,有几种程序写法? 一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数, ...
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
随机推荐
- sql server 2008 sql prompt 自动提示
sql server 2008 在编写SQL脚本的时候,总是希望能提示一些信息,或者自动提示需要查询的表的名字,或者表的基本信息,sql server默认会有一些提示的,如果没有可以设置工具--> ...
- 算法精解:DAG有向无环图
DAG是公认的下一代区块链的标志.本文从算法基础去研究分析DAG算法,以及它是如何运用到区块链中,解决了当前区块链的哪些问题. 关键字:DAG,有向无环图,算法,背包,深度优先搜索,栈,BlockCh ...
- 一次日语翻译的Chrome插件开发经历
序言 去年7月刚过了日语N2,想着今年考个N1,为了加深日语文化的了解,还有学习日语,平时免不了经常上日语网站. 但是毕竟水平有限,所以不免遇到不认识的单词,日语单词的一个特点就是很多单词你知道是什么 ...
- 关于Eclipse无法识别手机或者模拟器的解决方案
Android开发的时候经常会出现eclipse devices中不显示手机或模拟器的情况 网上有很多方法,但是都不实用.这里我提供一种方法: 如果手机连接上了不显示的话首先我们要确定我们手机的驱动是 ...
- guava cache使用和源码分析
guava cache的优点和使用场景,用来判断业务中是否适合使用此缓存 介绍常用的方法,并给出示例,作为使用的参考 深入解读源码. guava简介 guava cache是一个本地缓存.有以下优点: ...
- 基于Jmeter的自动化测试实施方案设计
前言: Jmeter是目前最流行的一种测试工具,基于此工具我们搭建了一整套的自动化方案,包括了脚本添加配置.本地配置和运行.服务器配置等内容,完成了自动化测试闭环,通过这种快捷简便高效的方式,希望可以 ...
- 1-3 Spring Bean 的属性值设置
详见http://www.cnblogs.com/chenssy/archive/2013/03/17/2964593.html 1.注入普通的属性值 <bean id="Cat&qu ...
- Lucene-01:创建索引
我们在D盘下建一个文件夹叫lucene,lucene内再建两个文件夹,一个叫example,一个叫index01.example文件夹下三个txt文件,a.txt内容为hello java,b.txt ...
- Java多线程JUC
1. volatile 关键字 多线程访问的时候,一个比较严重的问题就是内存不可见,其实在内存访问的时候每一个线程都有一个自己的缓冲区,每次在做修改的时候都是从主存取到数据,然后放到自己的缓冲区中,在 ...
- Java飞机大战源代码
刚学不久java,做了一个飞机大战的小小小小游戏,现在把这个思路总结以及代码分享出来.大佬别吐槽(emmmmmm .....开发环境:jdk1.7 开发工具:eclipese PlanelJPanel ...