构造函数、原型、继承原来这么简单?来吧,深入浅出

构造函数

小编上篇博客中介绍到的通过关键字class方式定义类,然后根据类再创建对象的方式,是ES6中语法,现在很多浏览器对ES6的支持还不是很好,所以也要学习通过构造函数(构建函数)的方式创建对象

问?既然浏览器对ES6的支持不是很好,是不是编写代码时不要使用ES6语法呢?(看完这篇文章你就有答案了)

1.构造函数和原型

1.1对象的三种创建方式–复习

  1. 字面量方式

    var obj = {};
    
  2. new关键字

    var obj = new Object();
    
  3. 构造函数方式

    function Person(name,age){this.name = name;this.age = age;
    }
    var obj = new Person('zs',12);
    

说明:

构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员的值进行初始化,其与new一起使用用于创建对象

这里所说的构造函数与前面讲的类中的构造函数不太一样,类中的构造函数主要是给类中的属性赋值,这里的构造函数中,既可以包属性,也可以包含方法,与上面所说的类的概念更接近,可以看成是J S 彻底向面向对象转变过程中的一种过度,四不像

所以在编写构造函数时,可以参考类的定义方式,将对象的一些公共的属性和方法抽象出来,然后封装到这个函数中

如下面分别使用ES6中的class和ES5中的构造函数的方式生成实例对象

		/**ES6 中创建对象的方法:先使用class关键字创建类,然后使用 new 类名() 的方式创建类的对象*/class Person {constructor(name, age) {this.name = namethis.age = age}speak(){console.log('哇哇哇哇哇哇哇')}}// 创建类的对象var p1 = new Person('李白', 20)// 访问类中的属性console.log(p1.name)p1.speak()console.log('---------------------')/**ES5 中创建对象的方法:先创建构造函数,然后使用 new 函数名称() 的方式创建这个函数的对象*/function Star(name, gender) {this.name = namethis.gender = genderthis.sing=function(){console.log('小呀嘛小二郎')}}// 通过构造函数创建对象var s1 = new Star('杜甫', '男')console.log(s1.gender)s1.sing()

图解

在这里插入图片描述

注意两点

1)构造函数首字母大写,就给使用class创建类一样

2)与new关键字一起使用,这更与class一样

3)最为重要的一点是:类的编写方法更像是语法糖,目的是让我们能够快速、舒服、优雅的编写类,但是从本质上来说,类其实就是函数。初学者可能感觉不到 class 方式定义类相较于 构造函数的优势:1)没有体会到通过构造函数的方式实现继承的痛苦,所以无法理解通过 ES6 中 extends 实现继承的优势; 2)没有见识过传统的面向变成语言

console.log(typeof Person);
console.log(typeof FPerson);

结果

在这里插入图片描述

new的解释

在内存中创建一个新的空对象

让this指向这个对象,所以在代码中使用this,就是使用这个对象,this 跟类没有关系

执行构造函数中的代码,给这个对象添加属性和方法,但是方法中的代码不会执行

1.2静态成员和实例成员

1.2.1实例成员

实例成员就是构造函数内部通过this添加的成员 如下列代码中 name age sing 就是实例成员,实例成员只能通过实例化的对象来访问

  /*通过this添加的成员就是实例成员1)实例成员只能通过对象.成员的方式访问2)实例成员与每个对象相关,也就是每个对象的成员的值是不一样的*/function Star(name, gender) {this.name = namethis.gender = genderthis.sing = function () {console.log('小呀嘛小二郎')}}// 通过构造函数创建对象var s1 = new Star('杜甫', '男')var s2 = new Star('蔡徐坤', '女')console.log(s1.gender)console.log(s2.gender)// 实例成员不能通过 【构造函数名称.成员】 的方式访问// console.log(Star.gender) // undefined

这点与ES6中 class 创建的类是一样的

class Star {constructor(uname, age) {this.uname = unamethis.age = age}sing() {console.log('我会唱歌')}
}var ldh=new Star('刘德华',17)
console.log(ldh.uname)

1.2.2静态成员

静态成员 在构造函数本身上添加的成员 如下列代码中 就是静态成员,静态成员只能通过构造函数来访问

在这里插入图片描述

这与通过 class 关键字定义类时一样的

总结:

实例成员属于对象,所以两个对象的实例成员的值不一样

静态成员,属于构造函数本身,每个对象都属于这个构造函数,所以多个对象共享一个静态成员

1.3构造函数的问题

构造函数方法很好用,但是存在浪费内存的问题。

在这里插入图片描述

1.4构造函数原型prototype

构造函数通过原型分配的函数是所有对象所共享的。

JavaScript 规定,每一个构造函数都有一个prototype 属性,指向另一个对象。注意这个prototype就是一个对象,叫做原型对象

ES6 中的类也是一样,因为我们说过,类从本质上来讲,也是一个函数

        function Star(name, gender) {this.name = namethis.gender = genderthis.sing = function () {console.log('小呀嘛小二郎')}}console.log(Star.prototype)

在这里插入图片描述

这个对象的所有属性和方法,都会被构造函数所拥有

function Star(name, gender) {this.name = namethis.gender = genderthis.sing = function () {console.log('小呀嘛小二郎')}}// 为Star的原型对象添加方法(相当于将方法添加到Star的父类上去)Star.prototype.cry=function(){console.log('我要cry,cry,cry,cry,cry')}Star.prototype.dance=function(){console.log('一步一步,似魔鬼的步伐')}// 通过输出发现,原型对象上确实有了 cry 方法console.log(Star.prototype)// 那么作为原型对象的子类的 Star 构造函数自然就拥有了cry 方法var s1 = new Star('杜甫', '男')s1.cry()s1.dance()var s2 = new Star('蔡徐坤', '女')s2.cry()s2.dance()

还可以使用对象的方式为原型添加多个方法

我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

解惑:

1)这个原型,就类似于其他语言中的基类。。。。

2)不仅使我们自己使用构造函数或类定义的对象,JS中的内置对象的方法,其实都定义在这个对象的原型对象上

var arr=[]
// 查看对象的原型对象使用 __proto__ 属性
console.log(arr.__proto__)
// 查看构造函数或类的原型对象使用 prototype 属性
console.log(Array.prototype)
// 总结:对象的__proto__ 属性和 类或者构造函数的 protptype 属性指向的是同一个对象

1.5对象原型

构造函数的prototype 属性获取的是当前构造函数的原型对象
构造函数的实例的__proto__属性获取的是当前对象的对象原型
这两者是一个对象,也就是说构造函数的原型对象与此构造函数的实例的对象原型是一个对象

在这里插入图片描述

在这里插入图片描述

 function Star(name, gender) {this.name = namethis.gender = genderthis.sing = function () {console.log('小呀嘛小二郎')}}// 为Star的原型对象添加方法(相当于将方法添加到Star的父类上去)Star.prototype.cry = function () {console.log('我要cry,cry,cry,cry,cry')}Star.prototype.dance = function () {console.log('一步一步,似魔鬼的步伐')}// 通过输出发现,原型对象上确实有了 cry 方法console.log(Star.prototype)// 那么作为原型对象的子类的 Star 构造函数自然就拥有了cry 方法var s1 = new Star('杜甫', '男')// s1.cry()// s1对象的 __proto__属性获取是的是s1对象的对象原型console.log(s1.__proto__)// 验证构造函数的原型对象与实力的对象原型是一个对象console.log(Star.prototype===s1.__proto__)

1.6constructor构造函数

对象原型( proto)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性(因为两个其实是一个东西) ,constructor 我们称为构造函数,因为它指回构造函数本身。

下面通过代码理解

        function Star(name, gender) {this.name = namethis.gender = genderthis.sing = function () {console.log('小呀嘛小二郎')}}      var s1 = new Star('杜甫', '男')// 输出构造函数的原型对象console.log(Star.prototype)// 输出对象的对象原型console.log(s1.__proto__)

在这里插入图片描述

通过上面的代码,我们看到,constructor 属性的值确实是这个对象对应的构造函数

不仅可以通过这个属性,获取原型对象所属的构造函数,constructor属性 还可以让原型对象重新指向原来的构造函数

一般情况下,对象的方法都在构造函数的原型对象中设置。

如下面这样

// 为构造方法的原型对象中添加speak 方法
Person.prototype.speak=function(){console.log('人类说话')
}

但是如果加入多个方法,使用上面的方式就比较麻烦

function Star(name, gender) {this.name = namethis.gender = gender
}
// 像原型添加sing方法
Star.prototype.sing = function () {console.log('红星闪闪放光彩');
}
// 向原型添加 dance 方法
Star.prototype.dance = function () {console.lo('魔鬼的步伐')
}
// 向原型添加fly
Star.prototype.fly = function () {console.log('上了飞机就拖鞋')
}

像上面这样,如果要添加多个方法,我们可以给原型对象采取对象形式赋值,如下面的代码

Star.prototype = {sing: function () {console.log('红星闪闪放光彩');},dance: function () {console.lo('魔鬼的步伐')},fly: function () {console.log('上了飞机就拖鞋')}
}

但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了

此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

在这里插入图片描述

结果

在这里插入图片描述

总结:如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数如:

完整代码

function Star(name, gender) {this.name = namethis.gender = gender
}        
Star.prototype = {construcotr:Star,sing: function () {console.log('红星闪闪放光彩');},dance: function () {console.lo('魔鬼的步伐')},fly: function () {console.log('上了飞机就拖鞋')}
}
console.log(Star.prototype)

1.7原型链

​ 每一个实例对象又有一个__proto__属性,指向的构造函数的原型对象,构造函数的原型对象也是一个对象,也有__proto__属性,这样一层一层往上找就形成了原型链。

可以类比基类,基类就是Object

其实所有的自定义的或者系统内置的构造函数或者类的最顶级的对象原型都是 Object

在这里插入图片描述

1.8构造函数实例和原型对象三角关系

1.构造函数的prototype属性指向了构造函数原型对象,构造函数的原型对象的constructor属性指向了构造函数

function Star(name, age) {this.name = namethis.age = age
}
// 获取输出构造方法的原型对象
console.log(Star.prototype)
// 获取并输出原型对象的构造函数
console.log(Star.prototype.constructor)
// 证明原型对象的constructor属性确实获取的是对应的构造函数
console.log(Star.prototype.constructor===Star)

2.实例对象是由构造函数创建的,实例对象的__proto__属性指向了构造函数的原型对象

// 实例对象由构造函数创建
var s1=new Star('肖战',18)
// 实例对象的__proto__属性指向了对应构造函数的原型对象
console.log(s1.__proto__)

3.构造函数的原型对象的constructor属性指向了构造函数,实例对象的原型就是构造函数的原型对象,此对象中有constructor属性也指向了构造函数

在这里插入图片描述

重要说明:上面所说的理论同样适用于ES6中

class Star {constructor(name){this.name=name}
}
var s=new Star('yhb')
console.log(Star.prototype)
console.log(s.__proto__)

1.9原型链和成员的查找机制

任何对象都有原型对象,也就是prototype属性,任何原型对象也是一个对象,该对象就有__proto__属性,这样一层一层往上找,就形成了一条链,我们称此为原型链;

当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。
如果还没有就查找原型对象的原型(Object的原型对象)。
依此类推一直找到 Object 为止(null)。
__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。

1.10原型对象中this指向

构造函数中的this和原型对象的this,都指向我们new出来的实例对象

1、构造函数中的this指向的就是new出来的对象

function Star(name, age) {this.name = namethis.age = ageconsole.log(this)
}
var s1=new Star('李白',20)
var s2=new Star('杜甫',17)

在这里插入图片描述

2、构造函数的原型对象上的this指向的也是new出来的对象

function Star(name, age) {this.name = namethis.age = ageconsole.log(this)
}
Star.prototype.sing=function(){console.log(this)
}
var s1=new Star('李白',20)
var s1=new Star('杜甫',17)

在这里插入图片描述

通过下面的代码也可以比较两个到底是不是都只想了 new 出来对象

 function Star(name, age) {this.name = namethis.age = age            }var that = null// 构造函数的原型对象中的thisStar.prototype.sing = function () {that = this}var s1 = new Star('李白', 20)// 韩炳旭说:sing方法一定要调用,否则无法执行赋值操作s1.sing()console.log(that === s1)

1.11通过原型为数组扩展内置方法

查看数组的原型

 console.log(Array.prototype);

为数组扩展和一个方法,可以计算数组中元素的和

 var numbers = new Array(1, 2, 3, 4, 5)// 传统方法求和// var sum = 0// for (var i = 0; i < numbers.length; i++) {//     sum += numbers[i]// }// 通过改变原型Array.prototype.sum = function () {var sum = 0for (var i = 0; i < this.length; i++) {sum += this[i]}return sum}console.log(numbers.sum())// 再创建一个数组,使用[]方式创建的也是Array类的实例var arr=[2,3,4,7]console.log(arr.sum())console.log(Array.prototype)

2.继承

在ES6之前,没有extends 关键字实现类的继承,需要通过构造函数+原型对象的方式模拟实现继承,这种方式叫做组合继承

2.1call()

  • call()可以调用函数
  • call()可以修改this的指向,使用call()的时候 参数一是修改后的this指向,参数2,参数3(普通参数)…使用逗号隔开连接

下面代码单纯的调用函数

function f1() {console.log(this) //window
}
f1.call()

下面代码修改this的指向

  function f1() {/**1)默认情况下,this=window*2)使用call修改后,this=p*/console.log(this) }f1.call() // 输出window// 创建对象pvar p={}// 将函数f1的this指向修改为对象pf1.call(p) // 输出p

上面call 方法的第一个参数就是this引用的新对象,后面的参数作为函数 f1 的普通参数

代码演示

2.2子构造函数继承父构造函数中的属性

下面利用上面讲到的知识实现构造函数的继承(所谓继承,就是让一个类拥有另一个类中的属性和方法,换言之,就是将A类中的属性和方法的宿主换成B的对象)

步骤如下

  1. 先定义一个父构造函数
  2. 再定义一个子构造函数
  3. 子构造函数继承父构造函数的属性(使用call方法)

在这里插入图片描述

通过调试证明上面的结论

上面的案例只演示了属性的继承,方法的继承是一样的

在这里插入图片描述

2.3借用原型对象继承方法

上面的方式,可以继承构造函数(为了简单,以后我们称其为类)中的方法,但前面讲过,实际开发中,我们更喜欢将方法注册到类的原型上

function Father(name, age) {this.name = namethis.age = age}Father.prototype.speak = function () {console.log('hello')}function Son(gender) {// 注释 ①Father.call(this, '张三', 20)this.gender = gender}var f=new Father('yhb',30)console.log(f)        var s = new Son('女')console.log(s)

输出结果

在这里插入图片描述

所以,Son 的对象中就没有 speak 方法

其实原因很简单,在Father的原型对象上添加了speak方法,那么Father会继承这个方法,但当前 Son与Father以及Father的原型并没有任何关系,我们只不过通过 call 方法巧妙的使用了其 name和age 属性而已,所以Son中自然没有speak 方法

如何解决呢?

我们可以修改Son的原型为Father的原型,这样的话Son就拥有了speak 方法

在这里插入图片描述

输出结果

在这里插入图片描述

我们发现,Son中确实拥有了speak 方法

但是问题也随之出现,因为 Father 与 Son 此时的原型对象是一个,所以此时我们如果想 Son的原型对象上添加一个方法

 Son.prototype.run=function(){console.log('run')}

再分别输出两个对象

在这里插入图片描述

这就违反了继承的原则:只能儿子继承父亲的,但现在是父亲也能继承儿子的

解决方案:将下面的代码

Son.prototype=Father.prototype

替换成下面这个

 Son.prototype=new Father()

也就是让Son的原型对象指向 Father 的对象实例,这个实例的 proto 属性指向Father的对象原型,所以其中具有speak方法,但这仅仅是一个实例对象,就想从Father类拷贝了一份,修改此对象的原型,不会影响ather类的对象,所以修改此实例,不会影响到Father 的原型对象

稍微有点小问题就是,此时 Son的构造函数指向的是Father的构造函数了

console.log(s.constructor)

在这里插入图片描述

使用下面的代码再将其构造函数指回Son的构造函数

 Son.prototype.constructor=Son

在这里插入图片描述

完整代码

 /* 利用call 实现构造函数的继承*/function Father(name, age) {this.name = namethis.age = age}Father.prototype.speak = function () {console.log('hello')}function Son(gender) {// 注释 ①Father.call(this, '张三', 20)this.gender = gender}Son.prototype=new Father()// 修改Son的构造函数为SonSon.prototype.constructor=Son// 像Son的原型对象中添加一个方法Son.prototype.run=function(){console.log('run')}//var f=new Father('yhb',30)// console.log(f)        var s = new Son('女')console.log(s)console.log(s.constructor)

图解:

3.ES5新增方法

关于 ECMAScript 与 JS 的关系,以及 ES 各个版本,大家可以自行百度,小编在这里不做展开说明

ES6 是在ES5的基础上升级,所以先学习ES5新增的特性,后面再学习ES6新增的特性

3.1数组方法forEach遍历数组

此方法用来便利数组,参数为一个函数

以后再想便利数组就不用自己编写循环了

var numbers = [1, 3, 5, 7, 9]
numbers.forEach(function (item, index, ary) {console.log('元素:' + item);console.log('索引:' + index);console.log('数组本身:' + ary);
})

案例:数组求和

var sum=0
numbers.forEach(function(item){sum+=item
})
console.log(sum)

3.2数组方法filter过滤数组

此方法有一个返回值,用于接收所有符合过滤条件的元素,返回值的类型为数组

var numbers = [1, 2, 3, 4, 5, 6]
/*下面代码从数组numbers中筛选出所有>4的元素,然后放到新数组result中注意:一定要有return 关键字*/
var result = numbers.filter(function (item, index) {return item > 4
})
console.log(result);

输出结果

在这里插入图片描述

3.3数组方法some


some 查找数组中是否有满足条件的元素 var arr = [10, 30, 4];var flag = arr.some(function(item,index,array) {//参数一是:数组元素//参数二是:数组元素的索引//参数三是:当前的数组return item < 3;});
console.log(flag);//false返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环

**some()** 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。

如果用一个空数组进行测试,在任何情况下它返回的都是false

语法:

arr.some(callback(element[, index[, array]])[, thisArg])

1)返回值为布尔值

2)找到满足条件的元素,就终止循环,不会继续向后查找

可以利用这个函数查询数组中是否存在某个值

 var numbers = [1, 2, 3, 4, 5, 6]function checkAvailability(arr, val) {var res = arr.some(function (element, index) {return element == val})return res}console.log(checkAvailability(numbers, 1))

3.4找水果案例

首先将数据定义在数组中,然后便利数组中的数据渲染到表格中,然后可以根据价格或者名称查询想吃的水果

  1. 定义数组对象数据

    var fruits = [{id: 001,title: '苹果',price: 5},{id: 001,title: '苹果',price: 5},{id: 002,title: '梨',price: 3},{id: 003,title: '香蕉',price: 6},{id: 004,title: '砂糖橘',price: 2}
    ]
    
  2. 使用forEach遍历数据并渲染到页面中

      var tbody = document.querySelector('tbody')fruits.forEach(function (item) {var tr = ` <tr><td>${item.id}</td><td>${item.title}</td><td>${item.price}</td></tr>`tbody.insertAdjacentHTML('beforeend',tr)})
    
  3. 根据价格筛选数据

    将筛选出的数据重新渲染到表中

    function setData(ary) {// 先删除以前的数据tbody.innerHTML = ''ary.forEach(function (item) {var tr = ` <tr><td>${item.id}</td><td>${item.title}</td><td>${item.price}</td></tr>`tbody.insertAdjacentHTML('beforeend', tr)})}// 根据价格过滤商品var btnPrice = document.querySelector('#btnPrice')var min_price = document.querySelector('#min_price')var max_price = document.querySelector('#max_price')btnPrice.addEventListener('click', function () {var result = fruits.filter(function (item) {return item.price >= min_price.value && item.price <= max_price.value})// 重新渲染数据setData(result)})
    
    1. 根据名称搜索数据
   // 根据名称搜索var btnTitle = document.querySelector('#btnTitle')var title = document.querySelector('#title')btnTitle.addEventListener('click', function () {var result = fruits.filter(function (item) {return item.title == title.value
})// 重新渲染表格setData(result)})

上面数组中,水果名称是唯一的

使用filter会便利每一个对象,然后比较,查询效率相对较低

find 方法只要查询到一个符合条件的就会停止,所以效率相对较高

 btnTitle.addEventListener('click', function () {// find 方法返回的不是数组,而是对象,所以要使用foreach,需要将// 返回的对象放到数组中var result = fruits.find(function (item) {console.log(item)return item.title == title.value})var arr = []arr.push(result)// 重新渲染表格setData(arr)})

完整代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}.box {width: 1000px;margin: 50px auto;}table,th,td {border: 1px solid #ccc;}table {width: 800px;border-collapse: collapse;text-align: center;margin-top: 20px;}th,td {padding: 5px 10px;}</style>
</head><body><div class="box"><label for="">价格</label><input type="text" id="min_price"><span>-</span><input type="text" id="max_price"><button id="btnPrice">搜索</button><label for="">名称</label><input type="text" id="title"><button id="btnTitle">搜索</button><table><thead><tr><th>编号</th><th>名称</th><th>价格</th></tr></thead><tbody></tbody></table></div><script>var fruits = [{id: 001,title: '苹果',price: 5},{id: 002,title: '桃子',price: 10},{id: 003,title: '梨',price: 3},{id: 004,title: '香蕉',price: 6},{id: 005,title: '砂糖橘',price: 2}]// 获取tbodyvar tbody = document.querySelector('tbody')setData(fruits)// 将数组中的数据渲染到表格中function setData(ary) {// 先删除以前的数据tbody.innerHTML = ''ary.forEach(function (item) {var tr = ` <tr><td>${item.id}</td><td>${item.title}</td><td>${item.price}</td></tr>`tbody.insertAdjacentHTML('beforeend', tr)})}// 根据价格过滤商品var btnPrice = document.querySelector('#btnPrice')var min_price = document.querySelector('#min_price')var max_price = document.querySelector('#max_price')btnPrice.addEventListener('click', function () {var result = fruits.filter(function (item) {return item.price >= min_price.value && item.price <= max_price.value})// 重新渲染数据setData(result)})// 根据名称搜索var btnTitle = document.querySelector('#btnTitle')var title = document.querySelector('#title')btnTitle.addEventListener('click', function () {// find 方法返回的不是数组,而是对象,所以要使用foreach,需要将// 返回的对象放到数组中var result = fruits.find(function (item) {console.log(item)return item.title == title.value})var arr = []arr.push(result)// 重新渲染表格setData(arr)})</script>
</body></html>

3.5some和forEach区别

  • 如果查询数组中唯一的元素, 用some方法更合适,在some 里面 遇到 return true 就是终止遍历 迭代效率更高
  • 在forEach和filter 里面 return 不会终止迭代

3.6 trim方法去除字符串两端的空格

var str = '   hello   '
console.log(str.trim()//hello 去除两端空格
var str1 = '   he l l o   '
console.log(str.trim()//he l l o  去除两端空格

3.7获取对象的属性名

Object.keys(对象) 获取到当前对象中的属性名 ,返回值是一个数组

 var obj = {id: 1,pname: '小米',price: 1999,num: 2000
};
var result = Object.keys(obj)
console.log(result)//[id,pname,price,num]

3.8Object.defineProperty

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty设置或修改对象中的属性

Object.defineProperty(对象,修改或新增的属性名,{value:修改或新增的属性的值,writable:true/false,//如果值为false 不允许修改这个属性值enumerable: false,//enumerable 如果值为false 则不允许遍历configurable: false  //configurable 如果为false 则不允许删除这个属性 属性是否可以被删除或是否可以再次修改特性
})	

利用上面的方法,我们可以在不为文本框添加事件的同时,将文本框的值与对象中的某个属性关联起来

var username=document.querySelector('#username')
var data = {}
Object.defineProperty(data, "title", {get: function () {return username.value},set: function (newValue) {username.value=newValue},enumerable: true,configurable: true
})

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你疏漏的 JS 函数硬核知识?这里帮你总结了

重点 更多前端知识 诚邀各位前端从事者爱好者加入前端大佬技术交流社区&#xff0c;本社区主要分享技术栈、个人心得、技术交流、问题解惑等前端体系交流 点击下方文字加入 前端大佬技术交流社区 1. 函数的定义和调用 1.1 函数的定义方式 方式1 函数声明方式 function 关键…

再见了 React、Angular,Vue3 才是 yyds

切记一定要看到最后&#xff01;&#xff01;&#xff01; 最近看到一篇文章上面是一作者资讯一位IT前辈&#xff0c;问他怎么看待工作 2 年的前端开发&#xff0c;月薪就高达 30k、40k 的现状。 他说&#xff0c;在众多编程技术中&#xff0c;前端算比较容易入门和提升的&am…

系统带你学习 WebAPIs 第一讲

Web APIs 本篇学习目标&#xff1a; 能够通过ID来获取元素 能够通过标签名来获取元素 能够通过class来获取元素 能够通过选择器来获取元素 能够获取body和html元素 能够给元素注册事件 能够修改元素的内容 能够区分innerText和innerHTML的区别 能够修改像div这类普通元素的属性…

react-webpack config webpack@3.4.1

1.最重要的一点 yarn add webpack3.4.1 -g 2. 解决跨域请求 webpack.json 中添加 https://segmentfault.com/q/1010000008190876?_ea1579884 webpack config less -----框架 ----查看考链接 https://blog.csdn.net/mjzhang1993/article/details/79013430转载于:https://w…

系统带你学习 WebAPIs 第二讲

Web APIs 本篇学习目标&#xff1a; 能够说出排他操作的一般实现步骤 能够使用html5中的dataset方式操作自定义属性 能够根据提示完成百度换肤的案例 能够根据提示完成全选案例 能够根据提示完成tab栏切换案例 能够区分元素节点、文本节点、属性节点 能够获取指定元素的父元素 …

Python爬虫学习笔记1:request、selenium、ChromeDrive、GeckoDriver等相关依赖安装

系列学习笔记参考&#xff1a;python3网络爬虫开发实战 requests # pip install requests import requestsselenium Selenium是一个自动化测试工具&#xff0c;利用它我们可以驱动浏览器执行特定的动作&#xff0c;如点击、下拉等 操作 。 对于一些 JavaScript谊染的页面来说&a…

系统带你学习 WebAPIs 第三讲

Web APIs 本篇学习目标&#xff1a; 能够使用removeChild()方法删除节点 能够完成动态生成表格案例 能够使用传统方式和监听方式给元素注册事件 能够说出事件流执行的三个阶段 能够在事件处理函数中获取事件对象 能够使用事件对象取消默认行为 能够使用事件对象阻止事件冒泡 能…

系统带你学习 WebAPIs 第四讲

Web APIs 本篇学习目标&#xff1a; 能够说出常用的3-5个键盘事件 能够知道如何获取当前键盘按下的是哪个键 能够知道浏览器的顶级对象window 能够使用window.onload事件 能够使用window.onresize事件 能够说出两种定时器的区别 能够使用location对象的href属性完成页面之间的跳…

系统带你学习 WebAPIs 第五讲

Web APIs 本篇学习目标: 能够说出常见 offset 系列属性的作用 能够说出常见 client 系列属性的作用 能够说出常见 scroll 系列属性的作用 能够封装简单动画函数 **1.1. **元素偏移量 offset 系列 1.1.1 offset 概述 offset 翻译过来就是偏移量&#xff0c; 我们使用 offset系…

有赞美业微前端的落地总结

2020年4月&#xff0c;有赞美业的前端团队历经7个月时间&#xff0c;完成了美业PC架构从单体SPA到微前端架构的设计、迁移工作。PPT在去年6月份就有了&#xff0c;现在再整理一下形成文章分享给大家。 头图 目录 Part 01 “大话”微前端 微前端是什么 背景 目标 达成价值 …

Markdown 编辑器才是yyds|CSDN编辑器测评

前言 今天小编为大家介绍一款编辑器&#xff0c;也正是小编书写这篇文章所使用的Markdown编辑器&#xff0c;正是广大博友想要发布文章的工具。那么 你知道他的都有哪些方便之处么 下面小编带你了解一下 Markdown是什么 Markdown是一种轻量标记语言,通过简单的语法&#xff…

45天带你玩转Node(第三天)Node环境安装

本篇目标 能够搭建 Node 运行环境掌握 NodeJS 程序的运行方法理解模块化开发理解系统模块和第三方模块理解package.json文件作用 1.Node 开发概述 1.1为什么要学习服务器端开发技术 前端人员为什么要学习服务器端开发技术&#xff1f; 能够和后端程序员更加紧密的配合网站…

系统带你学习 WebAPIs —— 动画篇(第六讲)

Web APIs 本篇学习目标: 能够封装简单动画函数 能够理解缓动动画的封装 能够使用动画函数 能够写出网页轮播图案例 能够写出移动端触屏事件 1.1. 动画函数封装 1.1.1 缓动效果原理 缓动动画就是让元素运动速度有所变化&#xff0c;最常见的是让速度慢慢停下来 思路&#xff…

Git使用教程:最详细、最傻瓜、最浅显、真正手把手教!(转载学习)

一&#xff1a;Git是什么&#xff1f; Git是目前世界上最先进的分布式版本控制系统。 二&#xff1a;SVN与Git的最主要的区别&#xff1f; SVN是集中式版本控制系统&#xff0c;版本库是集中放在中央服务器的&#xff0c;而干活的时候&#xff0c;用的都是自己的电脑&#xff0…

有些话别不当回事

1、别跟堕落的人比堕落。堕落起来非常容易&#xff0c;可是堕落后再想回到不堕落&#xff0c;难。不要给自己颓废的机会。 2、不要以为躲在学校里就可以忽略外面世界的残酷现实。竞争越来越激烈&#xff1a;人越来越多&#xff0c;职位却越来越少。学校里固然温柔&#xff0c;但…

梯度下降更新算法

梯度更新是要同时更新&#xff0c;如下图所示&#xff1a;θ0和θ1同时更新&#xff0c;而不是更新完一个后再更新另一个。 学习率α过小&#xff0c;梯度下降较慢&#xff0c;训练时间增长。若学习率α过大&#xff0c;梯度下降会越过最低点&#xff0c;难以得到最优的结果&am…

《深入理解Spark-核心思想与源码分析》(四)第四章存储体系

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。——《易经》 本章导读 Spark的初始化阶段、任务提交阶段、执行阶段&#xff0c;始终离不开存储体系。 Spark为了避免Hadoop读写磁盘的I/O操作成为性能瓶颈&#xff0c;优先将配置信息、计算结…

Django打造大型企业官网-项目部署

Django打造大型企业官网-项目部署 一、准备工作 1、在开发机上的准备工作 1&#xff09;确认项目没有bug。 2&#xff09;打开终端&#xff0c;进入虚拟环境&#xff0c;再 cd 到项目根目录下&#xff0c;执行命令&#xff1a;pip freeze > requirements.txt&#xff0c;将…

17 | 如何正确地显示随机消息?

我在上一篇文章&#xff0c;为你讲解完order by语句的几种执行模式后&#xff0c;就想到了之前一个做英语学习App的朋友碰到过的一个性能问题。今天这篇文章&#xff0c;我就从这个性能问题说起&#xff0c;和你说说MySQL中的另外一种排序需求&#xff0c;希望能够加深你对MySQ…

QT+VS中使用qDebbug()打印调试信息无法显示

首先右键点击项目名称&#xff0c;找到最后一项属性 然后依次设置为如图所示即可 再次编译后&#xff0c;会弹出CMD窗口&#xff0c;出现qDebug的调试信息。 转载于:https://www.cnblogs.com/WindSun/p/10328404.html