这一部分针对这个JavaScript中的内容相对较难,目前只是简单的进行一定的了解,一口也吃不成一个大胖子。
目录
词法作用域
基本的概念
先明白它也被称为静态作用域,用来确定变量和函数可访问性及生命周期的一种重要机制。
在词法作用域中,变量和函数的作用域是在代码编写阶段就根据程序的语法结构确定下来的,而不是在程序运行时动态决定,像 java 的 static 修饰一样。不过 static 规定的是类成员,词法作用域则是指向变量。
我这么联想记忆我觉得针对初步了解问题不大,虽然它们实质有很大不同。
作用域的嵌套
然后再看他的结构,很明显就是嵌套的使用,在嵌套中内部函数可以访问外部的变量,当出现最外层也没有找到对应变量,即没有引用,此时就会报错 undefined。
在 JavaScript 中写变量,建议先写变量的声明,之后在调用
如下是一个实例,通过 DOM 调用节点,传入对象,然后让 div 标签关联上 o 对象,通过提前写好的 json 字符串,然后使用 for 循环依次遍历添加到 div 标签的 style 属性上。
使用js来控制style的属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript">
var o = { css:function(styles){
//styles是json格式的样式,可以讲样式交给[0]这个节点
for(var k in styles){
this[0].style[k] = styles[k];
}
}};
var J = function(id){
var obj = document.getElementById(id);
o[0] = obj;
return o;
}
onload = function(){
// 先通过这个东西进入J函数,然后关联上o对象和div标签,然后调用css的方法传入这个写下的json对象
//css内部的forin循环遍历传入的样式对象的每一个属性,然后会一次将属性设置到相应的style属性上。
//这个方法简直酷毙了
J("dv").css({border:"1px solid red",
width:"200px",
height:"100px"
})
};
</script>
</head>
<body>
<div id="dv">
</div>
</body>
</html>
闭包的概念
闭包介绍
在 JavaScript 中,闭包是指 有权访问另一个函数作用域中的变量的函数,即使这个另一个函数已经执行完毕。
简单的说,闭包就是函数内部的函数,并且内部函数可以访问外部函数的变量,形成一个相对封闭的环境。
类似这个:
function outerFunction() {
var outerVariable = "I'm outside!";
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
var closureExample = outerFunction();
closureExample(); // 输出: I'm outside!
此时,innerFunction 就是一个闭包。
闭包是怎么来的
闭包产生源于 JavaScript 的词法作用域和函数嵌套的特性。
词法作用域:JavaScript 采用词法作用域(静态作用域),意味着函数的作用域在函数定义的时候就已经确定了,不是在函数执行的时候再确定。
函数嵌套:JavaScript 允许函数内部再定义函数。
例子:
function createCounter() {
var count = 0;
return function() {
count++;
console.log(count);
};
}
var counter = createCounter();
counter(); // 输出: 1
counter(); // 输出: 2
为什么会有闭包
闭包应运而生是为了满足如下几种编程需求:
数据隐藏和封装、状态保持(多次函数调用之间保持某个状态的值 );
闭包能用来干嘛
1.实现私有变量和函数
通过闭包可以将一些变量和函数隐藏起来,只对外提供有限的访问接口,实现类似面向对象编程中私有成员的效果,提高代码的安全性和可维护性。
2.计数器和累加器
可以用来制作简单的计数器、累加器等,能够在多次调用闭包函数时能够保持一个变量的状态,实现计数或者累加的功能。
3.事件处理
在时间处理会经常用到闭包。例如,当给多个按钮添加点击事件时,可以利用闭包来保存每个按钮的相关信息,以便在点击事件发生时能够准确地处理与该按钮相关的事情。
var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
(function(j) {
buttons[j].addEventListener('click', function() {
console.log('Button ' + (j + 1) + ' was clicked');
});
})(i);
}
闭包的应用和案例
模拟私有成员、斐波那契数列、html 字符串案例、方法的追加和移除、获得选中列表序号
闭包的劣势与处理方法
每个函数实例管理着自己的作用域和闭包,如果特定作用域不需要使用闭包的话,在其他函数中不必要的创建函数很不明智,函数多了内存和运行速度自然不行。
函数调用形式
函数字面量和Function()
构造函数的主要区别在于:
- 函数字面量允许递归,因为它们有自己的名称,而
Function()
构造函数创建的函数无法自我引用。 Function()
构造函数在运行时编译,效率较低,而函数字面量在解析时编译,执行效率更高。Function()
构造函数不遵循正常的作用域规则,它总是在全局作用域内执行。
js 函数中的四种调用形式
函数调用
this 表示全局对象,在文本中你即 window
这是最常见的调用方式,直接使用函数名后跟一对圆括号来调用函数。如果函数需要参数,可以在圆括号内传递相应的参数。
function sayHello(name) {
console.log("Hello, " + name);
}
sayHello("Alice"); // 输出: Hello, Alice
方法调用
this 表示当前对象
当一个函数作为对象的方法被调用时,称为方法调用。在这种情况下,函数内部的
this
关键字指向该对象。
const person = {
name: "Bob",
greet: function() {
console.log("Hello, " + this.name);
}
};
person.greet(); // 输出: Hello, Bob
构造器调用(constructor innovation)
this 表示当前创建对象
使用
new
关键字调用函数,这种调用会创建一个新的对象,并将这个对象的原型链指向函数的prototype属性。这种方式通常用于创建具有特定属性和方法的对象实例。
function Person(name) {
this.name = name;
}
const alice = new Person("Alice");
console.log(alice.name); // 输出: Alice
apply 与 call 调用
上下文调用,this 可以根据参数自定义
这些方法允许你指定函数调用时的
this
值,以及传递参数的方式。
call
方法接受一个参数列表,第一个参数是this
的值,后续参数是传递给函数的参数。apply
方法与call
类似,但它接受一个参数数组。bind
方法返回一个新的函数,永久地绑定了this
值和初始参数。
function introduce(greeting, punctuation) {
console.log(greeting + ', ' + this.name + punctuation);
}
const bob = { name: "Bob" };
introduce.call(bob, "Hi", "!"); // 输出: Hi, Bob!
introduce.apply(bob, ["Hello", "?"]); // 输出: Hello, Bob?
const boundIntroduce = introduce.bind(bob, "Hey", "!!");
boundIntroduce(); // 输出: Hey, Bob!!
面向对象与原型
对象,即键值对
方法,即值为函数的属性
原型,即对象继承实体
js 中原型是实现面向对象编程的一种重要机制,每个对象都有一个原型(__proto__ 属性,虽然不建议直接使用这个属性,更规范的是使用 Object.getPrototypeOf()等方法来获取原型),原型本身也是一个对象,他包含了可以被其他对象共享的属性和方法。
代码复用上:
将一些通用的属性和方法放在原型上,可以让多个对象共享这些资源,避免重复定义。
可以把一个特定方法放到一个共同原型上,让所有相关构造函数创建的动物对象都可以使用这个方法,不用每个对象都单独定义一次“sleep”方法。
继承与原型
JavaScript 使用原型继承
继承是面向对象编程中的一个关键特性,它允许一个类(在 JavaScript 中,更准确地说是构造函数创建的对象类型)获取另一个类的属性和方法,从而实现代码的复用和扩展。
每个对象都有一个原型,原型本身也是一个对象,它包含了可以被其他对象共享的属性和方法。我们可以把原型想象成一个模板,基于这个模板创建的对象可以继承它上面的属性和方法。
原型链继承
foo 是从 foo.prototype 继承来的
函数--生产--》原型
每一个对象都有一个属性叫 __proto__,这个 __proto__ 就是这个对象的原型
对象有原型,原型是对象,原型也有原型
js 成员的访问规则
成员.方法();
首先现在成员当前这个类型中寻找该成员的定义,如果存在该成员的定义,就直接用这个成员,不然就访问它的原型(也就是它的上一级),依次类推,直到 null,即 undefined
结语
目前js 的深入 部分就到此处了,如果其中有错误欢迎指出,如有帮助希望可以随手评论有用,毕竟其中有些内容是被csdn归为VIP可见。