龙空技术网

第28节 对象和构造函数-Javascript-零点程序员-王唯

零点程序员 125

前言:

现在姐妹们对“js对象字面量与构造函数创建”都比较看重,你们都需要了解一些“js对象字面量与构造函数创建”的相关知识。那么小编在网络上汇集了一些对于“js对象字面量与构造函数创建””的相关知识,希望各位老铁们能喜欢,朋友们一起来学习一下吧!

本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。

对象是ES的的一种复合数据类型,即引用类型;即,对象就是一组属性与方法的集合;

ES没有类的概念,所以它的对象也与其他语言中的对象有所不同;

ES把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数;相当于说对象是一组无序的值,对象的每个属性或方法都有一个名字,而每个名字都映射到一个值,正因为这样,可以把ES的对象看作成一个散列表,其中是一组名值对,它们的值可以是数据或函数;

每个对象都是基于一个引用类型创建的,这个引用类型可以原生类型,也可以是自定义的函数;

一.理解对象:

可以创建一个最简单的自定义对象,就是使用Object,然后再为它添加属性和方法,如:

var person = new Object();person.name = "wangwei";person.age = 18;person.jog = "Engineer";person.sayName = function(){    alert(this.name);}

在多种场景中,常用对象字面量创建对象,如:

var person = {    name:"wangwei",    age:18,    job:"Engineer",    sayName:function(){        alert(this.name);    }};

对象中的this:

当一个函数作为对象的属性存在时,并且通过对象调用这个方法,那么函数中的this就指向调用函数的对象;

this的好处在于,可以更加方便的访问对象内部成员;

早绑定和晚绑定:

绑定:把对象的成员与对象实例结合在一起的方法。

早绑定:

指在实例化对象之前定义它的属性和方法,这样编译器或解释程序就能够提前转换机器代码。ES不是强类型语言,所以不支持早绑定;

晚绑定:

编译器或解释程序在运行前,不知道对象的类型。使用晚绑定,无需检查对象的类型,只需检查对象是否支持属性和方法即可;ES中的所有变量都采用晚绑定方法;这样就允许执行大量的对象操作;

属性访问错误:

属性访问并不总是返回或设置一个值,如果访问一个不存在的属性并不会报错,会返回undefined;但如果试图访问一个不存在的对象的属性就会报错;null和undefined值是没有属性的,因此,访问这两个值的属性就会报错,如:

var book = {};console.log(book.subtitle);  // undefined// console.log(book.subtitle.length);  // 异常// 解决方案var len = book && book.subtitle && book.subtitle.length;console.log(len);  // undefined,不会报错

有些属性是只读的,不能重新赋值,有一些对象不允许新增属性,但如果操作这些属性,也不会报错,如:

// 内置构造函数的原型是只读的// 赋值失败,但没有报错,Object.prototype没有修改Object.prototype = 0;

这是历史遗留问题,但在严格模式下会抛出异常;

删除属性:

delete删除对象的属性,但只是断开属性和宿主对象的联系,而不会去操作属性中的属性;

var a = {p:{x:1}};var b = a.p;delete a.p;console.log(b.x);  // 1

删除的属性的引用还存在,因此在某些实现中,有可能会造成内存泄漏;因此,在销毁对象时,要遍历属性中的属性,依次删除;

delete删除成功或者没有任何副作用时,它返回true;或者删除的不是一个属性访问表达式,同样返回true,如:

var o = {x:1};delete o.x;delete o.x;console.log(delete o.toString);  // 什么也没做,toString是继承来的console.log(delete 1)  // 无意义

delete不能删除那些可置性为false的属性,

某些内置对象的属性是不可配置的,比如通过变量声明和函数声明创建的全局对象的属性;在严格模式下,删除一个不可配置属性会报一个类型错误,在非严格模式中,这些操作会返回false,如:

console.log(delete Object.prototype);// 不能删除,属性是不可配置的var x = 1;console.log(delete this.x); // 不能删除function f(){}console.log(delete this.f); // 不能删除

在非严格模式中,删除全局对象的可配置属性时,可以省略对全局对象的引用,但在严格模式下会报错,如:

"use strict";this.x = 1;console.log(delete this.x);console.log(delete x);  // 严格模式下异常

因此,必须显式指定对象及其属性;

虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方法有个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码;为解决这个问题,可以使用工厂模式的方式创建对象;

工厂模式:

工厂模式是软件工程领域一种广泛使用的设计模式,其抽象了创建具体对象的过程(还有其他设计模式);在ES中无法创建类,所以就发明了一种函数,用该函数来封装特定接口创建对象的细节,如:

function createPerson(name,age,job){    var o = new Object();    o.name = name;    o.age = age;    o.job = job;    o.sayName = function(){        alert(o.name);    };    return o;}var p1 = createPerson("wangwei",18,"Engineer");var p2 = createPerson("wujing",28,"doctor");alert(p1.name);alert(p2.name);

在工厂函数外定义对象方法,再通过属性指向该方法;

// 在上面的代码中改function sayName(){    alert(this.name);}// 在原来的o.sayName = function(){…}改成如下o.sayName = sayName;

构造函数:

可以使用构造函数来创建特定类型的对象,如:Object和Array这种原生构造函数,在运行时会自动出现在执行环境中;

构造函数内能初始化对象,并返回对象;

此外,也可以创建自定义的构造函数,从而自定义对象类型的属性和方法;使用此种方式的目的:更加类似真正的面向对象创建(类)对象方法,也就是首先创建类;如:

function Person(name,age,job){    this.name = name;    this.age = age;    this.job = job;    this.sayName = function(){        alert(this.name);    };}var p1 = new Person("wangwei",18,"Engineer");var p2 = new Person("wujing",28,"Doctor");alert(p1.name);alert(p2.name);

这里的Person本身就是函数,只不过可以用来创建对象而已;

要创建实例对象,必须使用new实例化对象;以这种方式调用函数实际上会经历经下4个步骤:

创建一个新对象;

将构造函数的作用域赋给新对象(因此this就指向了这个新对象)

执行构造函数中的代码(为这个新对象添加属性);

返回新对象,即隐式的返回了this;

关于构造函数的返回值:

// 先使用this,再使用ofunction Person(name,age){    var o = {};    o.name = name;    o.age = age;    return o;}var p = new Person("wangwei",18);console.log(p);

但如果返回是一个原始值,如:return 100,此时无任何影响,说明构造函数内返回的一定是一个对象;

在构造函数内还可以使用闭包:

function Person(name,age){    var money = 100;    this.name = name;    this.age = age;    function show(){        money ++;        console.log(money);    }    this.say = show;}var p1 = new Person();p1.say();p1.say();var p2 = new Person();p2.say();

constructor(构造函数)属性:

实例都有一个constructor(构造函数)属性,该属性指向Person;

即:构造函数方式创建的实例有constructor(构造函数)属性,该属性指向类函数,如:

alert(p1.constructor == Person);alert(p2.constructor == Person);

对象的constructor属性最初是用来标识对象类型的。但检测对象类型,instanceof操作符更可靠;

alert(p1 instanceof Object);alert(p1 instanceof Person);

构造函数的特点:

构造函数与其他函数的唯一区别:就在于调用它们的方式不同;构造函数也是函数,不存在定义构造函数的特殊语法;

任何函数,只要通过new操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过new操作符调用,就是一个普通函数,如:

// 当作构造函数使用var p1 = new Person("wangwei",18,"Engineer");p1.sayName();// 当作普通函数调用Person("wujing",28,"Doctor");window.sayName();// 在另一个对象的作用域中调用var o = new Object();Person.call(o,"Hello",38,"Worker");o.sayName();

构造函数的缺点:

这种方式虽然比较方便好用,但也并非没有缺点;缺点是:每个方法都要在每个实例上重新创建一遍,如sayName()方法,每个实例拥有的sayName(),但都不是同一个Function实例,如:

alert(p1.sayName == p2.sayName);  // false

在ES中的函数是对象,因此每定义一个函数,也就实例化了一个对象,从逻辑上说,相当于:

this.sayName = new Function("alert(this.name)");

以这种方式创建函数,会导致不同的作用域链和标识符解析;但创建Function新实例的机制仍然是相同的;

可以把函数定义在构造函数外部;如:

function sayName(){    alert(this.name);}function Person(name,age,job){    this.name = name;    this.age = age;    this.job = job;    this.sayName = sayName;}// 当作构造函数使用var p1 = new Person("wangwei",18,"Engineer");var p2 = new Person("wangwei",18,"Engineer");alert(p1.sayName == p2.sayName);  // true

Web前端开发之Javascript-零点程序员-王唯

标签: #js对象字面量与构造函数创建