一.原型对象
Q?:原型对象是什么?使用[]时为什么能够获得数组的数据?给对象保存数据是通过什么方法?调用方法的原理是什么?----这里要引入一个概念原型对象.
A.:原型对象是系统本身已经被编写的语句,对象的原型模型对象称为原型对象,一个对象没有自己的属性和方法时通过调用原型对象上的方法也可以使用.(个人理解:原型对象是系统在你编写代码前已经为你准备好的代码,当你调用的对象需要使用一个方法或数据时,如果这个对象并存方法和数据时这是就会去读取系统给你写好的代码)
eg:
var p1=new Array;
console.log(p1.some);//并没有给p1声明some属性,但是打印结果不会报错
打印结果为
为什么没有声明some这个对象,打印时也不会报错呢?这里就用到了原型变量,我们打印p1
这里的__proto__就是它的原型变量,当打印.some时,会从__proto__里再去找有没有这个对象,如果有就可以读取并打印出来.
二.new
在学习了原型变量以后,对new也有了新的了解.
new在使用时
- 创建一个空对象==>找一个对象:构造函数的prototype属性中保存了一个对象例如{xxx:“123”};它相当于对__proto__扩展:{proto:{xxx:“123”}},给它保存了一个新的对象.
- 用这个扩展对象去调用构造函数
function person (name) {
this.name=name
}
person.prototype={xxx:"123"}
var p1=new person("jack")
console.log(p1.name)
得到:{proto:{xxx:“123”},name:“jack”}}
3.生成了数据:{proto:{xxx:“66666666”},name:“jack”}
再进一步了解一下new构造函数:
- 噶偶早函数的第一个字母最好大写以便于区分普通函数
- 每一个函数都有一个属性叫length,它代表形参的个数
- 每一个函数都有一个属性叫prototype(每一个对象在引用数据时都有一个__proto__)
1.当把一个构造函数当成普通函数调用时,prototype这个属性就没什么用
2.如果把new当关键字调用函数,prototype属性的指向对象就是创建对象的原型对象
3.把prototype属性指向的对象放在扩展对象的__proto__属性中
4.我们称一个对象的__proto__属性指向的对象为这个对象的原型对象
通过一段代码来理解一下这几句话:
function fn () {
this.name="karen"
this.age=18
}
var f1=new fn()//通过new关键字来调用fn这个函数,所以f1指向的时(new fn())这个对象,__proto__指向的是fn.prototype;
通过new调用的函数就是构造函数,f1是fn()的实例;
f1的__proto__==>fn()的prototype
var f2=new fn()//同理,f2的__proto__==>也是fn()的prototype
||
||
console.log(f1) ||
console.log(f2) ?
console.log(f1.__proto__===f2.__proto__)//true ? 所以这里为真
console.log(f2.__proto__===fn.prototype)//true 同理这里也为真
console.log(f1.__proto__===fn.prototype)//true 同理这里也为真
- 获取:
obj.xx 取一个对象的成员:先取扩展空间的成员,扩展空间没有就去__proto__属性里取;直到null都没有,就取得undefined;
如果设置obj.xx=100时不管原型上有没有这个属性,都会在自己的扩展空间操作
eg:
function fn(age){
this.age=age;
this.name=mata;
}
var a=new fn(18);
console.log(a)
打印结果为
并不会影响__proto__里数据的值.
- 如果没有为函数指定prototype属性,系统会为每一个函数内置一个空对象:{}new object
- 构造函数如果是系统提供的,它的prototype属性指向的对象只能修改成员,不能把整个对象修改了(不会报错,但是代码无效,系统避免整体错乱)
- 构造函数如果时自己写的,他的prototype属性指向的对象可以随意操作.(引入工具时常常使用)
- 修改一个对象的原型对象的功能只能通过prototype或__proto__(常用prototype,当不知道原型对象的功能时使用__proto__:比如修改p标签的原型对象的功能时,不知道他的功能名使用__proto__:p1.proto.p:xx)
- 拓展:如果访问到原型上的数据自己该自己就可以修改原型上的数据
用代码说明一下以上描述:
eg:
var arr=new Array()
var arr1=[]//语法糖
Array.prototype={name1:"xxxx"};//无效代码
Array.prototype.xxx="hqyj"//给Array.prototype.xxx存了"hqyj"这个数据
var arr1=new Array()
arr1.__proto__.xxx="cd"//将hqyj修改为"cd"
console.log(arr1)//[ ]
console.log(arr1.name1)//undefined
console.log(arr1.xxx)//cd
扩展内容代码:
function fn () {
}
fn.prototype.com={xx:666}//[101233,1,23,12,31,2]
// var f1=new fn()//{__proto__:{com:[101233,1,23,12,31,2]}}
// f1.com=[100]
// console.log(f1)
var f2=new fn()
f2.com.push(6666)//为数组末尾添加一个新元素
f2.com.age="18"
console.log(f2.com)
var f3=new fn()
console.log(f3)
三.作用域
作用域的概念:
- 没有函数就不谈作用域
- 一个标识符,在哪写代码的地方能够使用,这个写他的区域就是这个标识符能够起作用的区域称作作用域
funstion fn(){var a=20}//在这串代码中a=20的作用域就在fn内,出了fn就读取不到a=20这个数据
- 在script脚本中的变量(window属性)称为全局变量
- 函数里能够访问函数外的标识符,但函数外的不能访问函数内标识符
- 注意!声明提前:显示提前到当前作用域的第一行
隐式提前,提前到全局里
//var c;隐式提前到了全局作用域里
fn() {
//①var b
console.log(b)//这里打印的值为undefined,②处的标识符被显示提前到了fn函数(当前作用域)的第一行,即①位置,所以打印b时不会报错,但没有给b赋值所以为undefined
var b=20//②
console.log(b)//这里打印的值为20,因为在②处b已经被赋值为20
c=20//这里没有声明c,所以会给c隐式声明,隐式提前声明到了全局作用域里
}
fn()//因为c被隐式提前成了全局变量在运行了一遍fn函数后c=20赋值在了window里
console.log(c)//所以这里打印20
console.log(b)//b的作用域在fn中,所以这里报错