(20)函数的原型
①Object.create(obj)
根据原型obj创建一个对象;
例如:
var obj = { a: 1 } var o1 = Object.create(obj); console.log(obj); console.log(o1);
输出为:
Object {a: 1}
Object {}
②使用构造函数方法:
使用构造函数,通过new来创建一个实例(之前有,这里略)
③
①和②之间的区别:
通过②的继承:
var obj = { a: 1 } var o1 = Object.create(obj); var o2 = Object.create(o1); o1.b = 5; o2.c = 2; console.log(o1.b); console.log(o2.b);
o1和o2都有属性b,并且值为5;
但是,通过继承来的,则不一样。
var obj = function () { a: 1 } var o1 = function(){} o1.prototype = new obj(); var o2 = function(){} o2.prototype = new o1(); o1.b = 5; o2.c = 2; console.log(o1.b); console.log(o2.b);
输出是5和undefined
通过查看console属性可以发现,Ojbect.create,其原型链是直接链接到创建时的原型对象的。
例如假设o2没有属性b,那么其值则为o1的属性b的值,假如o1.b的值被更改,那么o2.b的值也会被更改。
如代码:
var obj = { a: 1 } var o1 = Object.create(obj); var o2 = Object.create(o1); o1.b = 3; console.log(o2.b); o1.b = 5; console.log(o2.b);
其输出的值分别是3和5
④hasOwnProperty()
通过Object.create()方法声明的变量,其原型的属性,在自身调用 hasOwnProperty()会提示false
var obj = { a: 1 } var o1 = Object.create(obj); var o2 = Object.create(o1); o1.b = 5; console.log(o2.hasOwnProperty("b")); o2.b = 2; console.log(o2.hasOwnProperty("b"));
例如,第一个是true,第二个是false
但需要注意,这种方法无法通过
o2.prototype.b = 5;
来为之设置属性
而另一种方法和其的区别在于,可以通过o2.prototype.b = 5;来设置属性,以及继承。
(21)函数的作用域
①静态作用域:(JS使用的是这种)
var x = 1; function a() { console.log(x); } function b() { var x = 2; a(); } b();
输出结果是1,而不是2。
因为a()定义在window里,而不是在b()里,所以使用的是window中的x,而不是b中的x,如以下代码输出结果便为2:
var x = 1; function b() { var x = 2; function a() { console.log(x); } a(); } b();
②JS变量的作用域:全局作用域、函数作用域。没有块级作用域(即{}之间声明的变量的作用域);
③with方法的临时作用域:
var x = 1; with ({x: 2}) { function a() { console.log(x); } (function () { console.log(" " + x); //输出2 a() //输出1 })(); } console.log(x); //输出1
之所以,是因为匿名函数可以理解为在函数内部创建并执行的(类似一个表达式),因此其内部变量的作用域是在with环境创建的临时作用域。(这个作用域,是x=2的作用域)
而a函数是声明的,因此其作用域是全局的(因为没有块级作用域,只有全局和函数内部的)。(函数被预解析时,知道其作用域是全局的)
由于with环境作用域是临时的,并且声明的是一个对象,因此不会对全局变量x进行修改。