前言:
现在姐妹们对“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
标签: #js对象字面量与构造函数创建