对象是一组没有特定属性的值,对象的每个属性或方法都有一个名字,而每个名字都映射到一个值,其中值能够是数据或函数。每个对象都是基于一个引用类型建立的,这个引用类型能够是原生类型,也能够是开发人员自定义的类型。——高程
(好的,这里说的比较不容易理解)javascript
(不急,接下来再看)java
JavaScript中,一切都是对象,函数也是对象,数组也是对象,可是数组是对象的子集,而对于函数来讲,函数与对象之间有一种“鸡生蛋蛋生鸡”的关系。全部的对象都是由Object继承而来,而Object对象倒是一个函数。对象都是由函数来建立的。数组
好比,在控制台中
输入 typeof Object 结果是"function",
输入 typeof Function 结果仍是"function".浏览器
(好的,是否是更懵逼了,不急,如今先看一下怎么建立对象以及各类方法的孰优孰劣)安全
var box=new Object(); //建立一个 Object 对象 box.name='Lee'; //建立一个 name 属性并赋值 box.age= 100; //建立一个 age 属性并赋值 box.run= function(){ //建立一个run()方法并返回值 return this.name + this.age; }; console.log(box.run()); //输出属性和方法的值
优缺点:app
fuction creatPerson(name,age,job){ var o = new Object(); //建立对象 o.name = name; //添加属性 o.age = age; o.job = job; o.sayName = function(){ //添加方法 console.log(this.name); } return o; //返回对象引用 } var person1 = creatPerson("Nicholas",29,"engineer");//实例化 var person2 = creatPerson("Mike",28,"teacher");
优缺点:函数
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ console.log(this.name); } } //或 function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName;//注意这里不要写括号,要实现引用地址一致 } function sayName(){ console.log(this.name); }//这里是在外面写一个,但这种方法会有做用域问题,十分不推荐 var person1 = new Person("Nicholas",29,"Engineer");//通常这样实例化 var o = new Object;; Person.call(o,"Kkresten",25,"Nurse");//对象冒充法实例化
区别:学习
规范this
优缺点spa
全局做用域中定义的函数只能被某个对象调用,这让全局做用域有点名存实亡,并且,若是对象须要定义不少方法,那么就要定义不少个全局函数,因而,这个自定义的引用类型就丝毫没有封可言了(函数定义在外部时)。(因此函数在内部和外部都有缺点)
(好的,学到这里,你已经大致掌握了怎么建立一个对象,接下来将开始学习建立对象高大上的方法和概念)
咱们建立的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,(属性值是对象)而这个对象的用途是包含能够由特定类型的全部实例共享的属性和方法。:prototype 经过 调用构造函数而建立的那个对象的原型对象。使用原型的好处可让全部对象实例共享它所包含的属性和方法。也就是说,没必要在构造函数中定义对象信息,而是能够直接将这些信息 添加到原型中。———高程
(好的,又回到了懵逼的状态了,不急,先经过例子和图来了解一下先)
function Person(){//构造函数 } Person.prototype.name = "Nicholas";//添加原型属性 Person.prototype.age = 29; Person.prototype.job = "software Engineer"; Person.prototype.sayName = function() {//添加原型方法 console.log(this.name); } var person1 = new Person(); //实例化 person1.sayName(); //“Nicholas” var person2 = new Person(); //实例化 person2.sayName();//"Nicholas"
以下图:
而我本身画了个图来加深一下认识(结合高程里的那段话)
(是否是有点懂了,接下来再逐个仔细分析)
1.对于[[Prototype]]
注意:函数也是对象,天然它也有__proto__。
在控制台中,咱们发现:
即函数的__proto__是函数类型。(也就说函数的原型对象是函数,而函数也是对象,因此函数的原型仍是对象)(这里听着有点绕,可是能够先跳过)
还要注意一个特例,以下图:
这里,一切对象继承自Object,而咱们又知道Object.prototype是它的原型对象,是一个对象,可是这个对象的__proto__却为null,是否说明构建Object对象的函数没有原型对象,由于对象都是由函数建立的
(对于函数与对象的关系和涉及到的原型链的相关知识,还挺大挺深的,将单独做为一个话题来讨论。若是这里有点看得晕,能够先只是知道prototype是什么就能够了)
注意: __proto__这个指针没有标准的方法访问,IE 浏览器在脚本访问[[Prototype]]会不能识别,火狐和谷歌浏览器及其余某些浏览器均能识别。虽然能够输出,但没法获取内部信息。([[Prototype]] 也可写为__proto__)虽然没法访问到,可是能够经过: Object.isPrototypeOf(person1)判断这个实例对象是否指向它的原型对象 ;而咱们也知道Person.prototype就是Object类型,即一个原型对象
//承接上面的代码 Person.prototype.isPrototypeOf(person1);//true Person.prototype.isPrototypeOf(person2);//true
2.对于原型模式的执行流程:
①先检查这个对象自身有无这个属性;若是有,直接使用它。
②若是没法在对象自身找到须要的属性,就会继续访问对象的[[Prototype]]链,找到则直接使用,再也不查找下去;若是一直找不到,最后就会返回undefined
3.能够经过 hasOwnProperty()方法检测属性是否存在实例中,也能够经过 in 来判断 实例或原型中是否存在属性;能够经过Object.keys()方法或Object.getOwnPropertyNames()来获得实例属性,具体见高程。
4.优缺点:每添加一个属性和方法就要敲一遍Person.prototype,并且视觉上说封装性不够好。固然优势就是解决了上面构造函数的问题。
5.更简单的原型模式
function Person(){ } Person.prototype = { //将 Person.prototype 设置为等于一个以对象字面量形式建立的新对象 name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } //(但constructor属性再也不指向Person了,而是指向Object构造函数) //但能够这样手动设置: function Person(){ } Person.prototype = { constructor : Person,//手动设置 name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } //由于按上面的方式会致使它的[[Enumerable]]特性被设置为true,因此还能够像下面这样 function Person(){ } Person.prototype = { name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } Object.definePrototype(Person.prototype,"constructor"),{ enumerable : false; value : Person } }
6.原型的动态性:
//承接上面的Person构造函数 var friend = new Person(); Person.prototype.sayhi = function(){ alert("hi"); }; friend.sayhi(); //"hi"没有问题,虽然是在实例以后添加的属性,可是根据原型模式的搜索机制,会找到原型中的这个方法,缘由:实例与原型是松散链接的
//可是:若是是这样: function Person(){ } var friend = new Person(); Person.prototype = { name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } friend.sayName();//Uncaught TypeError: friend.sayName is not a function,虽然有将重写的原型的指针指向Person原型对象,可是很实际上却以下图:
6.优缺点:
function Person(){ } Person.prototype = { constructor : Person, name : "Nicholas", age: 29, job: "software Engineer", friend:["Mike","Jeny"], sayName : function() { console.log(this.name); } } var person1 = new Person(); var person2 = new Person(); person1.friend.push("Van"); console.log(person1.friend);//"Mike,Jeny,Van" console.log(person2.friend);//"Mike,Jeny,Van"
function Perosn(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby","Court']; } Person.prototype = { constructor : Person, sayName : function(){ console.log(this.name); } } var person1 = new Person("Nicholas",29," Engineer");
优缺点:
## 5.动态原型模式 ##
function Person(name,age,job){ //属性 this.name = name; this.age = age; this.job = job; //方法 if(typeof this.sayname != "function"){ Person.prototype.sayname = function(){ console.log(this.name);//只有在sayName方法不存在的状况下才会被添加到原型中 } } //这段代码在初次调用构造函数时才会执行,此后,原型已经初始化 var friend = new Person("Nicholas",29,"Engineer");
优缺点:
(好了,学到这里,大概经常使用的建立对象的方法就已经掌握了,接下来还有两种不经常使用的方法能够了解一下)
function Person(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ console.log(this.name); } return o; } var friend = new Person("Nicholas",29,"Software Engineer"); function SpecialArray(){ //建立数组 var values = new Array(); //用push方法初始化数组的值 values.push.apply(values,arguments); //添加方法 values.toPipedString = function(){ return this.join("|"); } //返回数组 return values; } var colors = new SpecialArray("red","blue","green"); console.log(colors.toPipedString()); //"red|blue|green"
优缺点:
console.log(friend instanceof Person) // false
所以,可使用其余模式的状况下不使用此类型
function Person(name,age,job){ //建立要返回的对象 var o = new Object(); //能够在这里定义私有变量和函数 //添加方法 o.sayName = function(){ console.log(name); } //返回对象 return o; } var friend = Person("Nicholas",29,"Software Engineer"); friend.sayName();
区别:
优势:安全
(好了,js对象的建立就大概有这几种方法,其实最经常使用的貌似仍是构造函数的模式,可是原型相关的东西也是必需要掌握的)
最后,欢迎你们围观指正!