对象继承

A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法。这对于代码的复用是非常有用的。
JavaScript 语言的继承不通过 class (es6 中的class 不过是 prototype 的语法糖),而是通过“原型对象”`prototype`实现

#### 传统原型链式继承

- 过多的继承属性
- 比如一个函数用不到某个原型方法或属性,那么方法或属性就过剩了
function Grand(){};
Grand.prototype.name="grand"; let grand = new Grand(); Father.prototype=grand;
function Father(){}
let father = new Father(); Son.prototype=father;
function Son(){}
let son = new Son();

#### 借用构造函数 使用call/appply

- 不是真正继承,因为不能调用原型上的方法,而且每调用一次都会调用多次函数,实际上步骤没有变少
- 工业级推荐使用
- 缺点无法添加私有原型
function Father() { }

function Son() {
Father.call(this); // 调用父类构造函数
} Son.prototype.print = function() {
Father.prototype.print.call(this);//只使用单个方法
}
// 子类继承父类的原型
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;

#### 圣杯模式

>隐式附加的东西就私有化,可以公共定义的东西提取出来公有化
let inherit =(function(){
let Interim =function Interim() {};
return function (Target,Origin){//继承源
Interim.prototype =Object.create(Origin);
Target.prototype = Interim.prototype; //现在 可以 制定自己的私有属性,但是 constuctor 不是 原函数所一手动赋值回来,如果想要知道函数真正继承那个原型需要保存它
Target.prototype.constuctor = Target;
Target.prototype.yliluokka =Origin;
}
}())

#### 多重继承

JavaScript 不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过`Object.assign`,实现这个功能。这种模式称之为 Mixin (混入)
function Fn1(){ }
function Fn2(){ }
function Son(){
F1.call(this);
F2.call(this);
}
//继承F1
Son.prototype =Object.create(Fn1.prototype);
//继承F2
Object.assign(Son.prototype,Fn2.prototype);
Son.prototype.constructor =Son;
let a =new Son();

### call,apply and bind difference

-  都可改变函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。
 
 

#### call and apply

function test() {}
//test() == test.call() let obj ={};
Object.prototype.toString.call(obj) //"[object Object]"
//因为call 和 apply 会将函数中的this指向第一个参数
//相当于 obj.toString()
`call and apply` 二者区别在于传参:
- call 第二个参数开始单个单个参数传
- apply 第二个参数为数组或类数组
//返回数组中最大的数
let a = [1, 2, 4, 1, 15];
Math.max.apply(null, a) // //将数组的空元素变为undefined
Array.apply(null [1,,3,,4)//[1,undefined,3,undefined,4];
空元素与undefined的差别
- forEach方法会跳过空元素,但是不会跳过undefined。因此,遍历内部元素的时候,会得到不同的结果。
 
转换类似数组的对象
let obj={0: 1, length: 2}
Array.protetype.slice.apply(obj);//[1,undefined]
被处理的对象必须有length属性,以及相对应的数字键。

参数为空、null和undefined,则默认传入全局对象。

#### bind

bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
let counter = {
count: 0,
inc: function () {
this.count++;
}
}; let func = counter.inc.bind(counter);
func();
counter.count // let add = function (x, y) {
return x * this.m + y * this.n;
} let obj = {
m: 2,
n: 2
}; let newAdd = add.bind(obj, 5); //将x 绑定为 5
newAdd(5) //
newAdd(1,5)//

第一个参数是null或undefined,等于将this绑定到全局对象

#### bind方法使用注意点

- bind方法每运行一次,就返回一个新函数 需要一个变量接收
- 结合回调函数使用
let counter = {
count: 0,
inc: function () {
'use strict';
this.count++;
}
}; function callIt(callback) {
callback();
} callIt(counter.inc.bind(counter));
counter.count //
- 结合call方法使用
[1, 2, 3].slice(0, 1) // [1]
// 等同于
Array.prototype.slice.call([1, 2, 3], 0, 1) // [1] //将Array.prototype.slice变成Function.prototype.call方法所在的对象
//调用时就变成了Array.prototype.slice.call。 let slice = Function.prototype.call.bind(Array.prototype.slice);
Function.prototype.slice.call([1, 2, 3], 0, 1) // [1]
//slice([1, 2, 3], 0, 1) let push = Function.prototype.call.bind(Array.prototype.push);
let pop = Function.prototype.call.bind(Array.prototype.pop); let a = [1 ,2 ,3];
push(a, 4)
a // [1, 2, 3, 4] pop(a)
a // [1, 2, 3]
- 将Function.prototype.bind方法变成Function.prototype.call的方法,就意味着bind的调用形式也可以被改写
function f() {
console.log(this.v);
} let o = { v: 123 };
let bind = Function.prototype.call.bind(Function.prototype.bind);
bind(f, o)() //

### `Object 系统默认方法`

- `getPrototypeOf` 获取对象原型,只有一个参数
function Foo (){}
let obj = new Foo ();
Object.getPrototypeOf(obj) // Foo.prototype //空对象原型
Object.getPrototypeOf({}) // Object.prototype
// Object.prototype 原型
Object.getPrototypeOf(Object.prototype) //null
// Foo
Object.getPrototypeOf(Foo) // Function.prototype
- `setPrototypeOf` 设置对象原型
有两个参数:
1. 现有对象
2. 继承的原型对象
let now = {};
let pro = {name:"Owen"}; Object.setPrototypeOf(now,pro);
now.name //"Owen"
- `Object.create()`
> 生成实例对象的常用方法 参数必须为对象 或 null
- 参数为 `null` 会生成一个不会继承任何属性和方法的对象
let obj = Object.create(null);
obj.toString()// Error //会继承第二个参数的属性和方法
let obj = Object.create({}, {
p1: {
value: 123,
enumerable: true,
configurable: true,
writable: true,
},
p2: {
value: 'Owen',
enumerable: true,
configurable: true,
writable: true,
}
}); // 等同于
let obj = Object.create({});
obj.p1 = 123;
obj.p2 = 'Owen'; //生成的对象会继承它的原型对象的构造函数。
function Foo() {}
let f = new Foo();
let b = Object.create(f); b.constructor === Foo // true
b instanceof Foo // true
- `object.isPrototypeOf`
> 判断对象是否再参数对象的原型链上
function F(){}
let f = new F()
F.prototype.isPrototypeOf(f) //true
- 获取原型的三种方法
1. `obj.__proto__`
2. `obj.constructor.prototype`
3. `Object.getPrototypeOf(obj)`
 
- 前两种不可靠,都个一手动修改, 而且 `__proto__` 只有浏览器才需要部署
- `getOwnPropertyNames` 和 `keys`
> 以数组形式返回参数对象所有属性名(不包含继承属性)
//不管可不可遍历都会返回出来
Object.getOwnPropertyNames(Date);//["length", "name", "prototype", "now", "parse", "UTC"]
//返回可遍历属性
Object.keys(Date)// []
- `hasOwnProperty`
> 判断参数是否是自身的属性,唯一一个不会遍历原型链的方法
Array.hasOwnProperty('length')//true

### 拷贝对象

拷贝对象需要确保两件事情:
- 与原对象具有同样的原型。
- 与原对象具有同样的实例属性。
function copyOwn (target,origin){
Object.getOwnPropertyNames(origin).forEach((key)=>{
let desc =Object.getOwnPropertyDescriptor(origin,key);
Object.defineProperty(target,origin,desc);
})
return target
} function copy(origin){
let clone = Object.create (Object.getPrototypeOf(origin));
copyOwn(clone,origin)
return clone
} //es8
const copyTwo = origin =>Object.create( Object.getPropertyOf(origin),Object.getOwnPropertyDescriptor(origin) );

oop(一)

JavaScript 对象继承 OOP (三)的更多相关文章

  1. 实现JavaScript中继承的三种方式

    在JavaScript中,继承可以通过三种手法实现原型链继承 使用apply.call方法 对象实例间的继承.     一.原型链继承 在原型链继承方面,JavaScript与java.c#等语言类似 ...

  2. javascript类继承系列三(对象伪装)

    原理:在子类的构造器上调用超类构造器(父类构造器中的this指向子类实例),js提供了apply()和call()函数,可以实现这种调用 function baseClass() { this.col ...

  3. 详解JavaScript对象继承方式

    一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Parent 构造函数成为 Children 的方法,然 ...

  4. javascript实现继承的三种方式

    一.原型链继承  function Parent(){} function Child(){} Child.prototype = new Parent(); 通过对象child的prototype属 ...

  5. JavaScript(JS)之Javascript对象DOM(三)

    https://www.cnblogs.com/haiyan123/p/7598320.html 一.什么是HTML  DOM HTML  Document Object Model(文档对象模型) ...

  6. JavaScript对象继承方式

    一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Parent 构造函数 成为 Children 的方法, ...

  7. 深入理解javascript对象系列第三篇——神秘的属性描述符

    × 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值 ...

  8. javascript对象继承的实现

    现在有两个对象,需要实现Chinese类型对象对Person类型对象的继承. 这里分两部分,属性和方法. 属性可以直接用构造函数的方法实现继承,而方法则要通过原型链来实现继承. 先解释什么是原型链,每 ...

  9. Javascript 对象继承 原型链继承 对象冒充 call 混合方式

    一.原型链继承 function ClassA() {} ClassA.prototype.color = "blue"; ClassA.prototype.sayColor = ...

随机推荐

  1. 编译安装log4cxx

    1.介绍 Log4cxx是开放源代码项目Apache Logging Service的子项目之一,是Java社区著名的log4j的c++移植版,用于为C++程序提供日志功能,以便开发者对目标程序进行调 ...

  2. poj3167(kmp)

    题目链接: http://poj.org/problem?id=3167 题意: 给出两串数字 s1, s2, 求主串 s1 中的 s2 匹配数并输出每个匹配的开头位置. 区间 [l, r] 是 s2 ...

  3. Q的进阶用法

    Q的实例化用法 #q1 里面的条件都是or的关系 q1=Q() q1.connector = 'OR' q1.children.append(('id',1)) q1.children.append( ...

  4. 出现epoll failed: Bad file descriptor的原因

    今天遇到了这个问题,之前找了半天原来是IO事件的socket描述符在epoll_ctl()处理之前关闭了. if(epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd ...

  5. P3613 睡觉困难综合征 LCT+贪心+位运算

    \(\color{#0066ff}{ 题目描述 }\) 由乃这个问题越想越迷糊,已经达到了废寝忘食的地步.结果她发现--晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给D ...

  6. 二分图【洛谷P2175】 小Z的游戏分队

    P2175 小Z的游戏分队 小Z受不了寂寞,准备举办一次DOTA比赛,为了能让ACM班全部都参加比赛,他还特制了一张DOTA地图能够支持任意多人打任意多人. 现在问题来了,怎么把这么多人分成两队?小Z ...

  7. 线段树 SP1716 GSS3 - Can you answer these queries III

    SP1716 GSS3 - Can you answer these queries III 题意翻译 n 个数,q 次操作 操作0 x y把A_xAx 修改为yy 操作1 l r询问区间[l, r] ...

  8. [BZOJ3337] ORZJRY I --块状链表大毒瘤

    link 题目大意:维护一个序列 支持: 1.单点插入 2.单点删除 3.区间翻转 4.区间旋转 5.区间加 6.区间赋值 7.询问区间和 8.询问区间极差 9.询问区间与给定某个数差值绝对值的最小值 ...

  9. linux进程切换问题

    #define switch_to(prev,next,last) do { \ unsigned long esi,edi; \ asm volatile("pushfl\n\t" ...

  10. 通过div实现arcgis自定义infowindow

    通过给地图绑定缩放,单击和平移命令,实现在地图附加div标签,实现infowindow效果: /* *作者 扰扰 *自定义esri弹窗 *paramter Map地图对象 *paramter x *p ...