1.原型链结构 什么是原型链? 每个“构造函数”都有 “原型对象” 每个“对象”都会有 “构造函数” 每个“构造函数”的原型都是一个对象 有一个很好的图,可惜这里放不进来,可以搜索一下原型链结构图看下,记住上面的三句话 另外: 1). 原型对象也有自己的构造函数:Object构造函数 2).”Object构造函数” 也有“原型对象” 例如,如下代码:
function Person(name){ this.name = name; } var p = new Person(); 每个“构造函数Person”都有 “原型对象Person.prototype” 每个“对象p”都会有 “构造函数Person” 每个“构造函数Person”的“原型Person.prototype”都是一个对象 另外: 1). 原型对象Person.prototype也有自己的构造函数:Object构造函数 2)."Object构造函数" 也有“原型对象” 原型链为 //p ---> Person.prototype --->Object.prototype---->null 其中p.__proto__ = Person.prototype; Person.prototype.__proto__ = Object.prototype; Object.prototype.__proto__ = null;2.创建函数的几种方式
//1.直接声明函数 function funcName(/*参数列表*/){ //函数体 } //2.函数表达式 var funcName = function(){ }; //3.new Function var func = new Function();3.Function构造函数
//Function这构造函数 可以用来新建函数对象 //语法: 0.一个参数都不传的情况 创建的就是一个空的函数 //var 函数名 = new Function() 1.只传一个参数的情况 这个参数就是函数体 //var 函数名 = new Function("函数体") var func = new Function("console.log('我是动态创建的函数');console.log(1);"); func(); 2.传多个参数的情况,最后一个参数为函数体,前面的参数都是该函数的形参名 //创建一个计算两个数的和的函数 var sum = new Function("a", "b", "return a + b;"); console.log(sum(1, 1111));4.静态成员和实例成员的概念
function Person() { this.name = "zs"; this.run = function() { console.log("跑"); } } //静态成员和实例成员的概念,是从其他编程语言中引入的 //静态成员: //是指构造函数的属性和方法 //如:Person.prototype Person.name //在Jquery中把工具方法,作为静态成员 // $.trim(); // $.each(); // $.extend(); console.log(Person.name); ---------------------------- var p = new Person(); //实例成员: //是指实例的属性和方法 // p.name // p.__proto__ //Jquery中把跟对象相关的方法,作为实例成员 // $("#id").css(); // $("#id").text();5.instanceof 关键字
//instanceof 关键字 //语法 对象 instanceof 构造函数 //判断该构造函数的原型是否存在于该对象的原型链上 function Person(){ } //原型链:p--->Person.prototype--->Object.prototype--->null var p = new Person(); //构造函数的**原型**是否在该 “对象” 的原型链上! console.log(p instanceof Person); //true console.log(p instanceof Object); //true6.!!很重要!!构造函数Person的构造函数是Function构造函数 Object构造函数的构造函数也是Function 构造函数 看完整的原型链结构和Object与Function的关系
function Person(){ } var p = new Person(); console.log(Person.__proto__); console.log(Person.__proto__.constructor);7.JS预解析的时候变量提升规则以及练习 js代码的执行分为两个步骤 1).预解析 提升(hoisting) JavaScript代码在预解析阶段,
会对 1).以var声明的"变量名" ` alert(a); var a = 1; //<=======> 提升之后的代码模拟 // var a; // alert(a); // a = 1; 和 2).function开头的"语句块",进行提升操作 func(); function func() { alert("Funciton has been called"); } //3).函数同名,如何提升? //预处理的时候,会将两个函数全部提升,但是后面的函数会覆盖掉前面函数 // func1(); //last // function func1(){ // console.log('This is first func1'); // } // func1(); //last // function func1(){ // console.log('This is last func1'); // } // //预解析提升后的代码 // function func1(){ // console.log('This is first func1'); // } // function func1(){ // console.log('This is last func1'); // } // func1(); //last // func1(); //last //4).变量和函数同名如何提升? //在提升的时候,如果有变量和函数同名,会忽略掉变量,只提升函数 // alert(foo); //undefined 函数体 // function foo(){} // var foo = 2; // alert(foo); //2 // //预解析 提升后的代码 // function foo(){}; // alert(foo); // foo=2; // alert(foo); //5).函数表达式,只会提升变量名,不会提后面的函数 func(); var func = function(){ alert("你猜我会不会被调用"); } Uncaught TypeError: func is not a function at 08-.html:9 //提升后的代码 // var func; // func(); // func = function(){ // alert("你猜我会不会被调用"); // }; 2).执行8.一道经典的变量提升题目
// 练习6: //函数表达式不会被提升 function Foo() { getName = function() { alert(1); }; return this; } Foo.getName = function() { alert(2); }; Foo.prototype.getName = function() { alert(3); }; var getName = function() { alert(4); }; function getName() { alert(5); } // ------预解析后---- function Foo() { getName = function() { alert(1); }; return this; } var getName; function getName() { alert(5); } Foo.getName = function() { alert(2); }; Foo.prototype.getName = function() { alert(3); }; getName = function() { alert(4); }; // ----------- Foo.getName(); // ? getName(); // ? 最后的getName覆盖前面的function getName 4 /* function getName() { alert(5); } <=====> var getName = function(){ alert(5); } */ Foo().getName(); //普通函数中的this是window // ?在执行Foo()的时候把全局的变量getName也重新赋值了 getName(); // ? //同上一个 new Foo.getName(); // 2 等价于直接调用Foo.getName(); (new Foo).getName(); // 3 构造函数没有形参可以去掉括号,等价于==>this.getName(),this中没有getName()所以去原型中找 new Foo().getName(); // 3 跟上一个等价 ,先执行new Foo()再执行.getName new new Foo().getName(); // ? tips: //条件式函数声明是否会被提升,取决浏览器 //条件式函数声明不推荐去写 foo(); //这里会报错,因为未被提升 if(true){ function foo(){ console.log("123"); } } foo();9.闭包的知识点 闭包的概念
闭包从字面意思理解就是闭合, 包起来.简单的来说闭包就是,一个具有封闭的对外不公开的, 包裹结构, 或空间.
在JavaScript中函数可以构成闭包. 一般函数是一个代码结构的封闭结构, 即包裹的特性, 同时根据作用域规则, 只允许函数访问外部的数据, 外部无法访问函数内部的数据, 即封闭的对外不公开的特性. 因此说函数可以构成闭包.
闭包要解决什么问题? 闭包内的数据不允许外界访问 要解决的问题就是间接访问该数据 函数就可以构成闭包, 要解决的问题就是访问到函数内部的数据
10.函数的四种调用模式
//1.函数模式 //this指向window全局对象 //2.方法模式 //this指向调用这个方法的对象 //3.构造函数模式 //this 使用new创建出来的对象 //4.上下文模式 function test(){ console.log(this); } test(); var obj1 = { test:function(){ console.log(this); } } obj1.test(); function Person(){ console.log(this); } var obj =new Person();决定写一篇关于闭包和一篇apply以及call使用的文章