JavaScript高级部分概念用法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript高级部分概念用法相关的知识,希望对你有一定的参考价值。
一、执行上下文
也称为可执行代码和执行上下文
执行代码:1.全局代码 2.函数代码 3.eval代码
eval("var a = 200;console.log(a)")
执行上下文 - Context
所处的一个环境,环境不同含义也随着改变了
当可执行代码执行的过程中,都会产生一个可执行环境
在执行完之后,执行上下文的环境也随着销毁
执行上下文中变量存在于:
变量对象:VO - var 声明的一个属性值 - 全局
活动对象:AO - 相对于函数创建的对象中的一个声明 - 局部 - 随执行完后销毁
不管变量在什么地方声明,都会在函数一运行就声明一个函数中的变量
变量提升:指一个函数上下文创建时,函数中的所有变量都会随函数的创建提升
var x = 100;
var outFunc = function(){
x++;
console.log(x);//NaN
var x = 200;
}
outFunc();
console.log(x);//100
函数中 x 声明提前,但是赋值并没有提前,所有此时的x为undefined,undefined进行运算结果就为NaN
var outFunc = function(){
var a = 100;
var innerhtml = function(){
var b = 200;
a = b;//a替换了outFunc()中a var a = 100的值 此时a = 200;
// c = a;
}
innerHtml();
console.log(["inner:",a]);//200
}
outFunc();//该函数在运行完后函数中的变量随之销毁
console.log("outer:",a);//not defined
二、作用域 作用域链
作用域:即为代码的作用范围
作用域链:函数的变量不使用var声明的情况下,声明变量会一直往上查找该变量的值,直到全局变量还没有就创建一个全局变量
Scope对象 - 存放上一层中的对象引用 - 属于某一个函数的属性,当函数一创建就已经有该函数的scope对象引用了
每个函数都包含自己本身的VO、Scope对象、作用域链对象
var food = "包子";
var eat = function(){
console.log(food);//包子
}
(function(){
var food = "油条";
eat()
})
var foo = 1;
function bar(){
if(!foo){
var foo = 10;//foo会变量提升到bar函数中,但值不会提升此时提升的foo为undefined !foo 刚好满足条件
}
console.log(foo);
}
bar();
var a = 1;
function b(){
a = 10 ;//a = a()
return;
function a(){}//会变量提升到函数的前面
}
b();
console.log(a);
var f = true;
if(f === true){
var a = 10;
}
function fn(){
var b = 20;
c = 30;
}
fn();
console.log(a);//10
console.log(b);//not definnd
console.log(c);//30
if(‘a‘ in window){
var a = 10;//变量提升至if判断外,但值不会提升;没有var 不会先变量提升会先判断是否进入判断
}
console.log(a);//10
var a = b =3;
(function(){
var a = b = 5;//var a = 3; b = 5
})();
console.log(a);//3
console.log(b);//5
var foo = ‘A‘;
console.log(foo); //A
var foo = function(){
console.log(‘B‘);
}
console.log(foo); //function(){console.log(‘B‘);}
foo(); //B
function foo(){ //函数是在最开始的时候就存在了,但在var foo 声明后被覆盖了,已经被提升;会影响代码的上下顺序
console.log(‘C‘);
}
console.log(foo); //function(){console.log(‘B‘);} -
foo(); //B
var a = 1;
function b(){
console.log(a);//undefined
a = 2;
console.log(a);//2
var a = 3;
console.log(a);//3
}
console.log(a);//1
b();
console.log(a);//1
//闭包相关的函数值
var x = 100;
var y = 200;
function funcA(x){
var y = 201;
function funcB(){
console.log(x);//101
console.log(y);//201
}
return funcB;
}
var f = funcA(101);
f();
三、this关键字
this 也称为当前对象,是用于对象当中,属于第一人称,所处的环境不一样指代的含义也不同
如果在对象的方法中只要在嵌套的函数中的this就不会再指向当前对象中的this了
比如:
var name = "张三";
var func = function(){
console.log(this.name);//此时的this指向的是全局变量
}
func();
fnnc.apply();
func.call()
var obj = {
name:"王五",
func:function(){
console.log(this.name);//此时的this 指向的是对象中的name
(function(){
console.log(this.name);//此时的this指向的不是对象的name,而是全局变量
})()
}
}
obj.func();
改变this指向的方法:
1.call
2.apply
两者的作用是相同的,可以帮助完成方法的调用,默认this指向为全局,要想访问嵌套对象,就将其赋值给一个变量
call() Or apply()可以改变this的对象,第一个参数是不能省的
区别:
var sum = function(a,b){console.log(a+b)}
sum.call(null,100,200) - 采用的是参数列表
sum.apply(null,[100,200]) - 采用的是数组
***练习***
var myObject = {
foo:"bar",
func:function(){
var self = this;
console.log(this.foo);//bar
console.log(self.foo);//bar
(function(){
console.log(this.foo);//undefined
console.log(self.foo);//bar
})()
}
}
myObject.func();
var user = {
count:1,
getcount:function(){
return this.count;
}
}
console.log(user.getcount());//1
var func = user.getcount;//func就代表user.getcount这个函数
console.log(func());//undefined - func()已经成为全局,全局中没有count这个变量,所以值为undefined
四、闭包 - closure
闭包:是指能够访问函数内部变量的函数,定义在函数内部的函数。
一个函数引用了外部的自由变量,那么这个函数就叫闭包,被引用的函数和引用的函数是一同存在的。
自由变量 - 跨作用域的变量或父级的变量
函数必须引用外部变量,函数还必须被引用才能成为闭包
优点:可以把一个局部变量存在的时间延长,进行持续保存
缺点:如果大量的使用闭包,持续保存的变量会一直占有内存,造成内存的浪费
常用:事件处理常常会使用到闭包
var lis = document.getElementsByTagName("li");
for(var i = 0;i<lis.length;i++){
//方法实现一
(function(index){//阻止闭包
lis[index].onclick = function(){
console.log("这是选中的地"+(index+1)+"项");
}
})(i)
//方法实现二
var func = function(index){
lis[index].onclick = function(){
console.log("这是选中的地"+(index+1)+"项");
}
}
func(i);
}
//闭包练习
function Foo(){
var i = 0;
return function(){
console.log(i++);//i++先赋值再运算
}
}
var f1 = Foo();
var f2 = Foo();
f1();//0
f2();//0
f2();//1
五、面向对象 - OO - Object Oriented
语言分类大致分为两大类 - 范式
1.命令式 - 通过语言告诉计算机应该如何做事情
比如:java、C语言(为程序语言的发展做出贡献)
命令式的两种思想:
1.1.面向过程 - 将过程逐一分解为一个一个的步骤执行 - 计算机的思维方式为主体
缺点:人的思维有限,如果程序实现的过程很复杂,人会不能完全考虑
1.2.面向对象 - 本身就是人的思考方式,人的思维为主体,从自身角度出发 - 特征、行为 - 万物皆对象,对象因关注而产生
2.声明式 - 告诉计算机我想要什么,然后计算机进行相关的动作,然后计算机自己进行运算得到我想要的结果
比如:Css
声明式的三大类:
2.1.领域特定语言 - DSL - 在特定范围的语言 - HTML、Css、SQL、正则表达式
2.2.函数式编程 - 类似公式,计算机就会按照这个公式进行计算并返回结果
与命令式编写相比,函数式编程更为精简,能够完善命令式编程的一些缺陷 - lisp、Haskell
2.3.逻辑编程 - prolog - 记日志比较好的方法
构建对象的两种方式:
1.基于类的面向对象 - 拥有相同属性的划分为一类,类是对象的抽象,对象是类的实例
2.基于原型的面向对象 - javascript原型就有一个Object对象,通过一个原型克隆一个对象
好处:足够灵活
缺点:随意性太强,对于初学者容易出错
面向对象三大特征:
1.封装 - 需重点了解 - 指实现细节隐藏起来的过程就是封装
优点: - 但还需要考虑参数的问题
1.1.隐藏实现的细节
1.2.重用 - 不变的整合在一起,变化的作为参数
JavaScript中属性都应为私有,方法可以为公共 - 由我们自己控制
pulic - 公共,其他方法可以访问
private - 私有,只能自己能够访问
set/get - 访问器/修改器
var Student = function(name,age,gender){
this.name = name;
var _age = age;//添加 _ 可将变量变为私有变量,外部不能随意访问
var _gender = gender;
if(!Student._init){
Student.prototype.getAge = function(){
return _age;
}
Student.prototype.setAge = function(age){
if(age > 20 && age < 30){
_age = age;
console.log(_age);
}else{
console.log("年龄修改不能在 20 - 30 之外");
}
}
Student.prototype.getGender = function(){
return _gender;
}
Student.prototype.setGender = function(gender){
_gender = gender;
console.log(_gender);
}
}
Student._init = true;
}
var stu = new Student("张飞",20,"男");
stu.name = "关羽";
stu.setAge(31);
console.log(stu.getAge());
console.log(stu.getGender());
stu.setGender("无");
2.继承 - 存在于有父与子的关系中 - 出现率较高 - 指采用一个对象的功能并且能够添加新的功能
优点:
2.1.复用
2.2.扩展
缺点:
如果继承设计的不够完善,会致使变得复杂,难以操控
继承的3种方法:
1.对象冒充法 - instanceof - 判断是否为继承
2.原型链 - 将自己的原型改变为父级的对象
3.混合方式 -
// 1.对象冒充法
/*var People = function(name){
this.name = name;
}
People.prototype.intro = function(){
console.log("HI,我是"+this.name);
}
var ChinesePeople = function(name){
this.inhert = People;
this.inhert(name)
delete this.inhert;
}
var info = new ChinesePeople("张三");
console.log(info.name);
console.log(info instanceof ChinesePeople);*/
// 2.原型链
/* var People = function(name){
this.name = name;
}
People.prototype.intro = function(){
console.log("HI,我是"+this.name);
}
var ChinesePeople = function(name){
}
ChinesePeople.prototype = new People("张三");
ChinesePeople.prototype.area = function(){
console.log("我是中国人");
}
var info = new ChinesePeople("张三");
console.log(info.name);
console.log(info instanceof ChinesePeople);
info.intro();
info.area();*/
// 3.混合
/*var People = function(name){
this.name = name;
}
People.prototype.intro = function(){
console.log("HI,我是"+this.name);
}
var ChinesePeople = function(name){
People.call(this.name);
}
ChinesePeople.prototype = new People("张三");
ChinesePeople.prototype.area = function(){
console.log("我是中国人");
}
var info = new ChinesePeople("张三");
console.log(info.name);
console.log(info instanceof ChinesePeople);
info.intro();
info.area();*/
3.多态 - JavaScript本身就是一个多态的行为
var Student = {
"name":"张飞",
"age":20,
"learn":function(){
console.log(this.name+"学习JavaScript")
}
}
Student.gander;//访问的属性不存在 值为 undefined
Student.learn();
Student.name;
Student["name"];
Student["lea"+"rn"];//动态的属性值使用中括号或者字符串拼接
//构造函数
var Student = function(name,age){
this.name = name;
this.age = age;
this.learn = function(){
console.log(this.name+" - "+this.age);
var that = this;
(function(){
console.log(that);
}())
}
}
var stu1 = new Student("张飞",20);//stu1 为一个对象
var stu2 = new Student("刘备",21);
Student.prototype.gander = "男";//在原型中添加一个性别的属性
Student.prototype.play = function(){//在原型中创建一个play 的方法
console.log(this.name+" - "+this.age+" - "+"喜欢玩游戏");
}
stu1.learn();
console.log(stu1.gander);
stu1.play();
stu2.learn();
Studetn.prototype;//可以改变一个对象真正的原型,但是不能多次调用
stu1.__proto__; //只是更改了stu1的引用原型,而不是本身的原型,只是对象的一个属性,可以通过属性一层一层的访问到对象的原型
对象 → 自定义对象原型 → Object对象 → Object原型 → Null
if(!Student._int){//首先判断Student._int是否为假,Student._int事先不存在即为假,进入判断,Student._int变为真,不在进入判断,该判断这样就只能判断一次
Student.prototype.learn = function(){
console.log(this.name+" - "+this.age);
}
Student.prototype.play = function(){//在原型中创建一个play 的方法
console.log(this.name+" - "+this.age+" - "+"喜欢玩游戏");
}
Student._int = true;
}
两个运算符:new - 创建对象; delete - 删除属性 - delete.stu1.name;//stu1中的name属性就被删除了,只能删除原型创建的而不能删不是原型创建的属性
两个语句:with - 性能有一定的问题,尽量不使用; for..in - 不拿来循环数组;
var stu1 = new Student("张飞",20);//stu1 为一个对象
var stu2 = new Student("刘备",21);
for(var key in stu1){
console.log([key,stu1[key]]);
}
以上是关于JavaScript高级部分概念用法的主要内容,如果未能解决你的问题,请参考以下文章