澳门新葡萄京官网首页 14

澳门新葡萄京官网首页深入浅出JavaScript之原型链和继承

Javascript语言的继承机制,它没有”子类”和”父类”的概念,也没有”类”(class)和”实例”(instance)的区分,全靠一种很奇特的”原型链”(prototype
chain)模式,来实现继承。

一、OOP的概念和继承

学过C++等语言的话,你一定明白面向对象的两个基本概念:

这部分知识也是JavaScript里的核心重点之一,同时也是一个难点。我把学习笔记整理了一下,方便大家学习,同时自己也加深印象。这部分代码的细节很多,需要反复推敲。那我们就开始吧。

1、OOP概念

 面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

OOP特点:继承、封装、多态和抽象。

  • 类:类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,Student表示学生类型,但不表示任何具体的某个学生;
  • 实例:实例是根据类创建的对象,例如,根据Student类可以创建出xiaoming、xiaohong等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。

系列目录

  • 深入浅出JavaScript之闭包(Closure)
  • 深入浅出JavaScript之this
  • 深入浅出JavaScript之原型链和继承

2、基于原型的继承

 澳门新葡萄京官网首页 1

function Foo(){
    this.y=2;
}

/*每个函数对象有一个对象属性prototype,这个prototype是个对象,Fooj就是Foo.prototype*/

Foo.prototype.x=1;
var obj3=new Foo();
/*创建一个Foo的实例obj3,
使用new调用的时候,Foo作为构造器来使用,并且this指向一个对象,而这个对象的原型会指向构造器的prototype属性,也就是Foo.prototype*/

console.log(obj3.y);  //2  对象上的
console.log(obj3.x);   //1 原型上的

所以,类和实例是大多数面向对象编程语言的基本概念。

小试身手

原型链例子(要点写在注释里,可以把代码复制到浏览器里测试,下同)

function foo(){}              //通过function foo(){}定义一个函数对象
foo.prototype.z = 3;          //函数默认带个prototype对象属性   (typeof foo.prototype;//"object")

var obj =new foo();           //我们通过new foo()构造器的方式构造了一个新的对象
obj.y = 2;                    //通过赋值添加两个属性给obj
obj.x = 1;                    //通过这种方式构造对象,对象的原型会指向构造函数的prototype属性,也就是foo.prototype

obj.x; // 1                 //当访问obj.x时,发现obj上有x属性,所以返回1
obj.y; // 2                 //当访问obj.y时,发现obj上有y属性,所以返回2
obj.z; // 3                 //当访问obj.z时,发现obj上没有z属性,那怎么办呢?它不会停止查找,它会查找它的原型,也就是foo.prototype,这时找到z了,所以返回3

//我们用字面量创建的对象或者函数的默认prototype对象,实际上它也是有原型的,它的原型指向Object.prototype,然后Object.prototype也是有原型的,它的原型指向null。
                                   //那这里的Object.prototype有什么作用呢?
typeof obj.toString; // ‘function'  

//我们发现typeof obj.toString是一个函数,但是不管在对象上还是对象的原型上都没有toString方法,因为在它原型链的末端null之前都有个Object.prototype方法,
//而toString正是Object.prototype上面的方法。这也解释了为什么JS基本上所有对象都有toString方法
'z' in obj; // true               //obj.z是从foo.prototype继承而来的,所以'z' in obj返回了true
obj.hasOwnProperty('z'); // false   //但是obj.hasOwnProperty('z')返回了false,表示z不是obj直接对象上的,而是对象的原型链上面的属性。(hsaOwnProperty也是Object.prototype上的方法)

澳门新葡萄京官网首页 2

刚才我们访问x,y和z,分别通过原型链去查找,我们可以知道:当我们访问对象的某属性时,而该对象上没有相应属性时,那么它会通过原型链向上查找,一直找到null还没有话,就会返回undefined。

3、prototype属性与原型

澳门新葡萄京官网首页 3

用函数声明创建一个空函数function
Foo(){}的时候,函数就会有一个prototype对象属性。

prototype对象属性默认会有2个属性,一个是constructor,会指向它本身Foo;另外一个是_proto_,一般的对象都会指向Object.prototype。

x:1是通过赋值语句Foo.prototype.x=1;增加的。

Foo.prototype的作用:

当使用new
Foo去构造Foo的实例的时候,这个prototype属性会用作new出来的对象(obj1,obj2,obj3…)的原型(_proto_)。

prototype:是函数对象上面预设的对象属性。

_proto_:对象上的原型,通常都是它的构造器的prototype属性。

BUT,JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。

基于原型的继承

澳门新葡萄京官网首页 4

function Foo(){
   this.y = 2;     
}

Foo.prototype.x = 1;
var obj3 = new Foo();  //①当使用new去调用的时候,函数会作为构造器去调用②this会指向一个对象(这里是obj3),而这个对象的原型会指向构造器的prototype属性(这里是Foo.prototype)
obj3.y; //2 
obj3.x; //1    //可以看到y是对象上的,x是原型链上的原型(也就是Foo.prototype上)

4、更复杂的实例:

Student继承Person

<script>
function Person(name,age){//new方法调用,this作为 return值
    this.name=name;
    this.age=age;
}
/*Person.prototype添加实例共享的属性和方法*/
Person.prototype.hi=function(){
    console.log('Hi,my name is'+this.name+"I'm"+this.age+"years old now.");
}

Person.prototype.LEGS_NUM=2;
Person.prototype.ARMS_NUM=2;
Person.prototype.walk=function(){
    console.log(this.name+" is wlking...");
}
/*初始化Student类*/
function Student(name,age,className) {
    Person.call(this,name,age);//先调用父类初始化
    this.className=className;
}

/*继承*/
Student.prototype=Object.create(Person.prototype);
Student.prototype.constructor=Student;
/*覆盖基类的hi方法*/
Student.prototype.hi=function(){
    console.log('Hi,my name is '+this.name+",I'm "+this.age+" years old now,and from "+this.className+'.');
}

Student.prototype.learn=function(subject){
    console.log(this.name+' is learning '+subject+' at '+this.className+'.');
}
//test
var bosn=new Student('Bosn',27,'Class 3,Grade 2');
console.log(bosn.hi());//Hi,my name is Bosn,I'm 27 years old now,and from Class 3,Grade 2.
console.log(bosn.LEGS_NUM);//2
bosn.walk();
//Bosn is wlking...
bosn.learn('math');
//Bosn is learning math at Class 3,Grade 2.
</script>

创建对象

JavaScript的所有数据都可以看成对象(Object)。
三种创建对象的方法:

  1. 对象字面量

 var xiaoming = {
    name: '小明',
    hello: function () {
        console.log('Hello, ' + this.name + '!');
    }
};
  1. 构造函数

function Student(name) {
    this.name = name;
    this.hello = function() {
         console.log('Hello, ' + this.name + '!');
    }
}
var xiaoming = new Student("小明")
  1. Object.create()构造
    Object.create(proto [, propertiesObject ])
    是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不是一个子函数,可以传一个null,第二个参数是对象的属性描述符,这个参数是可选的。

var Student = {
    name: 'Robot',
    hello: function () {
        console.log('Hello, ' + this.name + '!');
    }
};
var xiaoming = Object.create(Student);

其中,第二种构造函数,如果不写new,Student就是一个普通函数(也可以说是方法Function),它返回undefined。但是,如果写了new,它就变成了一个构造函数,它绑定的this指向新创建的对象,并默认返回this,也就是说,不需要在最后写return
this;了。

prototype属性与原型

澳门新葡萄京官网首页 5

澳门新葡萄京官网首页 6

我们再来看看Foo.prototype是什么样的结构,当我们用函数声明去创建一个空函数的时候,那么这个函数就有个prototype属性,并且它默认有两个属性,constructor和__proto__,

constructor属性会指向它本身Foo,__proto__是在chrome中暴露的(不是一个标准属性,知道就行),那么Foo.prototype的原型会指向Object.prototype。因此Object.prototype上

的一些方法toString,valueOf才会被每个一般的对象所使用。

function Foo(){}
typeof Foo.prototype; // "object"
Foo.prototype.x = 1;
var obj3 = new Foo();

总结一下:我们这里有个Foo函数,这个函数有个prototype的对象属性,它的作用就是当使用new
Foo()去构造实例的时候,这个构造器的prototype属性会用作new出来的这些对象的原型。

所以我们要搞清楚,prototype和原型是两回事,prototype是函数对象上的预设属性,原型通常是构造器上的prototype属性。

二、原型链

如下:

澳门新葡萄京官网首页 7从后往前:

bosn构造:通过 new
Student()创建了bosn实例,bosn实例的原型_proto_指向构造器的prototype属性,也就是Student.prototyep。Studnet.prototype上面有hi()方法和learn()方法。

Studnet.prototype构造:通过Object.create(Person.prototype)来构造。Student.prototype是个空对象,这个空对象随后添加了hi()方法和learn()方法,它的原型_proto_指向了Person.prototype。

Person.prototype:直接定义了一个Person函数,在Person.ptototype上添加了共享的属性和方法,这个Person.prototype就是一个内置的普通对象。它本身也会有原型就是Object.prototype。

坑1:

并不是所有的对象,最终原型链上都有Object.prototype。

通过Object.create(null)创建的对象原型链上没有Object.prototype,也就没有Object.prototype上的方法。

澳门新葡萄京官网首页 8

坑2:

并不是所有的函数对象都会有prototype属性。

ES5的bind()函数用来修改函数在运行时的this。

bind方法返回的也是一个函数,可以通过typeof判断一下,但是bind()方法返回的函数就没有prototype属性。

澳门新葡萄京官网首页 9

proto属性与prototype属性

我们只看前两种方法,第一种是直接创建对象,第二种是通过方法(Function)来创建对象。
JavaScript对每个创建的对象都会设置一个__proto__属性,指向该对象的构造函数的原型对象。而如果是通过第二种构造函数的方法来创建的创建的对象还会多出一个prototype属性。
解释如下:

//构造函数
function Student(name) {
    this.name = name;
    this.hello = function() {
         console.log('Hello, ' + this.name + '!');
    }
}
var xiaoming = new Student("小明")
var xiaosha = new Student("小傻")

//对象字面量
var Student1 = {
 name: 'XXX',
 hello: function () {
     console.log('Hello, ' + this.name + '!');
 }
};
var xiaohong = {
    name: "xiaohong"
}
xiaohong.__proto__ = Student1;

在创建xiaohong的时候我们直接把xiaohong.proto =
Student1;为甚么这样写呢,因为它不是Function创建的对象,当然也就不具备prototype属性哈哈。但是上述代码仅用于演示目的。在编写JavaScript代码时,不要直接用obj.__proto__去改变一个对象的原型,并且,低版本的IE也无法使用__proto__

澳门新葡萄京官网首页 10

对象的原型链

澳门新葡萄京官网首页 11

img3

澳门新葡萄京官网首页 12

Img1

说明几点:

  1. 由Img1可以看出,通过构造函数创建的对象除了__proto__属性还有prototype属性。事实上,只要是Function就会有该属性,也即普通函数也有prototype属性,原因是方法(Function)这个对象搞特殊,他还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象(这个被指向的对象我们后面细说)。
    2.在JS中,方法(Function)是对象,方法的原型(Function.prototype)也是对象啊

实现一个class继承另外一个class

function Person(name, age) {
   this.name = name;    //直接调用的话,this指向全局对象(this知识点整理)
   this.age = age;      //使用new调用Peoson的话,this会指向原型为Person.prototype的空对象,通过this.name给空对象赋值,最后this作为return值
}

Person.prototype.hi = function() {   //通过Person.prototype.hi创建所有Person实例共享的方法,(可以参考上节的左图:对象的原型会指向构造器的prototype属性,所以想让obj1,obj2,obj3共享一些方法的话,只需在原型对象上一次性地添加属性和方法就可以了);
   console.log('Hi, my name is ' + this.name + ',I am ' + this.age + ' years old now.')//这里的this是全局对象
};

Person.prototype.LEGS_NUM = 2;   //再设置一些对Person类的所有实例共享的数据
Person.prototype.ARMS_NUM = 2;
Person.prototype.walk = function() {
  console.log(this.name + ' is walking...');
};

function Student(name, age, className) {  //每个学生都属于人
  Person.call(this, name, age);  //在Student这个子类里面先调用一下父类
  this.className = className;
}

//下一步就是我们怎么去把Student的实例继承Person.prototype的一些方法

Student.prototype = Object.create(Person.prototype);    //Object.create():创建一个空对象,并且这个对象的原型指向它的参数  //这样子我们可以在访问Student.prototype的时候可以向上查找到Person.prototype,又可以在不影响Person的情况下,创建自己的方法
Student.prototype.constructor = Student;  //保持一致性,不设置的话constructor会指向Person

Student.prototype.hi = function() {    //通过Student.prototype.hi这样子的赋值可以覆盖我们基类Person.prototype.hi
  console.log('Hi, my name is ' + this.name + ',I am ' + this.age + ' years old now, and from ' + this.className + '.');
}
Student.prototype.learn = function(subject) {    //同时,我们又有自己的learn方法
  console.log(this.name + 'is learning ' + subject + ' at' + this.className + '.');
};

//test
var yun = new Student('Yunyun', 22, 'Class 3,Grade 2');
yun.hi(); //Hi,my name is Yunyun,I'm 22 years old now,and from Class 3, Grade 2.
console.log(yun.ARMS_NUM); // 2     //我们本身对象是没有的,对象的原型也就是Student.prototype也没有,但是我们用了继承,继续向上查找,找到了Person.prototype.ARMS_NUM,所以返回2
yun.walk(); //Yunyun is walking...
yun.learn('math'); //Yunyun is learning math at Class 3,Grade 2.

澳门新葡萄京官网首页 13

结合图我们来倒过来分析一下上面代码:我们先通过new
Student创建了一个Student的实例yun,yun的原型指向构造器的prototype属性(这里就是Student.prototype),
Student.prototype上有hi方法和learn方法,Student.prototype是通过Object.create(Person.prototype)构造的,所以这里的Student.prototype是空对象,并且这个对象的原型指向Person.prototype,接着我们在Person.prototype上也设置了LEGS_NUM,ARMS_NUM属性以及hi,walk方法。然后我们直接定义了一个Person函数,Person.prototype就是一个预置的对象,它本身也会有它的原型,它的原型就是Object.prototype,也正是因为这样,我们随便一个对象才会有hasOwnProperty,valueOf,toString这样些公共的函数,这些函数都是从Object.prototype上来的。这样子就实现了基于原型链的继承
     
那我们调用hi,walk,learn方法的时候发生了什么呢?比如我们调用hi方法的时候,我们首先看这个对象yun上有没有hi方法,但是在这个实例中没有所以会向上查找,查找到yun的原型也就是Student.protoype上有这hi方法,所以最终调用的是Student.prototype.hi,调用其他方法也是类似的。

三、prototype属性

通过原型(prototype)来实现面向对象编程

function Foo(){
  y = 2;
}
typeof Foo.prototype; //"object"
var obj = new Foo();

上面这个函数Foo是作为一个构造器来使用,this指向一个对象,而这个对象的原型会指向构造器的prototype属性(Foo.prototype也是一个对象)

function Person(name, age){
this.name = name;
this.age = age;
}

正常直接调用Person函数的话,this指向全局对象(在浏览器中为window),不写return的话,返回undefined。如果用new调用的话。this会指向为一个原型为Person.prototype的空对象,通过this.name给这个空对象赋值,绑定的this指向这个新创建的对象(此时已经不空了),并默认返回this,也就是说,不需要在最后写return this了。

改变prototype

我们知道JavaScript中的prototype原型不像Java中的class,Java中的class一旦写好就很难动态的去改变了,但是JavaScript中的原型实际上也是普通的对象,那就意味着在程序运行的阶段,我们也可以动态的给prototype添加或删除些属性。

澳门新葡萄京官网首页 14

在上述代码的基础上,我们已经有yun这个实例了,我们接着来进行实验:

Student.prototype.x = 101;        //通过Student.prototype.x把yun的原型动态地添加一个属性x
yun.x;   //101                    //那我们发现所有的实例都会受到影响
//接着我们做个有趣的实验
Student.prototype = {y:2};        //我们直接修改构造器的prototype属性,把它赋值为一个新的对象
yun.y;  //undefined               
yun.x;  //101                     //所以我们得出:当我们修改Student.prototype值的时候,并不能修改已经实例化的对象
var Tom = new Student('Tom',3,'Class LOL KengB');  
Tom.x; //undefined                //但当我们创建一个新的实例时,这一次x就不见了,
Tom.y; //2                        //并且y是新的值

所以说当动态修改prototype的时候,是会影响所有已创建或新创建的实例的,但是修改整个prototype赋值为新的对象的话,对已创建的实例是不会影响的,但是会影响后续的实例。

1、prototype相关的修改

/*给prototype添加属性和方法会影响到已创建或新创建的实例*/
Student.prototype.x=101;
console.log(bosn.x);     //101

/*修改prototype并不会影响已经创建的实例,会影响后续创建的实例*/
Student.prototype={y:2};
console.log(bosn.y);       //undefined
console.log(bosn.x);      //101


var nunnly=new Student('Nunnly',3,'Class LOL KengB');
console.log(nunnly.x); //undefined
console.log(nunnly.y);  //2

call、apply

call方法:
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明: call 方法可以用来代替另一个对象调用一个方法。call
方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj
指定的新对象。 如果没有提供 thisObj 参数,那么 Global 对象被用作
thisObj。
apply方法:
语法:apply([thisObj[,argArray]])

都知道这两个函数能改变函数执行的上下文,可是我总是搞不懂第一个参数到底传入的是什么。如果是this,那this又是什么。。。
所以今天测试一下,应该是懂了。

function Person(name, age){
    this.name = name;
    this.age = age;
}
function Stu(name, age, className){
    console.log(this) //Stu{}

    Person.call(this,name,age)
    console.log(this) //Stu{name: "Beatrice", age: 12}

    this.className = className;
    console.log(this) /Stu {name: "Beatrice", age: 12, className: 6}
}
var stu1 = new Stu("Beatrice", 12, 6);

最开始传入的是一个原型为Stu.prototype的空Stu{}对象。最后,我们把这个对象赋值给stu1。如何让Stu的实例能继承Person.prototype上的一些方法呢?

Stu.prototype = Object.create(Person.prototype);
Stu.prototype.constructor = Stu;

Object.create()创建一个空对象,并且对象的原型指向它的参数。这里就创建了一个原型指向Person.prototype的空对象。因为Stu.prototype会作为所有new Stu()实例的原型,为了继承Person.prototype上的一些方法,我们就把这个创建出来的空对象赋值给Stu.prototype,这样实例继承Stu.prototype,也就相当于实例继承这个原型为Person.prototype的空对象了。
那你也许会问,为什么不直接赋值Stu.prototype = Person.prototype,而是要通过Object.create呢?
如果直接赋值,Stu有一些自己的方法,当我们想增加Stu自己的方法的时候,也会加在Person上面,这显然不是我们想要的。所以我们搞一个中间的桥梁,也就是这个空对象。
这时,这个创建出的空对象的prototype == Person.prototype ==
Student.prototype。每一个prototype属性下面自带一个constructor属性,这个属性是指向自身的(所以这是个无限循环了呵呵)。所以prototype属性里面的constructor当然也都一致的,都是Person了。为了保证一致性,所以我们这里把Stu的constructor重新设置为指向自身。

实现继承的方式

实现继承有多种方式,下面我们还是以Person和Student来分析

function Person() {
}

function Student() {
}

Student.prototype = Person.prototype; // 我们可不可用这种方式呢?这种方法是错误的:因为子类Student有自己的一些方法
//,如果通过这样子赋值,改变Student的同时也改变了Person。

Student.prototype = new Person(); //这种方式是可以实现的,但是调用构造函数有时候也是有问题的,比如要传进Person一个name和age
//,这里的Student是个类,还没实例化,这时候有些奇怪了,传什么都不是。

Student.prototype = Object.create(Person.prototype); //相对来说这中方式是比较理想的,这里我们创建了一个空的对象
//,并且对象的原型指向Person.prototype,这样我们既保证了继承了Person.prototype上的方法,并且Student.prototype又有自己空的对象。
//但是Object.create是ES5以后才有的

2、内置的构造器的prototype

 内置的函数构造器也有prototype属性,比如Object,Number,Boolean,Function,等等。

bind,apply,call等等都是从Function的prototype上取到的。

边际效应:

修改这些构造器的prototype有时候会带来一些边际效应。

Object.prototype.x=1;
var obj={};
console.log(obj.x); //1
for(var key in obj){
    console.log('result: '+key);
}
//result: x

边际效应:在prototype上添加属性x,在for in遍历的时候会把x遍历出来。

解决办法:

ES5里面有defineProperty来控制对象属性。默认标签都是false,下面只设置writable:true。简洁表示不可枚举,也不可配置。

Object.defineProperty(Object.prototype,'x',
    {writable:true,value:1});
var obj={};
console.log(obj.x); //1
for(var key in obj){
    console.log('result: '+key);
}
//nothing output here

这样for
in的时候就不会有边际效应。所以如果写nodejs,判断一下如果有defineProperty,可以通过这种方式来改写Object.property这样一些内置构造器上的prototype的时候,可以跨过这样一个边际效应。

很少会用到修改Object.prototype,因为影响范围太广了。
但是有时候为了兼容性可能会通过Object.defineProperty做一些ES5才支持的方法模拟。

内置构造器的prototype属性

字面量创建的对象var object= {};的原型是Object.prototype
ES5中使用defineProperty()函数来对原型添加属性,而不是直接Object.prototype.x = 1这种形式来添加。
obj.hasOwnProperty()方法,只查找对象obj的方法,而不继续向上查找。

四、实现继承的方式

见代码。

<script>
function Person(){
}
function Student(){
}

Student.prototype=Person.prototype;//1   禁止用,改变Student也会修改Person

Student.prototype=new Person();//2     
/*可以实现,问题:比如构造函数有一个name和age,new Person()的时候name和age传什么呢?传任何东西都是很奇怪的。因为Student只是一个类,还没有实例化。

所以这里只是为了继承调用了Person的构造函数,创建了一个实例,在很多情况下也是比较奇怪的。
*/
Student.prototype=Object.create(Person.prototype);//3
Student.prototype.constructor=Person;

/*第三种是相对理想的办法*/
/*
创建了一个空的对象,并且对象的原型指向了Person.prototype。既保证了继承Person.prototype删的方法,并且Student.prototype又有自己的一个空的对象,Student.prototype的修改又不会影响Person.prototype。
*/

/*Object.create是ES5才支持的方法,在ES5之前可以模拟实现*/
if(!Object.create){
    Object.create=function(proto){
        function F(){};
        F.prototype=proto;
        return new F;  /*new调用时创建一个对象,并且原型指向F.prototype,即proto*/
    }
}
</script>

 

本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:http://www.cnblogs.com/starof/p/4904929.html有问题欢迎与我讨论,共同进步。 

 

instanceof

[1,2] instanceof Array === true
new Object() instanceof Array === false

在instanceof左侧是对象,右侧是构造器(函数),instanceof用于判断右边这个构造器的prototype属性是否在左侧这个对象的原型链上。

实现继承的方式

    function Person(){

    }
    function Student(){

    }
    Student.prototype = Person.prototype; //1 这是错的!!
    Student.prototype = new Person(); //2  有点小问题,当构造函数要传入参数的时候
    Student.prototype = Object.create(Person.prototype);  //3 这个方法较好,但要ES5
    Student.prototype.constructor = Student;
    //对于1,2,3步骤有一个比较好的方法,自己封装一个Object.create()方法
    if(!Object.create){  //4.
        Object.create = function(proto){
            function F(){}
            F.prototype = proto;
            return new F;
        }
    }
  1. 错的,因为子类有自己的方法,修改Student不能同时也把Person改掉
  2. 调用构造函数方法,也能将Student。prototype指向一个原型为Person.prototype的对象,但是这个方法当构造函数要传入参数的时候会有问题,因为我们还没有实例化呢,你参数要传入什么呢?对吧~
  3. 较为理想,Student的原型是个空的对象,这样修改就不会改到Person,But
    ES5采用。所以我们自己封装了一个4.
  4. 在ES5之前,模拟一个Object.create(),原理是模拟一个空函数,并且把这个空函数的prototype属性赋值为proto这个我们想作为原型的对象,用return new F这样呢就创建出一个空对象,这个对象的原型指向proto这个参数。

题目描述:
请给Array本地对象增加一个原型方法,它用于删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组。

Array.prototype.distinct = function() {
    var ret = [];
    for (var i = 0; i < this.length; i++)
    {
        console.log(this);
        for (var j = i+1; j < this.length;) {   
            if (this[i] === this[j]) {              
                var tmp = this.splice(j, 1);
                //console.log(tmp)
                ret.push(tmp[0]);
            } else {
                j++;
            }
        }
     }
     return ret;
}
//for test
console.info(['a','b','c','d','b','a','e'].distinct())

发表评论

电子邮件地址不会被公开。 必填项已用*标注