function fn(a){
console.log(a); //在AO里找值--->输出 function a() {}
var a = 123; //预编译将 var a,提升上去了,执行 a = 123;修改AO中a的值
console.log(a); //输出 123
function a() {} //预编译读过,不再读
console.log(a); //输出 123
var b = function() {} //函数表达式,将AO中b的值改为function () {}
console.log(b); //输出funtion () {}
function d() {}
}
fn(1);
第一步:AO{ }
第二步:
AO{
a : undefined,
b : undefined
}
第三步:
AO{
a : 1,
b : undefined
}
第四步:
AO{
a : function a() {},
b : undefined,
d : function d() {}
}
此类函数没有声明,在一次执行过后即释放,可以用来做初始化
var mrDeng = (function(){
var Deng = {
name : "MrDeng",
age : 40,
sex : "male",
health : 100,
smoke : function () {
console.log('I am smoking! cool!!!');
this.health --;
},
drink : function () {
console.log('I am drink');
this.health ++;
}
}
return Deng;
}())
这样可以实现初始化的效果
内部函数被返回到外部,函数本身保留了父函数的AO,即使父元素执行完了,取消对AO的引用,但依旧被子函数保留下来了,就形成了闭包。
闭包会导致原有作用域链不释放,造成内存泄漏。
因为子函数保留有父函数的AO,并在此基础上搭建自己的AO,所以父函数的AO会被作为一个公有变量被使用,即使函数执行完毕,也只会销毁自己创建的AO对象。
简单理解就是函数结束会销毁父函数的执行上下文,但是应用闭包可以使父函数的执行上下文被保留下来,给父函数下的其他函数使用,这样就实现了属性的私有化
模块化开发
防止污染全局变量
var name = 'abc';//全局变量
var init = (function() {
var name = 'ljc';
function callName() {
console.log(name);
}
return function () {
callName();
}//返回一个函数形成闭包,留有父函数的AO{name: 'ljc'}
}())
init();//ljc
闭包会导致多个执行函数共用一个公有变量,应当尽量避免
function test(){
var liCollection = document.getElementByTagName('li');
for(var i = 0; i < liCollection.length; i++){
(function (j){
liCollection[j].onclick = function(){ //把函数绑定到了每个li元素(外部)
console.log(i);
}
}(i))
}
}
test();
原始值没有属性和方法,强行添加属性或者访问属性的话,系统就会新建一个包装类,然后在包装类上进行操作,操作完成后再销毁。
var num = 4;//这里的num是原始值没有属性和方法
num.len = 3;//强行添加属性
//new Number(4).len = 3;执行完立刻销毁 delete
//再次调用的时候再次生成Number()
//new Number(4).len
consloe.log(num.len);
数组在改小length的时候会被截短
原型是function对象下的属性,它定义了构造函数的共同祖先,也就是一个父子级的关系,子对象会继承父对象的方法和属性
prototype
是函数下的属性,对象想要查看原型使用隐式属性__Proto__
constructor
指向构造函数通过给原型添加属性,可以让所有的实例化对象共享属性和方法
Car.prototype = {
height : 1400,
lang : 4900,
carName : 'BMW'
}
function Car() {
}
var car = new Car();
每个实例对象下都有__proto__
属性,通过属性__proto__
指向构造函数的原型对象,当到达末端时,返回null,这样一层一层向顶端查找,就形成了原型链
prototype
是函数特有的,__proto__
是对象有的,js中万物皆对象
prototype和——proto——
区别与作用prototype
把共有属性预先定义好,给之后对象使用
prototype
的存在实现了继承,节省内存空间
__proto__
是对象的,prototype
是函数的,因为函数也是对象,所以函数也有__proto__
;
__proto__
的作用是就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会沿着它的**__proto__
**属性所指向的那个对象(父对象)里找,也就是原型链
prototype
的作用是就是让该函数所实例化的对象们都可以找到公用的属性和方法
__proto__
对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype
constructor
属性存在于__proto__
和prototype
,它指向构造函数本身
一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。
问题 修改了函数的原型对象,constructor
的指向是谁
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor: Star, // 手动设置指回原来的构造函数
sing: function() {
console.log('我会唱歌');
},
movie: function() {
console.log('我会演电影');
}
}
var zxy = new Star('张学友', 19);
console.log(zxy)
在修改函数原型时,因为Star.prototype
就是一个对象,所以constructor
指向构造这个对象的原型,也就是object
通过call``apply
可以改变this的指向,借用别人的函数完成自己的功能
区别:call
传多个参数 apply
传一个参数数组
function Person(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name,age,sex,tel,grade) {
//var this = {name: "lin", age: "19", sex: "male", tel: 123, grade: 78}
Person.call(this,name,age,sex);//通过call改变this的指向这个函数
//Person.apply(this,[name,age,sex])
this.tel = tel;
this.grade = grade;
}
var student = new Student('lin','19','male',123,78);
var obj = {}//创建空对象
obj.__proto__ = Person.prototype;//继承作用域
Person.call(obj,)//改变this指向
//这三步是隐式的
var person = new Person();//new操作
继承了过多没用的属性
通过使用new
关键字来实现继承父元素属性和方法,再通过prototype
属性来改变函数原型,从而实现一条完整的原型链,从而实现子函数可以继承父函数的属性和方法
function Father() {
this.name = 'hhh';
}
var father = new Father();
Son.prototype = father;
function Son() {
}
var son = new Son();//son下继承了father的name
不能继承构造函数的原型
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
// 3.使用call方式实现子继承父的属性
Father.call(this, uname, age);
this.score = score;
}
var son = new Son('lin', 19, 100);
console.log(son);
Son.prototype = Father.prototype
,不能改动自己的原型
Father.prototype.lastName = 'lin';
function Father() {
this.name = 'hhh';
}
function Son() {
}
Son.prototype = Father.prototype;//son和father共用原型
var father = new Father();
var