博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从无到有的学习JavaScript之对象模型——第五篇
阅读量:4131 次
发布时间:2019-05-25

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

Javascript是一种基于原型的面向对象语言,而不是基于类的面向对象语言。JS是基于原型的语言,它只有原型对象的概念。原型对象就是一个模板,新的对象从这个模板构建,从而获得最初的属性,任何对象在运行时可以动态的增加属性。而且任何一个对象都可以作为另一个对象的原型,这样后者就可以共享前者的属性。

1.定义类

1.1 字面声明方式

let obj = {    a:1,    b: 'abc',    'c': 100,    show: () => {        console.log('show function')    }}let obj1 = {obj}console.log(obj1)// { obj: { a: 1, b: 'abc', c: 100 } }let x = 100, y = 200, z = 'abc'let obj2 = {x: x, y, z}  // 注意第一个x是字符串key,第二个x是变量,y,z都是变量// { x: 100, y: 200, z: 'abc' }console.log(obj2)let obj3 = {x: x, y, [z]: z}  // 想要使用z变量的值作为key,需要加中括号console.log(obj3)// { x: 100, y: 200, abc: 'abc' }

注意:对象的key只能是字符串类型,最后都会被转换成字符串。

2. ES6之前的构造器

  1. 定义一个函数(构造器)对象,函数名首字母大写
  2. 使用this定义属性
  3. 使用new和构造器创建一个对象
function Point(x, y){    this.x = x    this.y = y    console.log('Point~~~~~~~~~~~')}console.log(Point)  // 只有[Function: Point]p1 = new Point(4, 5)  // 实例化,如果前面没有new,则只是普通的函数调用,那么打印出的undefined;加new后,后面的就是构造器console.log(p1)p1.show()/*Point~~~~~~~~~~~Point { x: 4, y: 5, show: [Function] }*/console.log('------------------')function Point3D(x, y, z){    Point.call(this, x, y)  // 继承,此时的this是Point3D的实例    this.z = z    console.log('Point3D~~~~~~~~~~~~~')}console.log(Point3D)p2 = new Point3D(10, 11, 12)console.log(p2)p2.show()/*[Function: Point3D]Point~~~~~~~~~~~Point3D~~~~~~~~~~~~~Point3D { x: 10, y: 11, show: [Function], z: 12 }Point3D { x: 10, y: 11, show: [Function], z: 12 } 10 11*/

new构建一个新的通用对象,new操作符将新的对象的this值传递给Point3D构造器函数,函数为这个对象创建类z属性。new后得到一个对象,使用这个对象的this来调用构造器,那么如何执行“基类”的构造器方法呢?使用point3D对象的this来执行Point对象的构造器,所以使用call方法,传入子类的this。

 

3. ES6中的构造器

从ES6开始,新提供了class关键字,使得创建对象更加简单、清晰。

  • 类定义使用class关键字。创建的本质上还是函数,是一个特殊的函数
  • 一个类只能拥有一个名为constructor的构造器方法。如果没有显示的定义一个构造方法,则会添加一个默认的constructor方法。
  • 继承使用extends关键字
  • 一个构造器可以使用super关键字来调用一个父类的构造函数
  • 类没有私有属性

 

class Point{    constructor(x,y){  // 构造器        this.x = x        this.y = y        this.show = () => {console.log("Point")}    }    show(){  // 方法        console.log(this, this.x, this.y)    }}let p3 = new Point(1, 2)  // class 定义的是新语法,必须使用new关键字实例化p3.show()// Point { x: 1, y: 2 } 1 2class Point3D extends Point{    constructor(x, y, z){        super(x, y)        this.z = z        this.show = () => {console.log("Point3D")}    }    show(){        console.log(this, this.x, this.y, this.z)  // 重写了子类的方法,会覆盖父类的方法    }}let p4 = new Point3D(3, 4, 5)p4.show()// Point3D { x: 3, y: 4, z: 5 } 3 4

注意:父类、子类使用同一种方式定义属性或方法时,子类覆盖父类。访问同名属性或方法时,优先使用属性

class Add{    constructor(x, y){        this.x = x        this.y = y    }    static print(){  // 把此处的静态方法理解为python中的classmethod        console.log(this, this.x)  // this为[Function: Add],不是实例,就是说this指向类,不是类的实例    }}add = new Add(10, 20)console.log(Add)  // [Function: Add]Add.print()  // 结果为[Function: Add] undefined =>因为类没有定义x属性// add.print()  // 注意这里与python不同,实例不能直接访问静态方法,与c++、java是一致的add.constructor.print()  // 实例访问静态方法,需要借助构造器方法constructor

JS中静态的概念与pyhton的静态方法不同,相当于python中的类方法(classmethod)

4.this的坑

虽然js和c++_、java一样有this,但是js的表现是不同的。原因在于,c++、java是静态编译型语言,this是编译期绑定,而js是动态语言,运行期绑定。

var school = {    name : 'magedu',    getNameFunc: function(){        console.log(this.name)        console.log(this)        return function(){            console.log(this === global)  // this是否是global对象            return this.name        }    }}console.log(school.getNameFunc()())/*magedu{ name: 'magedu', getNameFunc: [Function: getNameFunc] }true // 此处是true说明this是全局变量,是global,没有name属性,所以最后打印undefinedundefined*/

 

为了分析上面的程序,先学习一些知识:函数执行时,会开启新的上下文环境ExecutionContext。创建this属性,但是this是什么就要看函数怎么调用了。

  • myFunction(1, 2, 3),普通的函数调用方式,this指向全局对象,全局对象是nodejs的global或者浏览器的window。
  • myObject.myFunction(1, 2, 3),对象方法的调用方式,this指向包含该方法的对象。
  • call、apply、bind方法调用时,要看第一参数是谁。

我们在使用时,有时候需要明确的让this必须是我们期望的对象,该如何做呢?解决上述的方法有很多:

显示传入:

var school = {    name : 'magedu',    getNameFunc: function(){        console.log(this.name)        console.log(this)        return function(that){            console.log(this == global)  // this是否是global对象            return that.name        }    }}console.log(school.getNameFunc()(school))/***magedu**{ name: 'magedu', getNameFunc: [Function: getNameFunc] }**true  **magedu*/

通过主动传入对象,避开了this的问题。

ES3引入了apply、call方法:

function Print(){    this.print = function(x, y) {console.log(x + y)}}p = new Print(100, 200)p.print(10, 20)p.print.call(p, 10, 20)  // 30p.print.apply(p, [10, 20])  // 30// apply、call方法都是函数对象的方法,第一参数都是对象的实例,apply传其他参数需要使用数组/*magedu{ name: 'magedu', getNameFunc: [Function: getNameFunc] }false  */var school = {    name : 'magedu',    getNameFunc: function(){        console.log(this.name)        console.log(this)        return () =>{            console.log(this == global)  // this是否是global对象            return this.name        }    }}console.log(school.getNameFunc().call(school))/*mageduschool { name: 'magedu' } 'object'falsemagedu*/

apply、call方法都是函数对象的方法,第一参数都是传入对象的实例。apply传其他参数需要使用数组。call传其他参数需要使用可变参数收集。

ES5引入bind方法:

var school = {    name: 'magedu',    getNameFunc: function(){        console.log(this.name)        console.log(this)        return function (){            console.log(this === global)            return this.name        }    }}var func = school.getNameFunc()console.log(func)/*magedu{ name: 'magedu', getNameFunc: [Function: getNameFunc] }[Function]*/var new_func = func.bind(school)  // 绑定后会返回新的函数console.log(new_func)  // [Function: bound ]console.log(new_func())/*falsemagedu*/

apply、call方法,参数不同,调用时传入this。bind方法是为函数先绑定this,调用时直接用。

ES6引入支持this的箭头函数:

// ES6新的定义class school{    constructor(){        this.name = 'magedu'    }    getNameFunc(){        console.log(this.name)        console.log(this, typeof this)  // this是object        return () => {            console.log(this === global)  // this不是全局变量            return this.name        }    }}console.log(new school().getNameFunc()())/*mageduschool { name: 'magedu' } 'object'falsemagedu*/

 

 

 

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

你可能感兴趣的文章
App开发:强制更新app
查看>>
CSS3的appearance属性-改变任何元素的浏览器默认风格
查看>>
JS eval()函数
查看>>
HTML DOM createDocumentFragment() 方法
查看>>
jQuery 遍历函数
查看>>
jQuery.extend 函数详解
查看>>
HTML 事件属性
查看>>
HTML属性
查看>>
CSS overflow 属性
查看>>
使用CSS3 backface-visibility:hidden;属性制作翻转动画效果
查看>>
jQuery 效果 - animate() 方法
查看>>
CSS cursor 属性
查看>>
navigator.userAgent.indexOf来判断浏览器类型
查看>>
触摸事件(touchstart、touchmove和touchend)
查看>>
Jquery.ScrollLoading图片延迟加载技术
查看>>
CSS3背景渐变属性 linear-gradient(线性渐变)和radial-gradient(径向渐变)
查看>>
内联元素和块级元素
查看>>
HTML 5 <progress>进度标签
查看>>
html <code> <pre>标签
查看>>
HTML iframe 用法小总结
查看>>