博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈面向对象的javascript几个特性
阅读量:6717 次
发布时间:2019-06-25

本文共 3556 字,大约阅读时间需要 11 分钟。

javascript中的thisnew

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相当是Classname相当于属性,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.prototypevar 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.prototypeDog.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属性!所以不会影响

转载地址:http://cvumo.baihongyu.com/

你可能感兴趣的文章
ORM数据层框架的设计热点:更新指定的列的几种设计方案
查看>>
access数据库注入
查看>>
语言的歧义
查看>>
dede后台空白或者登录以后空白,点注销以后也是空白的解决方式
查看>>
微软虚拟化之一Hyper-V 2.0的安装及基本配置
查看>>
Silverlight实用窍门系列:52.Silverlight中的MVVM框架极速入门(以MVVM Light Toolkit为例)...
查看>>
DNS服务-详解
查看>>
mysqldump结合脚本的备份方案
查看>>
httpd-2.4 基础配置图解及实现
查看>>
深入浅出分布式文件系统MogileFS集群
查看>>
nagios被监控端nrpe添加流量监控
查看>>
如何在ROS中使用PCL—数据格式(1)
查看>>
[cocos2d-x]动作+场景切换
查看>>
从传统运维到云运维演进历程之软件定义存储(五)下
查看>>
解决Druid设置Oracle的Clob字段时的小坑
查看>>
简单安装openwebmail
查看>>
【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记46 Persistence持久化
查看>>
java删除文件夹
查看>>
delphi 学生管理系统总结
查看>>
HTML5
查看>>