摘要:中的和是一门很灵活的语言,尤其是。即然是面向对象的编程语言,那也是不可或缺的。在中,永远指向的是他的调用者。定义是存在于实例化后对象的一个属性,并且指向原对象的属性。我们在扩展的时候,同时父类也会有对应的方法,这很显然是一个很严重的问题。
javascript中的this和new
javascript是一门很灵活的语言,尤其是function。他即可以以面向过程的方式来用,比如:
function getName() { return "张三" } getName()
也可以以面向对象的方式来用,比如:
function User() { this.name = "张三" } var user = new User()
javascript是如何实现面向对象编程的呢?他提供了new这个关健字,有了new就可以把对象进行实例化,比如:
function User(name, age){ this.name = name this.age = age } var zs = new User("zs", 20) var ls = new User("ls", 30)
new出来的两个实例,会开辟两块新的内存区域,来保存这些数据,同时有指针指向对象User。所以就有instanceof这个运算符,这个运算符的意思就是:a是不是A的实例。比如上例:zs instanceof User的返回值是true。
即然是面向对象的编程语言,那this也是不可或缺的。在javascript中,this永远指向的是他的调用者。要理解这句话,我们举几个例子:
例子1
function test(){ this.name = "zs" } test()
当执行完成之后,这个name会直接挂载到window下面,因为是这样执行的:winow.test()。
例子2
var game = document.getElementById("game") game.addEventListener("click", function () { setTimeout(function () { this.innerText = "Clicked" }, 1000) })
这个例子很简单,点击某个元素的时候,1秒后,让他里面的html改成Clicked,可是你发现这样不好使,就是因为this指向的问题,因为这里面的this也指向window了,所以你执行window.innerText会返回Clicked。
例子3
function User(name) { this.name = name this.getName = function () { console.log(this.name) } } var u = new User("zs") u.getName()
这里面的this的指向没有问题,因为按照之前的原则,调用者是u,也就是User的实例,所以在方法getName中,this.name相当于u.name,所以打印出zs。
prototype和__proto__prototype
javascript是面向对象的语言,这个上面已经提过了,其他面向对象语言有一个必备我就是继承,很显然在ES6之前,没有extends这个关键字,那么,javascript就是利用prototype的原型链来实现继承。先记住这句话,我们一会会说到继承。prototype其实只是对象的一个属性,在Chrome控制台下,可以直接看出来,但是这个属性很特殊,这个属性下可以挂载任何的对象、方法、属性,而且挂载的东西可以反映到实例下对象上。说的比较绕,我们看个例子:
function User(name) { this.name = name } User.prototype.getName = function () { console.log(this.name) } var u = new User("zs") u.getName()
我们在User.prototype上面挂载了getName的方法,在下面实例化User之后的u,就可以访问这个方法。
看到这,你可以有个疑问,既然是给实例化对象用的,那下面这种方式岂不是更好、更直观?
function User(name) { this.name = name this.getName = function () { console.log(this.name) } } var u = new User("zs") u.getName()
如果我们和Java语言进行对应,User相当是Class,name相当于属性,getName相当于里面的方法,完美映射!可以这样有一个问题啊,就是太费内存了。因为每new一个对象,都会占用一块内存区域,这样User里面方法属性越多,那么每个实例化的对象都会对这些进行 深复制,那么占用的内存空间就越大。那么javascript是如何通过prototype来解决内存占用的问题的呢?这就需要引用__proto__。
__proto__
定义:__proto__是存在于实例化后对象的一个属性,并且指向原对象的prototype属性。
比如上例中的u.__proto__ === User.prototype返回的是true。可以在Chrome控制台下查看u.__proto__。
你会发现,不对吧,User对象下也有__proto__啊。那是因为User也是Function的实例,不信你可以试一下User.__proto__ === Function.prototype的返回值。其实我们这样定义函数:function test(){}是一个语法糖的写法,全拼应该是这样:var test = new Function("alert(1)")。
现在我们来解释为什么使用prototype能节省内存。不知道你有没有注意到上面一句代码u.__proto__ === User.prototype,我为什么要使用三等?因为三等号除了值、类型外,内存地址也必须是相等的,也就是说User不管实例化多少对象,他们的prototype只有一份,放在User里。客户端的浏览器环境不像服务器,内存还是比较紧张的,所以javascript通过这种方式,来解决内存占用问题。
继承方式一:直接继承
先举个例子:
var Animal = function (name) { this.name = name } Animal.prototype.walk = function () { console.log("I can walk!") } Animal.prototype.getName = function () { console.log("My name is " + this.name + "!") } var Dog = function (name) { this.name = name } Dog.prototype = Animal.prototype var d = new Dog("Tom") d.getName() d.walk()
我们建立一个父类Animal对象,建立一个子类Dog,我们想让Dog也有walk方法和getName方法,通过上面对prototype的了解,我们最先想到的是Dog.prototype = Animal.prototype,这样子类和父类的prototype相等,那子类就有父类所有方法喽,继承链条是这样的:d.__proto__ === Dog.prototype === Animal.prototype。
这样很直观,但是也有一个比较严重的问题。我们在扩展Dog的时候,同时父类也会有对应的方法,这很显然是一个很严重的问题。
方式二:实例化继承
为了解决上面的问题,我们需要引入一个空函数,这个空函数做为桥梁,把子类和父类之间的连接切断。实现如下:
var F = function () {} F.prototype = Animal.prototype Dog.prototype = new F() Dog.prototype.say = function () { console.log("Say") }
为什么是Dog.prototype = new F()呢?因为这样即可以继承Animal的所有方法,他的原型链是这样的:
d.__proto__ --> Dog.prototype --> new F().__proto__
执行walk方法,F已经有了,所以就不会再找Animal了
新增加的方法又不影响父类,这句怎么讲?因实例化的对象没有prototype属性!所以不会影响
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/84429.html
摘要:不必在构造函数中定义对象实例的信息。其次,按照一切事物皆对象的这饿极本的面向对象的法则来说,类本身并不是一个对象,然而原型方式的构造函数和原型本身也是个对象。第二个问题就是在创建子类型的实例时,不能向超类型的构造函数中传递参数。 前言 对象(Object)应该算是js中最为重要的部分,也是js中非常难懂晦涩的一部分。更是面试以及框架设计中各出没。写这篇文章,主要参考与JavaScrip...
摘要:引言对于面向对象,相信大家一定不陌生。创建对象面向对象第一步是什么答创建对象。构造函数优于工厂模式也是在于它可以通过辨识出一类的对象。 引言 对于面向对象,相信大家一定不陌生。最近看了一些关于es6面向对象的知识,正好通过这篇文章把关于面向对象的东西给串起来分享给大家。 什么是对象 很多人会鄙视我,说你这篇文章是骗骗刚入行的小朋友的吧,什么是对象我还能不知道?骂我的吃瓜群众先冷静一下,...
摘要:会造成内存浪费的问题构造函数继承声明父类声明子类生成实例组合式继承组合式继承是汲取了两者的优点,既避免了内存浪费,又使得每个实例化的子类互不影响。 写在前面 既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解... 面向对象与面向过程 面向对象和面向过程是两种不同的编程思想,刚开始接触编程的时候,我们大都是从面向过程起步的,毕竟像我一样,大家接触的第一门计算机语言大概率都是C语...
摘要:面向对象面向对象编程的全称是,简称,面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式。面向对象编程的三个主要特征是封装继承多态。 面向对象 面向对象编程的全称是Object Oriented Programming,简称OOP,面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式。面向对象编程可以看做是使用一系列对象相互协作的软件设计,面向对象程序设计的目的是在编程中促...
摘要:如果没有学习过计算机科学的程序员,当我们在处理一些问题时,比较熟悉的数据结构就是数组,数组无疑是一个很好的选择。 showImg(https://segmentfault.com/img/bVTSjt?w=400&h=300); 1、常见 CSS 布局方式详见: 一些常见的 CSS 布局方式梳理,涉及 Flex 布局、Grid 布局、圣杯布局、双飞翼布局等。http://cherryb...
阅读 2233·2021-11-17 09:33
阅读 2773·2021-11-12 10:36
阅读 3394·2021-09-27 13:47
阅读 883·2021-09-22 15:10
阅读 3484·2021-09-09 11:51
阅读 1391·2021-08-25 09:38
阅读 2757·2019-08-30 15:55
阅读 2607·2019-08-30 15:53