开胃菜
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
的属性。
这就是所有对象都有valueOf
和toString
方法的原因,因为这是从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
// 此外,对于
undefined
和null
,instanceOf
运算符总是返回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这个对象的
郭培:Javascript中call的使用【关于以上的call的使用】
function定义的方法(对象方法 or 构造方法)有一个prototype属性:它是对象方法或者构造方法的专有属性。它指向一个prototype对象。
使用new生成的对象就没有这个prototype属性。
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不是对象,会自动转为对象。
// 但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。
// 由于undefined
和null
无法转为对象,所以如果第一个参数是undefined
或null
,就会报错。 proto.y = 20;
proto.z = 40; obj.x //
obj.y //
obj.z //
- Object.getPrototypeOf()
用于读取一个对象的原型对象。
- 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 引擎确认,定义的是对象的方法。
下面代码中,super.foo
指向原型对象proto
的foo
方法,但是绑定的this
却还是当前对象obj
,因此输出的就是world
。
const proto = {
x: 'hello',
foo() { // <-- 指向了这里,但this却还是当前对象obj
console.log(this.x);
},
}; const obj = {
x: 'world',
foo() {
super.foo(); // -->super.foo
指向原型对象proto
的foo
方法
}
} Object.setPrototypeOf(obj, proto); obj.foo() // "world"
/* implemnet */
Javascript中call的使用
[JS] ECMAScript 6 - Prototype : compare with c#的更多相关文章
-
[JS] ECMAScript 6 - Class : compare with c#
Ref: Class 的基本语法 Ref: Class 的基本继承 许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为.目前,有一个提案将这项功能,引入了 ECMAScript. ...
-
[JS] ECMAScript 6 - Inheritance : compare with c#
这一章,估计是js最操蛋的一部分内容. 现代方法: 简介 Object.getPrototypeOf() super 关键字 类的 prototype 属性和__proto__属性 原生构造函数的继承 ...
-
[JS] ECMAScript 6 - Variable : compare with c#
前言 范围包括:ECMAScript 新功能以及对象. 当前的主要目的就是,JS的学习 --> ECMAScript 6 入门 let 命令 js 因为let, i的范围限制在了循环中. var ...
-
[JS] ECMAScript 6 - Async : compare with c#
一段引言: Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对 ...
-
[JS] ECMAScript 6 - Array : compare with c#
扩展运算符(spread) 先复习下 rest 参数. (1) argument模式,但不够好. // https://blog.csdn.net/weixin_39723544/article/de ...
-
[JS] ECMAScript 6 - Object : compare with c#
Ref: 对象的扩展 Outline: 属性的简洁表示法 属性名表达式 方法的 name 属性 Object.is() Object.assign() 属性的可枚举性和遍历 Object.getOwn ...
-
论js中的prototype
今天在阅读代码时,碰到了prototype //判断是否是数组function isArray(obj) { return Object.prototype.toString.call(obj) == ...
-
JS中对于prototype的理解
JS中的prototype是JS中比较难理解的一个部分 本文基于下面几个知识点: 1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原型法的主要思想是,现在有1个类A,我想要创建一个 ...
-
帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...
随机推荐
-
浅析:setsockopt()改善socket网络程序的健壮性
1. 如果在已经处于 ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BO ...
-
汽车Vin码识别——&#160;一款二手车行业值得拥有的OCR识别软件
一.汽车Vin码识别产品描述 汽车Vin码识别系统,主要应用在智能手机IOS与Android两个平台中.前端扫描查询模式,无需联网,只需扫描汽车前挡风玻璃右下角的Vin码(车架号),即可轻松识别出车辆 ...
-
C++格式化输出,C++输出格式控制
在输出数据时,为简便起见,往往不指定输出的格式,由系统根据数据的类型采取默认的格式,但有时希望数据按指定的格式输出,如要求以十六进制或八进制形式 输出一个 整数,对输出的小数只保留两位小数等.有两种方 ...
-
css中的颜色
我常用的是win10里面的自带的3D画图工具里面的颜色表 CSS 设置颜色的几种方式: 1.颜色名 2.rgb值 3十六进制表示 4. HSL color values CSS3 adds numer ...
-
基于ARM9和嵌入式Linux系统的多功能综合通信控制系统的框架
基于ARM9硬件平台和嵌入式Linux系统的多功能综合通信控制系统的框架设计及各模块的功能.系统采用符合POSIX.1标准的C语言编写,实现了对下位机传送数据帧的采集.分析和存储,并能根据上位机的配置 ...
-
Vue2.0+组件库总结
转自:https://blog.csdn.net/lishanleilixin/article/details/84025459 UI组件 element - 饿了么出品的Vue2的web UI工具套 ...
-
云端搭建内网局域网+NAT冗余上网:vps-centos6.10 +pptp client +2个ros 实现默认走pptp上网,万一pptp断了,走另外一个ros路由+centos7补充了下
介绍下环境: 1.ROS1也是PPTP SERVER,IP为172.16.22.3/24,pptp pool为172.16.23.0/24,pptp的默认帐号是111,密码是123 2.ROS2的IP ...
-
ElasticSearch 2 (27) - 信息聚合系列之故事开始
ElasticSearch 2 (27) - 信息聚合系列之故事开始 摘要 到目前为止,本书都在着重介绍搜索.对于搜索,我们有查询条件以及与查找到与条件匹配的集合.这个过程就和如大海捞针一样. 对于聚 ...
-
Extending_and_embedding_php翻译
http://blog.csdn.net/lgg201 博客翻译了Extending_and_embedding_php
-
oracle修改字符编码
ALTER DATABASE character set INTERNAL_USE ZHS16GBK; ALTER DATABASE CHARACTER SET ZHS16GBK; oracle修 ...