**js高级知识点整理
-
实例对象中有一个属性叫__proto__, 叫原型, 也是对象.这个属性是浏览器使用, 不是标准的属性
构造函数中有一个属性叫prototype, 叫原型, 也是对象, 这是属性是程序员使用的,才是标准的属性
实例对象的__proto__和构造函中的prototype相等
又因为实例对象是由构造函数创建的
所以 实例对象的__proto__ 指向了构造函数中的原型对象1.通过原型添加方法
//需求: 点击换颜色
//1.体会面向过程
// document.getElementById("btn").onclick = function () {
// document.getElementById("box").style.backgroundColor = "red";
// }
//面向对象的思想
// 操作谁, 按钮, div, 换颜色
function Style(btnId, boxId, color) {
this.btnId = document.getElementById(btnId);
this.boxId = document.getElementById(boxId);
this.color = color;
}
//在原型中添加方法-----共享数据, 节省空间
Style.prototype.init = function () {
console.log(this);//指向的实例对象
var that = this;
//当函数嵌套时, this指向会发生变化. 解决: 使用变量储存
//点击按钮换颜色
console.log(this.btnId);
this.btnId.onclick = function () {
console.log(this.btnId);//this指向有问题
that.boxId.style.backgroundColor = that.color;
}
}
//实例化对象-----创建对象并初始化
var changeColor = new Style("btn", "box", "green");
var changeColor2 = new Style("btn1", "box1", "blue");
changeColor.init();
changeColor2.init();
console.log(changeColor);
2.简单的原型写法---缺少构造器
function Student(name, score) {
this.name = name;
this.score = score;
}
Student.prototype = {
//手动添加构造器
constructor: Student,
height:"180mm",
weight: "70kg",
study: function () {
console.log("学习使我快乐, 我要每天写5000行代码");
}
}
var stu1 = new Student("徐小小", "59分");
stu1.study();
console.dir(stu1);
3.//找属性, 先从实例对象中获取, 如果找不到, 去构造函数的原型对象上面去找
function Person(name, sex) {
this.name = name;
//this.sex = sex;
}
Person.prototype.sex = function () {
console.log("女");
return "女";
};
var per1 = new Person("小明", "男");
console.dir(per1);
var result = per1.sex();
console.log(result);
console.log(per1.sex());//
4.为内置对象添加方法—使用原型
//需求: 在字符串中有一个倒序字符串的方法
var string = new String();
String.prototype.daoStr = function () {
var ss = '';
for(var i = this.length - 1; i >= 0 ; i--){
ss += this[i];
}
return ss;
}
var str2 = new String("123456789");
console.log(str2.daoStr());
console.dir(str2);
5.局部变量变成全局变量
// 局部变量 变成 全局变量: 把局部变量暴露给window
//浏览器的顶级对象是: window
//js是一门动态类型语言
(function () {
var num = 10;
window.number = num;
})();
console.log(window.number);//window可以省略
console.log(number);//window可以省略
-
原型和原型链
原型链: 是实例对象和原型对象之间的关系. 是__proto__原型来链接的1.原型链最终指向哪里?
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.eat = function () {
console.log("六一要吃棒棒糖")
}
var per = new Person("徐小小","12岁");
per.__proto__.eat();
console.dir(per);
console.dir(Person.prototype.__proto__);// object
console.log(Object.prototype.__proto__);//Object是系统的构造函数, 里面就应该有prototype.又是对象, 那么对象里就应该有__proto__, 最终这个会指向null
var obj = new Object();
2.原型指向能不能改变
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.eat = function () {
console.log("六一要吃棒棒糖")
}
var per = new Person();
function Student() {
}
Student.prototype.study = function () {
console.log("六一要学习")
}
Student.prototype = new Person();//学生的原型, 指向了人的对象
var stu = new Student();
//他们之间没有任何. 想让他们有关系
//stu.study();//报错了
stu.eat();//能访问到. 因为指向已经改变. 所以能访问到人对象的方法
// 所以原型指向可以改变
3.原型指向改变后如何添加方法
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
play: function () {
console.log(this)
}
}
Person.prototype.eat = function () {
console.log(this)
console.log("六一要吃棒棒糖")
}
var per = new Person();
per.eat();//不报错 等会解释
per.play();
// 1.所以原型指向可以改变
// 2.原型指向改变后再添加方法
4.继承: 是一种关系,父类与子类的继承关系. 通过原型来实现继承. 继承也是为了数据共享(四种方法)
4.1 * .原型继承: 改变原型的指向
* 例子:
* 人--> 小明 有钱, 有名字, 有功夫
* 儿子-->小小明. 继承钱, 继承功夫, 继承姓氏
* */
function Person(name, money) {
this.name = name;
this.money = money;
}
Person.prototype.play = function () {
console.log("咏春 , 叶问")
}
var per = new Person("小明","100块")
function SmallPer(score) {
this.score = score;
}
SmallPer.prototype = new Person("小小明", "1块");
SmallPer.prototype.study = function () {
console.log("学习")
}
var xiaoxiaoming = new SmallPer("99分")
console.log(xiaoxiaoming.name, xiaoxiaoming.money, xiaoxiaoming.score);
xiaoxiaoming.study();
xiaoxiaoming.play();
4.2.借用构造函数继承: 改变构造函数属性的指向
为了数据共享.改变原型指向. 坐到了继承, 但是继承过来的属性值也是一样的.
改善方法:继承的时候不改变原型的指向. 直接调用父级的构造函数的方式来赋值. 叫借用构造函数
function Person(name, money) {
this.name = name;
this.money = money;
}
Person.prototype.play = function () {
console.log("咏春 , 叶问")
}
function Student(score, name, money) {
this.score = score;
//把父亲的构造函数借过来--->改变构造函数的指向, 继承属性
Person.call(this,name, money)
//this指的是当前函数的所创建出来的对象, 后面的参数是父亲的形参. 这个形参学生要用, 所以需要学生的构造函数的小括号接收一下;
}
var stu1 = new Student("33分","小明", "1块钱");
var stu2 = new Student("99分","小红", "99块钱");
console.log(stu1.name, stu1.score, stu1.money);
console.log(stu2.name, stu2.score, stu2.money);
stu1.play();//此时会报错
stu2.play();//此时会报错
4.3.组合继承: 原型继承 + 借用构造函数继承. 既能解决属性问题, 又能解决方法问题
function Person(name, money) {
this.name = name;
this.money = money;
}
Person.prototype.play = function () {
console.log("咏春 , 叶问")
}
function Student(score, name, money) {
this.score = score;
//把父亲的构造函数借过来--->改变构造函数的指向, 继承属性
Person.call(this,name, money)
//this指的是当前函数的所创建出来的对象, 后面的参数是父亲的形参. 这个形参学生要用, 所以需要学生的构造函数的小括号接收一下;
}
//改变原型指向继承方法
Student.prototype = new Person();
var stu1 = new Student("33分","小明", "1块钱");
var stu2 = new Student("99分","小红", "99块钱");
console.log(stu1.name, stu1.score, stu1.money);
console.log(stu2.name, stu2.score, stu2.money);
stu1.play();
stu2.play();
- 4.拷贝继承: 就是把对象中需要共享的属性和方法, 以遍历的方法复制到另一个对象
//拷贝继承: 就是把对象中需要共享的属性和方法, 以遍历的方法复制到另一个对象
function Person() {
}
Person.prototype.name = "lucy";
Person.prototype.sex = "boy";
Person.prototype.play = function () {
console.log("rap rap go go go");
}
var obj2 = {}
for(var key in Person.prototype){
obj2[key] = Person.prototype[key];
}
console.log(obj2);
- this指向的改变
1.call(this,参数1,参数2…参数n);
用法说明:①不传参数1, 或者只传一个null, 那么this还是 默认的window
function f1(x,y){
console.log(x+y,this);
}
f1(10,20);
f1.call(null,10,30);
f1.apply(null,[10,30]);
效果图
②传参数1,但参数1不等于null时,this指向传入的参数1所对应的对象
function f1(x,y){
console.log(x+y,this);
}
var obj={
age:19,
sex:"男"
}
f1.call(obj,10,30);
效果图
2.apply(this,参数1,参数2…参数n);
用法说明:①不传参数1, 或者只传一个null, 那么this还是 默认的window
function f1(x,y){
console.log(x+y,this);
}
f1.apply(null,[10,30]);
效果图
②传参数1,但参数1不等于null时,this指向传入的参数1所对应的对象
var obj={
age:19,
sex:"男"
}
f1.apply(obj,[10,30]);
效果图
3.bind(this,参数1,参数2…参数n)只是绑定this,不是调用的时候改变this
用法说明:①不传参数1, 或者只传一个null, 那么this还是 默认的window
function f1(x,y){
console.log(x+y,this);
}
var ff=f1.bind(null,10,20);//此时bind方法相当于复制了一份返回值给某个对象
console.log(ff);
console.log(ff());
//var ff=f1.bind(null);
// console.log(ff(10,20));//可以在复制的时候传入参数,也可以在复制之后传参
效果图
②传参数1,但参数1不等于null时,this指向传入的参数1所对应的对象
function f1(x,y){
console.log(x+y,this);
}
function Person(name,age){
}
Person.prototype.eat=function(){
console.log("吃");
};
var per=new Person();
var fff=f1.bind(per);
fff(10,20);
var ff=f1.bind(per);
ff(100,200);
效果图
总结: 1.使用一个函数需要改变this指向
1.1.传递的参数不多,使用fn.call(需要指向的对象,参数1,参数2…)
1.2.传递的参数教多,使用fn.apply(需要指向的对象,[参数1,参数2…])
1.3.只想将函数长期的绑定给某一个对象使用fn.bind(需要指向的对象,参数1,参数2…)
- 函数
1.函数的几个参数
function f1(x, y) {
console.log(f1.arguments.length);//实参的个数
console.log(f1.length);//形参的个数
console.log(f1.name);//函数名
console.log(f1.caller);//f1的调用者是f2
}
f1.name = "fff";//不能修改
f1(10, 20, 30, 40);
function f2() {
f1(1,2)
}
f2();
console.dir(f1);
2.高阶函数之函数作为参数
function f1(fn) {
fn();
}
//传匿名函数
f1(function () {
console.log("我是匿名函数");
});
//传有名函数
function f3() {
console.log("我是有名函数");
}
f1(f3);//f3不要带小括号
3.高阶函数之函数作为返回值
function f1() {
console.log("f1函数的开始");
return function () {
console.log("哈哈哈哈");
}
}
var ff = f1();
console.log(ff);
ff();
4.*闭包
闭包的概念: 函数a中, 有一个函数b, 函数b可以读取函数a中定义的变量. 就形成了闭包
闭包就是将函数内部和函数外部链接起来的桥梁
闭包的作用: 缓存数据, 延长作用域链
优点及缺点: 缓存数据,延长作用域链(缺点: 就是因为缓存数据,导致变量不能及时的释放, 延长了作用域链)
//函数的闭包
// function f1() {
// var num = 10;
// function f2() {
// console.log(num);
// }
// f2();
// }
// f1();
//
// //对象的闭包
// function ff() {
// var age = 30;
// return {
// age:age
// }
// }
// var result = ff();
// console.log(result.age);
闭包的练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>点赞案例</title>
<style>
ul {
list-style-type: none;
}
li {
float: left;
margin-left: 10px;
}
img {
width: 200px;
height: 180px;
}
input {
margin-left: 30%;
}
</style>
</head>
<body>
<ul>
<li><img src="images/1.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="images/2.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="images/3.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="images/4.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
</ul>
<script>
var btns = document.getElementsByTagName("input");
for (var i = 0 ; i < btns.length ; i++) {
//var index = 1;
btns[i].onclick = getValue();
}
function getValue() {
var index = 1;
return function clickHandle() {
this.value = "赞(" + (++index) + ")";
}
}
</script>
</body>
</html>
5.沙箱-----函数的自调用
//沙箱: 独立, 虚拟的环境. 可以在环境中模拟真实的世界. 所做的实验结果和真实的世界的结果是一样的, 但是不会影响
var num = 10;
//这就是沙箱环境
(function () {
var num = 100;
console.log()
})();
console.log(num);
6.递归: 函数中调用自己
//求斐波那契数列 1、1、2、3、5、8、13, 21, 34,55, 89, 144
function getFib(x) {
if(x == 1 || x == 2){
return 1;
}
//后一个数 = 前两个数的和
return getFib(x - 1) + getFib(x - 2);
}
console.log(getFib(12));
- cookie : 用于储存页面的用户信息
- 例子: 自动登录, 记住用户名
- 特征: 1. 同一个网站的所有页面共享一套cookie
-
2. 数量大小有限 一般是4k . 只能文本 1m = 1024k, 1k = 1000多个字节(字母)或者500多汉字
-
3.有过期时间 ①临时性质的 cookie ②设置失效的时间的cookie
- */
- 1.临时的cookie
//1.在文档中创建cookie document.cookie = "名字=值"; 以键值对的方式来写
//①创建临时cookie----->关闭浏览器消失, 跟注释没关系
//document.cookie = "username1=张三";
//alert(document.cookie);
2.有失效时间的cookie
//②设置失效的时间的cookie(3天之后过期) document.cookie = "名字=值;expires=过期时间";
var dt = new Date();
//设置日期 setDate()
dt.setHours(dt.getHours() - 8);//获得的时间是国际时间,和我国相差八小时
dt.setMinutes(dt.getMinutes() + 1);
//console.log(dt);
// document.cookie = "username=胡小歌;expires="+dt;
// document.cookie = "username1=霍建华;expires="+dt;
// document.cookie = "username2=彭于晏;expires="+dt;
//document.cookie = "username3=彭于晏;expires="+dt;
alert(document.cookie);