资讯专栏INFORMATION COLUMN

深度剖析js原型及面向对象

Corwien / 2493人阅读

摘要:返回一个对象先说一个最常用的方法构造函数获取所有节点获取节点的长度作用于链式调用测试上面的代码就可以实现的效果因为我没读过源码。

es5版本:(过两天写es6 版本的)
由浅入深地讲,
先说使用,

function person(age, sex) {
        this.age = age;
        this.sex = sex;
        this.clothes = [];
    }
    
     person.prototype.addCloud = function(cloth) {
           this.clothes.push(cloth);
    }  // 给对象增加增添服装的方法
    
    var a = new person(18, 0); // a  = {age: 18, sex: 0, clothes: []}, a 现在就是一个18岁的小女孩了
    var b = new person(19, 1); // b  = {age: 19, sex: 1, clothes: []}, b 现在就是一个19岁的小男孩了
    
    a.addCloud("redCloth") // a = {age: 18, sex: 0, clothes: ["redCloth"]},a新添 红色衣服 
以上内容是原型最简单的使用,相当于构造一个对象,person被称为构造函数,new person()被称为实例化,a,b被称为实例对象

稍微增加点难度
  person.prototype.sayHello = function(word) {
      console.log( "I am " + this.age + "years old!" + word);
  }
  
  a.sayHello("nice to meet you"); //I am 18years old!nice to meet you
这里输出了a的一个属性age;

再增加一点难度,插个题外话,讲一下this 的指向问题。
这里调用实例对象的age,在声明方法的时候,是用的this。刚刚增添衣服的时候,也是用的this,原因是因为a调用的这个方法,要是写一个
  var c = a.sayHello;
  c("nice to meet you") //I am undefinedyears!nice to meet you
  那么如果想像刚刚一样的执行效果有以下四种方法
  1.window.age = a.age;
  2.c.bind(a)("nice to meet you");
  3.c.call(a, "nice to meet you");
  4.c.apply(a, ["nice to meet you"]);
稍微增加点难度,实现一个jQuery的效果;
以前经常有人问为什么JQ不能混搭原生js写,这里也将作出解答。
   
  
测试

上面的代码就可以实现jquery 的效果(因为我没读过jquery 源码。所以就不胡乱判断jquery 是不是也用这个原理)
说一下为什么jq 不能和 原生js 混搭用
从上面的内容不难看出,$之后返回的是一个实例化对象,而不是一个或多个节点。所以实际上我们并不是直接去操作节点,而且通知这个实例化对象,这个对象再去处理的节点。
上面click之后有一个return this , 这个是链式调用的核心。所谓的链式调用,表面上是一个个调用下去,比如
$().click(1).click(2)
实际上可以理解为 click完成后 返回到 $ ,然后再去click ,也就是

$().click(1) =>返回 $() 然后=> $().click(2);

如果再深入一点说

$()创建$对象 -> 对象$.click(1)执行1中事件并抛出执行结果---$对象 -> click(1)抛出的结果$对象再去执行click(2)的事件,并抛出执行结果---$对象

上面讲了创造一个对象,下面说一原型链

原型链这方面有两个关键词 __proto__ 以及 prototype

前者是针对于实例化对象的,后者是针对于构造函数

写成代码

    function test() {}
    
    new test().__proto__ == test.prototype; //true

这个如果说到内存层次的话,就是他两公用的一个内存,如果有很多实例化对象的话,就是他们__proto__的指针都指向这块内存地址

这里有一个知识点。

一个对象,如果自身属性里面没有,就会去 __proto__属性里面去搜索

就跟员工一样,有房子住自己房子,没房子就住集体宿舍。自己买了高配电脑就用自己的,没买就用公司的低配电脑。实例化对象.__proto__就像员工瞅瞅公司有啥公用物品,构造函数.prototype就是公司给员工购买啥公用物品, 所以实例化对象.__proto__ 也就和 构造函数.prototype指向一块了

所以 即便test 已经实例化了。如果 test.prototype增加一个属性, 实例化的test依旧会获得这个属性。

function test() {}
 var x = new test();
 console.log(x.age) // undefined
 test.prototype.age = 5;
 console.log(x.age) // 5

如果代码写成这样

function test() {}
 var x = new test();
 console.log(x.age) // undefined
 test.prototype.age = 5;
 x.age = 10;
 console.log(x.age) // 10

所以 x.age 实际上搜索的是 x.__proto__.age

话都说到这份上了,我就随便聊下继承吧。

最简单的继承,合二为一。

    function test() {}
    test.prototype.age = 5;
    function newTest() {}
    newTest.prototype = new test();
    new newTest().age//5

讲下这个继承的原理。 刚刚说过了
一个对象,如果自身属性里面没有,就会去 __proto__属性里面去搜索
那么new NewTest()的__proto__也就是 new test();
new Newtest()里面没有的,就去__proto__里面(new test())里面找
new test()没有的就去new test()的 __proto__里面找,然后就找到了test的prototype
当然这个继承他是没有灵魂的,因为test变化了newTest 也会变。

call继承,一次性产品
    function test() {
        this.sex = 0;
    }
    function newTest() {
        this.sex = 1;
        test.call(this);
    }
    new newTest().sex//0

call 我以前对他有过很多的理解,后来终于想到了一个最简单的理解,就是洗脑,而且是强制性的,有的替换,没有的,送你;
call的常用方法 func.call(小a, func参数);
func 大热天跑到了小a家里,问小a 有没有扇子,借过来扇了扇之后,对小a说他的扇子太破,他这边有个新的,强制塞给了小a,并收取了小a两块钱
写成代码

 function func(money) {
     console.log(this.fan);
     this.fan= "new_fan";
     this.money -= money;
     console.log(this.fan);
 }
 
 var obj_a  = {
     money: 10,
     fan: "pretty_fan"
 }
 
 func.call(obj_a, 2);
 console.log(obj_a);
     //pretty_fan
     //new_fan
     //{money: 8, fan: "new_fan"}

继续聊继承,call 这个继承也是不怎么有灵魂的继承,说白了就是把别人的东西都替换成自己的东西,别人没有的,给别人,弄不好还被套路一波。但是继承不到prototype里面的。

有一个继承用Object.create()去继承。。。
这个看上去比上面的高档不少,实际上也没什么用;

互不干扰式继承

    这个就显得比较有灵魂,因为单纯继承,而且还不会被干扰
    c = JSON.parse(JSON.stringify(new test()));
    因为会拷贝不到里面不可遍历的属性
    所以再合并一下之前的__proto__就行了。
    newTest.prototype = Object.assign(new test().__proto__, c);

至于其他各种花里胡哨的继承,网上一查一堆,我就不多介绍了,反正也就是花架子而已

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105144.html

相关文章

  • js对象详解(JavaScript对象深度剖析深度理解js对象)

    摘要:对象详解对象深度剖析,深度理解对象这算是酝酿很久的一篇文章了。用空构造函数设置类名每个对象都共享相同属性每个对象共享一个方法版本,省内存。 js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了。 JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕。 平时发的文章基本都是开发中遇到的问题和对...

    CatalpaFlat 评论0 收藏0
  • 剖析JS原型链和继承

    摘要:接下来我们来聊一下的原型链继承和类。组合继承为了复用方法,我们使用组合继承的方式,即利用构造函数继承属性,利用原型链继承方法,融合它们的优点,避免缺陷,成为中最常用的继承。 JavaScript是一门面向对象的设计语言,在JS里除了null和undefined,其余一切皆为对象。其中Array/Function/Date/RegExp是Object对象的特殊实例实现,Boolean/N...

    darkerXi 评论0 收藏0
  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0
  • js细节剖析】通过"="操作符为对象添加新属性时,结果会受到原型链上的同名属性

    摘要:在使用的过程中,通过操作符为对象添加新属性是很常见的操作。但是,这个操作的结果实际上会受到原型链上的同名属性影响。通过它,可以做到操作符做不到的事情,比如为对象设置一个新属性,即使它的原型链上已经有一个的同名属性。 在使用JavaScript的过程中,通过=操作符为对象添加新属性是很常见的操作:obj.newProp = value;。但是,这个操作的结果实际上会受到原型链上的同名属性...

    wemallshop 评论0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函数式编程前端掘金引言面向对象编程一直以来都是中的主导范式。函数式编程是一种强调减少对程序外部状态产生改变的方式。 JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,...

    cfanr 评论0 收藏0

发表评论

0条评论

Corwien

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<