js原型链,Javascript重温OOP之原型与原型链

时间: 2017-11-03阅读: 633标签: js知识作者: Allin_Lin

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

一般面向对象包含:继承,封装,多态,抽象

对象形式的继承

浅拷贝

var Person = {
    name: 'allin',
    age: 18,
    address: {
        home: 'home',
        office: 'office',
    }
    sclools: ['x','z'],
};

var programer = {
    language: 'js',
};

function extend(p, c){
    var c = c || {};
    for( var prop in p){
        c[prop] = p[prop];
    }
}
extend(Person, programer);
programer.name;  // allin
programer.address.home;  // home
programer.address.home = 'house';  //house
Person.address.home;  // house

从上面的结果看出,浅拷贝的缺陷在于修改了子对象中引用类型的值,会影响到父对象中的值,因为在浅拷贝中对引用类型的拷贝只是拷贝了地址,指向了内存中同一个副本。

深拷贝

function extendDeeply(p, c){
    var c = c || {};
    for (var prop in p){
        if(typeof p[prop] === "object"){
            c[prop] = (p[prop].constructor === Array)?[]:{};
            extendDeeply(p[prop], c[prop]);
        }else{
            c[prop] = p[prop];
        }
    }
}

利用递归进行深拷贝,这样子对象的修改就不会影响到父对象。

extendDeeply(Person, programer);
programer.address.home = 'allin';
Person.address.home; // home

利用call和apply继承

function Parent(){
    this.name = "abc";
    this.address = {home: "home"};
}
function Child(){
    Parent.call(this);
    this.language = "js"; 
}

ES5中的Object.create()

var p = { name : 'allin'};
var obj = Object.create(o);
obj.name; // allin

Object.create()作为new操作符的替代方案是ES5之后才出来的。我们也可以自己模拟该方法:

//模拟Object.create()方法
function myCreate(o){
    function F(){};
    F.prototype = o;
    o = new F();
    return o;
}
var p = { name : 'allin'};
var obj = myCreate(o);
obj.name; // allin

目前,各大浏览器的最新版本(包括IE9)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署。

  if (!Object.create) {
    Object.create = function (o) {
       function F() {}
      F.prototype = o;
      return new F();
    };
  }

类的继承

Object.create()

function Person(name, age){}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
    console.log('eating...');
}
function Programmer(name, age, title){}

Programmer.prototype = Object.create(Person.prototype); //建立继承关系
Programmer.prototype.constructor = Programmer;  // 修改constructor的指向

调用父类方法

function Person(name, age){
    this.name = name;
    this.age = age;
}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
    console.log('eating...');
}

function Programmer(name, age, title){
    Person.apply(this, arguments); // 调用父类的构造器
}


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

Programmer.prototype.language = "js";
Programmer.prototype.work = function(){
    console.log('i am working code in '+ this.language);
    Person.prototype.eat.apply(this, arguments); // 调用父类上的方法
}

封装

命名空间

js是没有命名空间的,因此可以用对象模拟。

var app = {};  // 命名空间app
//模块1
app.module1 = {
    name: 'allin',
    f: function(){
        console.log('hi robot');
    }
};
app.module1.name; // "allin"
app.module1.f();  // hi robot

静态成员

function Person(name){
    var age = 100;
    this.name = name;
}
//静态成员
Person.walk = function(){
    console.log('static');
};
Person.walk();  // static

私有与公有

function Person(id){
    // 私有属性与方法
    var name = 'allin';
    var work = function(){
        console.log(this.id);
    };
    //公有属性与方法
    this.id = id;
    this.say = function(){
        console.log('say hello');
        work.call(this);
    };
};
var p1 = new Person(123);
p1.name; // undefined
p1.id;  // 123
p1.say();  // say hello 123

模块化

var moduleA;
moduleA = function() {
    var prop = 1;

    function func() {}

    return {
        func: func,
        prop: prop
    };
}(); // 立即执行匿名函数

prop,func 不会被泄露到全局作用域。或者另一种写法,使用 new

moduleA = new function() {
    var prop = 1;

    function func() {}

    this.func = func;
    this.prop = prop;
}

多态

模拟方法重载

arguments属性可以取得函数调用的实参个数,可以利用这一点模拟方法的重载。

function demo(a, b ){
    console.log(demo.length); // 得到形参个数
    console.log(arguments.length); //得到实参个数
    console.log(arguments[0]);  // 第一个实参 4
    console.log(arguments[1]);  // 第二个实参 5
}

demo(4, 5, 6);
//实现可变长度实参的相加
function add(){
    var total = 0;
    for( var i = arguments.length - 1; i >= 0; i--){
        total += arguments[i];
    }
    return total;
}

console.log(add(1));  // 1
console.log(add(1, 2, 3));  // 7


// 参数不同的情况
function fontSize(){
    var ele = document.getElementById('js');
    if(arguments.length == 0){
        return ele.style.fontSize;
    }else{
        ele.style.fontSize = arguments[0];
    }
}
fontSize(18);
console.log(fontSize());

// 类型不同的情况
function setting(){
    var ele = document.getElementById('js');
    if(typeof arguments[0] === "object"){
        for(var p in arguments[0]){
            ele.style[p] = arguments[0][p];
        }
    }else{
        ele.style.fontSize = arguments[0];
        ele.style.backgroundColor = arguments[1];
    }
}
setting(18, 'red');
setting({fontSize:20, backgroundColor: 'green'});

方法重写

function F(){}
var f = new F();
F.prototype.run = function(){
    console.log('F');
}
f.run(); // F

f.run = function(){
    console.log('fff');
}
f.run();  // fff

抽象类

在构造器throw new Error('');中抛异常。这样防止这个类被直接调用。

function DetectorBase() {
    throw new Error('Abstract class can not be invoked directly!');
}

DetectorBase.prototype.detect = function() {
    console.log('Detection starting...');
};
DetectorBase.prototype.stop = function() {
    console.log('Detection stopped.');
};
DetectorBase.prototype.init = function() {
    throw new Error('Error');
};

// var d = new DetectorBase();// Uncaught Error: Abstract class can not be invoked directly!

function LinkDetector() {}
LinkDetector.prototype = Object.create(DetectorBase.prototype);
LinkDetector.prototype.constructor = LinkDetector;

var l = new LinkDetector();
console.log(l); //LinkDetector {}__proto__: LinkDetector
l.detect(); //Detection starting...
l.init(); //Uncaught Error: Error

转载地址:http://www.jianshu.com/p/ac3e6c88987a

解密JavaScript执行上下文

首先我们先了解一下什么是执行上下文栈(Execution context stack)。分别展示了栈、堆和队列,其中栈就是我们所说的执行上下文栈;堆是用于存储对象这种复杂类型,我们复制对象的地址引用就是这个堆内存的地址

javascript中的依赖注入

使用没有依赖的模块,显然这是很难实现的。即使你创建了很好的像黑盒一样的组件,但总有个将所有部分合并起来的地方。这就是依赖注入起作用的地方,当前来看,高效管理依赖的能力是迫切需要的,本文总结了原作者对这个问题的看法。

js中&与&&,|与||的区别

&、|、~都是位操作符,而&&、|、~|都是逻辑操作!。&&是逻辑与运算符假前真后,||是逻辑或运算符真前假后,&是按位与操作两个数值的个位分别相与,同时为1才得1,只要一个为0就为0。

Js常用基础算法

冒泡排序;插入排序 过程就像你拿到一副扑克牌然后对它排序一样;快速排序;回文字符串;翻转字符串;字符串中出现最多次数的字符;数组去重;二分查找

如何掌握并用好defer(延迟执行)

defer:在函数A内用defer关键字调用的函数B会在在函数A return后执行。先看一个基础的例子,了解一下defer的效果,这段代码运行后会打印出:

44道JS难题

国外某网站给出了44道JS难题,这些题涉及面非常广,涵盖JS原型、函数细节、强制转换、闭包等知识,而且都是非常细节的东西,透过这些小细节可以折射出很多高级的JS知识点。

JS 超类和子类

看到javascript高级程序设计的面向对象章节看到超类与子类这个概念词,不懂上度娘查了才知道是怎么一回事。说到超类与子类,就不得不提起原型模式,原型对象,原型链与原型链继承了

js中void 0 与 undefined

偶然看到一个问题:为什么有的编程规范要求用 void 0 代替 undefined?如果不知道这个答案的小伙伴,第一反应就要问void 0是什么鬼?

document.write和innerHTML的区别

document.write只能重绘整个页面,innerHTML可以重绘页面的一部分。 document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。

js中delete关键字

delete关键字的作用:删除对象的属性 语法:delete 对象.属性、可以删除没有使用var关键字声明的全局变量(直接定义在window上面的属性)、删除数组元素、不能删除内置对象的属性、不能直接删除从原型上继承的属性

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

广告赞助文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全