[JS] ECMAScript 6 - Prototype : compare with c#

时间:2022-10-01 10:17:38

开胃菜


prototype 对象

JavaScript 语言的继承则是通过“原型对象”(prototype)。

function Cat(name, color) {  // <----构造函数
this.name = name;
this.color = color;
this.meow = function () {
console.log('喵喵');
};
} var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色'); cat1.meow === cat2.meow  // <----无法共享,这就是个问题,需要解决,否则浪费内存
// false

JavaScript 规定,每个函数都有一个prototype属性,指向一个对象,这个对象其实也有自己的原型对象,然后形成了一个原型链

共享属性

function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white';  // <---- 相当于一个共享属性的东西 var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛'); cat1.color // 'white'
cat2.color // 'white'

当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。

如果本来就有,当然是用自己本身的啦。

另一个例子:属性livesIn和price希望能够共享

你看到所有的鱼都有属性livesIn和price,我们甚至都没有为每一条不同的鱼特别声明这些属性。

这时因为当一个对象被创建时,这个构造函数 将会把 它的属性prototype ----> 新对象的内部属性__proto__。

这个__proto__被这个对象用来查找它的属性

你也可以通过prototype来给所有对象添加共用的函数。这有一个好处:你不需要每次在构造一个对象的时候创建并初始化这个函数。

所有对象的祖宗 - Object.prototype

如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。

也就是说,所有对象都继承了Object.prototype的属性。

这就是所有对象都有valueOftoString方法的原因,因为这是从Object.prototype继承的。

因此,原型链的尽头就是null

Object.getPrototypeOf(Object.prototype)
// null

伪装之术

自己定义的对象MyArray, 其构造函数是MyArray,内部的prototype属性指向数组Array

var MyArray = function () {};  

MyArray.prototype = new Array();        // 指向一个数组实例
MyArray.prototype.constructor = MyArray; // prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数 var mine = new MyArray();   // 实例对象
mine.push(1, 2, 3);
mine.length //
mine instanceof Array // true

原型的构造函数就是自己

function P() {}
var p = new P(); /**
* P类的prototype也即是上一级的constructor 就是它本身。
* 自己是没有constructor之说的,自己的其实就是自己原型的。
**/
p.constructor === P // true
p.constructor === P.prototype.constructor // true p.hasOwnProperty('constructor') // false, 小p自己是没有constructor的

创建一个兄弟

function Constr() {}
var x = new Constr(); var y = new x.constructor();  // 调用自身的构造函数常见一个兄弟
y instanceof Constr        // true

雷区:修改原型对象时,一般要同时修改constructor属性的指向。

function Person(name) {
this.name = name;
} Person.prototype.constructor === Person // true /**
* 构造函数Person的原型对象改掉了,但是没有修改constructor属性
* 那么,prototype.constructor当然就不是从前了
**/

Person.prototype
= {
method: function () {}
}; Person.prototype.constructor === Person // false
Person.prototype.constructor === Object // true 

雷图:修改原型对象时,一般要同时修改constructor属性的指向。

// 坏的写法
C.prototype = {
method1: function (...) { ... },
// ...
};
--------------------------------------------------------
// 好的写法
C.prototype = {
constructor: C,  // <---- 记得一定要同时set construtor
method1: function (...) { ... },
// ...
}; // 更好的写法
C.prototype.method1 = function (...) { ... };

instanceof 运算符

是否在左边对象的原型链上 - 判断类型

var v = new Vehicle();
v instanceof Vehicle // true
v instanceof Object // true
Vehicle.prototype.isPrototypeOf(v)

// Jeff: instanceof运算符只能用于对象,不适用原始类型的值(such as string)。
var s = 'hello';
s instanceof String // false  // 此外,对于undefinednullinstanceOf运算符总是返回false
undefined instanceof Object          // false
null instanceof Object // false

常用方法


People是对象的构造函数。

function People(name)
{
this.name=name;
//对象方法
this.Introduce=function(){     // (1) 生成一个实例,就能使用该方法
alert("My name is "+this.name);
}
}
-----------------------------------------------
//类方法
People.Run=function(){ // (2) 不需要通过生成实例,可直接使用的方法
alert("I can run");
}
-----------------------------------------------
//原型方法
People.prototype.IntroduceChinese=function(){ // (3) 给(1)带来了额外的补充
alert("我的名字是"+this.name);
}
-----------------------------------------------
//测试
var p1=new People("Windking");
p1.Introduce(); // (1)
People.Run(); // (2)
p1.IntroduceChinese(); // (3)

基本概念理解:

(1)、对象方法理解就很简单了,主要是如果类生成一个实例,那么该实例就能使用该方法
(2)、类方法,不需要通过生成实例就可以使用的方法
(3)、原型方法主要是用来对JS已有的系统对象进行扩展而生的,例如Array数组没有什么方法,你可以为其增加原型方法,那么创建的数组就拥有了该方法。

1、对象方法包括构造函数中的方法以及构造函数原型上面的方法;
2、类方法,其实这里的类就是一个函数,在js中由于函数也是一个对象,所以可以为函数添加属性以及方法,这种方法在node中用的比较多;
3、原型方法一般用于对象实例共享,比如Person.prototype.sayName=function(){console.log(this.name);};在原型上面添加该方法,就能实现共享。这样就不用每一次初始化一个实例的时候,为其分配相应的内存了。

添加共有方法

为什么要这么搞?因为我们可以先定义属性,然后在我们“想好了"之后,再添加方法。

// 1. 先定义好了必要的属性
function Employee(name, salary){
this.name=name;
this.salary=salary;
} // 2. 等知道如何操作了才定义方法,如此,灵活的不要不要的
Employee.prototype.getSalary=function getSalaryFunction(){
return this.salary;
}
Employee.prototype.addSalary=function addSalaryFunction(addition){
this.salary=this.salary+addition;
}
var boss1=new Employee("Joan", 200000);
var boss2=new Employee("Kim", 100000);
var boss3=new Employee("Sam", 150000);

添加私有方法

function Aclass(){
  this.Property = 1;
  this.Method = function(){
  alert(1);
  }
}
var obj = new Aclass();
obj.Property2 = 2;        // 对象为自己添加了私有属性
obj.Method2 = function(){ // 对象为自己添加了私有方法
alert(2);
}
alert(obj.Property2);
obj.Method2();

重写父类属性和方法

function AClass(){
this.Property = 1;
this.Method = function(){
alert(1);
}
}
function AClass2(){
this.Property2 = 2;
this.Method2 = function(){
alert(2);
}
}
AClass2.prototype = new AClass();    // AClass2继承了AClass?No! ----> 补充
AClass2.prototype.Property = 3; // 然后重写了属性
AClass2.prototype.Method = function(){ // 之后重写了方法
alert(4);
}
var obj = new AClass2();
alert(obj.Property);
obj.Method();

补充 ---->

理解prototype不应把它和继承混淆。

可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。

A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。

例子:

定义了baseClass类,然后我们要定义extendClass

但是我们打算以baseClass的一个实例为原型,来克隆的extendClass,也同时包含showMsg这个对象方法。

function baseClass(){
this.showMsg = function(){
alert("baseClass::showMsg");
}
}
function extendClass(){}
extendClass.prototype = new baseClass();  // 以一个实例(对象)为原型,全部克隆了一遍 // 扩展好了extendClass,再new个对象执行里面的方法
var instance = new extendClass();
instance.showMsg(); // 显示baseClass::showMsg

调用父类属性和方法

如果我想使用extendClass的一个实例instance调用baseClass的对象方法showMsg怎么办?

function baseClass(){
this.showMsg = function(){
alert("baseClass::showMsg");
}
} function extendClass(){
this.showMsg =function (){      //有自己的,就不甩父类的同命名的方法了
alert("extendClass::showMsg");
}
}
-----------------------------------------------------------------------------
extendClass.prototype = new baseClass();
var instance = new extendClass();
instance.showMsg();//显示extendClass::showMsg

但是,我还是偏偏想调用父类中的被覆盖的方法,怎么办?

-----------------------------------------------------------------------------
extendClass.prototype = new baseClass();
var instance = new extendClass();
var baseinstance = new baseClass();  // 通过对象方法,而不是类方法!
baseinstance.showMsg.call(instance);//显示baseClass::showMsg  <---- 使用call重定义this这个对象的

function定义的方法(对象方法 or 构造方法)有一个prototype属性:它是对象方法或者构造方法的专有属性。它指向一个prototype对象。

使用new生成的对象就没有这个prototype属性。

[JS] ECMAScript 6 - Prototype : compare with c#

function Person(name)
{
this.name=name;
this.showMe=function()
{
alert(this.name);
}
};
var one = new Person('js');
alert(one.prototype)//undefined       // 使用new生成的对象就没有这个prototype属性。
alert(typeof Person.prototype); //object 但是这个就有
alert(Person.prototype.constructor); //function Person(name) {...};   prototype是Person的属性,该属性指向同名的prototype对象

对象中的Prototype相关


  • __proto__属性

读取或设置当前对象的prototype对象。

  • Object.setPrototypeOf()

ES6 正式推荐的设置原型对象的方法。

// 格式
Object.setPrototypeOf(object, prototype) // 用法
const o = Object.setPrototypeOf({}, null); /** 该方法等同于下面的函数 **/ function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}

实际用法,设置共享属性

let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);  // proto与obj有了关系,proto有了什么,obj就能有什么,有福共享的意思

// 如果第一个参数obj不是对象,会自动转为对象。
// 但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。
// 由于undefinednull无法转为对象,所以如果第一个参数是undefinednull,就会报错。 proto.y = 20;
proto.z = 40; obj.x //
obj.y //
obj.z //
  • Object.getPrototypeOf()

用于读取一个对象的原型对象。

[JS] ECMAScript 6 - Prototype : compare with c#

  • super 关键字

ES6 新增,指向当前对象的原型对象

const proto = {
foo: 'hello'
}; const obj = {
foo: 'world',
find() {
return super.foo;
}
}; Object.setPrototypeOf(obj, proto);
obj.find() // "hello"

雷区:表示原型对象时,只能用在对象的方法之中

第一种写法是super用在属性里面,

第二种和第三种写法是super用在一个函数里面,然后赋值给foo属性。

只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。

[JS] ECMAScript 6 - Prototype : compare with c#

下面代码中,super.foo指向原型对象protofoo方法,但是绑定的this却还是当前对象obj,因此输出的就是world

const proto = {
x: 'hello',
foo() {            // <-- 指向了这里,但this却还是当前对象obj
console.log(this.x);
},
}; const obj = {
x: 'world',
foo() {
super.foo();    // --> super.foo指向原型对象protofoo方法
}
} Object.setPrototypeOf(obj, proto); obj.foo() // "world"

/* implemnet */

Javascript中call的使用

[JS] ECMAScript 6 - Prototype : compare with c#的更多相关文章

  1. &lbrack;JS&rsqb; ECMAScript 6 - Class &colon; compare with c&num;

    Ref: Class 的基本语法 Ref: Class 的基本继承 许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为.目前,有一个提案将这项功能,引入了 ECMAScript. ...

  2. &lbrack;JS&rsqb; ECMAScript 6 - Inheritance &colon; compare with c&num;

    这一章,估计是js最操蛋的一部分内容. 现代方法: 简介 Object.getPrototypeOf() super 关键字 类的 prototype 属性和__proto__属性 原生构造函数的继承 ...

  3. &lbrack;JS&rsqb; ECMAScript 6 - Variable &colon; compare with c&num;

    前言 范围包括:ECMAScript 新功能以及对象. 当前的主要目的就是,JS的学习 --> ECMAScript 6 入门 let 命令 js 因为let, i的范围限制在了循环中. var ...

  4. &lbrack;JS&rsqb; ECMAScript 6 - Async &colon; compare with c&num;

    一段引言: Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对 ...

  5. &lbrack;JS&rsqb; ECMAScript 6 - Array &colon; compare with c&num;

    扩展运算符(spread) 先复习下 rest 参数. (1) argument模式,但不够好. // https://blog.csdn.net/weixin_39723544/article/de ...

  6. &lbrack;JS&rsqb; ECMAScript 6 - Object &colon; compare with c&num;

    Ref: 对象的扩展 Outline: 属性的简洁表示法 属性名表达式 方法的 name 属性 Object.is() Object.assign() 属性的可枚举性和遍历 Object.getOwn ...

  7. 论js中的prototype

    今天在阅读代码时,碰到了prototype //判断是否是数组function isArray(obj) { return Object.prototype.toString.call(obj) == ...

  8. JS中对于prototype的理解

    JS中的prototype是JS中比较难理解的一个部分 本文基于下面几个知识点: 1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原型法的主要思想是,现在有1个类A,我想要创建一个 ...

  9. 帮你彻底搞懂JS中的prototype、&lowbar;&lowbar;proto&lowbar;&lowbar;与constructor(图解)

    作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...

随机推荐

  1. 浅析&colon;setsockopt&lpar;&rpar;改善socket网络程序的健壮性

    1. 如果在已经处于 ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BO ...

  2. 汽车Vin码识别——&&num;160&semi;一款二手车行业值得拥有的OCR识别软件

    一.汽车Vin码识别产品描述 汽车Vin码识别系统,主要应用在智能手机IOS与Android两个平台中.前端扫描查询模式,无需联网,只需扫描汽车前挡风玻璃右下角的Vin码(车架号),即可轻松识别出车辆 ...

  3. C&plus;&plus;格式化输出,C&plus;&plus;输出格式控制

    在输出数据时,为简便起见,往往不指定输出的格式,由系统根据数据的类型采取默认的格式,但有时希望数据按指定的格式输出,如要求以十六进制或八进制形式 输出一个 整数,对输出的小数只保留两位小数等.有两种方 ...

  4. css中的颜色

    我常用的是win10里面的自带的3D画图工具里面的颜色表 CSS 设置颜色的几种方式: 1.颜色名 2.rgb值 3十六进制表示 4. HSL color values CSS3 adds numer ...

  5. 基于ARM9和嵌入式Linux系统的多功能综合通信控制系统的框架

    基于ARM9硬件平台和嵌入式Linux系统的多功能综合通信控制系统的框架设计及各模块的功能.系统采用符合POSIX.1标准的C语言编写,实现了对下位机传送数据帧的采集.分析和存储,并能根据上位机的配置 ...

  6. Vue2&period;0&plus;组件库总结

    转自:https://blog.csdn.net/lishanleilixin/article/details/84025459 UI组件 element - 饿了么出品的Vue2的web UI工具套 ...

  7. 云端搭建内网局域网&plus;NAT冗余上网:vps-centos6&period;10 &plus;pptp client &plus;2个ros 实现默认走pptp上网,万一pptp断了,走另外一个ros路由&plus;centos7补充了下

    介绍下环境: 1.ROS1也是PPTP SERVER,IP为172.16.22.3/24,pptp pool为172.16.23.0/24,pptp的默认帐号是111,密码是123 2.ROS2的IP ...

  8. ElasticSearch 2 &lpar;27&rpar; - 信息聚合系列之故事开始

    ElasticSearch 2 (27) - 信息聚合系列之故事开始 摘要 到目前为止,本书都在着重介绍搜索.对于搜索,我们有查询条件以及与查找到与条件匹配的集合.这个过程就和如大海捞针一样. 对于聚 ...

  9. Extending&lowbar;and&lowbar;embedding&lowbar;php翻译

    http://blog.csdn.net/lgg201 博客翻译了Extending_and_embedding_php

  10. oracle修改字符编码

    ALTER DATABASE character set INTERNAL_USE ZHS16GBK;  ALTER DATABASE CHARACTER SET ZHS16GBK;  oracle修 ...