会及时修正巴黎人手机版:,如有错误
分类:巴黎人-前端

先说说如何快速快速寻求解答

遇到不会的问题,肯定第一目标就是如何快速寻求解决方案,答案是:

  • 先去stackoverflow上看看有没有类似的题。。。

于是,借助搜索引擎搜索了下,第一条就符合条件,点开进去看描述

巴黎人手机版 1

ES5 面向对象

ES6的class语法糖

不知道为什么标题都是跟吃的有关

可能是因为到了半夜吧(虚

在学ES6之前,我们苦苦背下JS继承的典型方法

学习ES6后,发现官方鸡贼地给我们一个语法糖——class。它可以看作是构造函数穿上了统一的制服,所以class的本质依然是函数,一个构造函数。

class是es6新定义的变量声明方法(复习:es5的变量声明有var function和隐式声明 es6则新增let const class import),它的内部是严格模式。class不存在变量提升

例:

//定义类

classPoint{

    constructor(x,y){

        this.x=x;

        this.y=y;

    }

    toString(){

        return'('+this.x+', '+this.y+')';

    }

}

constructor就是构造函数,不多说,跟c++学的时候差不多吧,this对象指向实例。

类的所有方法都定义在类的prototype属性上面,在类的内部定义方法不用加function关键字。在类的外部添加方法,请指向原型,即实例的__proto__或者类的prototype。

Object.assign方法可以很方便地一次向类添加多个方法。

Object.assign(Point.prototype,{toString(){},toValue(){}});

为什么无法被继承?

首先,看看MDN上的解释,上面有提到,JavaScript的日期对象只能通过JavaScript Date作为构造函数来实例化。

巴黎人手机版 2

然后再看看stackoverflow上的回答:

巴黎人手机版 3

有提到,v8引擎底层代码中有限制,如果调用对象的[[Class]]不是Date,则抛出错误。

总的来说,结合这两点,可以得出一个结论:

要调用Date上方法的实例对象必须通过Date构造出来,否则不允许调用Date的方法

2.4 原型式继承

核心:原型式继承的object方法本质上是对参数对象的一个浅复制。

优点:父类方法可以复用

缺点:

  • 父类的引用属性会被所有子类实例共享
  • 子类构建实例时不能向父类传递参数

function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function object(o){
  function F(){}
  F.prototype = o;
  return new F();
}
 
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
 
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
 
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
 

ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:一 个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下, Object.create()与 object()方法的行为相同。——《JAVASCript高级编程》

所以上文中代码可以转变为

var yetAnotherPerson = object(person); => var yetAnotherPerson = Object.create(person);

1
var yetAnotherPerson = object(person); => var yetAnotherPerson = Object.create(person);

如何快速判断是否继承?

其实,在判断继承时,没有那么多的技巧,就只有关键的一点:[[prototype]]__ptoto__)的指向关系

譬如:

console.log(instance instanceof SubClass); console.log(instance instanceof SuperClass);

1
2
console.log(instance instanceof SubClass);
console.log(instance instanceof SuperClass);

实质上就是:

  • SubClass.prototype是否出现在instance的原型链上
  • SuperClass.prototype是否出现在instance的原型链上

然后,对照本文中列举的一些图,一目了然就可以看清关系。有时候,完全没有必要弄的太复杂。

ES6 面向对象

ES6中引入了Class(类)这个概念,通过关键字class可以创建一个类。类的数据类型就是函数,类的所有方法都定义在prototype属性上。

class Person () {
        constructor (x,y) {
              this.name= x
              this.age= y
        }
        sayName () {
                alert("快乐")
        }
}
var liHua= new Person("张俊泽",26)

注: 可以理解为constuctor中的属性和方法为ES5中的构造函数部分,和constructor同级的是ES5中原型上的方法和属性。


ES6的继承通过extends关键字实现

class Father(){}
class Child extends Father {
        constructor(x,y,color){
                  super(x,y)
                  this.color= color
        }
        toString() {
                retunr "世界和平!"
        }
}

上面代码中,constructor方法和toString方法之中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。


类的prototype和__proto__属性

Class作为构造函数的语法唐,同时有prototype和__proto__属性,因此存在两条继承链:

①  子类的__proto__,表示构造函数的继承,总是指向父类

②  子类的prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

class Father {

}

class Child extends Father{

          constructor () {

                  super()

          }

}

var childOne= new Child()

Child.__proto__ ==  Father        //  true

childOne.__proto__ ==  Child.prototype        //  true

Child.prototype.__proto__ ==  Fahter.prototype            //  true

私有方法,私有属性

类的特性是封装,在其他语言的世界里,有private、public和protected来区分,而js就没有

js在es5的时代,尝试了一些委婉的方法,比如对象属性的典型的set和get方法,在我之前说的JS的数据属性和访问器属性

现在es6规定,可以在class里面也使用setter和getter:

class MyClass {

constructor() { // ... }

get prop() { return 'getter'; }

set prop(value) { console.log('setter: '+value); }

}

let inst = new MyClass();

inst.prop = 123; // setter: 123

inst.prop // 'getter'

那么在这次es6的class里面,如何正式地去表示私有呢?

方法有叁:

1,老办法,假装私有。私有的东西,命名前加个下划线,当然了这只是前端程序员的自我暗示,实际上在外部应该还是可以访问得到私有方法。

2,乾坤大挪移。把目标私有方法挪出class外,class的一个公有方法内部调用这个外部的“私有”方法。

class Widget {

foo (baz) { bar.call(this, baz); } // ...

}

function bar(baz) { return this.snaf = baz; }

3,ES6顺风车,SYMBOL。利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。Symbol是第三方无法获取的,所以外部也就无法偷看私有方法啦。

const bar = Symbol('bar');

const snaf = Symbol('snaf');

export default class myClass{

// 公有方法

foo(baz) { this[bar](baz); }

// 私有方法

[bar](baz) { return this[snaf] = baz; }

// ... };

那属性怎么私有化呢?现在还不支持,但ES6有一个提案,私有属性应在命名前加#号。

前言

见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正。

----------长文+多图预警,需要花费一定时间----------

故事是从一次实际需求中开始的。。。

某天,某人向我寻求了一次帮助,要协助写一个日期工具类,要求:

  • 此类继承自Date,拥有Date的所有属性和对象

  • 此类可以自由拓展方法

形象点描述,就是要求可以这样:

// 假设最终的类是 MyDate,有一个getTest拓展方法
let date = new MyDate();

// 调用Date的方法,输出GMT绝对毫秒数
console.log(date.getTime());
// 调用拓展的方法,随便输出什么,譬如helloworld!
console.log(date.getTest());

于是,随手用JS中经典的组合寄生法写了一个继承,然后,刚准备完美收工,一运行,却出现了以下的情景:

巴黎人手机版 4

但是的心情是这样的:

本文由巴黎人手机版发布于巴黎人-前端,转载请注明出处:会及时修正巴黎人手机版:,如有错误

上一篇:没有了 下一篇:没有了
猜你喜欢
热门排行
精彩图文